mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 13:55:48 +08:00
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(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
bfd812f0b8
commit
126c7d00ec
20
src/common.c
20
src/common.c
@ -674,6 +674,26 @@ int parseconnusername(char *username, struct clientparam *param, int extpasswd,
|
||||
}
|
||||
|
||||
|
||||
/* What waits for a socket waits in sockpoll(): 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
|
||||
|
||||
@ -54,6 +54,8 @@ static void serveparam(struct clientparam *param){
|
||||
}
|
||||
param->remsock = param->srv->so._accept(param->sostate, param->srv->cbsock, (struct sockaddr*)¶m->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;
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@ static int cblisten(struct srvstart *s){
|
||||
return -6;
|
||||
}
|
||||
setopts(srv->cbsock, &srv->cbssockopts, srv->maxseg);
|
||||
/* 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");
|
||||
|
||||
@ -333,6 +333,8 @@ int nsbroken(void);
|
||||
lines among its arguments */
|
||||
SOCKET nssocket(struct srvparam *srv, struct sockfuncs *sf, void *state, int side, int domain, int type, int protocol);
|
||||
int sockpoll(struct sockfuncs *sf, void *state, struct pollfd *fds, unsigned nfds, int timeout);
|
||||
void nonblock(SOCKET sock);
|
||||
int acceptagain(void);
|
||||
int socksend(struct clientparam *param, SOCKET sock, unsigned char * buf, int bufsize, int to);
|
||||
int socksendto(struct clientparam *param, SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to);
|
||||
int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user