From 6f1e681e0d9bc87205e98348f09bc0acef6faaad Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Thu, 11 Sep 2025 23:20:17 -0400 Subject: [PATCH 1/5] check socket writable after non-blocking connect() check socket writable after non-blocking connect() to find when connect() has completed, and then check for connect() success/failure This is the portable way to determine status of a non-blocking connect() --- src/sock.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/sock.c b/src/sock.c index a91cb93..cab7cdc 100644 --- a/src/sock.c +++ b/src/sock.c @@ -267,25 +267,24 @@ new_socket(CONN *C, const char *hostparam, int portparam) case EISCONN: {NOTIFY(ERROR, "socket: %d already connected.", pthread_self()); break;} default: {NOTIFY(ERROR, "socket: %d unknown network error.", pthread_self()); break;} } socket_close(C); return -1; - } else { - if (__socket_check(C, READ) == FALSE) { + } else if (conn < 0) { /* && errno == EINPROGRESS */ + if (__socket_check(C, WRITE) == FALSE) { pthread_testcancel(); - NOTIFY(WARNING, "socket: read check timed out(%d) %s:%d", my.timeout, __FILE__, __LINE__); + NOTIFY(WARNING, "socket: connect() check timed out(%d) %s:%d", my.timeout, __FILE__, __LINE__); socket_close(C); - return -1; - } else { - /** - * If we reconnect and receive EISCONN, then we have a successful connection - */ - res = connect(C->sock, s_addr, addrlen); - if((res < 0)&&(errno != EISCONN)){ - NOTIFY(ERROR, "socket: unable to connect %s:%d", __FILE__, __LINE__); + return -1; + } else { + int opt = 0; + socklen_t len = sizeof(opt); + if (0 != getsockopt(C->sock, SOL_SOCKET, SO_ERROR, &opt, &len) || 0 != opt) { + pthread_testcancel(); + NOTIFY(WARNING, "socket: connect() error (%d) %s:%d", opt ? opt : errno, __FILE__, __LINE__); socket_close(C); - return -1; + return -1; } - C->status = S_READING; } } /* end of connect conditional */ + C->status = S_READING; if ((__socket_block(C->sock, TRUE)) < 0) { NOTIFY(ERROR, "socket: unable to set socket to non-blocking %s:%d", __FILE__, __LINE__); From 85207728eaff68f51605644cdc2392fe5caf7e5a Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Thu, 11 Sep 2025 23:24:27 -0400 Subject: [PATCH 2/5] do not change sock blocking mode when using poll() --- src/sock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sock.c b/src/sock.c index cab7cdc..cf43b6e 100644 --- a/src/sock.c +++ b/src/sock.c @@ -320,7 +320,6 @@ __socket_poll(CONN *C, SDSET mode) { int res; int timo = (my.timeout) ? my.timeout * 1000 : 15000; - __socket_block(C->sock, FALSE); C->pfd[0].fd = C->sock + 1; C->pfd[0].events |= POLLIN; From b8624fda481d43f3a2b1d2a87ca78e8758ea9e0f Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Thu, 11 Sep 2025 23:29:06 -0400 Subject: [PATCH 3/5] prefer poll(), where available Since selecting ready events on a single descriptor, prefer poll(), where available --- src/sock.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sock.c b/src/sock.c index cf43b6e..0d43f0b 100644 --- a/src/sock.c +++ b/src/sock.c @@ -70,7 +70,9 @@ private int __socket_block(int socket, BOOLEAN block); private ssize_t __socket_write(int sock, const void *vbuf, size_t len); private BOOLEAN __socket_check(CONN *C, SDSET mode); +#ifndef HAVE_POLL private BOOLEAN __socket_select(CONN *C, SDSET mode); +#endif private int __socket_create(CONN *C, int domain); private void __hostname_strip(char *hn, int len); #ifdef HAVE_POLL @@ -304,11 +306,7 @@ private BOOLEAN __socket_check(CONN *C, SDSET mode) { #ifdef HAVE_POLL - if (C->sock >= FD_SETSIZE) { - return __socket_poll(C, mode); - } else { - return __socket_select(C, mode); - } + return __socket_poll(C, mode); #else return __socket_select(C, mode); #endif/*HAVE_POLL*/ @@ -348,6 +346,7 @@ __socket_poll(CONN *C, SDSET mode) } #endif/*HAVE_POLL*/ +#ifndef HAVE_POLL private BOOLEAN __socket_select(CONN *C, SDSET mode) { @@ -386,6 +385,7 @@ __socket_select(CONN *C, SDSET mode) return TRUE; } } +#endif /** * Create new socket and set socket options. From 71a008ed53ce693e48febac4314c1a00bea97245 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Thu, 11 Sep 2025 23:35:17 -0400 Subject: [PATCH 4/5] disable TCP Nagle algorithm --- src/sock.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sock.c b/src/sock.c index 0d43f0b..7555c1f 100644 --- a/src/sock.c +++ b/src/sock.c @@ -288,6 +288,16 @@ new_socket(CONN *C, const char *hostparam, int portparam) } /* end of connect conditional */ C->status = S_READING; +#ifdef TCP_NODELAY + { + int opt = 1; + socklen_t len = sizeof(opt); + if (0 != setsockopt(C->sock, IPPROTO_TCP, TCP_NODELAY, &opt, &len)) { + NOTIFY(ERROR, "socket: unable to set socket to disable TCP Nagle algo %s:%d", __FILE__, __LINE__); + } + } +#endif + if ((__socket_block(C->sock, TRUE)) < 0) { NOTIFY(ERROR, "socket: unable to set socket to non-blocking %s:%d", __FILE__, __LINE__); return -1; From 21b9c0653f1f59b143057231e704b51728d82fc4 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 12 Sep 2025 00:05:22 -0400 Subject: [PATCH 5/5] poll for READ or WRITE based on mode arg --- src/sock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sock.c b/src/sock.c index 7555c1f..526d23a 100644 --- a/src/sock.c +++ b/src/sock.c @@ -330,7 +330,7 @@ __socket_poll(CONN *C, SDSET mode) int timo = (my.timeout) ? my.timeout * 1000 : 15000; C->pfd[0].fd = C->sock + 1; - C->pfd[0].events |= POLLIN; + C->pfd[0].events |= (mode == READ ? POLLIN : POLLOUT); do { res = poll(C->pfd, 1, timo); @@ -376,8 +376,8 @@ __socket_select(CONN *C, SDSET mode) do { FD_ZERO(&rs); FD_ZERO(&ws); - FD_SET(C->sock, &rs); - FD_SET(C->sock, &ws); + if (mode == READ) FD_SET(C->sock, &rs); + if (mode == WRITE) FD_SET(C->sock, &ws); res = select(C->sock+1, &rs, &ws, NULL, &timeout); pthread_testcancel(); } while (res < 0 && errno == EINTR);