Code

frontend: Make connection I/O handling more flexible.
authorSebastian Harl <sh@tokkee.org>
Sat, 10 Jan 2015 15:28:20 +0000 (16:28 +0100)
committerSebastian Harl <sh@tokkee.org>
Sat, 10 Jan 2015 15:28:20 +0000 (16:28 +0100)
That'll allow to create connection objects which require special I/O
operations.

src/frontend/connection-private.h
src/frontend/connection.c
src/frontend/sock.c
t/unit/frontend/connection_test.c

index 361af166867e5ce230415c64475af57812952723..a0f28ae985b37a81442ad7145eb3a056e9dffbca 100644 (file)
@@ -58,6 +58,12 @@ struct sdb_conn {
        struct sockaddr_storage client_addr;
        socklen_t client_addr_len;
 
+       /* connection handling */
+       ssize_t (*read)(sdb_conn_t *, size_t);
+       ssize_t (*write)(sdb_conn_t *, const void *, size_t);
+       int (*finish)(sdb_conn_t *);
+       void *session;
+
        /* read buffer */
        sdb_strbuf_t *buf;
 
index ed1eb2c8565058f562922f3d0b11071d46287ccb..f35f7b39c82a8278f47137e65810163094c33044 100644 (file)
@@ -107,6 +107,18 @@ peer(int sockfd)
        return strdup(result->pw_name);
 } /* peer */
 
+static ssize_t
+conn_read(sdb_conn_t *conn, size_t len)
+{
+       return sdb_strbuf_read(conn->buf, conn->fd, len);
+} /* conn_read */
+
+static ssize_t
+conn_write(sdb_conn_t *conn, const void *buf, size_t len)
+{
+       return sdb_write(conn->fd, len, buf);
+} /* conn_write */
+
 static int
 connection_init(sdb_object_t *obj, va_list ap)
 {
@@ -144,6 +156,12 @@ connection_init(sdb_object_t *obj, va_list ap)
                return -1;
        }
 
+       /* defaults */
+       conn->read = conn_read;
+       conn->write = conn_write;
+       conn->finish = NULL;
+       conn->session = NULL;
+
        if (conn->client_addr.ss_family != AF_UNIX) {
                sdb_log(SDB_LOG_ERR, "frontend: Accepted connection using "
                                "unexpected family type %d", conn->client_addr.ss_family);
@@ -193,6 +211,10 @@ connection_destroy(sdb_object_t *obj)
 
        conn->ready = 0;
 
+       if (conn->finish)
+               conn->finish(conn);
+       conn->finish = NULL;
+
        if (conn->buf) {
                len = sdb_strbuf_len(conn->buf);
                if (len)
@@ -400,7 +422,7 @@ connection_read(sdb_conn_t *conn)
                ssize_t status;
 
                errno = 0;
-               status = sdb_strbuf_read(conn->buf, conn->fd, 1024);
+               status = conn->read(conn, 1024);
                if (status < 0) {
                        if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
                                break;
@@ -458,6 +480,10 @@ sdb_connection_close(sdb_conn_t *conn)
        if (! conn)
                return;
 
+       if (conn->finish)
+               conn->finish(conn);
+       conn->finish = NULL;
+
        /* close the connection even if someone else still references it */
        if (conn->fd >= 0)
                close(conn->fd);
@@ -510,7 +536,7 @@ sdb_connection_send(sdb_conn_t *conn, uint32_t code,
        if (sdb_proto_marshal(buf, sizeof(buf), code, msg_len, msg) < 0)
                return -1;
 
-       status = sdb_write(conn->fd, sizeof(buf), buf);
+       status = conn->write(conn, buf, sizeof(buf));
        if (status < 0) {
                char errbuf[1024];
 
index cb6b9fcdd7a889405e0da21771a99a9acd2c47fa..642f03f92b0f87d25e3783bb501ecbce793ff6c3 100644 (file)
@@ -68,14 +68,15 @@ typedef struct {
        int   type;
 
        int sock_fd;
+       int (*accept)(sdb_conn_t *);
 } listener_t;
 
 typedef struct {
        int type;
        const char *prefix;
 
-       int (*opener)(listener_t *);
-       void (*closer)(listener_t *);
+       int (*open)(listener_t *);
+       void (*close)(listener_t *);
 } fe_listener_impl_t;
 
 struct sdb_fe_socket {
@@ -200,7 +201,7 @@ listener_listen(listener_t *listener)
 
        /* try to reopen */
        if (listener->sock_fd < 0)
-               if (listener_impls[listener->type].opener(listener))
+               if (listener_impls[listener->type].open(listener))
                        return -1;
        assert(listener->sock_fd >= 0);
 
@@ -218,8 +219,8 @@ listener_close(listener_t *listener)
 {
        assert(listener);
 
-       if (listener_impls[listener->type].closer)
-               listener_impls[listener->type].closer(listener);
+       if (listener_impls[listener->type].close)
+               listener_impls[listener->type].close(listener);
 
        if (listener->sock_fd >= 0)
                close(listener->sock_fd);
@@ -299,8 +300,9 @@ listener_create(sdb_fe_socket_t *sock, const char *address)
                return NULL;
        }
        listener->type = type;
+       listener->accept = NULL;
 
-       if (listener_impls[type].opener(listener)) {
+       if (listener_impls[type].open(listener)) {
                /* prints error */
                listener_destroy(listener);
                return NULL;
@@ -396,6 +398,12 @@ connection_accept(sdb_fe_socket_t *sock, listener_t *listener)
        if (! obj)
                return -1;
 
+       if (listener->accept && listener->accept(CONN(obj))) {
+               /* accept() is expected to log an error */
+               sdb_object_deref(obj);
+               return -1;
+       }
+
        status = sdb_llist_append(sock->open_connections, obj);
        if (status)
                sdb_log(SDB_LOG_ERR, "frontend: Failed to append "
index 1e9b351679e2b17533fd82d43fe8f46dee01cb3f..9b0cde48da0ca11e725729fd01fe46318bc22d89 100644 (file)
@@ -69,6 +69,18 @@ mock_conn_destroy(sdb_conn_t *conn)
        free(conn);
 } /* mock_conn_destroy */
 
+static ssize_t
+mock_conn_read(sdb_conn_t *conn, size_t len)
+{
+       return sdb_strbuf_read(conn->buf, conn->fd, len);
+} /* conn_read */
+
+static ssize_t
+mock_conn_write(sdb_conn_t *conn, const void *buf, size_t len)
+{
+       return sdb_write(conn->fd, len, buf);
+} /* conn_write */
+
 static sdb_conn_t *
 mock_conn_create(void)
 {
@@ -102,6 +114,9 @@ mock_conn_create(void)
 
        unlink(tmp_file);
 
+       conn->read = mock_conn_read;
+       conn->write = mock_conn_write;
+
        conn->username = strdup(username);
        assert(conn->username);