diff --git a/src/mainloop.c b/src/mainloop.c index 5d216f0..391bda1 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -497,13 +497,7 @@ static void cbbuf(struct clientparam *param, int side, unsigned char **buf, unsi relay can use it: the client's fiber gave up its stack. The next read makes it again. */ static void cbbufdrop(struct cbmap *m, int side){ - struct clientparam *param = m->param; - unsigned char **own = side? ¶m->srvbufdata : ¶m->clibufdata; - unsigned char **buf = side? ¶m->srvbuf : ¶m->clibuf; - - if(!m->abandoned || !*own || *buf != *own || (side? param->srvinbuf : param->cliinbuf)) return; - free(*own); - *own = *buf = NULL; + if(m->abandoned) bufdrop(m->param, side? SERVER : CLIENT); } /* what a way has buffered and in its pipe: none once it is not moving */ diff --git a/src/proxy.h b/src/proxy.h index 858e8cb..64846e4 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -361,6 +361,7 @@ int paramstr(unsigned char *field, size_t size, const unsigned char *s); #define PARAMSTR(p, f, s) paramstr((p)->f, sizeof((p)->f), (const unsigned char *)(s)) void bufrelease(struct clientparam * param, DIRECTION which); int bufget(struct clientparam * param, DIRECTION which); +void bufdrop(struct clientparam * param, DIRECTION which); int bufalloc(struct clientparam * param); void buffree(struct clientparam * param); diff --git a/src/sockgetchar.c b/src/sockgetchar.c index 2dd5744..5f27cb5 100644 --- a/src/sockgetchar.c +++ b/src/sockgetchar.c @@ -102,6 +102,20 @@ void buffree(struct clientparam * param){ param->clibufdata = param->srvbufdata = NULL; } +/* An empty own buffer let go, while the connection's last mapping has + no use for it, its direction spliced; bufget() makes it again. */ +void bufdrop(struct clientparam * param, DIRECTION which){ + unsigned char **own = which? ¶m->srvbufdata : ¶m->clibufdata; + unsigned char **buf = which? ¶m->srvbuf : ¶m->clibuf; + unsigned *in = which? ¶m->srvinbuf : ¶m->cliinbuf; + unsigned *off = which? ¶m->srvoffset : ¶m->clioffset; + + if(!*own || *buf != *own || *in != *off) return; + free(*own); + *own = *buf = NULL; + *in = *off = 0; +} + /* Starts an empty buffer over from its beginning, and goes back to the connection's own buffer if a filter needed a bigger one. Does nothing while anything is left unread. */ diff --git a/src/sockmap.c b/src/sockmap.c index 8ce6599..d6ce27c 100644 --- a/src/sockmap.c +++ b/src/sockmap.c @@ -378,6 +378,12 @@ log("done send to client from buf"); splicesrv = wantbufsrv = streaksrv = 0; if(param->srvinbuf < SRVROOM) TOSERVERBUF = 1; } + /* the connection's last mapping: a direction spliced has no use for + its buffer while it is empty */ + if(param->maptail){ + if(splicecli && !wantbufcli && !draincli && !inclientbuf) bufdrop(param, CLIENT); + if(splicesrv && !wantbufsrv && !drainsrv && !inserverbuf) bufdrop(param, SERVER); + } { /* each direction goes through its pipe if spliced, through its buffer otherwise; what was in the buffer before is sent first */ @@ -597,6 +603,8 @@ log("done read from server to pipe\n"); #ifdef WITHLOG log("read from client to buf"); #endif + /* let go while spliced: made again */ + if(!param->clibuf && bufget(param, CLIENT)) RETURN(21); /* no address: it would overwrite the client's with what a stream socket gives, an empty one for a Unix socket */ res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)CLIROOM - param->cliinbuf, fromclient-inclientbuf), 0, NULL, NULL); @@ -654,6 +662,7 @@ log("done read from client to buf"); #ifdef WITHLOG log("read from server to buf"); #endif + if(!param->srvbuf && bufget(param, SERVER)) RETURN(21); res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)SRVROOM - param->srvinbuf, fromserver-inserverbuf), 0, NULL, NULL); if(res <= 0) { FROMSERVER = 0; @@ -1009,6 +1018,9 @@ log("timeout"); CLEANRET: + /* what comes after a mapping finds the buffers there */ + if(((!param->clibuf && bufget(param, CLIENT)) || (!param->srvbuf && bufget(param, SERVER))) && !res) res = 21; + #ifdef WITHSPLICE /* empty pipes stay with the connection for its next mapping; one still holding data, left by an error or a timeout, cannot be used again */