Correctly process half-closed connections; add grace sleep before closing sockets

This commit is contained in:
Vladimir Dubrovin 2026-04-28 16:15:18 +03:00
parent fb70d06d3e
commit a4527783d6

View File

@ -50,7 +50,7 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
int FROMCLIENT = 1, TOCLIENTBUF = 1, FROMCLIENTBUF = 1, TOSERVER = 1, int FROMCLIENT = 1, TOCLIENTBUF = 1, FROMCLIENTBUF = 1, TOSERVER = 1,
FROMSERVER = 1, TOSERVERBUF = 1, FROMSERVERBUF = 1, TOCLIENT = 1; FROMSERVER = 1, TOSERVERBUF = 1, FROMSERVERBUF = 1, TOCLIENT = 1;
int HASERROR=0; int HASERROR=0;
int CLIENTTERM = 0, SERVERTERM = 0; int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
int after = 0; int after = 0;
struct pollfd fds[6]; struct pollfd fds[6];
struct pollfd *fdsp = fds; struct pollfd *fdsp = fds;
@ -62,6 +62,8 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
int needaction = 0; int needaction = 0;
int graceclinum=0, gracesrvnum=0, graceclitraf=0, gracesrvtraf=0; int graceclinum=0, gracesrvnum=0, graceclitraf=0, gracesrvtraf=0;
time_t gracetime = 0; time_t gracetime = 0;
int cli_events = 0;
int srv_events = 0;
#ifdef WITHSPLICE #ifdef WITHSPLICE
uint64_t inclientpipe = 0, inserverpipe = 0; uint64_t inclientpipe = 0, inserverpipe = 0;
@ -121,24 +123,24 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
if(action != PASS) RETURN(19); if(action != PASS) RETURN(19);
while( while(
((!CLIENTTERM) && fromserver && (inserverbuf ((!CLIENTTERMWRITE) && fromserver && (inserverbuf
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| inserverpipe || inserverpipe
#endif #endif
|| (!SERVERTERM ))) || (!SERVERTERMREAD )))
|| ||
((!SERVERTERM) && fromclient && (inclientbuf ((!SERVERTERMWRITE) && fromclient && (inclientbuf
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| inclientpipe || inclientpipe
#endif #endif
|| (!CLIENTTERM ))) || (!CLIENTTERMREAD )))
){ ){
#if WITHLOG > 1 #if WITHLOG > 1
sprintf(logbuf, "int FROMCLIENT = %d, TOCLIENTBUF = %d, FROMCLIENTBUF = %d, TOSERVER = %d, " sprintf(logbuf, "int FROMCLIENT = %d, TOCLIENTBUF = %d, FROMCLIENTBUF = %d, TOSERVER = %d, "
"FROMSERVER = %d, TOSERVERBUF = %d, FROMSERVERBUF = %d, TOCLIENT = %d; inclientbuf=%d; " "FROMSERVER = %d, TOSERVERBUF = %d, FROMSERVERBUF = %d, TOCLIENT = %d; inclientbuf=%d; "
"inserverbuf=%d, CLIENTTERM = %d, SERVERTERM =%d, fromserver=%u, fromclient=%u" "inserverbuf=%d, CLIENTTERMREAD=%d CLIENTTERMWRITE=%d SERVERTERMREAD=%d SERVERTERMWRITE=%d fromserver=%u, fromclient=%u"
#ifdef WITHSPLICE #ifdef WITHSPLICE
", inserverpipe=%d, inclentpipe=%d " ", inserverpipe=%d, inclentpipe=%d "
"TOCLIENTPIPE=%d FROMCLIENTPIPE==%d TOSERVERPIPE==%d FROMSERVERPIPE=%d" "TOCLIENTPIPE=%d FROMCLIENTPIPE==%d TOSERVERPIPE==%d FROMSERVERPIPE=%d"
@ -146,7 +148,7 @@ sprintf(logbuf, "int FROMCLIENT = %d, TOCLIENTBUF = %d, FROMCLIENTBUF = %d, TOSE
, ,
FROMCLIENT, TOCLIENTBUF, FROMCLIENTBUF, TOSERVER, FROMCLIENT, TOCLIENTBUF, FROMCLIENTBUF, TOSERVER,
FROMSERVER, TOSERVERBUF, FROMSERVERBUF, TOCLIENT, FROMSERVER, TOSERVERBUF, FROMSERVERBUF, TOCLIENT,
(int)inclientbuf, (int)inserverbuf, CLIENTTERM, SERVERTERM, (int)inclientbuf, (int)inserverbuf, CLIENTTERMREAD, CLIENTTERMWRITE, SERVERTERMREAD, SERVERTERMWRITE,
(unsigned)fromserver, (unsigned)fromclient (unsigned)fromserver, (unsigned)fromclient
#ifdef WITHSPLICE #ifdef WITHSPLICE
,(int)inserverpipe, (int)inclientpipe, ,(int)inserverpipe, (int)inclientpipe,
@ -215,7 +217,8 @@ log("send to server from buf");
if(res <= 0) { if(res <= 0) {
TOSERVER = 0; TOSERVER = 0;
if(errno && errno != EAGAIN && errno != EINTR){ if(errno && errno != EAGAIN && errno != EINTR){
SERVERTERM = 1; SERVERTERMREAD = 1;
SERVERTERMWRITE = 1;
HASERROR |= 2; HASERROR |= 2;
} }
} }
@ -260,7 +263,8 @@ log("send to client from buf");
if(res <= 0) { if(res <= 0) {
TOCLIENT = 0; TOCLIENT = 0;
if(errno && errno != EAGAIN && errno != EINTR){ if(errno && errno != EAGAIN && errno != EINTR){
CLIENTTERM = 1; CLIENTTERMREAD = 1;
CLIENTTERMWRITE = 1;
HASERROR |= 1; HASERROR |= 1;
} }
@ -357,7 +361,7 @@ log(logbuf);
if(res <= 0) { if(res <= 0) {
FROMCLIENT = TOCLIENTPIPE = 0; FROMCLIENT = TOCLIENTPIPE = 0;
if(res == 0 && !errno) { if(res == 0 && !errno) {
CLIENTTERM = 1; CLIENTTERMREAD = 1;
continue; continue;
} }
} }
@ -394,7 +398,7 @@ log(logbuf);
if(res <= 0) { if(res <= 0) {
FROMSERVER = TOSERVERPIPE = 0; FROMSERVER = TOSERVERPIPE = 0;
if(res == 0 && !errno) { if(res == 0 && !errno) {
SERVERTERM = 1; SERVERTERMREAD = 1;
continue; continue;
} }
} }
@ -430,8 +434,13 @@ log("read from client to buf");
res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, (struct sockaddr *)&param->sincr, &sasize); res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, (struct sockaddr *)&param->sincr, &sasize);
if(res <= 0) { if(res <= 0) {
FROMCLIENT = 0; FROMCLIENT = 0;
if(res == 0 || (errno && errno != EINTR && errno !=EAGAIN)){ if(res == 0) {
CLIENTTERM = 1; CLIENTTERMREAD = 1;
continue;
}
if(errno && errno != EINTR && errno !=EAGAIN){
CLIENTTERMREAD = 1;
CLIENTTERMWRITE = 1;
continue; continue;
} }
} }
@ -458,8 +467,13 @@ log("read from server to buf");
res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, (struct sockaddr *)&param->sinsr, &sasize); res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, (struct sockaddr *)&param->sinsr, &sasize);
if(res <= 0) { if(res <= 0) {
FROMSERVER = 0; FROMSERVER = 0;
if(res == 0 || (errno && errno != EINTR && errno !=EAGAIN)) { if(res == 0) {
SERVERTERM = 1; SERVERTERMREAD = 1;
continue;
}
if(errno && errno != EINTR && errno !=EAGAIN) {
SERVERTERMREAD = 1;
SERVERTERMWRITE = 1;
continue; continue;
} }
} }
@ -485,42 +499,45 @@ log("done read from server to buf");
} }
} }
} }
for(after = 0; after < 2; after ++){ for(after = 0, cli_events=0, srv_events=0; after < 2; after ++){
fdsc = 0; fdsc = 0;
if(!after){ if(!after){
memset(fds, 0, sizeof(fds)); memset(fds, 0, sizeof(fds));
} }
if(!CLIENTTERM){ // if(!CLIENTTERMREAD || !CLIENTTERMWRITE){
if(!after){ if(!after){
fds[fdsc].fd = param->clisock; if(fromclient && !CLIENTTERMREAD && !FROMCLIENT && ((
if(fromclient && !FROMCLIENT && ((
#ifdef WITHSPLICE #ifdef WITHSPLICE
!usesplice && !usesplice &&
#endif #endif
TOCLIENTBUF) TOCLIENTBUF)
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| (usesplice) || (usesplice)
#endif #endif
)){ ))
#ifdef WITHLOG cli_events |= POLLIN;
log("wait reading from client"); if(!TOCLIENT && !CLIENTTERMWRITE && (inserverbuf
#endif
fds[fdsc].events |= (POLLIN);
}
if(!TOCLIENT && (inserverbuf
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| inserverpipe || inserverpipe
#endif #endif
)){ ))
cli_events |= POLLOUT;
if(cli_events){
fds[fdsc].fd = param->clisock;
fds[fdsc].events = cli_events;
#ifdef WITHLOG #ifdef WITHLOG
if(cli_events & POLLIN)
log("wait reading from client");
if(cli_events & POLLOUT)
log("wait writing to client"); log("wait writing to client");
#endif #endif
fds[fdsc].events |= POLLOUT; }
}
} }
else{ else if(cli_events){
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) { if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
CLIENTTERM = 1; CLIENTTERMREAD = 1;
CLIENTTERMWRITE = 1;
HASERROR |= 1; HASERROR |= 1;
} }
else { else {
@ -538,47 +555,49 @@ log("ready to write to client");
} }
if(fds[fdsc].revents & (POLLHUP)) { if(fds[fdsc].revents & (POLLHUP)) {
if(fds[fdsc].events & POLLIN) FROMCLIENT = 1; if(fds[fdsc].events & POLLIN) FROMCLIENT = 1;
if(fds[fdsc].events & POLLOUT) CLIENTTERM = 1; if(fds[fdsc].events & POLLOUT) CLIENTTERMWRITE = 1;
} }
} }
} }
fdsc++; fdsc++;
}
if(!SERVERTERM){ // if(!SERVERTERMREAD || !SERVERTERMWRITE){
if(!after){ if(!after){
fds[fdsc].fd = param->remsock; if(fromserver && !SERVERTERMREAD && !FROMSERVER && ((
if(fromserver && !FROMSERVER && ((
#ifdef WITHSPLICE #ifdef WITHSPLICE
!usesplice && !usesplice &&
#endif #endif
TOSERVERBUF) TOSERVERBUF)
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| (usesplice) || (usesplice)
#endif #endif
)){ ))
#ifdef WITHLOG srv_events |= POLLIN;
log("wait reading from server"); if(!TOSERVER && !SERVERTERMWRITE && (inclientbuf
#endif
fds[fdsc].events |= (POLLIN);
}
if(!TOSERVER && (inclientbuf
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| inclientpipe || inclientpipe
#endif #endif
)){ ))
srv_events |= POLLOUT;
if(srv_events){
fds[fdsc].fd = param->remsock;
fds[fdsc].events = srv_events;
#ifdef WITHLOG #ifdef WITHLOG
if(srv_events & POLLIN)
log("wait reading from server");
if(srv_events & POLLOUT)
log("wait writing from server"); log("wait writing from server");
#endif #endif
fds[fdsc].events |= POLLOUT; }
}
} }
else{ else if(srv_events){
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) { if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
#ifdef WITHLOG #ifdef WITHLOG
log("poll from server failed"); log("poll from server failed");
#endif #endif
SERVERTERM = 1; SERVERTERMREAD = 1;
SERVERTERMWRITE = 1;
HASERROR |=2; HASERROR |=2;
} }
else { else {
@ -599,12 +618,12 @@ log("ready to write to server");
log("server terminated connection"); log("server terminated connection");
#endif #endif
if(fds[fdsc].events & POLLIN) FROMSERVER = 1; if(fds[fdsc].events & POLLIN) FROMSERVER = 1;
if(fds[fdsc].events & POLLOUT) SERVERTERM = 1; if(fds[fdsc].events & POLLOUT) SERVERTERMWRITE = 1;
} }
} }
} }
fdsc++; fdsc++;
} // }
#ifdef WITHSPLICE #ifdef WITHSPLICE
if(usesplice){ if(usesplice){
if(fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < MAXSPLICE){ if(fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < MAXSPLICE){
@ -727,7 +746,7 @@ log("timeout");
else if(inclientpipe || inserverpipe) res = 94; else if(inclientpipe || inserverpipe) res = 94;
#endif #endif
if((param->nwrites > 0 && !SERVERTERM) || (param->nreads > 0 && !CLIENTTERM)) if((param->nwrites > 0 && !SERVERTERMWRITE) || (param->nreads > 0 && !CLIENTTERMWRITE))
usleep(SLEEPTIME * 10); usleep(SLEEPTIME * 10);
CLEANRET: CLEANRET: