diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2016-08-06 04:11:16 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2016-08-06 04:28:45 -0400 |
commit | 4bc06bfc0b72b92c67f21ac0dc7de7d67be73728 (patch) | |
tree | 39a0984eaf1ed53e0ebbd9be55b83881b97d012a /src/fdevent.c | |
parent | 1de652f40badac2d2c6c3f4d348b8c35635519e1 (diff) | |
download | lighttpd-git-4bc06bfc0b72b92c67f21ac0dc7de7d67be73728.tar.gz |
[core] check if client half-closed TCP if POLLHUP (#2743)
Check if client half-closed TCP connection if POLLHUP is received.
This more robustly handles if client called shutdown(fd, SHUT_WR).
This patch reverts commit:ab05eb7c which should now be handled properly.
(Time will tell.)
x-ref:
"1.4.40/41 mod_proxy, mod_scgi may trigger POLLHUP on *BSD,Darwin"
https://redmine.lighttpd.net/issues/2743
Diffstat (limited to 'src/fdevent.c')
-rw-r--r-- | src/fdevent.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/src/fdevent.c b/src/fdevent.c index 6d5096c8..756c8e6a 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -250,3 +250,35 @@ int fdevent_event_next_fdndx(fdevents *ev, int ndx) { return -1; } + +#include <netinet/tcp.h> +#if (defined(__APPLE__) && defined(__MACH__)) \ + || defined(__FreeBSD__) || defined(__NetBSD__) \ + || defined(__OpenBSD__) || defined(__DragonflyBSD__) +#include <netinet/tcp_fsm.h> +#endif + +/* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */ +int fdevent_is_tcp_half_closed(int fd) { + #ifdef TCP_CONNECTION_INFO /* Darwin */ + struct tcp_connection_info tcpi; + socklen_t tlen = sizeof(tcpi); + return (0 == getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tlen) + && tcpi.tcpi_state == TCPS_CLOSE_WAIT); + #elif defined(TCPS_CLOSE_WAIT) /* FreeBSD, NetBSD (not present in OpenBSD) */ + struct tcp_info tcpi; + socklen_t tlen = sizeof(tcpi); + return (0 == getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tlen) + && tcpi.tcpi_state == TCPS_CLOSE_WAIT); + #elif defined(TCP_INFO) /* Linux */ + struct tcp_info tcpi; + socklen_t tlen = sizeof(tcpi);/*SOL_TCP == IPPROTO_TCP*/ + return (0 == getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &tlen) + && tcpi.tcpi_state == TCP_CLOSE_WAIT); + #else + UNUSED(fd); + /*(0 != getpeername() error might indicate TCP RST, but success + * would not differentiate between half-close and full-close)*/ + return 0; /* false (not half-closed) or TCP state unknown */ + #endif +} |