From 632194d1187066a987596eebefd37a34a23e042c Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sat, 23 Nov 2013 09:50:50 +0100 Subject: [PATCH] frontend: Handle STARTUP and PING commands. 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 | 1 + src/frontend/connection.c | 110 +++++++++++++++++++++++++++--- src/frontend/session.c | 51 ++++++++++++++ src/include/frontend/connection.h | 54 +++++++++++++++ 4 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 src/frontend/session.c diff --git a/src/Makefile.am b/src/Makefile.am index 24b41ae..32c493e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/frontend/connection.c b/src/frontend/connection.c index f235dc7..23bbb33 100644 --- a/src/frontend/connection.c +++ b/src/frontend/connection.c @@ -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 index 0000000..b1e527a --- /dev/null +++ b/src/frontend/session.c @@ -0,0 +1,51 @@ +/* + * SysDB - src/frontend/session.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * 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 : */ + diff --git a/src/include/frontend/connection.h b/src/include/frontend/connection.h index 5748211..a5ea092 100644 --- a/src/include/frontend/connection.h +++ b/src/include/frontend/connection.h @@ -36,6 +36,19 @@ 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 -- 2.30.2