mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-15 16:15:49 +08:00
splice() per direction, pipes per connection, automatic mode
-s takes the directions to splice: -s1 what the server sends (downloads), -s2 what the client sends (uploads), -s3 both. -s alone (-s7) splices both only where it pays, as -s5 and -s6 do for one direction: - a body of known length is spliced if at least 16K of it is left to read once what is already buffered is counted, so an answer read whole with its headers is just copied; - a stream of unknown length starts copied, is spliced after 2 reads in a row of at least 16K, and goes back to copying after 3 splices in a row of less than 4K, once its pipe is empty. Pipes are made when a direction first splices and kept with the connection for its next mappings, so a kept-alive connection no longer makes and closes two pipes per request; one left holding data by an error or a timeout is closed. The direction not spliced keeps its buffer. Before, -s spliced both directions and every mapping made both pipes, which made small answers slower than without splice: with kept-alive 50K answers 2 pipe2() and 4 close() per request, now none. Also corrects the default buffer size in the -b help (65536 for TCP). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ee5a7588f8
commit
b00e3b9a9c
@ -34,7 +34,7 @@ Each connected client requires:
|
|||||||
<ul>
|
<ul>
|
||||||
<li>1 thread (process)
|
<li>1 thread (process)
|
||||||
<li>2 sockets (file descriptors). For FTP, 4 sockets are required.
|
<li>2 sockets (file descriptors). For FTP, 4 sockets are required.
|
||||||
<br>With splice() (Linux, -s), 2 more pipes (file descriptors) = 4 file descriptors, 6 for FTP.
|
<br>With splice() (Linux, -s), a pipe (2 file descriptors) for each spliced direction: up to 4 more file descriptors, 6 for FTP.
|
||||||
<br>Up to 128K (up to 256K with splice()) of kernel buffer memory. This is the theoretical maximum; actual numbers depend on connection quality and traffic amount.
|
<br>Up to 128K (up to 256K with splice()) of kernel buffer memory. This is the theoretical maximum; actual numbers depend on connection quality and traffic amount.
|
||||||
<br>1 additional socket (file descriptor) during name resolution for non-cached names
|
<br>1 additional socket (file descriptor) during name resolution for non-cached names
|
||||||
<br>1 additional socket during authentication or logging for RADIUS authentication or logging.
|
<br>1 additional socket during authentication or logging for RADIUS authentication or logging.
|
||||||
@ -664,15 +664,20 @@ include it, but a service uses it only when given the -s option:
|
|||||||
<pre>
|
<pre>
|
||||||
proxy -s
|
proxy -s
|
||||||
socks -s
|
socks -s
|
||||||
tcppm -s 8080 192.168.1.1 80
|
tcppm -s3 8080 192.168.1.1 80
|
||||||
</pre>
|
</pre>
|
||||||
-s0 turns it off explicitly. In builds without it (CMake option 3PROXY_USE_SPLICE=OFF,
|
-s alone splices both directions where it pays: an HTTP body of known length if at
|
||||||
|
least 16K of it is left to read, a stream (CONNECT, SOCKS, tcppm) once it carries
|
||||||
|
large reads, going back to copying when they turn small. -s1 always splices what the
|
||||||
|
server sends to the client (downloads), -s2 what the client sends to the server
|
||||||
|
(uploads), -s3 both; -s5, -s6 and -s7 (the same as -s) do it for those directions
|
||||||
|
only where it pays. -s0, the default, turns it off. In builds without it (CMake option 3PROXY_USE_SPLICE=OFF,
|
||||||
or -DWITHSPLICE removed from the Makefile) -s is accepted and ignored.
|
or -DWITHSPLICE removed from the Makefile) -s is accepted and ignored.
|
||||||
<p>splice() pays off when most of the traffic is large transfers: in the
|
<p>splice() pays off when most of the traffic is large transfers: in the
|
||||||
<a href="https://github.com/3proxy/3proxy/tree/master/bench">benchmarks</a> it moved
|
<a href="https://github.com/3proxy/3proxy/tree/master/bench">benchmarks</a> it moved
|
||||||
1.4 to 1.7 times more data than the read/write path at about half the CPU per gigabyte.
|
1.4 to 1.7 times more data than the read/write path at about half the CPU per gigabyte.
|
||||||
It does not help small requests and short connections, which go slower with it, and
|
It does not help small requests and short connections, which go slower with it, and
|
||||||
every spliced connection needs two more pipes (file descriptors) and more kernel
|
every spliced direction needs a pipe (two file descriptors) and more kernel
|
||||||
buffer memory. Data filters are not applied to spliced data.
|
buffer memory. Data filters are not applied to spliced data.
|
||||||
<p>TCP_NODELAY and splice() do not conflict and can be combined on high-speed connections.
|
<p>TCP_NODELAY and splice() do not conflict and can be combined on high-speed connections.
|
||||||
|
|
||||||
|
|||||||
@ -203,12 +203,17 @@ delay GRACE_DELAY milliseconds before polling if average polling size is below G
|
|||||||
view without ability to reset.
|
view without ability to reset.
|
||||||
.br
|
.br
|
||||||
(for TCP services, Linux) use splice() to pass data between the client and the
|
(for TCP services, Linux) use splice() to pass data between the client and the
|
||||||
server without copying it through 3proxy. It is off unless -s is given (-s0 turns
|
server without copying it through 3proxy. \fB-s\fR alone splices both directions where
|
||||||
it off explicitly). splice() suits large transfers: they go faster and use less
|
it pays: a body of known length if at least 16K of it is left to read, a stream
|
||||||
CPU. Small requests and short connections go slower with it, every connection
|
once it carries large reads, back to copying when they turn small. \fB-s1\fR always
|
||||||
needs two more pipes (file descriptors) and more kernel memory, and data filters
|
splices what the server sends to the client (downloads), \fB-s2\fR what the client
|
||||||
are not applied to spliced data. Available in builds with WITHSPLICE, the default
|
sends (uploads), \fB-s3\fR both; adding 4 (\fB-s5\fR, \fB-s6\fR, \fB-s7\fR, the last the same as
|
||||||
on Linux.
|
\fB-s\fR) splices those directions only where it pays. \fB-s0\fR, the default, turns it
|
||||||
|
off. splice() suits large transfers: they go faster and use less CPU; small
|
||||||
|
requests go slower with it. A spliced direction needs a pipe (two file
|
||||||
|
descriptors), made when first needed and kept for the connection, and more
|
||||||
|
kernel memory; data filters are not applied to spliced data. Available in builds
|
||||||
|
with WITHSPLICE, the default on Linux.
|
||||||
.br
|
.br
|
||||||
.B -C
|
.B -C
|
||||||
(for TCP services) a connection closed by any of the sides terminates the
|
(for TCP services) a connection closed by any of the sides terminates the
|
||||||
|
|||||||
@ -239,6 +239,11 @@ extern struct extparam conf;
|
|||||||
|
|
||||||
extern int timeouts[12];
|
extern int timeouts[12];
|
||||||
|
|
||||||
|
/* directions sockmap() passes with splice(): -s1, -s2, -s3; with
|
||||||
|
SPLICE_AUTO (-s alone, -s5 to -s7) only when it pays */
|
||||||
|
#define SPLICE_DOWNLOAD 1
|
||||||
|
#define SPLICE_UPLOAD 2
|
||||||
|
#define SPLICE_AUTO 4
|
||||||
int sockmap(struct clientparam * param, int timeo, int usesplice);
|
int sockmap(struct clientparam * param, int timeo, int usesplice);
|
||||||
int udpsockmap(struct clientparam * param, int timeo);
|
int udpsockmap(struct clientparam * param, int timeo);
|
||||||
int udpbind(struct clientparam * param);
|
int udpbind(struct clientparam * param);
|
||||||
@ -481,7 +486,7 @@ extern struct datatype datatypes[64];
|
|||||||
extern struct commands commandhandlers[];
|
extern struct commands commandhandlers[];
|
||||||
|
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
#define mapsocket(a,b) ((a->srv->usesplice && !a->ndatfilterssrv && !a->ndatfilterscli)?sockmap(a,b,1):sockmap(a,b,0))
|
#define mapsocket(a,b) ((a->srv->usesplice && !a->ndatfilterssrv && !a->ndatfilterscli)?sockmap(a,b,a->srv->usesplice):sockmap(a,b,0))
|
||||||
#else
|
#else
|
||||||
#define mapsocket(a,b) sockmap(a,b, 0)
|
#define mapsocket(a,b) sockmap(a,b, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -366,7 +366,9 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
" -De(DEVICENAME) bind external interface to device, e.g. eth1\n"
|
" -De(DEVICENAME) bind external interface to device, e.g. eth1\n"
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
" -s Use splice() - no filtering for data, off by default\n"
|
" -s[N] Use splice(): -s1 server to client, -s2 client to server, -s3 both\n"
|
||||||
|
" directions; -s (-s7) both, -s5 or -s6 one, only where it pays (large\n"
|
||||||
|
" transfers) - no filtering for data, off by default\n"
|
||||||
" -C connection closed by any of the sides terminates the session, by default\n"
|
" -C connection closed by any of the sides terminates the session, by default\n"
|
||||||
" the session is kept until both sides close it (TCP half-close)\n"
|
" the session is kept until both sides close it (TCP half-close)\n"
|
||||||
" -U(0-3) (for socks) what to do when the destination changes within an UDP\n"
|
" -U(0-3) (for socks) what to do when the destination changes within an UDP\n"
|
||||||
@ -377,7 +379,7 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
" -fFORMAT logging format (see documentation)\n"
|
" -fFORMAT logging format (see documentation)\n"
|
||||||
" -l log to stderr\n"
|
" -l log to stderr\n"
|
||||||
" -lFILENAME log to FILENAME\n"
|
" -lFILENAME log to FILENAME\n"
|
||||||
" -b(BUFSIZE) size of network buffer (default 4096 for TCP, 16384 for UDP)\n"
|
" -b(BUFSIZE) size of network buffer (default 65536 for TCP, 16384 for UDP)\n"
|
||||||
" -S(STACKSIZE) value to add to default client thread stack size\n"
|
" -S(STACKSIZE) value to add to default client thread stack size\n"
|
||||||
" -t be silent (do not log service start/stop)\n"
|
" -t be silent (do not log service start/stop)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -698,7 +700,9 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
srv.s_option = 1 + atoi(argv[i]+2);
|
srv.s_option = 1 + atoi(argv[i]+2);
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
else
|
else
|
||||||
srv.usesplice = *(argv[i]+2)? atoi(argv[i]+2) : 1;
|
srv.usesplice = (*(argv[i]+2)? atoi(argv[i]+2) :
|
||||||
|
SPLICE_DOWNLOAD|SPLICE_UPLOAD|SPLICE_AUTO) &
|
||||||
|
(SPLICE_DOWNLOAD|SPLICE_UPLOAD|SPLICE_AUTO);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
@ -1325,6 +1329,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){
|
|||||||
param->version = srv->version;
|
param->version = srv->version;
|
||||||
param->paused = srv->paused;
|
param->paused = srv->paused;
|
||||||
param->remsock = param->clisock = param->ctrlsock = param->ctrlsocksrv = INVALID_SOCKET;
|
param->remsock = param->clisock = param->ctrlsock = param->ctrlsocksrv = INVALID_SOCKET;
|
||||||
|
param->pipecli[0] = param->pipecli[1] = param->pipesrv[0] = param->pipesrv[1] = -1;
|
||||||
*SAFAMILY(¶m->req) = *SAFAMILY(¶m->sinsl) = *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->sincr) = *SAFAMILY(¶m->sincl) = AF_INET;
|
*SAFAMILY(¶m->req) = *SAFAMILY(¶m->sinsl) = *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->sincr) = *SAFAMILY(¶m->sincl) = AF_INET;
|
||||||
_3proxy_mutex_init(&srv->counter_mutex);
|
_3proxy_mutex_init(&srv->counter_mutex);
|
||||||
(void)_3proxy_sem_init_timed(srv->childslots, srv->maxchild, srv->maxchild);
|
(void)_3proxy_sem_init_timed(srv->childslots, srv->maxchild, srv->maxchild);
|
||||||
@ -1447,6 +1452,12 @@ void freeparam(struct clientparam * param) {
|
|||||||
}
|
}
|
||||||
if(param->clibuf) free(param->clibuf);
|
if(param->clibuf) free(param->clibuf);
|
||||||
if(param->srvbuf) free(param->srvbuf);
|
if(param->srvbuf) free(param->srvbuf);
|
||||||
|
#ifdef WITHSPLICE
|
||||||
|
if(param->pipecli[0] >= 0) close(param->pipecli[0]);
|
||||||
|
if(param->pipecli[1] >= 0) close(param->pipecli[1]);
|
||||||
|
if(param->pipesrv[0] >= 0) close(param->pipesrv[0]);
|
||||||
|
if(param->pipesrv[1] >= 0) close(param->pipesrv[1]);
|
||||||
|
#endif
|
||||||
/* Not shut down on Windows: there shutting down receiving resets the
|
/* Not shut down on Windows: there shutting down receiving resets the
|
||||||
connection as soon as the peer sends anything more, and close()
|
connection as soon as the peer sends anything more, and close()
|
||||||
alone sends whatever is queued before its FIN. Elsewhere it stays:
|
alone sends whatever is queued before its FIN. Elsewhere it stays:
|
||||||
|
|||||||
190
src/sockmap.c
190
src/sockmap.c
@ -39,6 +39,18 @@ ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t le
|
|||||||
|
|
||||||
#define MAXSPLICE 65536
|
#define MAXSPLICE 65536
|
||||||
|
|
||||||
|
/* With SPLICE_AUTO, when a direction allowed to splice actually does
|
||||||
|
(without it, an allowed direction always does).
|
||||||
|
A body of known length is spliced if at least SPLICE_MIN of it is left
|
||||||
|
to read once what is already buffered is counted: a smaller one, or one
|
||||||
|
read whole with its headers, is cheaper to copy.
|
||||||
|
A stream of unknown length starts copied and is spliced after
|
||||||
|
SPLICE_STREAK reads in a row of at least SPLICE_MIN each, and goes back to
|
||||||
|
copying after SPLICE_STREAK+1 splices in a row of less than SPLICE_SMALL. */
|
||||||
|
#define SPLICE_MIN 16384
|
||||||
|
#define SPLICE_SMALL 4096
|
||||||
|
#define SPLICE_STREAK 2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MIN(a,b) ((a>b)?b:a)
|
#define MIN(a,b) ((a>b)?b:a)
|
||||||
@ -49,6 +61,9 @@ ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t le
|
|||||||
before the sockets are closed. */
|
before the sockets are closed. */
|
||||||
#define SESSIONEND (!halfclose && (CLIENTTERMREAD || SERVERTERMREAD))
|
#define SESSIONEND (!halfclose && (CLIENTTERMREAD || SERVERTERMREAD))
|
||||||
|
|
||||||
|
/* usesplice is a mask of the directions passed with splice() rather than
|
||||||
|
through a buffer: SPLICE_DOWNLOAD, server to client, and SPLICE_UPLOAD,
|
||||||
|
client to server. */
|
||||||
int sockmap(struct clientparam * param, int timeo, int usesplice){
|
int sockmap(struct clientparam * param, int timeo, int usesplice){
|
||||||
int halfclose = param->srv->halfclose;
|
int halfclose = param->srv->halfclose;
|
||||||
uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
|
uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
|
||||||
@ -76,16 +91,30 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
|
|||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
uint64_t inclientpipe = 0, inserverpipe = 0;
|
uint64_t inclientpipe = 0, inserverpipe = 0;
|
||||||
int TOCLIENTPIPE = 0, FROMCLIENTPIPE = 0, TOSERVERPIPE = 0, FROMSERVERPIPE = 0;
|
int TOCLIENTPIPE = 0, FROMCLIENTPIPE = 0, TOSERVERPIPE = 0, FROMSERVERPIPE = 0;
|
||||||
int pipesrv[2] = {-1,-1};
|
/* The client's data goes through pipecli, the server's through pipesrv.
|
||||||
int pipecli[2] = {-1,-1};
|
They belong to the connection: made when first needed, kept for the
|
||||||
|
next mapping, closed with the connection. */
|
||||||
|
int *pipecli = param->pipecli, *pipesrv = param->pipesrv;
|
||||||
|
/* allowed to splice (-s), splicing now, and a run of reads counted
|
||||||
|
towards switching; wantbuf: go back to copying once the pipe is empty */
|
||||||
|
int allowcli = 0, allowsrv = 0, splicecli = 0, splicesrv = 0, autosplice;
|
||||||
|
int streakcli = 0, streaksrv = 0, wantbufcli = 0, wantbufsrv = 0;
|
||||||
|
|
||||||
if((!param->nolongdatfilter && (param->ndatfilterscli > 0 || param->ndatfilterssrv))) usesplice = 0;
|
if((!param->nolongdatfilter && (param->ndatfilterscli > 0 || param->ndatfilterssrv))) usesplice = 0;
|
||||||
if(usesplice){
|
allowcli = (usesplice & SPLICE_UPLOAD) != 0;
|
||||||
TOCLIENTPIPE = FROMCLIENTPIPE = TOSERVERPIPE = FROMSERVERPIPE = 1;
|
allowsrv = (usesplice & SPLICE_DOWNLOAD) != 0;
|
||||||
TOCLIENTBUF = TOSERVERBUF = 0;
|
autosplice = (usesplice & SPLICE_AUTO) != 0;
|
||||||
if(pipe2(pipecli, O_NONBLOCK) < 0) RETURN (21);
|
if(!autosplice){
|
||||||
if(pipe2(pipesrv, O_NONBLOCK) < 0) RETURN (21);
|
splicecli = allowcli;
|
||||||
|
splicesrv = allowsrv;
|
||||||
}
|
}
|
||||||
|
TOCLIENTPIPE = FROMCLIENTPIPE = allowcli;
|
||||||
|
TOSERVERPIPE = FROMSERVERPIPE = allowsrv;
|
||||||
|
#else
|
||||||
|
#define splicecli 0
|
||||||
|
#define splicesrv 0
|
||||||
|
#define wantbufcli 0
|
||||||
|
#define wantbufsrv 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inserverbuf = param->srvinbuf - param->srvoffset;
|
inserverbuf = param->srvinbuf - param->srvoffset;
|
||||||
@ -108,16 +137,16 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
|
|||||||
if(inserverbuf >= fromserver) FROMSERVER = 0;
|
if(inserverbuf >= fromserver) FROMSERVER = 0;
|
||||||
if(inclientbuf >= fromclient) FROMCLIENT = 0;
|
if(inclientbuf >= fromclient) FROMCLIENT = 0;
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
if(!usesplice)
|
/* a body of known length large enough is spliced from the start */
|
||||||
|
if(autosplice && allowsrv && param->waitserver64 && fromserver > inserverbuf && fromserver - inserverbuf >= SPLICE_MIN) splicesrv = 1;
|
||||||
|
if(autosplice && allowcli && param->waitclient64 && fromclient > inclientbuf && fromclient - inclientbuf >= SPLICE_MIN) splicecli = 1;
|
||||||
#endif
|
#endif
|
||||||
{
|
/* a spliced direction needs no buffer, only what was read before */
|
||||||
if(fromserver && !param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))){
|
if(!splicesrv && fromserver && !param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))){
|
||||||
RETURN (21);
|
RETURN (21);
|
||||||
}
|
}
|
||||||
if(fromclient && !param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))){
|
if(!splicecli && fromclient && !param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))){
|
||||||
RETURN (21);
|
RETURN (21);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if(param->srvinbuf == param->srvoffset) param->srvinbuf =param->srvoffset = 0;
|
if(param->srvinbuf == param->srvoffset) param->srvinbuf =param->srvoffset = 0;
|
||||||
if(param->cliinbuf == param->clioffset) param->cliinbuf =param->clioffset = 0;
|
if(param->cliinbuf == param->clioffset) param->cliinbuf =param->clioffset = 0;
|
||||||
@ -292,8 +321,21 @@ log("done send to client from buf");
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
if(usesplice){
|
/* a direction going back to copying does once its pipe is empty */
|
||||||
if(inclientpipe && !inclientbuf && FROMCLIENTPIPE && TOSERVER){
|
if(wantbufcli && !inclientpipe){
|
||||||
|
splicecli = wantbufcli = streakcli = 0;
|
||||||
|
if(!param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))) RETURN (21);
|
||||||
|
if(param->cliinbuf < param->clibufsize) TOCLIENTBUF = 1;
|
||||||
|
}
|
||||||
|
if(wantbufsrv && !inserverpipe){
|
||||||
|
splicesrv = wantbufsrv = streaksrv = 0;
|
||||||
|
if(!param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))) RETURN (21);
|
||||||
|
if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* each direction goes through its pipe if spliced, through its
|
||||||
|
buffer otherwise; what was in the buffer before is sent first */
|
||||||
|
if(splicecli && inclientpipe && !inclientbuf && FROMCLIENTPIPE && TOSERVER){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("send to server from pipe");
|
log("send to server from pipe");
|
||||||
#endif
|
#endif
|
||||||
@ -330,7 +372,7 @@ log(logbuf);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(inserverpipe && !inserverbuf && FROMSERVERPIPE && TOCLIENT){
|
if(splicesrv && inserverpipe && !inserverbuf && FROMSERVERPIPE && TOCLIENT){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("send to client from pipe");
|
log("send to client from pipe");
|
||||||
#endif
|
#endif
|
||||||
@ -360,12 +402,17 @@ log(logbuf);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE && !SESSIONEND){
|
if(splicecli && !wantbufcli && fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE && !SESSIONEND){
|
||||||
int error;
|
|
||||||
socklen_t len=sizeof(error);
|
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from client to pipe");
|
log("read from client to pipe");
|
||||||
#endif
|
#endif
|
||||||
|
if(pipecli[0] < 0 && pipe2(pipecli, O_NONBLOCK) < 0){
|
||||||
|
/* no pipe to be had: copy instead */
|
||||||
|
allowcli = splicecli = TOCLIENTPIPE = FROMCLIENTPIPE = 0;
|
||||||
|
if(!param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))) RETURN (21);
|
||||||
|
if(param->cliinbuf < param->clibufsize) TOCLIENTBUF = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
res = splice(param->clisock, NULL, pipecli[1], NULL, (int)MIN((uint64_t)MAXSPLICE - inclientpipe, (uint64_t)fromclient-inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
|
res = splice(param->clisock, NULL, pipecli[1], NULL, (int)MIN((uint64_t)MAXSPLICE - inclientpipe, (uint64_t)fromclient-inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
@ -396,19 +443,27 @@ log("done read from client to pipe");
|
|||||||
graceclinum++;
|
graceclinum++;
|
||||||
graceclitraf += res;
|
graceclitraf += res;
|
||||||
gracesrvnum = gracesrvtraf = 0;
|
gracesrvnum = gracesrvtraf = 0;
|
||||||
|
if(autosplice && !param->waitclient64){
|
||||||
|
if(res >= SPLICE_SMALL) streakcli = 0;
|
||||||
|
else if(++streakcli > SPLICE_STREAK) wantbufcli = 1;
|
||||||
|
}
|
||||||
inclientpipe += res;
|
inclientpipe += res;
|
||||||
if(inclientpipe >= MAXSPLICE) TOCLIENTPIPE = 0;
|
if(inclientpipe >= MAXSPLICE) TOCLIENTPIPE = 0;
|
||||||
needaction = 0;
|
needaction = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE && !SESSIONEND){
|
if(splicesrv && !wantbufsrv && fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE && !SESSIONEND){
|
||||||
int error;
|
|
||||||
socklen_t len=sizeof(error);
|
|
||||||
errno = 0;
|
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from server to pipe\n");
|
log("read from server to pipe\n");
|
||||||
#endif
|
#endif
|
||||||
|
if(pipesrv[0] < 0 && pipe2(pipesrv, O_NONBLOCK) < 0){
|
||||||
|
allowsrv = splicesrv = TOSERVERPIPE = FROMSERVERPIPE = 0;
|
||||||
|
if(!param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))) RETURN (21);
|
||||||
|
if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
res = splice(param->remsock, NULL, pipesrv[1], NULL, MIN(MAXSPLICE - inserverpipe, fromserver - inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
|
res = splice(param->remsock, NULL, pipesrv[1], NULL, MIN(MAXSPLICE - inserverpipe, fromserver - inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("server to pipe splice finished\n");
|
log("server to pipe splice finished\n");
|
||||||
@ -438,6 +493,10 @@ log("done read from server to pipe\n");
|
|||||||
gracesrvnum++;
|
gracesrvnum++;
|
||||||
gracesrvtraf += res;
|
gracesrvtraf += res;
|
||||||
graceclinum = graceclitraf = 0;
|
graceclinum = graceclitraf = 0;
|
||||||
|
if(autosplice && !param->waitserver64){
|
||||||
|
if(res >= SPLICE_SMALL) streaksrv = 0;
|
||||||
|
else if(++streaksrv > SPLICE_STREAK) wantbufsrv = 1;
|
||||||
|
}
|
||||||
param->nreads++;
|
param->nreads++;
|
||||||
param->statssrv64 += res;
|
param->statssrv64 += res;
|
||||||
inserverpipe += res;
|
inserverpipe += res;
|
||||||
@ -452,10 +511,9 @@ log("done read from server to pipe\n");
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if(fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF && !SESSIONEND){
|
if(!splicecli && fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF && !SESSIONEND){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from client to buf");
|
log("read from client to buf");
|
||||||
#endif
|
#endif
|
||||||
@ -480,6 +538,17 @@ log("done read from client to buf");
|
|||||||
graceclinum++;
|
graceclinum++;
|
||||||
graceclitraf += res;
|
graceclitraf += res;
|
||||||
gracesrvnum = gracesrvtraf = 0;
|
gracesrvnum = gracesrvtraf = 0;
|
||||||
|
#ifdef WITHSPLICE
|
||||||
|
if(autosplice && allowcli && !param->waitclient64){
|
||||||
|
if(res < SPLICE_MIN) streakcli = 0;
|
||||||
|
else if(++streakcli >= SPLICE_STREAK){
|
||||||
|
/* a stream: splice from now on, after what is
|
||||||
|
buffered has been sent */
|
||||||
|
splicecli = TOCLIENTPIPE = FROMCLIENTPIPE = 1;
|
||||||
|
streakcli = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
inclientbuf += res;
|
inclientbuf += res;
|
||||||
param->cliinbuf += res;
|
param->cliinbuf += res;
|
||||||
if(param->clibufsize == param->cliinbuf) TOCLIENTBUF = 0;
|
if(param->clibufsize == param->cliinbuf) TOCLIENTBUF = 0;
|
||||||
@ -488,7 +557,7 @@ log("done read from client to buf");
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fromserver > inserverbuf && FROMSERVER && TOSERVERBUF && !SESSIONEND){
|
if(!splicesrv && fromserver > inserverbuf && FROMSERVER && TOSERVERBUF && !SESSIONEND){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from server to buf");
|
log("read from server to buf");
|
||||||
#endif
|
#endif
|
||||||
@ -513,6 +582,15 @@ log("done read from server to buf");
|
|||||||
gracesrvnum++;
|
gracesrvnum++;
|
||||||
gracesrvtraf += res;
|
gracesrvtraf += res;
|
||||||
graceclinum = graceclitraf = 0;
|
graceclinum = graceclitraf = 0;
|
||||||
|
#ifdef WITHSPLICE
|
||||||
|
if(autosplice && allowsrv && !param->waitserver64){
|
||||||
|
if(res < SPLICE_MIN) streaksrv = 0;
|
||||||
|
else if(++streaksrv >= SPLICE_STREAK){
|
||||||
|
splicesrv = TOSERVERPIPE = FROMSERVERPIPE = 1;
|
||||||
|
streaksrv = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
param->nreads++;
|
param->nreads++;
|
||||||
param->statssrv64 += res;
|
param->statssrv64 += res;
|
||||||
inserverbuf += res;
|
inserverbuf += res;
|
||||||
@ -553,15 +631,8 @@ log("done read from server to buf");
|
|||||||
// if(!CLIENTTERMREAD || !CLIENTTERMWRITE){
|
// if(!CLIENTTERMREAD || !CLIENTTERMWRITE){
|
||||||
if(!after){
|
if(!after){
|
||||||
fds[fdsc].fd = param->clisock;
|
fds[fdsc].fd = param->clisock;
|
||||||
if(fromclient && !CLIENTTERMREAD && !FROMCLIENT && !SESSIONEND && ((
|
if(fromclient && !CLIENTTERMREAD && !FROMCLIENT && !SESSIONEND &&
|
||||||
#ifdef WITHSPLICE
|
((!splicecli && TOCLIENTBUF) || (splicecli && !wantbufcli)))
|
||||||
!usesplice &&
|
|
||||||
#endif
|
|
||||||
TOCLIENTBUF)
|
|
||||||
#ifdef WITHSPLICE
|
|
||||||
|| (usesplice)
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
cli_events |= POLLIN;
|
cli_events |= POLLIN;
|
||||||
if(!TOCLIENT && !CLIENTTERMWRITE && (inserverbuf
|
if(!TOCLIENT && !CLIENTTERMWRITE && (inserverbuf
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
@ -613,15 +684,8 @@ log("ready to write to client");
|
|||||||
// if(!SERVERTERMREAD || !SERVERTERMWRITE){
|
// if(!SERVERTERMREAD || !SERVERTERMWRITE){
|
||||||
if(!after){
|
if(!after){
|
||||||
fds[fdsc].fd = param->remsock;
|
fds[fdsc].fd = param->remsock;
|
||||||
if(fromserver && !SERVERTERMREAD && !FROMSERVER && !SESSIONEND && ((
|
if(fromserver && !SERVERTERMREAD && !FROMSERVER && !SESSIONEND &&
|
||||||
#ifdef WITHSPLICE
|
((!splicesrv && TOSERVERBUF) || (splicesrv && !wantbufsrv)))
|
||||||
!usesplice &&
|
|
||||||
#endif
|
|
||||||
TOSERVERBUF)
|
|
||||||
#ifdef WITHSPLICE
|
|
||||||
|| (usesplice)
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
srv_events |= POLLIN;
|
srv_events |= POLLIN;
|
||||||
if(!TOSERVER && !SERVERTERMWRITE && (inclientbuf
|
if(!TOSERVER && !SERVERTERMWRITE && (inclientbuf
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
@ -678,8 +742,8 @@ log("server terminated connection");
|
|||||||
fdsc++;
|
fdsc++;
|
||||||
// }
|
// }
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
if(usesplice){
|
{
|
||||||
if(fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < MAXSPLICE){
|
if(splicecli && fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < MAXSPLICE){
|
||||||
if(!after){
|
if(!after){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("wait writing to client pipe");
|
log("wait writing to client pipe");
|
||||||
@ -700,7 +764,7 @@ log("ready to write to client pipe");
|
|||||||
}
|
}
|
||||||
fdsc++;
|
fdsc++;
|
||||||
}
|
}
|
||||||
if(inclientpipe && !FROMCLIENTPIPE){
|
if(splicecli && inclientpipe && !FROMCLIENTPIPE){
|
||||||
if(!after){
|
if(!after){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("wait reading from client pipe");
|
log("wait reading from client pipe");
|
||||||
@ -719,7 +783,7 @@ log("ready reading from client pipe");
|
|||||||
}
|
}
|
||||||
fdsc++;
|
fdsc++;
|
||||||
}
|
}
|
||||||
if(fromserver>inserverpipe && !TOSERVERPIPE && inserverpipe < MAXSPLICE){
|
if(splicesrv && fromserver>inserverpipe && !TOSERVERPIPE && inserverpipe < MAXSPLICE){
|
||||||
if(!after){
|
if(!after){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("wait writing to server pipe");
|
log("wait writing to server pipe");
|
||||||
@ -738,7 +802,7 @@ log("ready writing to server pipe");
|
|||||||
}
|
}
|
||||||
fdsc++;
|
fdsc++;
|
||||||
}
|
}
|
||||||
if(inserverpipe && !FROMSERVERPIPE){
|
if(splicesrv && inserverpipe && !FROMSERVERPIPE){
|
||||||
if(!after){
|
if(!after){
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("wait reading from server pipe");
|
log("wait reading from server pipe");
|
||||||
@ -822,12 +886,26 @@ log("timeout");
|
|||||||
CLEANRET:
|
CLEANRET:
|
||||||
|
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
if(pipecli[0] >= 0) close(pipecli[0]);
|
/* empty pipes stay with the connection for its next mapping; one still
|
||||||
if(pipecli[1] >= 0) close(pipecli[1]);
|
holding data, left by an error or a timeout, cannot be used again */
|
||||||
if(pipesrv[0] >= 0) close(pipesrv[0]);
|
if(inclientpipe && pipecli[0] >= 0){
|
||||||
if(pipesrv[1] >= 0) close(pipesrv[1]);
|
close(pipecli[0]);
|
||||||
|
close(pipecli[1]);
|
||||||
|
pipecli[0] = pipecli[1] = -1;
|
||||||
|
}
|
||||||
|
if(inserverpipe && pipesrv[0] >= 0){
|
||||||
|
close(pipesrv[0]);
|
||||||
|
close(pipesrv[1]);
|
||||||
|
pipesrv[0] = pipesrv[1] = -1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#undef SESSIONEND
|
#undef SESSIONEND
|
||||||
|
#ifndef WITHSPLICE
|
||||||
|
#undef splicecli
|
||||||
|
#undef splicesrv
|
||||||
|
#undef wantbufcli
|
||||||
|
#undef wantbufsrv
|
||||||
|
#endif
|
||||||
|
|||||||
@ -743,6 +743,11 @@ struct clientparam {
|
|||||||
*clibuf,
|
*clibuf,
|
||||||
*srvbuf;
|
*srvbuf;
|
||||||
|
|
||||||
|
/* splice() pipes for the client's and the server's data, -1 until
|
||||||
|
made; kept for the life of the connection */
|
||||||
|
int pipecli[2],
|
||||||
|
pipesrv[2];
|
||||||
|
|
||||||
unsigned cliinbuf,
|
unsigned cliinbuf,
|
||||||
srvinbuf,
|
srvinbuf,
|
||||||
clioffset,
|
clioffset,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user