From 143158e97f9df91a613787939ada3824ff6adf6f Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Wed, 28 Oct 2026 11:49:38 +0300 Subject: [PATCH] Relays: the size of a splice() pipe chosen at build time sockmap() and the callbacks' relay each had their own 64K for what a pipe is given at most (MAXSPLICE, CBSPLICE). It is PIPESIZE now, one for both, 64K as before: what a pipe holds unless asked otherwise. Built with -DPIPESIZE=, pipes are made that large with F_SETPIPE_SZ (pipenew()); one the system will not make so large is not used, and the data is copied, as when there is no pipe to be had. Measured on ARM and Intel (mix-http, mix-relay), 16K and 32K were slower, 128K and 256K no faster than 64K, which stays the default. Co-Authored-By: Claude Opus 5.5 --- src/mainloop.c | 8 +++----- src/proxy.h | 6 ++++++ src/sockmap.c | 39 ++++++++++++++++++++++++++++----------- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/mainloop.c b/src/mainloop.c index d642301..a539e8e 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -446,8 +446,6 @@ DONE: #define SPLICE_F_NONBLOCK 0x02 #endif ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags); -/* what a pipe of splice() takes at once, as sockmap()'s MAXSPLICE */ -#define CBSPLICE 65536 #endif /* One way of the relay: from the side src to dst, through the buffer of @@ -621,13 +619,13 @@ static int cbway(struct cbmap *m, struct cbway *w){ /* what was buffered goes first: the pipe is read once it is through */ - if(!inb && !w->wantbuf && w->left > w->inpipe && !m->term_r[w->src] && !end && w->inpipe < CBSPLICE && + if(!inb && !w->wantbuf && w->left > w->inpipe && !m->term_r[w->src] && !end && w->inpipe < PIPESIZE && (rs->ready & (POLLIN | POLLHUP | POLLERR))){ - if(pipe[0] < 0 && pipe2(pipe, O_NONBLOCK) < 0){ + if(pipe[0] < 0 && pipenew(pipe) < 0){ w->splice = 0; return 1; } - n = splice(from, NULL, pipe[1], NULL, (size_t)CBMIN((uint64_t)CBSPLICE - w->inpipe, + n = splice(from, NULL, pipe[1], NULL, (size_t)CBMIN((uint64_t)PIPESIZE - w->inpipe, w->left - w->inpipe), SPLICE_F_NONBLOCK | SPLICE_F_MOVE); if(n > 0){ w->inpipe += n; diff --git a/src/proxy.h b/src/proxy.h index 694a0d0..da6dfbf 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -628,6 +628,12 @@ extern struct commands commandhandlers[]; #define SPLICE_TLS 1 #define SPLICE_TLSPENDING 2 extern int (*splicetls)(struct clientparam *param, SOCKET s); +/* what a pipe of splice() is given at most: 64K, what a pipe holds; + built with -DPIPESIZE=, pipes are made that large */ +#ifndef PIPESIZE +#define PIPESIZE 65536 +#endif +int pipenew(int p[2]); #define mapsocket(a,b) ((a->srv->usesplice && !a->nosplice && !a->ndatfilterssrv && !a->ndatfilterscli)?sockmap(a,b,a->srv->usesplice):sockmap(a,b,0)) #else #define mapsocket(a,b) sockmap(a,b, 0) diff --git a/src/sockmap.c b/src/sockmap.c index 16af624..5ca5f8c 100644 --- a/src/sockmap.c +++ b/src/sockmap.c @@ -36,12 +36,29 @@ ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t le #define SPLICE_F_GIFT 0x08 #endif +#ifndef F_SETPIPE_SZ +#define F_SETPIPE_SZ 1031 +#endif -#define MAXSPLICE 65536 /* splice() refuses a kernel TLS record that is not data: EINVAL, or EIO and EBADMSG on some kernels */ #define SPLICEREFUSED(e) ((e) == EINVAL || (e) == EIO || (e) == EBADMSG) +/* A pipe for splice(), nonblocking, of PIPESIZE: -1 if there is none to be + had, or not of that size. */ +int pipenew(int p[2]){ + if(pipe2(p, O_NONBLOCK) < 0) return -1; +#if PIPESIZE != 65536 + if(fcntl(p[0], F_SETPIPE_SZ, PIPESIZE) < 0){ + close(p[0]); + close(p[1]); + p[0] = p[1] = -1; + return -1; + } +#endif + return 0; +} + /* 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 splicemin of it is left @@ -391,7 +408,7 @@ log("done send to client from buf"); #ifdef WITHLOG log("send to server from pipe"); #endif - res = splice(pipecli[0], NULL, param->remsock, NULL, MIN(MAXSPLICE, inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE); + res = splice(pipecli[0], NULL, param->remsock, NULL, MIN(PIPESIZE, inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE); /* from a pipe holding data: the socket is full */ if(res < 0 && errno == EAGAIN && fiberblockfunc) fiberblockfunc(param->remsock, POLLOUT); #ifdef WITHLOG @@ -430,7 +447,7 @@ log(logbuf); #ifdef WITHLOG log("send to client from pipe"); #endif - res = splice(pipesrv[0], NULL, param->clisock, NULL, MIN(MAXSPLICE, inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE); + res = splice(pipesrv[0], NULL, param->clisock, NULL, MIN(PIPESIZE, inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE); /* from a pipe holding data: the socket is full */ if(res < 0 && errno == EAGAIN && fiberblockfunc) fiberblockfunc(param->clisock, POLLOUT); #ifdef WITHLOG @@ -462,7 +479,7 @@ log(logbuf); #ifdef WITHLOG log("read from client to pipe"); #endif - if(pipecli[0] < 0 && pipe2(pipecli, O_NONBLOCK) < 0){ + if(pipecli[0] < 0 && pipenew(pipecli) < 0){ /* no pipe to be had: copy instead */ allowcli = splicecli = TOCLIENTPIPE = FROMCLIENTPIPE = 0; if(param->cliinbuf < CLIROOM) TOCLIENTBUF = 1; @@ -479,7 +496,7 @@ log("read from client to pipe"); continue; } 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)PIPESIZE - inclientpipe, (uint64_t)fromclient-inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE); #ifdef WITHLOG log("client to pipe splice finished\n"); #if WITHLOG > 1 @@ -521,7 +538,7 @@ log("done read from client to pipe"); else if(++streakcli > splicestreak) wantbufcli = 1; } inclientpipe += res; - if(inclientpipe >= MAXSPLICE) TOCLIENTPIPE = 0; + if(inclientpipe >= PIPESIZE) TOCLIENTPIPE = 0; needaction = 0; continue; } @@ -530,7 +547,7 @@ log("done read from client to pipe"); #ifdef WITHLOG log("read from server to pipe\n"); #endif - if(pipesrv[0] < 0 && pipe2(pipesrv, O_NONBLOCK) < 0){ + if(pipesrv[0] < 0 && pipenew(pipesrv) < 0){ allowsrv = splicesrv = TOSERVERPIPE = FROMSERVERPIPE = 0; if(param->srvinbuf < SRVROOM) TOSERVERBUF = 1; continue; @@ -544,7 +561,7 @@ log("read from server to pipe\n"); 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(PIPESIZE - inserverpipe, fromserver - inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE); #ifdef WITHLOG log("server to pipe splice finished\n"); #if WITHLOG > 1 @@ -586,7 +603,7 @@ log("done read from server to pipe\n"); param->nreads++; param->statssrv64 += res; inserverpipe += res; - if(inserverpipe >= MAXSPLICE) TOSERVERPIPE = 0; + if(inserverpipe >= PIPESIZE) TOSERVERPIPE = 0; if(param->bandlimfunc) { int sl1; sl1 = (*param->bandlimfunc)(param, res, 0); @@ -876,7 +893,7 @@ log("server terminated connection"); // } #ifdef WITHSPLICE { - if(splicecli && fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < MAXSPLICE){ + if(splicecli && fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < PIPESIZE){ if(!after){ #ifdef WITHLOG log("wait writing to client pipe"); @@ -916,7 +933,7 @@ log("ready reading from client pipe"); } fdsc++; } - if(splicesrv && fromserver>inserverpipe && !TOSERVERPIPE && inserverpipe < MAXSPLICE){ + if(splicesrv && fromserver>inserverpipe && !TOSERVERPIPE && inserverpipe < PIPESIZE){ if(!after){ #ifdef WITHLOG log("wait writing to server pipe");