diff --git a/src/common.c b/src/common.c index 3bd4462..737a738 100644 --- a/src/common.c +++ b/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 diff --git a/src/mainclient.c b/src/mainclient.c index 6c17f5e..396aedb 100644 --- a/src/mainclient.c +++ b/src/mainclient.c @@ -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; } diff --git a/src/maintcp.c b/src/maintcp.c index 6c72a4c..cd9d839 100644 --- a/src/maintcp.c +++ b/src/maintcp.c @@ -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"); diff --git a/src/proxy.h b/src/proxy.h index 7538307..3dfc914 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -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);