Leave a hung-up socket out of poll() rather than pass an invalid one
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run

A socket which hung up and of which nothing is asked was given to poll()
as INVALID_SOCKET, so that poll() would not return at once for the
hang-up every time. poll() ignores a negative descriptor, but SOCKET is
unsigned on Windows, and WSAPoll fails the whole call for it: sockmap()
ended the session as soon as a client half-closed. Such a socket is now
not in the array at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 98fd0f329f)
This commit is contained in:
Vladimir Dubrovin 2026-10-13 13:09:41 +03:00
parent 84dd84a993
commit 41edaa9757

View File

@ -99,6 +99,8 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0; int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
/* the side has hung up: closed by the peer after its own was shut down */ /* the side has hung up: closed by the peer after its own was shut down */
int CLIENTHUP = 0, SERVERHUP = 0; int CLIENTHUP = 0, SERVERHUP = 0;
/* whether the side's socket is in this round's poll() */
int clipolled = 1, srvpolled = 1;
int after = 0; int after = 0;
struct pollfd fds[8]; struct pollfd fds[8];
int fdsc = 0; int fdsc = 0;
@ -665,8 +667,10 @@ log("done read from server to buf");
)) ))
cli_events |= POLLOUT; cli_events |= POLLOUT;
/* poll() reports a hang-up whatever is asked, and would /* poll() reports a hang-up whatever is asked, and would
return at once every time: wait for the other side then */ return at once every time: the socket is left out then,
if(!cli_events && CLIENTHUP) fds[fdsc].fd = INVALID_SOCKET; rather than given as an invalid one, which WSAPoll takes
for an error */
clipolled = cli_events || !CLIENTHUP;
if(cli_events){ if(cli_events){
fds[fdsc].fd = param->clisock; fds[fdsc].fd = param->clisock;
fds[fdsc].events = cli_events; fds[fdsc].events = cli_events;
@ -678,6 +682,8 @@ log("wait writing to client");
#endif #endif
} }
} }
else if(!clipolled){
}
else if(cli_events){ else if(cli_events){
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) { if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
CLIENTTERMREAD = 1; CLIENTTERMREAD = 1;
@ -713,7 +719,7 @@ log("ready to write to client");
read, once the buffer has room for it */ read, once the buffer has room for it */
CLIENTHUP = 1; CLIENTHUP = 1;
} }
fdsc++; if(clipolled) fdsc++;
// if(!SERVERTERMREAD || !SERVERTERMWRITE){ // if(!SERVERTERMREAD || !SERVERTERMWRITE){
if(!after){ if(!after){
@ -727,7 +733,7 @@ log("ready to write to client");
#endif #endif
)) ))
srv_events |= POLLOUT; srv_events |= POLLOUT;
if(!srv_events && SERVERHUP) fds[fdsc].fd = INVALID_SOCKET; srvpolled = srv_events || !SERVERHUP;
if(srv_events){ if(srv_events){
fds[fdsc].fd = param->remsock; fds[fdsc].fd = param->remsock;
fds[fdsc].events = srv_events; fds[fdsc].events = srv_events;
@ -739,6 +745,8 @@ log("wait writing from server");
#endif #endif
} }
} }
else if(!srvpolled){
}
else if(srv_events){ else if(srv_events){
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) { if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
#ifdef WITHLOG #ifdef WITHLOG
@ -780,7 +788,7 @@ log("server terminated connection");
/* the rest of the answer may still be waiting to be read */ /* the rest of the answer may still be waiting to be read */
SERVERHUP = 1; SERVERHUP = 1;
} }
fdsc++; if(srvpolled) fdsc++;
// } // }
#ifdef WITHSPLICE #ifdef WITHSPLICE
{ {