Use a non blocking connect with a 1 second select timeout when initiating stratum to allow us to iterate over all IPs returned by getaddrinfo in round robin DNS pools.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
diff --git a/util.c b/util.c
index d3d2897..bae736d 100644
--- a/util.c
+++ b/util.c
@@ -2045,6 +2045,40 @@ static bool socks4_negotiate(struct pool *pool, int sockd, bool socks4a)
return true;
}
+static void noblock_socket(SOCKETTYPE fd)
+{
+#ifndef WIN32
+ int flags = fcntl(fd, F_GETFL, 0);
+
+ fcntl(fd, F_SETFL, O_NONBLOCK | flags);
+#else
+ u_long flags = 1;
+
+ ioctlsocket(fd, FIONBIO, &flags);
+#endif
+}
+
+static void block_socket(SOCKETTYPE fd)
+{
+#ifndef WIN32
+ int flags = fcntl(fd, F_GETFL, 0);
+
+ fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+#else
+ u_long flags = 0;
+
+ ioctlsocket(fd, FIONBIO, &flags);
+#endif
+}
+
+static bool sock_connecting(void)
+{
+#ifndef WIN32
+ return errno == EINPROGRESS;
+#else
+ return WSAGetLastError() == WSAEWOULDBLOCK;
+#endif
+}
static bool setup_stratum_socket(struct pool *pool)
{
struct addrinfo servinfobase, *servinfo, *hints, *p;
@@ -2096,11 +2130,41 @@ static bool setup_stratum_socket(struct pool *pool)
continue;
}
+ /* Iterate non blocking over entries returned by getaddrinfo
+ * to cope with round robin DNS entries, finding the first one
+ * we can connect to quickly. */
+ noblock_socket(sockd);
if (connect(sockd, p->ai_addr, p->ai_addrlen) == -1) {
+ struct timeval tv_timeout = {1, 0};
+ int selret;
+ fd_set rw;
+
+ if (!sock_connecting()) {
+ CLOSESOCKET(sockd);
+ applog(LOG_DEBUG, "Failed sock connect");
+ continue;
+ }
+ FD_ZERO(&rw);
+ FD_SET(sockd, &rw);
+ selret = select(sockd + 1, NULL, &rw, NULL, &tv_timeout);
+ if (selret > 0 && FD_ISSET(sockd, &rw)) {
+ socklen_t len;
+ int err, n;
+
+ len = sizeof(err);
+ n = getsockopt(sockd, SOL_SOCKET, SO_ERROR, (void *)&err, &len);
+ if (!n && !err) {
+ applog(LOG_DEBUG, "Succeeded delayed connect");
+ block_socket(sockd);
+ break;
+ }
+ }
CLOSESOCKET(sockd);
- applog(LOG_DEBUG, "Failed connect");
+ applog(LOG_DEBUG, "Select timeout/failed connect");
continue;
}
+ applog(LOG_WARNING, "Succeeded immediate connect");
+ block_socket(sockd);
break;
}