From ad77ec3d257ac66d74e91452d098882247abdc0a Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sat, 10 Jan 2015 16:28:20 +0100 Subject: [PATCH] frontend: Make connection I/O handling more flexible. That'll allow to create connection objects which require special I/O operations. --- src/frontend/connection-private.h | 6 ++++++ src/frontend/connection.c | 30 ++++++++++++++++++++++++++++-- src/frontend/sock.c | 20 ++++++++++++++------ t/unit/frontend/connection_test.c | 15 +++++++++++++++ 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/frontend/connection-private.h b/src/frontend/connection-private.h index 361af16..a0f28ae 100644 --- a/src/frontend/connection-private.h +++ b/src/frontend/connection-private.h @@ -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; diff --git a/src/frontend/connection.c b/src/frontend/connection.c index ed1eb2c..f35f7b3 100644 --- a/src/frontend/connection.c +++ b/src/frontend/connection.c @@ -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]; diff --git a/src/frontend/sock.c b/src/frontend/sock.c index cb6b9fc..642f03f 100644 --- a/src/frontend/sock.c +++ b/src/frontend/sock.c @@ -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 " diff --git a/t/unit/frontend/connection_test.c b/t/unit/frontend/connection_test.c index 1e9b351..9b0cde4 100644 --- a/t/unit/frontend/connection_test.c +++ b/t/unit/frontend/connection_test.c @@ -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); -- 2.30.2