/* 3APA3A simplest proxy server (c) 2002-2026 by Vladimir Dubrovin please read License Agreement */ #include "proxy.h" int socksend(struct clientparam *param, SOCKET sock, unsigned char * buf, int bufsize, int to){ int sent = 0; int res; struct pollfd fds; fds.fd = sock; fds.events = POLLOUT; do { if(conf.timetoexit) return 0; /* try to send first; poll only when the socket would block */ res = param?param->srv->so._send(param->sostate, sock, (char *)buf + sent, bufsize - sent, 0) : so._send(so.state, sock, (char *)buf + sent, bufsize - sent, 0); if(res > 0) { sent += res; continue; } if(res < 0 && errno != EAGAIN && errno != EINTR) break; res = param?param->srv->so._poll(param->sostate, &fds, 1, to*1000):so._poll(so.state, &fds, 1, to*1000); if(res < 0 && (errno == EAGAIN || errno == EINTR)) continue; if(res < 1) break; } while (sent < bufsize); return sent; } int socksendto(struct clientparam *param, SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to){ int sent = 0; int res; struct pollfd fds; fds.fd = sock; do { if(conf.timetoexit) return 0; fds.events = POLLOUT; res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to); if(res < 0 && (errno == EAGAIN || errno == EINTR)) continue; if(res < 1) break; res = param?param->srv->so._sendto(param->sostate, sock, (char *)buf + sent, bufsize - sent, 0, sin, SASIZE(sin)):so._sendto(so.state, sock, (char *)buf + sent, bufsize - sent, 0, sin, SASIZE(sin)); if(res < 0) { if(errno != EAGAIN && errno != EINTR) break; continue; } sent += res; } while (sent < bufsize); return sent; } int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to){ struct pollfd fds; SASIZETYPE sasize; int res; fds.fd = sock; fds.events = POLLIN; if(conf.timetoexit) return EOF; res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to); if (res<1) return 0; sasize = SASIZE(sin); do { res = param?param->srv->so._recvfrom(param->sostate, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize):so._recvfrom(so.state, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize); } while (res < 0 && (errno == EAGAIN || errno == EINTR)); return res; } int sockgetcharcli(struct clientparam * param, int timeosec, int timeousec){ int len; if(!param->clibuf){ if(!(param->clibuf = malloc(SRVBUFSIZE))) return 0; param->clibufsize = SRVBUFSIZE; param->clioffset = param->cliinbuf = 0; } if(param->cliinbuf && param->clioffset < param->cliinbuf){ return (int)param->clibuf[param->clioffset++]; } param->clioffset = param->cliinbuf = 0; if ((len = sockrecvfrom(param, param->clisock, (struct sockaddr *)¶m->sincr, param->clibuf, param->clibufsize, timeosec*1000 + timeousec))<=0) return EOF; param->cliinbuf = len; param->clioffset = 1; return (int)*param->clibuf; } unsigned long sockfillbuffcli(struct clientparam * param, unsigned long size, int timeosec){ int len; if(!param->clibuf) return 0; if(param->cliinbuf == param->clioffset){ param->cliinbuf = param->clioffset = 0; } else if(param->clioffset){ memmove(param->clibuf, param->clibuf + param->clioffset, param->cliinbuf - param->clioffset); param->cliinbuf -= param->clioffset; param->clioffset = 0; } if(size <= param->cliinbuf) return size; size -= param->cliinbuf; if((len = sockrecvfrom(param, param->clisock, (struct sockaddr *)¶m->sincr, param->clibuf + param->cliinbuf, (param->clibufsize - param->cliinbuf) < size? param->clibufsize - param->cliinbuf:size, timeosec*1000)) > 0){ param->cliinbuf += len; } return param->cliinbuf; } unsigned long sockfillbuffsrv(struct clientparam * param, unsigned long size, int timeosec){ int len; if(!param->srvbuf) return 0; if(param->srvinbuf == param->srvoffset){ param->srvinbuf = param->srvoffset = 0; } else if(param->srvoffset){ memmove(param->srvbuf, param->srvbuf + param->srvoffset, param->srvinbuf - param->srvoffset); param->srvinbuf -= param->srvoffset; param->srvoffset = 0; } if(size <= param->srvinbuf) return size; size -= param->srvinbuf; if((len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, param->srvbuf + param->srvinbuf, (param->srvbufsize - param->srvinbuf) < size? param->srvbufsize - param->srvinbuf:size, timeosec*1000)) > 0){ param->srvinbuf += len; param->nreads++; param->statssrv64 += len; } return param->srvinbuf; } int sockgetcharsrv(struct clientparam * param, int timeosec, int timeousec){ int len; int bufsize; if(!param->srvbuf){ bufsize = SRVBUFSIZE; if(param->ndatfilterssrv > 0 && bufsize < 32768) bufsize = 32768; if(!(param->srvbuf = malloc(bufsize))) return 0; param->srvbufsize = bufsize; param->srvoffset = param->srvinbuf = 0; } if(param->srvinbuf && param->srvoffset < param->srvinbuf){ return (int)param->srvbuf[param->srvoffset++]; } param->srvoffset = param->srvinbuf = 0; if ((len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, param->srvbuf, param->srvbufsize, timeosec*1000 + timeousec))<=0) return EOF; param->srvinbuf = len; param->srvoffset = 1; param->nreads++; param->statssrv64 += len; return (int)*param->srvbuf; } int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char * buf, int bufsize, int delim, int to){ int c; int i=0; for(;;){ unsigned char *base = which? param->srvbuf : param->clibuf; unsigned *offp = which? ¶m->srvoffset : ¶m->clioffset; unsigned *inp = which? ¶m->srvinbuf : ¶m->cliinbuf; /* drain already-buffered bytes in bulk instead of one call per byte */ if(base && *offp < *inp && i < bufsize){ int avail = (int)(*inp - *offp); int n = (bufsize - i < avail)? bufsize - i : avail; if(delim != EOF){ unsigned char *d = (unsigned char *)memchr(base + *offp, delim, n); if(d) n = (int)(d - (base + *offp)) + 1; /* 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 { memmove(buf + i, base + *offp, n); i += n; *offp += n; if(i >= bufsize) return i; } } if(i >= bufsize) return i; /* buffer empty: one call forces a refill (with poll + accounting), then bulk-drain the rest */ if((c = which? sockgetcharsrv(param, to, 0) : sockgetcharcli(param, to, 0)) == EOF) return i; buf[i++] = c; if((delim != EOF && c == delim) || i >= bufsize) return i; } }