summaryrefslogtreecommitdiff
path: root/src/fdevent.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2016-08-06 04:11:16 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2016-08-06 04:28:45 -0400
commit4bc06bfc0b72b92c67f21ac0dc7de7d67be73728 (patch)
tree39a0984eaf1ed53e0ebbd9be55b83881b97d012a /src/fdevent.c
parent1de652f40badac2d2c6c3f4d348b8c35635519e1 (diff)
downloadlighttpd-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.c32
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
+}