From b73339b87f298299a89b3ce298ff24dff560db75 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 29 Jul 2026 21:59:45 +0300 Subject: add single-shot mode + Useful for testing in particular --- src/server.c | 115 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/server.c b/src/server.c index 2fae757..9154a3c 100644 --- a/src/server.c +++ b/src/server.c @@ -48,7 +48,8 @@ enum server_cmd { }; struct server_conn { - int fd; + int fdin; + int fdout; struct sockaddr addr; socklen_t addrlen; @@ -71,7 +72,8 @@ struct server_conn { #include struct server_ctx { - int tcp_sock; + int sock; + bool oneshot; struct server_conns conns; struct conn_polls polls; int timeout; @@ -130,6 +132,8 @@ static bool streq(const char *s1, const char *s2) static int new_connection(struct server_ctx *ctx, int new_conn_fd) { + assert(!ctx->oneshot); + struct sockaddr addr; socklen_t addrlen; @@ -159,7 +163,8 @@ static int new_connection(struct server_ctx *ctx, int new_conn_fd) } struct server_conn conn = { - .fd = fd, + .fdin = fd, + .fdout = fd, .addr = addr, .addrlen = addrlen, .cmd = META_PARSE_CMD, @@ -176,7 +181,10 @@ static int new_connection(struct server_ctx *ctx, int new_conn_fd) * freed by now. Invalidates the conn pointer! */ static int kill_connection(struct server_ctx *ctx, struct server_conn *conn) { - close(conn->fd); + close(conn->fdin); + if (conn->fdout != conn->fdin) + close(conn->fdout); + strbuf_destroy(&conn->strbuf); assert(server_conns_len(&ctx->conns) >= 1); @@ -203,7 +211,7 @@ static ssize_t reread(struct server_conn *conn, size_t c) size_t n = strbuf->n; strbuf_reserve(strbuf, n + c); - ssize_t r = readx(conn->fd, strbuf->buf + n, c); + ssize_t r = readx(conn->fdin, strbuf->buf + n, c); if (r < 0) return r; @@ -609,7 +617,7 @@ static enum que_op sync_cmd(struct server_ctx *ctx, struct server_conn *conn) syslog(LOG_DEBUG, "sending sync\n"); const char buf[] = "From: urmum@amazon.com"; - ssize_t ret = writex(conn->fd, buf, sizeof(buf)); + ssize_t ret = writex(conn->fdout, buf, sizeof(buf)); assert(ret == sizeof(buf)); conn->cmd = META_PARSE_CMD; destroy_sync(cmd); @@ -621,22 +629,44 @@ static enum que_op sync_cmd(struct server_ctx *ctx, struct server_conn *conn) return LARK_KILL; } -static int event_loop(int tcp_sock) +static int event_loop(int sock, bool oneshot) { struct server_ctx ctx = { - .tcp_sock = tcp_sock, + .sock = sock, + .oneshot = oneshot, .conns = server_conns_create(0), .polls = conn_polls_create(0), .timeout = -1 }; + /* set up a connection */ + if (oneshot) { + struct server_conn conn = { + .fdin = sock, + .fdout = sock == STDIN_FILENO ? STDOUT_FILENO : sock, + .addr = {}, + .addrlen = 0, + .cmd = META_PARSE_CMD, + .strbuf = strbuf_create(0), + .nextlen = 0 + }; + + memset(&conn.u, 0, sizeof(conn.u)); + server_conns_append(&ctx.conns, conn); + } + int ret = 0; while (1) { + if (ctx.oneshot && server_conns_len(&ctx.conns) == 0) + break; + /* build up set of connections to poll */ conn_polls_reset(&ctx.polls); + /* no need to poll if we're in oneshot mode, but keep pollfd + * around to simplify index calculations */ struct pollfd tcp_poll = { - .fd = ctx.tcp_sock, + .fd = ctx.oneshot ? -1 : ctx.sock, .events = POLLIN, .revents = 0 }; @@ -644,7 +674,7 @@ static int event_loop(int tcp_sock) foreach(server_conns, c, &ctx.conns) { struct pollfd conn_poll = { - .fd = c->fd, + .fd = c->fdin, .events = POLLIN, .revents = 0 }; @@ -732,31 +762,54 @@ static int event_loop(int tcp_sock) int main(int argc, char *argv[argc]) { - int ret = 0; - - openlog(NULL, LOG_PERROR, LOG_USER); - - int tcp_sock = socket(AF_INET, SOCK_STREAM, 0); - if (tcp_sock == -1) { - err(EXIT_FAILURE, "failed opening tcp socket"); + int ret = 0, opt; + + const char *single_conn = NULL; + while ((opt = getopt(argc, argv, "s:")) != -1) { + switch (opt) { + case 's': + single_conn = optarg; + break; + + default: + fprintf(stderr, "usage: %s [-s socket or - for stdin]\n", + argv[0]); + exit(EXIT_FAILURE); + } } - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - /* should probably come up with a reasonable port at some point */ - addr.sin_port = htons(24242); - - if (bind(tcp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - err(EXIT_FAILURE, "failed binding tcp socket"); - } + openlog(NULL, LOG_PERROR, LOG_USER); - if (listen(tcp_sock, 64) == -1) { - err(EXIT_FAILURE, "failed listening on tcp socket"); + int sock = -1; + if (single_conn) { + if (streq(single_conn, "-")) + sock = STDIN_FILENO; + else + sock = open(single_conn, O_RDONLY); + + if (sock == -1) + err(EXIT_FAILURE, "failed opening single connection"); + + } else { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) + err(EXIT_FAILURE, "failed opening tcp socket"); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + /* should probably come up with a reasonable port at some point */ + addr.sin_port = htons(24242); + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) + err(EXIT_FAILURE, "failed binding tcp socket"); + + if (listen(sock, 64) == -1) + err(EXIT_FAILURE, "failed listening on tcp socket"); } - ret = event_loop(tcp_sock); - close(tcp_sock); + ret = event_loop(sock, single_conn != NULL); + close(sock); return ret; } -- cgit v1.3