mirror of
https://github.com/3proxy/3proxy.git
synced 2026-09-03 13:25:48 +08:00
193 lines
6.4 KiB
C
193 lines
6.4 KiB
C
/*
|
|
3APA3A simplest proxy server
|
|
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
|
|
|
|
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;
|
|
}
|
|
}
|
|
|