aboutsummaryrefslogtreecommitdiff
path: root/fcgi.c
diff options
context:
space:
mode:
authorOmar Polo <op@omarpolo.com>2021-10-02 17:20:56 +0000
committerOmar Polo <op@omarpolo.com>2021-10-02 17:20:56 +0000
commitefe7d180292726775fb3ae5e6af593490a264c60 (patch)
treefb80d8c133a34cea6cce5be538202aad76a6729e /fcgi.c
parent403c42204182515d7281d8c11084eef596f8a6ee (diff)
new I/O handling on top of bufferevents
This is a big change in how gmid handles I/O. Initially we used a hand-written loop over poll(2), that then was evolved into something powered by libevent basic API. This meant that there were a lot of small "asynchronous" function that did one step, eventually scheduling the re-execution, that called each others in a chain. The new implementation revolves completely around libevent' bufferevents. It's more clear, as everything is implemented around the client_read and client_write functions. There is still space for improvements, like adding timeouts for one, but it's solid enough to be committed as is and then further improved.
Diffstat (limited to 'fcgi.c')
-rw-r--r--fcgi.c83
1 files changed, 12 insertions, 71 deletions
diff --git a/fcgi.c b/fcgi.c
index 8de518a..c87a0e6 100644
--- a/fcgi.c
+++ b/fcgi.c
@@ -223,16 +223,18 @@ fcgi_end_param(struct bufferevent *bev, int id)
return 0;
}
-static int
-fcgi_abort_request(struct bufferevent *bev, int id)
+void
+fcgi_abort_request(struct client *c)
{
+ struct fcgi *f;
struct fcgi_header h;
- prepare_header(&h, FCGI_ABORT_REQUEST, id, 0, 0);
- if (bufferevent_write(bev, &h, sizeof(h)) == -1)
- return -1;
+ f = &fcgi[c->fcgi];
- return 0;
+ prepare_header(&h, FCGI_ABORT_REQUEST, c->id, 0, 0);
+
+ if (bufferevent_write(f->bev, &h, sizeof(h)) == -1)
+ fcgi_close_backend(f);
}
static inline int
@@ -247,55 +249,6 @@ reclen(struct fcgi_header *h)
return h->content_len0 + (h->content_len1 << 8);
}
-static void
-copy_mbuf(int fd, short ev, void *d)
-{
- struct client *c = d;
- struct mbuf *mbuf;
- size_t len;
- ssize_t r;
- char *data;
-
- for (;;) {
- mbuf = TAILQ_FIRST(&c->mbufhead);
- if (mbuf == NULL)
- break;
-
- len = mbuf->len - mbuf->off;
- data = mbuf->data + mbuf->off;
- switch (r = tls_write(c->ctx, data, len)) {
- case -1:
- /*
- * Can't close_conn here. The application
- * needs to be informed first, otherwise it
- * can interfere with future connections.
- * Check also that we're not doing recursion
- * (copy_mbuf -> handle_fcgi -> copy_mbuf ...)
- */
- if (c->next != NULL)
- goto end;
- fcgi_abort_request(0, c->id);
- return;
- case TLS_WANT_POLLIN:
- event_once(c->fd, EV_READ, &copy_mbuf, c, NULL);
- return;
- case TLS_WANT_POLLOUT:
- event_once(c->fd, EV_WRITE, &copy_mbuf, c, NULL);
- return;
- }
- mbuf->off += r;
-
- if (mbuf->off == mbuf->len) {
- TAILQ_REMOVE(&c->mbufhead, mbuf, mbufs);
- free(mbuf);
- }
- }
-
-end:
- if (c->next != NULL)
- c->next(0, 0, c);
-}
-
void
fcgi_close_backend(struct fcgi *f)
{
@@ -315,7 +268,6 @@ fcgi_read(struct bufferevent *bev, void *d)
struct fcgi_header hdr;
struct fcgi_end_req_body end;
struct client *c;
- struct mbuf *mbuf;
size_t len;
#if DEBUG_FCGI
@@ -372,8 +324,8 @@ fcgi_read(struct bufferevent *bev, void *d)
/* TODO: do something with the status? */
fcgi->pending--;
c->fcgi = -1;
- c->next = close_conn;
- event_once(c->fd, EV_WRITE, &copy_mbuf, c, NULL);
+ c->type = REQUEST_DONE;
+ client_write(c->bev, c);
break;
case FCGI_STDERR:
@@ -382,16 +334,7 @@ fcgi_read(struct bufferevent *bev, void *d)
break;
case FCGI_STDOUT:
- if ((mbuf = calloc(1, sizeof(*mbuf) + len)) == NULL)
- fatal("calloc");
- mbuf->len = len;
- bufferevent_read(bev, mbuf->data, len);
-
- if (TAILQ_EMPTY(&c->mbufhead))
- event_once(c->fd, EV_WRITE, &copy_mbuf,
- c, NULL);
-
- TAILQ_INSERT_TAIL(&c->mbufhead, mbuf, mbufs);
+ bufferevent_write_buffer(c->bev, EVBUFFER_INPUT(bev));
break;
default:
@@ -439,7 +382,7 @@ fcgi_error(struct bufferevent *bev, short err, void *d)
continue;
if (c->code != 0)
- close_conn(0, 0, 0);
+ client_close(c);
else
start_reply(c, CGI_ERROR, "CGI error");
}
@@ -466,8 +409,6 @@ fcgi_req(struct fcgi *f, struct client *c)
fatal("getnameinfo failed: %s (%s)",
gai_strerror(e), strerror(errno));
- c->next = NULL;
-
fcgi_begin_request(f->bev, c->id);
fcgi_send_param(f->bev, c->id, "GATEWAY_INTERFACE", "CGI/1.1");
fcgi_send_param(f->bev, c->id, "GEMINI_URL_PATH", c->iri.path);