From 0d6b2950f0d08eafff42c5143374423091c09bc3 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Sat, 24 Oct 2026 20:34:46 +0300 Subject: [PATCH] Sockets read after a wait are non-blocking, and a read finding nothing waits again A wait may end with nothing to read: a TLS record not yet whole, a connection gone before it is accepted, and, once clients share a thread, nothing more than a chance to try. Where a read or an accept() followed a wait on a blocking socket, or ended the operation when it found nothing, the socket is non-blocking and the wait is made again: the listening sockets of SOCKS BIND and of FTP passive mode, httpsrv reading what is left of a request body, and the RADIUS client, which reads with sockrecvfrom(). Co-Authored-By: Claude Opus 5.5 --- src/authradius.c | 16 +++------------- src/ftppr.c | 15 +++++++++------ src/httpsrv.c | 1 + src/socks.c | 10 +++++++--- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/authradius.c b/src/authradius.c index 635547c..e62a4bc 100644 --- a/src/authradius.c +++ b/src/authradius.c @@ -294,10 +294,8 @@ int radsend(struct clientparam * param, int auth, int stop){ int total_length; int len; PROXYSOCKADDRTYPE saremote; - struct pollfd fds[1]; char vector[AUTH_VECTOR_LEN]; radius_packet_t packet, rpacket; - SASIZETYPE salen; int data_len; int count=0; uint8_t *attr; @@ -545,6 +543,7 @@ int radsend(struct clientparam * param, int auth, int stop){ if ((sockfd = so._socket(so.state, SASOCK(&saremote), SOCK_DGRAM, 0)) < 0) { return 4; } + nonblock(sockfd); remsock = sockfd; /* } @@ -557,17 +556,8 @@ int radsend(struct clientparam * param, int auth, int stop){ continue; } - memset(fds, 0, sizeof(fds)); - fds[0].fd = remsock; - fds[0].events = POLLIN; - if(sockpoll(&so, so.state, fds, 1, param->srv->config->timeouts[SINGLEBYTE_L]*1000) <= 0) { - continue; - } - - salen = sizeof(saremote); - - data_len = so._recvfrom(so.state, remsock, (char *)&rpacket, sizeof(packet)-16, - 0, (struct sockaddr *)&saremote, &salen); + data_len = sockrecvfrom(NULL, remsock, (struct sockaddr *)&saremote, (unsigned char *)&rpacket, + sizeof(packet)-16, param->srv->config->timeouts[SINGLEBYTE_L]*1000); if (data_len < 20) { diff --git a/src/ftppr.c b/src/ftppr.c index f920f41..181ae76 100644 --- a/src/ftppr.c +++ b/src/ftppr.c @@ -138,6 +138,7 @@ void * ftpprchild(struct clientparam* param) { if(bindwithrange(param, clidatasock, ¶m->sincl, param->intport)){RETURN(822);} if (pasv) { if(param->srv->so._listen(param->sostate, clidatasock, 1)) {RETURN(823);} + nonblock(clidatasock); sasize = sizeof(param->sincl); if(param->srv->so._getsockname(param->sostate, clidatasock, (struct sockaddr *)¶m->sincl, &sasize)){RETURN(824);} if(pasv == 1){ @@ -222,12 +223,14 @@ void * ftpprchild(struct clientparam* param) { fds.fd = clidatasock; fds.events = POLLIN; - res = sockpoll(¶m->srv->so, param->sostate, &fds, 1, param->srv->timeouts[STRING_L]*1000); - if(res != 1) { - RETURN(857); - } - sasize = sizeof(param->sincr); - ss = param->srv->so._accept(param->sostate, clidatasock, (struct sockaddr *)¶m->sincr, &sasize); + do { + res = sockpoll(¶m->srv->so, param->sostate, &fds, 1, param->srv->timeouts[STRING_L]*1000); + if(res != 1) { + RETURN(857); + } + sasize = sizeof(param->sincr); + ss = param->srv->so._accept(param->sostate, clidatasock, (struct sockaddr *)¶m->sincr, &sasize); + } while (ss == INVALID_SOCKET && acceptagain()); if (ss == INVALID_SOCKET) { RETURN (858);} #ifdef _WIN32 { unsigned long ul = 1; ioctlsocket(ss, FIONBIO, &ul); } diff --git a/src/httpsrv.c b/src/httpsrv.c index 3b135ba..3e35b0e 100644 --- a/src/httpsrv.c +++ b/src/httpsrv.c @@ -1189,6 +1189,7 @@ static void httpsrv_linger(struct clientparam *param) if(sockpoll(¶m->srv->so, param->sostate, &fd, 1, timeo * 1000) <= 0) break; got = (int)param->srv->so._recv(param->sostate, param->clisock, buf, (left > HTTPSRV_BLOCK)? (int)HTTPSRV_BLOCK : (int)left, 0); + if(got < 0 && (errno == EAGAIN || errno == EINTR)) continue; if(got <= 0) break; left -= (uint64_t)got; } diff --git a/src/socks.c b/src/socks.c index 467e3c8..e5086ff 100644 --- a/src/socks.c +++ b/src/socks.c @@ -351,17 +351,21 @@ fflush(stderr); break; case 2: param->srv->so._listen (param->sostate, param->remsock, 1); + nonblock(param->remsock); fds[0].fd = param->remsock; fds[1].fd = param->clisock; fds[0].events = fds[1].events = POLLIN; - res = sockpoll(¶m->srv->so, param->sostate, fds, 2, param->srv->timeouts[CONNECTION_L] * 1000); + do { + res = sockpoll(¶m->srv->so, param->sostate, fds, 2, param->srv->timeouts[CONNECTION_L] * 1000); + if (res < 1 || fds[1].revents) break; + sasize = sizeof(param->sinsr); + s = param->srv->so._accept(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsr, &sasize); + } while (s == INVALID_SOCKET && acceptagain()); if (res < 1 || fds[1].revents) { res = 460; break; } - sasize = sizeof(param->sinsr); - s = param->srv->so._accept(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsr, &sasize); param->srv->so._closesocket(param->sostate, param->remsock); param->remsock = s; if(s == INVALID_SOCKET) {