Code

frontend: Handle STARTUP and PING commands.
authorSebastian Harl <sh@tokkee.org>
Sat, 23 Nov 2013 08:50:50 +0000 (09:50 +0100)
committerSebastian Harl <sh@tokkee.org>
Sat, 23 Nov 2013 08:52:39 +0000 (09:52 +0100)
Implemented an initial, trivial "framework" for session handling /
authentication. Simply send back OK status for now.

Fixed preconditions for initialization and handling of commands.

src/Makefile.am
src/frontend/connection.c
src/frontend/session.c [new file with mode: 0644]
src/include/frontend/connection.h

index 24b41ae51bedb40ba510eccb7f0f75d1731ce792..32c493e56900702d702838f4473825d5a4a582c6 100644 (file)
@@ -28,6 +28,7 @@ libsysdb_la_SOURCES = \
                core/error.c include/core/error.h \
                frontend/connection.c include/frontend/connection.h \
                frontend/sock.c include/frontend/sock.h \
+               frontend/session.c \
                utils/channel.c include/utils/channel.h \
                utils/llist.c include/utils/llist.h \
                utils/strbuf.c include/utils/strbuf.h \
index f235dc7a84e09d2697010276c089dfc6422270a6..23bbb33920f2186b56004c5b3d8d52d5730a6b01 100644 (file)
@@ -58,22 +58,49 @@ connection_get_int32(sdb_conn_t *conn, size_t offset)
 static int
 command_handle(sdb_conn_t *conn)
 {
-       assert(conn && conn->cmd && conn->cmd_len);
-       /* XXX */
-       sdb_strbuf_skip(conn->buf, conn->cmd_len);
-       conn->cmd = conn->cmd_len = 0;
-       return 0;
+       int status = -1;
+
+       assert(conn && (conn->cmd != CONNECTION_IDLE));
+
+       sdb_log(SDB_LOG_DEBUG, "frontend: Handling command %u (len: %u)",
+                       conn->cmd, conn->cmd_len);
+
+       switch (conn->cmd) {
+               case CONNECTION_PING:
+                       status = sdb_connection_ping(conn);
+                       break;
+               case CONNECTION_STARTUP:
+                       status = sdb_session_start(conn);
+                       break;
+               default:
+                       sdb_log(SDB_LOG_WARNING, "frontend: Ignoring invalid command");
+                       status = -1;
+                       break;
+       }
+
+       /* remove the command from the buffer */
+       if (conn->cmd_len)
+               sdb_strbuf_skip(conn->buf, conn->cmd_len);
+       conn->cmd = CONNECTION_IDLE;
+       conn->cmd_len = 0;
+       return status;
 } /* command_handle */
 
 /* initialize the connection state information */
 static int
 command_init(sdb_conn_t *conn)
 {
-       assert(conn && (! conn->cmd) && (! conn->cmd_len));
+       size_t len;
+
+       assert(conn && (conn->cmd == CONNECTION_IDLE) && (! conn->cmd_len));
 
        conn->cmd = connection_get_int32(conn, 0);
        conn->cmd_len = connection_get_int32(conn, sizeof(uint32_t));
-       sdb_strbuf_skip(conn->buf, 2 * sizeof(uint32_t));
+
+       len = 2 * sizeof(uint32_t);
+       if (conn->cmd == CONNECTION_IDLE)
+               len += conn->cmd_len;
+       sdb_strbuf_skip(conn->buf, len);
        return 0;
 } /* command_init */
 
@@ -123,7 +150,8 @@ sdb_connection_init(sdb_conn_t *conn)
                return -1;
        }
 
-       conn->cmd = conn->cmd_len = 0;
+       conn->cmd = CONNECTION_IDLE;
+       conn->cmd_len = 0;
        conn->fd = -1;
        return 0;
 } /* sdb_connection_init */
