[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.
personal/stbuehler/fix-fdevent
Glenn Strauss 2017-12-11 01:20:43 -05:00
parent e4ed2ed4ae
commit 84b5064dc4
4 changed files with 43 additions and 5 deletions

View File

@ -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;

View File

@ -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 <sys/ioctl.h>
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h> /* FIONREAD (for illumos (OpenIndiana)) */

View File

@ -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);

View File

@ -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;