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){
|
if(param->srv->cbsock != INVALID_SOCKET){
|
||||||
SASIZETYPE size = sizeof(param->sinsr);
|
SASIZETYPE size = sizeof(param->sinsr);
|
||||||
struct pollfd fds;
|
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.fd = param->srv->cbsock;
|
||||||
fds.events = POLLIN;
|
fds.events = POLLIN;
|
||||||
fds.revents = 0;
|
fds.revents = 0;
|
||||||
@ -73,6 +75,24 @@ static void serveparam(struct clientparam *param){
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#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){
|
if(socksend(param, param->remsock, (unsigned char *)"C", 1, CONNBACK_TO) != 1){
|
||||||
dolog(param, (unsigned char *)"Connect back sending command failed");
|
dolog(param, (unsigned char *)"Connect back sending command failed");
|
||||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||||
|
|||||||
@ -37,6 +37,9 @@ static int cblisten(struct srvstart *s){
|
|||||||
|
|
||||||
#endif
|
#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. */
|
/* What getting the next client came to. */
|
||||||
enum { NEXT_CLIENT, NEXT_RETRY, NEXT_STOP };
|
enum { NEXT_CLIENT, NEXT_RETRY, NEXT_STOP };
|
||||||
|
|
||||||
@ -49,7 +52,7 @@ static int tcpnext(struct srvstart *s, SOCKET *client, int *nlog){
|
|||||||
SOCKET new_sock;
|
SOCKET new_sock;
|
||||||
SASIZETYPE size;
|
SASIZETYPE size;
|
||||||
unsigned char buf[256];
|
unsigned char buf[256];
|
||||||
int error = 0, opt = 1;
|
int error = 0, opt = 1, res, waited;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
struct linger lg;
|
struct linger lg;
|
||||||
#else
|
#else
|
||||||
@ -81,7 +84,18 @@ static int tcpnext(struct srvstart *s, SOCKET *client, int *nlog){
|
|||||||
return NEXT_RETRY;
|
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);
|
so._closesocket(so.state, new_sock);
|
||||||
usleep(SLEEPTIME);
|
usleep(SLEEPTIME);
|
||||||
return NEXT_RETRY;
|
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."""
|
slots, and is dropped where that cannot be."""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import select
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@ -128,7 +129,13 @@ def run(t):
|
|||||||
"""A request over a connection the -r service made: the peer is its
|
"""A request over a connection the -r service made: the peer is its
|
||||||
client once it has sent C."""
|
client once it has sent C."""
|
||||||
try:
|
try:
|
||||||
c, _ = peer.accept()
|
# 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.settimeout(30)
|
||||||
c.sendall(b"C")
|
c.sendall(b"C")
|
||||||
auth = base64.b64encode(b"alice:one").decode()
|
auth = base64.b64encode(b"alice:one").decode()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user