summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2018-01-24 21:02:46 +0100
committerJo-Philipp Wich <jo@mein.io>2018-01-25 10:55:59 +0100
commitccd9717ba5d501b45fda957f0ea41c4660ef414c (patch)
tree60c05d4128e70d95aad9459c53a8c1ca89492746
parentdb86175c2d90ba640b158e8eebd7409227544c4b (diff)
downloaduhttpd2-ccd9717ba5d501b45fda957f0ea41c4660ef414c.tar.gz
proc: avoid stdio deadlocks
When a request handler accepting post data is too slow in consuming stdin, uhttpd might deadlock with the master process stuck in a blocking write() to the child and the child stuck with a blocking write() to the master. Avoid this issue by putting the master side write end of the child pipe into nonblocking mode right away and by raising the data_blocked flag when attempts to write to the child yield EAGAIN. Setting the flag ensures that client_poll_post_data() does not immediately trigger a write attempt again, which effectively yields the master write cycle so that the relay ustream has a chance to consume output of the client process, thus solving the deadlock. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--proc.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/proc.c b/proc.c
index e360897..edfcc8f 100644
--- a/proc.c
+++ b/proc.c
@@ -265,6 +265,7 @@ static void proc_write_cb(struct uloop_fd *fd, unsigned int events)
struct client *cl = container_of(fd, struct client, dispatch.proc.wrfd);
client_poll_post_data(cl);
+ cl->dispatch.data_blocked = false;
}
static void proc_relay_write_cb(struct client *cl)
@@ -291,8 +292,10 @@ static int proc_data_send(struct client *cl, const char *data, int len)
if (errno == EINTR)
continue;
- if (errno == EAGAIN || errno == EWOULDBLOCK)
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ cl->dispatch.data_blocked = true;
break;
+ }
/* consume all data */
ret = len;
@@ -366,6 +369,7 @@ bool uh_create_process(struct client *cl, struct path_info *pi, char *url,
proc->wrfd.fd = wfd[1];
uh_relay_open(cl, &proc->r, rfd[0], pid);
+ uloop_fd_add(&proc->wrfd, ULOOP_WRITE);
d->free = proc_free;
d->close_fds = proc_close_fds;