mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 22:05:48 +08:00
connect back: a replaced -r service stops waiting at the reload
A -r service waited up to 60 s for the go-ahead on the connection it made, without looking at a reload. One replaced by a reload went on waiting, holding a slot and a thread, and took a client if the far side's go-ahead came in that time; every reload left another such connection in the far side's queue. The wait is now a second at a time (60 s in all, as before): at a reload the service takes a go-ahead already there, its client going on in the service which replaced it, and otherwise closes the connection and stops. The far side (-R) sent its go-ahead to any connection it accepted, and a closed one cost it a client. A connection the -r side closed, at a reload or after its wait, is readable before any go-ahead, since that side sends nothing first: once past the ACL it is passed over, without counting as one of the tries for as many as the listen queue holds (1 + maxchild/16), so that connections made to be closed or to send something cannot keep a client's thread in the loop. Tests: reattach's far side passes over closed connections as -R does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
63a736c693
commit
8cc7d255af
@ -41,6 +41,8 @@ static void serveparam(struct clientparam *param){
|
||||
if(param->srv->cbsock != INVALID_SOCKET){
|
||||
SASIZETYPE size = sizeof(param->sinsr);
|
||||
struct pollfd fds;
|
||||
/* closed connections passed over free: the listen queue's length */
|
||||
int skips = 1 + (param->srv->maxchild>>4);
|
||||
fds.fd = param->srv->cbsock;
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
@ -73,6 +75,24 @@ static void serveparam(struct clientparam *param){
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
/* the side connecting back sends nothing before the go-ahead:
|
||||
readable, the connection was closed there, by a service
|
||||
which stopped waiting (a reload, its time out); the next
|
||||
one is taken, and this one does not count as a try, for as
|
||||
many as the queue holds: past that it does */
|
||||
struct pollfd rf;
|
||||
|
||||
rf.fd = param->remsock;
|
||||
rf.events = POLLIN;
|
||||
rf.revents = 0;
|
||||
if(param->srv->so._poll(param->sostate, &rf, 1, 0) == 1){
|
||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||
param->remsock = INVALID_SOCKET;
|
||||
if(skips > 0){ skips--; i++; }
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(socksend(param, param->remsock, (unsigned char *)"C", 1, CONNBACK_TO) != 1){
|
||||
dolog(param, (unsigned char *)"Connect back sending command failed");
|
||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||
|
||||
@ -37,6 +37,9 @@ static int cblisten(struct srvstart *s){
|
||||
|
||||
#endif
|
||||
|
||||
/* How long, in seconds, a connection made back (-r) waits for its go-ahead */
|
||||
#define CBWAIT 60
|
||||
|
||||
/* What getting the next client came to. */
|
||||
enum { NEXT_CLIENT, NEXT_RETRY, NEXT_STOP };
|
||||
|
||||
@ -49,7 +52,7 @@ static int tcpnext(struct srvstart *s, SOCKET *client, int *nlog){
|
||||
SOCKET new_sock;
|
||||
SASIZETYPE size;
|
||||
unsigned char buf[256];
|
||||
int error = 0, opt = 1;
|
||||
int error = 0, opt = 1, res, waited;
|
||||
#ifndef _WIN32
|
||||
struct linger lg;
|
||||
#else
|
||||
@ -81,7 +84,18 @@ static int tcpnext(struct srvstart *s, SOCKET *client, int *nlog){
|
||||
return NEXT_RETRY;
|
||||
}
|
||||
|
||||
if(sockrecvfrom(NULL, new_sock, NULL, buf, 1, 60*1000) != 1 || *buf!='C') {
|
||||
/* the far side's go-ahead, waited for a second at a time to notice
|
||||
a reload: a service paused then takes no more connections and
|
||||
closes this one, unless the go-ahead came already, and its client
|
||||
goes on in the service which took its place */
|
||||
for(waited = 0; !(res = sockrecvfrom(NULL, new_sock, NULL, buf, 1, 1000)); ){
|
||||
if(srv->config->paused != srv->paused){
|
||||
res = sockrecvfrom(NULL, new_sock, NULL, buf, 1, 0);
|
||||
break;
|
||||
}
|
||||
if(++waited >= CBWAIT) break;
|
||||
}
|
||||
if(res != 1 || *buf!='C') {
|
||||
so._closesocket(so.state, new_sock);
|
||||
usleep(SLEEPTIME);
|
||||
return NEXT_RETRY;
|
||||
|
||||
@ -3,6 +3,7 @@ the rules of the newest service on its listener, taking one of its maxconn
|
||||
slots, and is dropped where that cannot be."""
|
||||
|
||||
import base64
|
||||
import select
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
@ -128,7 +129,13 @@ def run(t):
|
||||
"""A request over a connection the -r service made: the peer is its
|
||||
client once it has sent C."""
|
||||
try:
|
||||
# as the far side of a connect-back service does: a connection
|
||||
# closed by a service which stopped waiting is passed over
|
||||
while True:
|
||||
c, _ = peer.accept()
|
||||
if not select.select([c], [], [], 0)[0]:
|
||||
break
|
||||
c.close()
|
||||
c.settimeout(30)
|
||||
c.sendall(b"C")
|
||||
auth = base64.b64encode(b"alice:one").decode()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user