Use memmove for overlapping region

This commit is contained in:
Vladimir Dubrovin 2026-08-08 20:46:52 +03:00
parent a986ed7a07
commit 8c2ad56665
5 changed files with 32 additions and 10 deletions

View File

@ -199,6 +199,13 @@ is disabled even when built, because current Linux does not implement
SPLICE_F_MOVE, so no real zero-copy takes place and the read/write path is faster SPLICE_F_MOVE, so no real zero-copy takes place and the read/write path is faster
for most traffic. Rebuild with -DWITHSPLICE to make -s available, -s0 disables it for most traffic. Rebuild with -DWITHSPLICE to make -s available, -s0 disables it
explicitly. explicitly.
.br
.B -C
(for TCP services) keep the session until both sides close the connection
(TCP half-close). By default a connection closed by any of the sides terminates
the session, buffered data is delivered before the sockets are closed. Half-close
is required for the protocols where one of the sides closes its sending side and
expects the answer, it may cause the sockets to be kept in CLOSE_WAIT state.
.br .br
(for dnspr) simple, do not use resolver and 3proxy cache, always use external DNS server. (for dnspr) simple, do not use resolver and 3proxy cache, always use external DNS server.
.br .br

View File

@ -329,6 +329,8 @@ int MODULEMAINFUNC (int argc, char** argv){
#endif #endif
#ifdef WITHSPLICE #ifdef WITHSPLICE
" -s Use splice() - no filtering for data, off by default\n" " -s Use splice() - no filtering for data, off by default\n"
" -C keep the session until both sides close the connection (TCP half-close),\n"
" by default connection closed by any of the sides terminates the session\n"
#endif #endif
"-g(GRACE_TRAFF,GRACE_NUM,GRACE_DELAY) - delay GRACE_DELAY milliseconds before polling if average polling size below GRACE_TRAFF bytes and GRACE_NUM read operations in single directions are detected within 1 second to minimize polling\n" "-g(GRACE_TRAFF,GRACE_NUM,GRACE_DELAY) - delay GRACE_DELAY milliseconds before polling if average polling size below GRACE_TRAFF bytes and GRACE_NUM read operations in single directions are detected within 1 second to minimize polling\n"
" -fFORMAT logging format (see documentation)\n" " -fFORMAT logging format (see documentation)\n"
@ -596,6 +598,9 @@ int MODULEMAINFUNC (int argc, char** argv){
case 'g': case 'g':
sscanf(argv[i]+2, "%d,%d,%d", &srv.gracetraf, &srv.gracenum, &srv.gracedelay); sscanf(argv[i]+2, "%d,%d,%d", &srv.gracetraf, &srv.gracenum, &srv.gracedelay);
break; break;
case 'C':
srv.halfclose = *(argv[i]+2)? atoi(argv[i]+2) : 1;
break;
case 's': case 's':
#ifdef WITHSPLICE #ifdef WITHSPLICE
if(isudp || srv.service == S_ADMIN) if(isudp || srv.service == S_ADMIN)
@ -1247,6 +1252,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){
#ifdef WITHSPLICE #ifdef WITHSPLICE
srv->usesplice = 0; srv->usesplice = 0;
#endif #endif
srv->halfclose = 0;
memset(param, 0, sizeof(struct clientparam)); memset(param, 0, sizeof(struct clientparam));
param->srv = srv; param->srv = srv;
param->version = srv->version; param->version = srv->version;

View File

@ -171,12 +171,13 @@ int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char *
if(delim != EOF){ if(delim != EOF){
unsigned char *d = (unsigned char *)memchr(base + *offp, delim, n); unsigned char *d = (unsigned char *)memchr(base + *offp, delim, n);
if(d) n = (int)(d - (base + *offp)) + 1; if(d) n = (int)(d - (base + *offp)) + 1;
memcpy(buf + i, base + *offp, n); /* caller may use param->srvbuf / param->clibuf as buf */
memmove(buf + i, base + *offp, n);
i += n; *offp += n; i += n; *offp += n;
if(d || i >= bufsize) return i; if(d || i >= bufsize) return i;
} }
else { else {
memcpy(buf + i, base + *offp, n); memmove(buf + i, base + *offp, n);
i += n; *offp += n; i += n; *offp += n;
if(i >= bufsize) return i; if(i >= bufsize) return i;
} }

View File

@ -44,7 +44,13 @@ ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t le
#define MIN(a,b) ((a>b)?b:a) #define MIN(a,b) ((a>b)?b:a)
#define RETURN(xxx) { res = xxx; goto CLEANRET; } #define RETURN(xxx) { res = xxx; goto CLEANRET; }
/* Unless half-close is requested for the service, a connection closed by any
of the sides terminates the session, remaining buffered data is delivered
before the sockets are closed. */
#define SESSIONEND (!halfclose && (CLIENTTERMREAD || SERVERTERMREAD))
int sockmap(struct clientparam * param, int timeo, int usesplice){ int sockmap(struct clientparam * param, int timeo, int usesplice){
int halfclose = param->srv->halfclose;
uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff; uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
uint64_t inclientbuf = 0, inserverbuf = 0; uint64_t inclientbuf = 0, inserverbuf = 0;
int FROMCLIENT = 1, TOCLIENTBUF = 1, TOSERVER = 1, int FROMCLIENT = 1, TOCLIENTBUF = 1, TOSERVER = 1,
@ -129,13 +135,13 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| inserverpipe || inserverpipe
#endif #endif
|| (!SERVERTERMREAD ))) || (!SERVERTERMREAD && !SESSIONEND)))
|| ||
((!SERVERTERMWRITE) && fromclient && (inclientbuf ((!SERVERTERMWRITE) && fromclient && (inclientbuf
#ifdef WITHSPLICE #ifdef WITHSPLICE
|| inclientpipe || inclientpipe
#endif #endif
|| (!CLIENTTERMREAD ))) || (!CLIENTTERMREAD && !SESSIONEND)))
){ ){
@ -354,7 +360,7 @@ log(logbuf);
} }
} }
} }
if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE){ if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE && !SESSIONEND){
int error; int error;
socklen_t len=sizeof(error); socklen_t len=sizeof(error);
#ifdef WITHLOG #ifdef WITHLOG
@ -396,7 +402,7 @@ log("done read from client to pipe");
continue; continue;
} }
} }
if(fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE){ if(fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE && !SESSIONEND){
int error; int error;
socklen_t len=sizeof(error); socklen_t len=sizeof(error);
errno = 0; errno = 0;
@ -449,7 +455,7 @@ log("done read from server to pipe\n");
else else
#endif #endif
{ {
if(fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF){ if(fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF && !SESSIONEND){
#ifdef WITHLOG #ifdef WITHLOG
log("read from client to buf"); log("read from client to buf");
#endif #endif
@ -482,7 +488,7 @@ log("done read from client to buf");
} }
} }
if(fromserver > inserverbuf && FROMSERVER && TOSERVERBUF){ if(fromserver > inserverbuf && FROMSERVER && TOSERVERBUF && !SESSIONEND){
#ifdef WITHLOG #ifdef WITHLOG
log("read from server to buf"); log("read from server to buf");
#endif #endif
@ -547,7 +553,7 @@ 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 && (( if(fromclient && !CLIENTTERMREAD && !FROMCLIENT && !SESSIONEND && ((
#ifdef WITHSPLICE #ifdef WITHSPLICE
!usesplice && !usesplice &&
#endif #endif
@ -607,7 +613,7 @@ 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 && (( if(fromserver && !SERVERTERMREAD && !FROMSERVER && !SESSIONEND && ((
#ifdef WITHSPLICE #ifdef WITHSPLICE
!usesplice && !usesplice &&
#endif #endif
@ -827,3 +833,4 @@ CLEANRET:
return res; return res;
} }
#undef SESSIONEND

View File

@ -551,6 +551,7 @@ struct srvparam {
#ifdef WITHSPLICE #ifdef WITHSPLICE
int usesplice; int usesplice;
#endif #endif
int halfclose;
unsigned bufsize; unsigned bufsize;
unsigned authcachetype, authcachetime; unsigned authcachetype, authcachetime;
unsigned logdumpsrv, logdumpcli; unsigned logdumpsrv, logdumpcli;