Connect back: a connection one client takes leaves the others waiting

The clients of a -R service all wait for the connection back on the
same listening socket, which was blocking: one connection woke them
all, one took it, and the others were left in accept() until the next,
past their time out and through a reload. The socket is non-blocking,
and an accept() which finds nothing, the connection taken by another
client or gone, is not one of the client's tries. nonblock() makes a
socket non-blocking, acceptagain() tells such an accept().
(cherry picked from commit 126c7d0)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-24 20:56:15 +03:00
parent 62fd5e3a8d
commit 0c80c9f526
3 changed files with 26 additions and 0 deletions

View File

@ -634,6 +634,26 @@ int parseconnusername(char *username, struct clientparam *param, int extpasswd,
}
/* What waits for a socket waits in poll(): a call on it never does. */
void nonblock(SOCKET sock){
#ifdef _WIN32
unsigned long ul = 1;
ioctlsocket(sock, FIONBIO, &ul);
#else
fcntl(sock, F_SETFL, O_NONBLOCK | fcntl(sock, F_GETFL));
#endif
}
/* accept() with nothing to accept: another took it, or it was gone */
int acceptagain(void){
#ifdef _WIN32
int err = WSAGetLastError();
return err == WSAEWOULDBLOCK || err == WSAECONNRESET || err == WSAEINTR;
#else
return errno == EAGAIN || errno == EWOULDBLOCK || errno == ECONNABORTED || errno == EINTR;
#endif
}
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to){
struct pollfd fds[1];
#ifdef _WIN32

View File

@ -405,6 +405,8 @@ unsigned char * dologname (unsigned char *buf, unsigned char *name, const unsign
int readconfig(FILE * fp);
void initcommands(void);
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to);
void nonblock(SOCKET sock);
int acceptagain(void);
int bindwithrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa, uint32_t range);
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family);
int extbindtodevice(struct clientparam *param, SOCKET sock);

View File

@ -63,6 +63,8 @@ void * threadfunc (void *p) {
}
param->remsock = param->srv->so._accept(param->sostate, param->srv->cbsock, (struct sockaddr*)&param->sinsr, &size);
if(param->remsock == INVALID_SOCKET) {
/* another client of the service took it: not a try */
if(acceptagain()) { i++; continue; }
dolog(param, (unsigned char *)"Connect back accept() failed");
continue;
}
@ -864,6 +866,8 @@ static int cblisten(struct srvstart *s){
return -6;
}
setopts(srv->cbsock, &srv->cbssockopts);
/* the clients of the service all wait for it: one accepts what comes */
nonblock(srv->cbsock);
if(srv->so._bind(srv->so.state, srv->cbsock, (struct sockaddr*)&cbsa, SASIZE(&cbsa))==-1) {
dolog(defparam, (unsigned char *)"Failed to bind connect back socket");