From b622a6ec8d9329b7736491dc7641c7f55933df07 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 14 Dec 2015 23:22:16 +1100 Subject: [PATCH] Check for errors in wait_read_select, closing the socket if they occur, and add a variant for non-unix sockets that checks for hangups as well --- src/ckpool.c | 2 +- src/generator.c | 4 ++-- src/libckpool.c | 38 +++++++++++++++++++++++++++----------- src/libckpool.h | 5 ++++- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/ckpool.c b/src/ckpool.c index 70269b46..aff75444 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -527,7 +527,7 @@ rewait: ret = 0; goto out; } - ret = wait_read_select(cs->fd, eom ? 0 : *timeout); + ret = wait_recv_select(cs->fd, eom ? 0 : *timeout); if (ret < 1) { if (!ret) { if (eom) diff --git a/src/generator.c b/src/generator.c index 2853baf7..da28e55f 100644 --- a/src/generator.c +++ b/src/generator.c @@ -290,7 +290,7 @@ retry: ckmsgq_add(gdata->srvchk, si); do { - selret = wait_read_select(us->sockd, 5); + selret = wait_recv_select(us->sockd, 5); if (!selret && !ping_main(ckp)) { LOGEMERG("Generator failed to ping main process, exiting"); ret = 1; @@ -1632,7 +1632,7 @@ retry: ckmsgq_add(gdata->srvchk, proxi->si); do { - selret = wait_read_select(us->sockd, 5); + selret = wait_recv_select(us->sockd, 5); if (!selret && !ping_main(ckp)) { LOGEMERG("Generator failed to ping main process, exiting"); ret = 1; diff --git a/src/libckpool.c b/src/libckpool.c index 8e08253a..3ba15232 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -758,17 +758,15 @@ out: void empty_socket(int fd) { + char buf[PAGESIZE]; int ret; if (fd < 1) return; do { - char buf[PAGESIZE]; - - ret = wait_read_select(fd, 0); + ret = recv(fd, buf, PAGESIZE - 1, MSG_DONTWAIT); if (ret > 0) { - ret = recv(fd, buf, PAGESIZE - 1, 0); buf[ret] = 0; LOGDEBUG("Discarding: %s", buf); } @@ -907,21 +905,39 @@ int wait_close(int sockd, int timeout) return sfd.revents & (POLLHUP | POLLRDHUP | POLLERR); } -/* Emulate a select read wait for high fds that select doesn't support */ -int wait_read_select(int sockd, float timeout) +/* Emulate a select read wait for high fds that select doesn't support. + * wait_read_select is for unix sockets and _wait_recv_select for regular + * sockets. */ +int _wait_read_select(int *sockd, float timeout) { struct pollfd sfd; int ret = -1; - if (unlikely(sockd < 0)) + if (unlikely(*sockd < 0)) goto out; - sfd.fd = sockd; + sfd.fd = *sockd; sfd.events = POLLIN | POLLRDHUP; - sfd.revents = 0; timeout *= 1000; ret = poll(&sfd, 1, timeout); - if (ret && !(sfd.revents & POLLIN)) - ret = -1; + if (ret > 0 && sfd.revents & (POLLERR)) + _Close(sockd); +out: + return ret; +} + +int _wait_recv_select(int *sockd, float timeout) +{ + struct pollfd sfd; + int ret = -1; + + if (unlikely(*sockd < 0)) + goto out; + sfd.fd = *sockd; + sfd.events = POLLIN | POLLRDHUP; + timeout *= 1000; + ret = poll(&sfd, 1, timeout); + if (ret > 0 && sfd.revents & (POLLHUP | POLLRDHUP | POLLERR)) + _Close(sockd); out: return ret; } diff --git a/src/libckpool.h b/src/libckpool.h index 9d8ba341..222ce26f 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -496,7 +496,10 @@ int _open_unix_server(const char *server_path, const char *file, const char *fun int _open_unix_client(const char *server_path, const char *file, const char *func, const int line); #define open_unix_client(server_path) _open_unix_client(server_path, __FILE__, __func__, __LINE__) int wait_close(int sockd, int timeout); -int wait_read_select(int sockd, float timeout); +int _wait_read_select(int *sockd, float timeout); +#define wait_read_select(SOCKD, TIMEOUT) _wait_read_select(&(SOCKD), TIMEOUT) +int _wait_recv_select(int *sockd, float timeout); +#define wait_recv_select(SOCKD, TIMEOUT) _wait_recv_select(&(SOCKD), TIMEOUT) int read_length(int sockd, void *buf, int len); char *_recv_unix_msg(int sockd, int timeout1, int timeout2, const char *file, const char *func, const int line); #define RECV_UNIX_TIMEOUT1 30