commit 112802ea3116b6e11a70d6060e6e238495498bbc from: Omar Polo date: Mon Feb 01 20:00:33 2021 UTC client state machine: function pointers instead of enum+switch commit - 1e7591a9220359bc646562b161719d406cbbc267 commit + 112802ea3116b6e11a70d6060e6e238495498bbc blob - 5d4becfadf20bfc62c907d4ff56193abad4314ec blob + e2a5e5e6d5cb982b5f412f0713f562c86f0e8387 --- gmid.h +++ gmid.h @@ -124,22 +124,16 @@ struct parser { const char *err; }; -enum { - S_HANDSHAKE, - S_OPEN, - S_INITIALIZING, - S_SENDING_FILE, - S_SENDING_DIR, - S_SENDING_CGI, - S_CLOSING, -}; +struct client; +typedef void (*statefn)(struct pollfd*, struct client*); + struct client { struct tls *ctx; char req[GEMINI_URL_LEN]; struct iri iri; char domain[DOMAIN_NAME_LEN]; - int state, next; + statefn state, next; int code; const char *meta; int fd, waiting_on_child; @@ -209,6 +203,7 @@ void mark_nonblock(int); void handle_handshake(struct pollfd*, struct client*); void handle_open_conn(struct pollfd*, struct client*); void start_reply(struct pollfd*, struct client*, int, const char*); +void handle_start_reply(struct pollfd*, struct client*); void start_cgi(const char*, const char*, struct pollfd*, struct client*); void send_file(struct pollfd*, struct client*); void open_dir(struct pollfd*, struct client*); @@ -220,7 +215,6 @@ void cgi_poll_on_client(struct pollfd*, struct clien void handle_cgi(struct pollfd*, struct client*); void close_conn(struct pollfd*, struct client*); void do_accept(int, struct tls*, struct pollfd*, struct client*); -void handle(struct pollfd*, struct client*); void loop(struct tls*, int, int); /* ex.c */ blob - 30f413c685dc2e63601f4fc5428bdad8875bec86 blob + 2f8112db514c87161d2be9c4b42b56bf72f3a4cc --- server.c +++ server.c @@ -195,7 +195,7 @@ load_file(struct pollfd *fds, struct client *c) return; } c->i = c->buf; - c->next = S_SENDING_FILE; + c->next = send_file; start_reply(fds, c, SUCCESS, mime(c->host, c->iri.path)); } @@ -294,7 +294,7 @@ handle_handshake(struct pollfd *fds, struct client *c) /* h->domain != NULL ? h->domain : "(null)"); */ if (h->domain != NULL) { - c->state = S_OPEN; + c->state = handle_open_conn; c->host = h; handle_open_conn(fds, c); return; @@ -354,19 +354,24 @@ handle_open_conn(struct pollfd *fds, struct client *c) void start_reply(struct pollfd *pfd, struct client *c, int code, const char *meta) { + c->code = code; + c->meta = meta; + c->state = handle_start_reply; + c->state(pfd, c); +} + +void +handle_start_reply(struct pollfd *pfd, struct client *c) +{ char buf[1030]; /* status + ' ' + max reply len + \r\n\0 */ const char *lang; size_t len; - c->code = code; - c->meta = meta; - c->state = S_INITIALIZING; - lang = vhost_lang(c->host, c->iri.path); - snprintf(buf, sizeof(buf), "%d ", code); - strlcat(buf, meta, sizeof(buf)); - if (!strcmp(meta, "text/gemini") && lang != NULL) { + snprintf(buf, sizeof(buf), "%d ", c->code); + strlcat(buf, c->meta, sizeof(buf)); + if (!strcmp(c->meta, "text/gemini") && lang != NULL) { strlcat(buf, "; lang=", sizeof(buf)); strlcat(buf, lang, sizeof(buf)); } @@ -396,7 +401,7 @@ start_reply(struct pollfd *pfd, struct client *c, int /* advance the state machine */ c->state = c->next; - handle(pfd, c); + c->state(pfd, c); } void @@ -439,7 +444,7 @@ start_cgi(const char *spath, const char *relpath, start_reply(fds, c, TEMP_FAILURE, "internal server error"); return; } - c->state = S_SENDING_CGI; + c->state = handle_cgi; cgi_poll_on_child(fds, c); c->code = -1; /* handle_cgi(fds, c); */ @@ -455,9 +460,6 @@ send_file(struct pollfd *fds, struct client *c) { ssize_t ret, len; - /* ensure the correct state */ - c->state = S_SENDING_FILE; - len = (c->buf + c->len) - c->i; while (len > 0) { @@ -542,7 +544,7 @@ open_dir(struct pollfd *fds, struct client *c) } c->fd = dirfd; - c->next = S_SENDING_DIR; + c->next = send_directory_listing; if ((c->dir = fdopendir(c->fd)) == NULL) { LOGE(c, "can't fdopendir(%d) (vhost:%s) %s: %s", @@ -762,7 +764,7 @@ end: void close_conn(struct pollfd *pfd, struct client *c) { - c->state = S_CLOSING; + c->state = close_conn; switch (tls_close(c->ctx)) { case TLS_WANT_POLLIN: @@ -816,8 +818,8 @@ do_accept(int sock, struct tls *ctx, struct pollfd *fd fds[i].fd = fd; fds[i].events = POLLIN; - clients[i].state = S_HANDSHAKE; - clients[i].next = S_SENDING_FILE; + clients[i].state = handle_handshake; + clients[i].next = send_file; clients[i].fd = -1; clients[i].waiting_on_child = 0; clients[i].buf = MAP_FAILED; @@ -830,44 +832,6 @@ do_accept(int sock, struct tls *ctx, struct pollfd *fd } close(fd); -} - -void -handle(struct pollfd *fds, struct client *client) -{ - switch (client->state) { - case S_HANDSHAKE: - handle_handshake(fds, client); - break; - - case S_OPEN: - handle_open_conn(fds, client); - break; - - case S_INITIALIZING: - start_reply(fds, client, client->code, client->meta); - break; - - case S_SENDING_FILE: - send_file(fds, client); - break; - - case S_SENDING_DIR: - send_directory_listing(fds, client); - break; - - case S_SENDING_CGI: - handle_cgi(fds, client); - break; - - case S_CLOSING: - close_conn(fds, client); - break; - - default: - /* unreachable */ - abort(); - } } void @@ -920,7 +884,7 @@ loop(struct tls *ctx, int sock4, int sock6) else if (fds[i].fd == sock6) do_accept(sock6, ctx, fds, clients); else - handle(&fds[i], &clients[i]); + clients[i].state(&fds[i], &clients[i]); } } }