mirror of
https://github.com/emikulic/darkhttpd.git
synced 2023-08-10 21:13:08 +03:00
Fix hung connection from consecutive requests (#7)
A client making quick consecutive requests with keep-alive, such as `ab` with `-k`, can cause the connection to become hung. This happens because of an optimization in `http_poll` function. When a connection state becomes `DONE`, `httpd_poll` recycles the connection and immediately calls `poll_recv_request`. However, it doesn't handle this resulting in the connection state becoming `DONE` again. If this occurs, the state stays in `DONE`, and the further calls to `httpd_poll` ignore the connection. Fix this by calling `poll_recv_request` in a loop until the state is no longer `DONE`. * Enable TCP_NODELAY optimization It looks like `TCP_NODELAY` was disabled due to the bug fixed in the previous commit. Enabling it substantially improves keep-alive performance with `ab`: Before: ``` Time per request: 0.272 [ms] (mean) ``` After: ``` Time per request: 0.033 [ms] (mean) ``` * Remove keep-alive optimization from `httpd_poll` Benchmarking with `ab` shows that bypassing `select` for keep-alive connections in the `DONE` state doesn't significantly impact performance. Since this optimization previously caused a bug, remove it.
This commit is contained in:
parent
5c0f9babf1
commit
667edacaa3
2
TODO
2
TODO
@ -1,3 +1 @@
|
||||
- keepalive performance against ab sucks
|
||||
- keepalive+TCP_NODELAY hangs!
|
||||
- send headers using sendfile syscall - fewer packets
|
||||
|
@ -817,13 +817,11 @@ static void init_sockin(void) {
|
||||
&sockopt, sizeof(sockopt)) == -1)
|
||||
err(1, "setsockopt(SO_REUSEADDR)");
|
||||
|
||||
#if 0
|
||||
/* disable Nagle since we buffer everything ourselves */
|
||||
sockopt = 1;
|
||||
if (setsockopt(sockin, IPPROTO_TCP, TCP_NODELAY,
|
||||
&sockopt, sizeof(sockopt)) == -1)
|
||||
err(1, "setsockopt(TCP_NODELAY)");
|
||||
#endif
|
||||
|
||||
#ifdef TORTURE
|
||||
/* torture: cripple the kernel-side send buffer so we can only squeeze out
|
||||
@ -2495,7 +2493,7 @@ static void httpd_poll(void) {
|
||||
LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
|
||||
switch (conn->state) {
|
||||
case DONE:
|
||||
/* do nothing */
|
||||
/* do nothing, no connection should be left in this state */
|
||||
break;
|
||||
|
||||
case RECV_REQUEST:
|
||||
@ -2586,10 +2584,6 @@ static void httpd_poll(void) {
|
||||
free(conn);
|
||||
} else {
|
||||
recycle_connection(conn);
|
||||
/* and go right back to recv_request without going through
|
||||
* select() again.
|
||||
*/
|
||||
poll_recv_request(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user