From 84b5064dc4ca6a9e670f4566923ee8c8b4706c55 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Mon, 11 Dec 2017 01:20:43 -0500 Subject: [PATCH] [core] discard from socket using recv MSG_TRUNC discard from socket using recv MSG_TRUNC on Linux TCP SOCK_STREAM socket Currently, lighttpd supports only TCP SOCK_STREAM. If UDP SOCK_DGRAM were to be supported in the future, then socket type will need to be stored so that MSG_TRUNC is used appropriately for the desired effect. To find out socket type on arbitrary socket fd: getsockopt(..., SOL_SOCKET, SO_TYPE, ...) but better to store it with each listening socket. --- src/connections.c | 7 ++++--- src/fdevent.c | 22 ++++++++++++++++++++++ src/fdevent.h | 2 ++ src/mod_extforward.c | 17 +++++++++++++++-- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/connections.c b/src/connections.c index 80c63f45..03122fd5 100644 --- a/src/connections.c +++ b/src/connections.c @@ -161,10 +161,11 @@ static void connection_read_for_eos(server *srv, connection *con) { * it will make the client not see all our output. */ ssize_t len; - char buf[4096]; - + const int type = con->dst_addr.plain.sa_family; + char buf[16384]; do { - len = read(con->fd, buf, sizeof(buf)); + len = fdevent_socket_read_discard(con->fd, buf, sizeof(buf), + type, SOCK_STREAM); } while (len > 0 || (len < 0 && errno == EINTR)); if (len < 0 && errno == EAGAIN) return; diff --git a/src/fdevent.c b/src/fdevent.c index 441744a7..e8b94dfa 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -889,6 +889,28 @@ int fdevent_cycle_logger(const char *logger, int *curfd) { } +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + + +ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type) { + #if defined(MSG_TRUNC) && defined(__linux__) + if ((family == AF_INET || family == AF_INET6) && so_type == SOCK_STREAM) { + ssize_t len = recv(fd, buf, sz, MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL); + if (len >= 0 || errno != EINVAL) return len; + } + #else + UNUSED(family); + UNUSED(so_type); + #endif + return read(fd, buf, sz); +} + + #include #ifdef HAVE_SYS_FILIO_H #include /* FIONREAD (for illumos (OpenIndiana)) */ diff --git a/src/fdevent.h b/src/fdevent.h index 4c7f42a9..44dbbb9d 100644 --- a/src/fdevent.h +++ b/src/fdevent.h @@ -78,6 +78,8 @@ void fdevent_close_logger_pipes(void); void fdevent_breakagelog_logger_pipe(int fd); void fdevent_clr_logger_pipe_pids(void); +ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type); + int fdevent_ioctl_fionread (int fd, int fdfmt, int *toread); int fdevent_connect_status(int fd); diff --git a/src/mod_extforward.c b/src/mod_extforward.c index 0d1d7d7b..edccbfbf 100644 --- a/src/mod_extforward.c +++ b/src/mod_extforward.c @@ -1224,7 +1224,7 @@ indicating which element is present : #endif /* returns 0 if needs to poll, <0 upon error or >0 is protocol vers (success) */ -static int hap_PROXY_recv (const int fd, union hap_PROXY_hdr * const hdr) +static int hap_PROXY_recv (const int fd, union hap_PROXY_hdr * const hdr, const int family, const int so_type) { static const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"; @@ -1273,10 +1273,22 @@ static int hap_PROXY_recv (const int fd, union hap_PROXY_hdr * const hdr) /* we need to consume the appropriate amount of data from the socket * (overwrites existing contents of hdr with same data) */ + UNUSED(family); + UNUSED(so_type); do { + #if defined(MSG_TRUNC) && defined(__linux__) + if ((family==AF_INET || family==AF_INET6) && so_type == SOCK_STREAM) { + ret = recv(fd, hdr, sz, MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL); + if (ret >= 0 || errno != EINVAL) continue; + } + #endif ret = recv(fd, hdr, sz, MSG_DONTWAIT|MSG_NOSIGNAL); } while (-1 == ret && errno == EINTR); if (ret < 0) return -1; + if (ret != (ssize_t)sz) { + errno = EIO; /*(partial read; valid but unexpected; not handled)*/ + return -1; + } if (1 == ver) hdr->v1.line[sz-2] = '\0'; /*terminate str to ease parsing*/ return ver; } @@ -1540,7 +1552,8 @@ static int mod_extforward_network_read (server *srv, connection *con, * In the future, might add config switch to enable doing this extra work */ union hap_PROXY_hdr hdr; - int rc = hap_PROXY_recv(con->fd, &hdr); + int rc = hap_PROXY_recv(con->fd, &hdr, + con->dst_addr.plain.sa_family, SOCK_STREAM); switch (rc) { case 2: rc = mod_extforward_hap_PROXY_v2(con, &hdr); break; case 1: rc = mod_extforward_hap_PROXY_v1(con, &hdr); break;