From bfbe3a1039dfe8aef9559439756d58697c15b068 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 14 Dec 2015 22:07:22 +1100 Subject: [PATCH 1/3] Don't block on dead servers if possible when calling server_alive from the gen_loop --- src/ckpool.h | 1 + src/generator.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/ckpool.h b/src/ckpool.h index 6d0e7348..61108868 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -111,6 +111,7 @@ struct server_instance { char *auth; char *pass; bool notify; + bool alive; connsock_t cs; void *data; // Private data diff --git a/src/generator.c b/src/generator.c index 5dc76b22..88bf20b2 100644 --- a/src/generator.c +++ b/src/generator.c @@ -147,6 +147,7 @@ static bool server_alive(ckpool_t *ckp, server_instance_t *si, bool pinging) /* Has this server already been reconnected? */ if (cs->fd > 0) return true; + si->alive = false; if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { LOGWARNING("Failed to extract address from %s", si->url); return ret; @@ -189,6 +190,7 @@ out: /* Close and invalidate the file handle */ Close(cs->fd); } else { + si->alive = true; LOGNOTICE("Server alive: %s:%s", cs->url, cs->port); keep_sockalive(cs->fd); } @@ -207,19 +209,30 @@ retry: if (!ping_main(ckp)) goto out; + /* First find a server that is already flagged alive if possible + * without blocking on server_alive() */ for (i = 0; i < ckp->btcds; i++) { server_instance_t *si = ckp->servers[i]; - if (server_alive(ckp, si, false)) { + if (si->alive) { alive = si; - break; + goto living; } } - if (!alive) { - LOGWARNING("CRITICAL: No bitcoinds active!"); - sleep(5); - goto retry; + + /* No servers flagged alive, try to connect to them blocking */ + for (i = 0; i < ckp->btcds; i++) { + server_instance_t *si = ckp->servers[i]; + + if (server_alive(ckp, si, false)) { + alive = si; + goto living; + } } + LOGWARNING("CRITICAL: No bitcoinds active!"); + sleep(5); + goto retry; +living: cs = &alive->cs; LOGINFO("Connected to live server %s:%s", cs->url, cs->port); out: From 6ff89b31a25014b18d06f25920ccd1a355903e1f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 14 Dec 2015 22:08:48 +1100 Subject: [PATCH 2/3] Check server fd is still valid as well as having its alive flag set --- src/generator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/generator.c b/src/generator.c index 88bf20b2..2853baf7 100644 --- a/src/generator.c +++ b/src/generator.c @@ -213,8 +213,9 @@ retry: * without blocking on server_alive() */ for (i = 0; i < ckp->btcds; i++) { server_instance_t *si = ckp->servers[i]; + cs = &si->cs; - if (si->alive) { + if (si->alive && cs->fd > 0) { alive = si; goto living; } From b622a6ec8d9329b7736491dc7641c7f55933df07 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 14 Dec 2015 23:22:16 +1100 Subject: [PATCH 3/3] 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