@@ -157,10 +185,11 @@ sdb_connection_read(sdb_conn_t *conn)
        while (42) {
                ssize_t status = connection_read(conn);
 
-               if ((! conn->cmd) && (! conn->cmd_len)
+               if ((conn->cmd == CONNECTION_IDLE) && (! conn->cmd_len)
                                && (sdb_strbuf_len(conn->buf) >= 2 * sizeof(int32_t)))
                        command_init(conn);
-               if (conn->cmd_len && (sdb_strbuf_len(conn->buf) >= conn->cmd_len))
+               if ((conn->cmd != CONNECTION_IDLE)
+                               && (sdb_strbuf_len(conn->buf) >= conn->cmd_len))
                        command_handle(conn);
 
                if (status <= 0)
@@ -171,5 +200,66 @@ sdb_connection_read(sdb_conn_t *conn)
        return n;
 } /* sdb_connection_read */
 
+ssize_t
+sdb_connection_send(sdb_conn_t *conn, uint32_t code,
+               uint32_t msg_len, char *msg)
+{
+       size_t len = 2 * sizeof(uint32_t) + msg_len;
+       char buffer[len];
+       char *buf;
+
+       uint32_t tmp;
+
+       if ((! conn) || (conn->fd < 0))
+               return -1;
+
+       tmp = htonl(code);
+       memcpy(buffer, &tmp, sizeof(uint32_t));
+
+       tmp = htonl(msg_len);
+       memcpy(buffer + sizeof(uint32_t), &tmp, sizeof(uint32_t));
+
+       if (msg_len)
+               memcpy(buffer + 2 * sizeof(uint32_t), msg, msg_len);
+
+       buf = buffer;
+       while (len > 0) {
+               ssize_t status;
+
+               /* XXX: use select() */
+
+               errno = 0;
+               status = write(conn->fd, buf, len);
+               if (status < 0) {
+                       char errbuf[1024];
+
+                       if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+                               continue;
+                       if (errno == EINTR)
+                               continue;
+
+                       sdb_log(SDB_LOG_ERR, "frontend: Failed to send msg "
+                                       "(code: %u, len: %u) to client: %s", code, msg_len,
+                                       sdb_strerror(errno, errbuf, sizeof(errbuf)));
+                       return status;
+               }
+
+               len -= (size_t)status;
+               buf += status;
+       }
+       return (ssize_t)len;
+} /* sdb_connection_send */
+
+int
+sdb_connection_ping(sdb_conn_t *conn)
+{
+       if ((! conn) || (conn->cmd != CONNECTION_PING))
+               return -1;
+
+       /* we're alive */
+       sdb_connection_send(conn, CONNECTION_OK, 0, NULL);
+       return 0;
+} /* sdb_connection_ping */
+
 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */
 
diff --git a/src/frontend/session.c b/src/frontend/session.c
new file mode 100644 (file)
index 0000000..b1e527a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SysDB - src/frontend/session.c
+ * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysdb.h"
+
+#include "frontend/connection.h"
+
+/*
+ * public API
+ */
+
+int
+sdb_session_start(sdb_conn_t *conn)
+{
+       if ((! conn) || (conn->username))
+               return -1;
+
+       if (conn->cmd != CONNECTION_STARTUP)
+               return -1;
+
+       /* XXX: for now, simply accept all connections */
+       sdb_connection_send(conn, CONNECTION_OK, 0, NULL);
+       return 0;
+} /* session_start */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
index 5748211f4c1d5c78f367eb1fc9672c825f757c2c..a5ea092c425d65f570af2b838f2febbdf9e64611 100644 (file)
 extern "C" {
 #endif
 
+/* status codes returned to a client */
+typedef enum {
+       CONNECTION_OK = 0,
+       CONNECTION_ERROR
+} sdb_conn_status_t;
+
+/* accepted commands / state of the connection */
+typedef enum {
+       CONNECTION_IDLE = 0,
+       CONNECTION_PING,
+       CONNECTION_STARTUP,
+} sdb_conn_state_t;
+
 /* a generic connection object */
 typedef struct {
        /* file-descriptor of the open connection */
@@ -47,6 +60,9 @@ typedef struct {
        /* connection / protocol state information */
        uint32_t cmd;
        uint32_t cmd_len;
+
+       /* user information */
+       char *username; /* NULL if the user has not been authenticated */
 } sdb_conn_t;
 
 /*
@@ -80,6 +96,44 @@ sdb_connection_close(sdb_conn_t *conn);
 ssize_t
 sdb_connection_read(sdb_conn_t *conn);
 
+/*
+ * sdb_connection_send:
+ * Send to an open connection.
+ *
+ * Returns:
+ *  - the number of bytes written
+ *  - a negative value on error
+ */
+ssize_t
+sdb_connection_send(sdb_conn_t *conn, uint32_t code,
+               uint32_t msg_len, char *msg);
+
+/*
+ * sdb_connection_ping:
+ * Send back a backend status indicator to the connected client.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_connection_ping(sdb_conn_t *conn);
+
+/*
+ * session handling
+ */
+
+/*
+ * sdb_session_start:
+ * Start a new user session on the specified connection.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_session_start(sdb_conn_t *conn);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif