diff --git a/src/imapp.c b/src/imapp.c index 42368f1..d7e4398 100644 --- a/src/imapp.c +++ b/src/imapp.c @@ -25,6 +25,24 @@ #define NOSTARTTLS param->srv->nostarttls #endif +/* as the end below, once mapping is over: data is the tag */ +static void imapptail(struct clientparam *param, void *data){ + unsigned char buf[320]; + char *tag = (char *)data; + + if(*param->hostname&&*param->extusername) { + sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(¶m->sinsr)==143)?0:':', ntohs(*SAPORT(¶m->sinsr))); + dolog(param, buf); + } + else dolog(param, NULL); + if(param->clisock != INVALID_SOCKET) { + if ((param->res > 0 && param->res < 100) || (param->res > 691 && param->res <700)) { + sprintf((char *)buf, "%.60s NO proxy error\r\n", (tag && *tag)? tag : "*"); + socksend(param, param->clisock, buf, (int)strlen((char *)buf),param->srv->timeouts[STRING_S]); + } + } +} + void * imappchild(struct clientparam* param) { int i=0, res, method=CL_LOGINCMD, caps=0; unsigned char buf[2048]; @@ -224,6 +242,7 @@ void * imappchild(struct clientparam* param) { } param->statscli64 += (uint64_t)(strlen((char *)tag) + strlen((char *)param->extusername) + strlen((char *)pb) + 11); param->nwrites++; + if((param->maptaildata = strdup((char *)tag))) param->maptail = imapptail; RETURN (mapsocket(param, 180)); CLEANRET: diff --git a/src/mainloop.c b/src/mainloop.c index bcf26ff..bf94ef9 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -848,51 +848,51 @@ static void cbmapidle(struct loop *l, struct looptimer *t){ cbmapdone(m); } -/* What the child of the client does once mapping is over, as its end and - that of its fiber would: the result, its tail, the connection released - and freed. */ -static void cbmapfinish(struct clientparam *param, int res){ +/* The end of a client whose fiber gave up its stack while it was relayed, + on a fiber again, which the child's end (maptail) may wait on: after a + reload sockmap() goes on with the mapping first. Then what the child and + its fiber would do: the result, the tail, the connection released and + freed. */ +static void cbmapfinish(void *arg){ + struct cbmap *m = (struct cbmap *)arg; + struct clientparam *param = m->param; + int res = m->res, timeo = m->timeosec, usesplice = m->usesplice0; + + free(m); + if(res == -2) res = sockmap(param, timeo, usesplice); param->res = res; if(param->maptail) param->maptail(param, param->maptaildata); releaseparam(param); freeparam(param); } -/* a fiber for the client again: sockmap() goes on with the mapping after - a reload, then the child's end */ -static void cbmapresume(void *arg){ - struct cbmap *m = (struct cbmap *)arg; - struct clientparam *param = m->param; - int timeo = m->timeosec, usesplice = m->usesplice0; - - free(m); - cbmapfinish(param, sockmap(param, timeo, usesplice)); -} - -/* The mapping is over: its fiber goes on, or, with none, the loop ends it - as the child would, or gives it a fiber again for sockmap() to take it - over after a reload. m is freed. */ +/* The mapping is over: its fiber goes on, which frees m, or, with none, a + fiber is taken to end the client as the child would. */ static void cbmapdone(struct cbmap *m){ - struct clientparam *param = m->param; struct fiberslot *fs; - int res; if(!m->abandoned){ - /* the fiber frees m */ fiberrun(m->lp, m->f); return; } - if(m->res == -2){ - if((fs = fibertake(m->lp, param->stacksize))){ - fiberstart(&fs->f, cbmapresume, m); - fiberrun(m->lp, &fs->f); - return; - } - m->res = 21; + if((fs = fibertake(m->lp, m->param->stacksize))){ + fiberstart(&fs->f, cbmapfinish, m); + fiberrun(m->lp, &fs->f); + return; + } + /* no stack for it: as it can be, here, with no waits left to its + tail, a reload taken for its end */ + if(m->res == -2) m->res = 21; + { + struct clientparam *param = m->param; + + param->res = m->res; + free(m); + param->maptail = NULL; + dolog(param, NULL); + releaseparam(param); + freeparam(param); } - res = m->res; - free(m); - cbmapfinish(param, res); } /* sockmapcbfunc: sockmap() of a fiber, as callbacks, its result; -2 for diff --git a/src/pop3p.c b/src/pop3p.c index 8eea358..f711e09 100644 --- a/src/pop3p.c +++ b/src/pop3p.c @@ -18,6 +18,20 @@ #define NOSTARTTLS param->srv->nostarttls #endif +/* as the end below, once mapping is over */ +static void pop3ptail(struct clientparam *param, void *data){ + unsigned char buf[320]; + + if(*param->hostname&&*param->extusername) { + sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(¶m->sinsr)==110)?0:':', ntohs(*SAPORT(¶m->sinsr))); + dolog(param, buf); + } + else dolog(param, NULL); + if(param->clisock != INVALID_SOCKET) { + if ((param->res > 0 && param->res < 100) || (param->res > 611 && param->res <700)) socksend(param, param->clisock, (unsigned char *)"-ERR\r\n", 6,param->srv->timeouts[STRING_S]); + } +} + void * pop3pchild(struct clientparam* param) { int i=0, res; unsigned char buf[320]; @@ -65,6 +79,7 @@ void * pop3pchild(struct clientparam* param) { {RETURN(623);} param->statscli64 += (uint64_t)(strlen((char *)param->extusername) + 7); param->nwrites++; + param->maptail = pop3ptail; RETURN (mapsocket(param, 180)); CLEANRET: diff --git a/src/proxy.c b/src/proxy.c index ab2076d..f8157d8 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -493,6 +493,50 @@ void file2url(unsigned char *sb, unsigned char *buf, unsigned bufsize, int * inb } +/* The status page the client is sent for the result in param->res, where + one is: the rest of a request whose headers were not all read is read + first. */ +static void proxystatus(struct clientparam *param, int hdrsdone, char *ftpbuf, int inftpbuf){ + int stidx = -1, i; + int r = param->res; + + if(r == 555 || !r || param->clisock == INVALID_SOCKET || !(r < 90 || r >=800 || r == 100 ||(r > 500 && r< 800))) + return; + if(!hdrsdone && ((r >= 509 && r < 517) || r > 900)) { + unsigned char rest[256]; + int atstart = 1; + + while((i = sockgetlinebuf(param, CLIENT, rest, sizeof(rest) - 1, '\n', param->srv->timeouts[STRING_S])) > 0){ + if(atstart && i <= 2 && rest[i-1] == '\n') break; + atstart = (rest[i-1] == '\n'); + } + } + if(r == 10) stidx = 2; + else if(r == 700 || r == 701) stidx = 16; + else if(r == 100 || (r > 10 && r < 20) || (r > 701 && r <= 705)) stidx = 1; + else if(r >= 20 && r < 30) stidx = 6; + else if(r >= 30 && r < 80) stidx = 5; + else if(r == 1 || (!param->srv->needuser && r < 10)) stidx = 11; + else if(r < 10) stidx = 7; + else if(r == 999) stidx = 4; + else if(r == 519) stidx = 3; + else if(r == 517) stidx = 15; + else if(r == 780) stidx = 10; + else if(r >= 511 && r <= 516) stidx = 0; + + if(stidx >= 0) { + send_st(param, stidx); + if((r == 700 || r == 701) && ftpbuf) socksend(param, param->clisock, (unsigned char *)ftpbuf, inftpbuf, param->srv->timeouts[STRING_S]); + } +} + +/* the end of a CONNECT, as proxychild()'s, once mapping is over: data is + its request line */ +static void proxytail(struct clientparam *param, void *data){ + proxystatus(param, 1, NULL, 0); + logurl(param, (char *)data, 0); +} + void * proxychild(struct clientparam* param) { int res=0, i=0; unsigned char* buf = NULL, *newbuf; @@ -1250,6 +1294,10 @@ for(;;){ return (void *)param->redirectfunc; } hdrfree(&buf, &bufown); + /* mapping its last thing, but in a request httpsrv hands over, whose + end is httpsrv's: the rest of the end can be a loop's */ + if(!param->onerequest && (param->maptaildata = req? (void *)strdup((char *)req) : NULL)) + param->maptail = proxytail; param->res = mapsocket(param, param->srv->timeouts[CONNECTION_L]); RETURN(param->res); } @@ -1617,38 +1665,7 @@ REQUESTEND: CLEANRET: - if(param->res != 555 && param->res && param->clisock != INVALID_SOCKET && (param->res < 90 || param->res >=800 || param->res == 100 ||(param->res > 500 && param->res< 800))) { - int stidx = -1; - int r = param->res; - - /* the rest of a request whose headers were not all read */ - if(!hdrsdone && ((r >= 509 && r < 517) || r > 900)) { - unsigned char rest[256]; - int atstart = 1; - - while((i = sockgetlinebuf(param, CLIENT, rest, sizeof(rest) - 1, '\n', param->srv->timeouts[STRING_S])) > 0){ - if(atstart && i <= 2 && rest[i-1] == '\n') break; - atstart = (rest[i-1] == '\n'); - } - } - if(r == 10) stidx = 2; - else if(r == 700 || r == 701) stidx = 16; - else if(r == 100 || (r > 10 && r < 20) || (r > 701 && r <= 705)) stidx = 1; - else if(r >= 20 && r < 30) stidx = 6; - else if(r >= 30 && r < 80) stidx = 5; - else if(r == 1 || (!param->srv->needuser && r < 10)) stidx = 11; - else if(r < 10) stidx = 7; - else if(r == 999) stidx = 4; - else if(r == 519) stidx = 3; - else if(r == 517) stidx = 15; - else if(r == 780) stidx = 10; - else if(r >= 511 && r <= 516) stidx = 0; - - if(stidx >= 0) { - send_st(param, stidx); - if(r == 700 || r == 701) socksend(param, param->clisock, (unsigned char *)ftpbuf, inftpbuf, param->srv->timeouts[STRING_S]); - } - } + proxystatus(param, hdrsdone, ftpbuf, inftpbuf); logurl(param, (char *)req, ftp); freeptr(&req); hdrfree(&buf, &bufown); freeptr(&ftpbase); return (NULL); diff --git a/src/smtpp.c b/src/smtpp.c index 7381ce5..8a3d545 100644 --- a/src/smtpp.c +++ b/src/smtpp.c @@ -114,6 +114,25 @@ int readdata (struct clientparam* param) { } +/* as the end below, once mapping is over */ +static void smtpptail(struct clientparam *param, void *data){ + unsigned char buf[320]; + + if(*param->hostname&&*param->extusername) { + sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(¶m->sinsr)==587?0:':',ntohs(*SAPORT(¶m->sinsr))); + dolog(param, buf); + } + else dolog(param, NULL); + if(param->clisock != INVALID_SOCKET) { + if ((param->res > 0 && param->res < 100) || (param->res > 661 && param->res <700)) socksend(param, param->clisock, (unsigned char *)"571 \r\n", 6,param->srv->timeouts[STRING_S]); + } +} + +/* mapping the last thing: what is not needed any more freed, the end left + to the tail */ +#define SMTPLASTMAP { if(command){ free(command); command = NULL; } param->maptail = smtpptail; \ + RETURN (mapsocket(param, 180)); } + void * smtppchild(struct clientparam* param) { int i=0, res; unsigned char buf[320]; @@ -309,7 +328,7 @@ void * smtppchild(struct clientparam* param) { if(param->nhdrfilterscli || param->nhdrfilterssrv || param->ndatfilterscli || param->ndatfilterssrv){ do { - if(res == 22) RETURN (mapsocket(param, 180)); + if(res == 22) SMTPLASTMAP if(res != 2 && (res = readreply(param)) <= 0) break; if(res == 221) RETURN(0); if(res == 354) res = readdata(param); @@ -323,7 +342,7 @@ void * smtppchild(struct clientparam* param) { #endif - RETURN (mapsocket(param, 180)); + SMTPLASTMAP CLEANRET: diff --git a/src/socks.c b/src/socks.c index 865d59c..af3255b 100644 --- a/src/socks.c +++ b/src/socks.c @@ -30,6 +30,14 @@ static void printcommand(unsigned char * buf, int command, struct clientparam *p } +/* the end of a CONNECT, as below, once mapping is over */ +static void sockstail(struct clientparam *param, void *data){ + unsigned char logline[340]; + + printcommand(logline, 1, param); + dolog(param, logline); +} + void * sockschild(struct clientparam* param) { int res; unsigned i=0; @@ -347,6 +355,13 @@ fflush(stderr); if(buf != param->tmpbuf) free(buf); return (void *)param->redirectfunc; } + /* the request is not needed any more: its end is + the log line, which mapping may leave to a loop */ + if(buf != param->tmpbuf){ + free(buf); + buf = param->tmpbuf; + } + param->maptail = sockstail; param->res = mapsocket(param, param->srv->timeouts[CONNECTION_L]); break; case 2: