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 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-24 20:34:46 +03:00
parent 7718ffa9f7
commit 0d6b2950f0
4 changed files with 20 additions and 22 deletions

View File

@ -294,10 +294,8 @@ int radsend(struct clientparam * param, int auth, int stop){
int total_length; int total_length;
int len; int len;
PROXYSOCKADDRTYPE saremote; PROXYSOCKADDRTYPE saremote;
struct pollfd fds[1];
char vector[AUTH_VECTOR_LEN]; char vector[AUTH_VECTOR_LEN];
radius_packet_t packet, rpacket; radius_packet_t packet, rpacket;
SASIZETYPE salen;
int data_len; int data_len;
int count=0; int count=0;
uint8_t *attr; 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) { if ((sockfd = so._socket(so.state, SASOCK(&saremote), SOCK_DGRAM, 0)) < 0) {
return 4; return 4;
} }
nonblock(sockfd);
remsock = sockfd; remsock = sockfd;
/* /*
} }
@ -557,17 +556,8 @@ int radsend(struct clientparam * param, int auth, int stop){
continue; continue;
} }
memset(fds, 0, sizeof(fds)); data_len = sockrecvfrom(NULL, remsock, (struct sockaddr *)&saremote, (unsigned char *)&rpacket,
fds[0].fd = remsock; sizeof(packet)-16, param->srv->config->timeouts[SINGLEBYTE_L]*1000);
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);
if (data_len < 20) { if (data_len < 20) {

View File

@ -138,6 +138,7 @@ void * ftpprchild(struct clientparam* param) {
if(bindwithrange(param, clidatasock, &param->sincl, param->intport)){RETURN(822);} if(bindwithrange(param, clidatasock, &param->sincl, param->intport)){RETURN(822);}
if (pasv) { if (pasv) {
if(param->srv->so._listen(param->sostate, clidatasock, 1)) {RETURN(823);} if(param->srv->so._listen(param->sostate, clidatasock, 1)) {RETURN(823);}
nonblock(clidatasock);
sasize = sizeof(param->sincl); sasize = sizeof(param->sincl);
if(param->srv->so._getsockname(param->sostate, clidatasock, (struct sockaddr *)&param->sincl, &sasize)){RETURN(824);} if(param->srv->so._getsockname(param->sostate, clidatasock, (struct sockaddr *)&param->sincl, &sasize)){RETURN(824);}
if(pasv == 1){ if(pasv == 1){
@ -222,12 +223,14 @@ void * ftpprchild(struct clientparam* param) {
fds.fd = clidatasock; fds.fd = clidatasock;
fds.events = POLLIN; fds.events = POLLIN;
res = sockpoll(&param->srv->so, param->sostate, &fds, 1, param->srv->timeouts[STRING_L]*1000); do {
if(res != 1) { res = sockpoll(&param->srv->so, param->sostate, &fds, 1, param->srv->timeouts[STRING_L]*1000);
RETURN(857); if(res != 1) {
} RETURN(857);
sasize = sizeof(param->sincr); }
ss = param->srv->so._accept(param->sostate, clidatasock, (struct sockaddr *)&param->sincr, &sasize); sasize = sizeof(param->sincr);
ss = param->srv->so._accept(param->sostate, clidatasock, (struct sockaddr *)&param->sincr, &sasize);
} while (ss == INVALID_SOCKET && acceptagain());
if (ss == INVALID_SOCKET) { RETURN (858);} if (ss == INVALID_SOCKET) { RETURN (858);}
#ifdef _WIN32 #ifdef _WIN32
{ unsigned long ul = 1; ioctlsocket(ss, FIONBIO, &ul); } { unsigned long ul = 1; ioctlsocket(ss, FIONBIO, &ul); }

View File

@ -1189,6 +1189,7 @@ static void httpsrv_linger(struct clientparam *param)
if(sockpoll(&param->srv->so, param->sostate, &fd, 1, timeo * 1000) <= 0) break; if(sockpoll(&param->srv->so, param->sostate, &fd, 1, timeo * 1000) <= 0) break;
got = (int)param->srv->so._recv(param->sostate, param->clisock, buf, got = (int)param->srv->so._recv(param->sostate, param->clisock, buf,
(left > HTTPSRV_BLOCK)? (int)HTTPSRV_BLOCK : (int)left, 0); (left > HTTPSRV_BLOCK)? (int)HTTPSRV_BLOCK : (int)left, 0);
if(got < 0 && (errno == EAGAIN || errno == EINTR)) continue;
if(got <= 0) break; if(got <= 0) break;
left -= (uint64_t)got; left -= (uint64_t)got;
} }

View File

@ -351,17 +351,21 @@ fflush(stderr);
break; break;
case 2: case 2:
param->srv->so._listen (param->sostate, param->remsock, 1); param->srv->so._listen (param->sostate, param->remsock, 1);
nonblock(param->remsock);
fds[0].fd = param->remsock; fds[0].fd = param->remsock;
fds[1].fd = param->clisock; fds[1].fd = param->clisock;
fds[0].events = fds[1].events = POLLIN; fds[0].events = fds[1].events = POLLIN;
res = sockpoll(&param->srv->so, param->sostate, fds, 2, param->srv->timeouts[CONNECTION_L] * 1000); do {
res = sockpoll(&param->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 *)&param->sinsr, &sasize);
} while (s == INVALID_SOCKET && acceptagain());
if (res < 1 || fds[1].revents) { if (res < 1 || fds[1].revents) {
res = 460; res = 460;
break; break;
} }
sasize = sizeof(param->sinsr);
s = param->srv->so._accept(param->sostate, param->remsock, (struct sockaddr *)&param->sinsr, &sasize);
param->srv->so._closesocket(param->sostate, param->remsock); param->srv->so._closesocket(param->sostate, param->remsock);
param->remsock = s; param->remsock = s;
if(s == INVALID_SOCKET) { if(s == INVALID_SOCKET) {