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
for most traffic. Rebuild with -DWITHSPLICE to make -s available, -s0 disables it
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
(for dnspr) simple, do not use resolver and 3proxy cache, always use external DNS server.
.br

View File

@ -329,6 +329,8 @@ int MODULEMAINFUNC (int argc, char** argv){
#endif
#ifdef WITHSPLICE
" -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
"-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"
@ -596,6 +598,9 @@ int MODULEMAINFUNC (int argc, char** argv){
case 'g':
sscanf(argv[i]+2, "%d,%d,%d", &srv.gracetraf, &srv.gracenum, &srv.gracedelay);
break;
case 'C':
srv.halfclose = *(argv[i]+2)? atoi(argv[i]+2) : 1;
break;
case 's':
#ifdef WITHSPLICE
if(isudp || srv.service == S_ADMIN)
@ -1247,6 +1252,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){
#ifdef WITHSPLICE
srv->usesplice = 0;
#endif
srv->halfclose = 0;
memset(param, 0, sizeof(struct clientparam));
param->srv = srv;
param->version = srv->version;

View File

@ -171,12 +171,13 @@ int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char *
if(delim != EOF){
unsigned char *d = (unsigned char *)memchr(base + *offp, delim, n);
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;
if(d || i >= bufsize) return i;
}
else {
memcpy(buf + i, base + *offp, n);
memmove(buf + i, base + *offp, n);
i += n; *offp += n;
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 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 halfclose = param->srv->halfclose;
uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
uint64_t inclientbuf = 0, inserverbuf = 0;
int FROMCLIENT = 1, TOCLIENTBUF = 1, TOSERVER = 1,
@ -129,13 +135,13 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
#ifdef WITHSPLICE
|| inserverpipe
#endif
|| (!SERVERTERMREAD )))
|| (!SERVERTERMREAD && !SESSIONEND)))
||
((!SERVERTERMWRITE) && fromclient && (inclientbuf
#ifdef WITHSPLICE
|| inclientpipe
#endif
|| (!CLIENTTERMREAD )))
|| (!CLIENTTERMREAD && !SESSIONEND)))
){
@ -354,7 +360,7 @@ log(logbuf);
}
}
}
if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE){
if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE && !SESSIONEND){
int error;
socklen_t len=sizeof(error);
#ifdef WITHLOG
@ -396,7 +402,7 @@ log("done read from client to pipe");
continue;
}
}
if(fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE){
if(fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE && !SESSIONEND){
int error;
socklen_t len=sizeof(error);
errno = 0;
@ -449,7 +455,7 @@ log("done read from server to pipe\n");
else
#endif
{
if(fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF){
if(fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF && !SESSIONEND){
#ifdef WITHLOG
log("read from client to buf");
#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
log("read from server to buf");
#endif
@ -547,7 +553,7 @@ log("done read from server to buf");
// if(!CLIENTTERMREAD || !CLIENTTERMWRITE){
if(!after){
fds[fdsc].fd = param->clisock;
if(fromclient && !CLIENTTERMREAD && !FROMCLIENT && ((
if(fromclient && !CLIENTTERMREAD && !FROMCLIENT && !SESSIONEND && ((
#ifdef WITHSPLICE
!usesplice &&
#endif
@ -607,7 +613,7 @@ log("ready to write to client");
// if(!SERVERTERMREAD || !SERVERTERMWRITE){
if(!after){
fds[fdsc].fd = param->remsock;
if(fromserver && !SERVERTERMREAD && !FROMSERVER && ((
if(fromserver && !SERVERTERMREAD && !FROMSERVER && !SESSIONEND && ((
#ifdef WITHSPLICE
!usesplice &&
#endif
@ -827,3 +833,4 @@ CLEANRET:
return res;
}
#undef SESSIONEND

View File

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