Просмотр исходного кода

Major code refactoring

- sockmapping rewritten from stratch to minimilse polling. poll() is now
only called if blocking is actually expected, splice pipes are now
polled if splice fails, buffers flushing is much more accurate.
- logging code moved to separate files
- signal masks added to client threads to prevent unneeded interruptions
- bandwidth limitation will not delay the thread after client or server
shutdown
z3APA3A 5 лет назад
Родитель
Сommit
eb829b062b
17 измененных файлов с 683 добавлено и 545 удалено
  1. 10 0
      doc/html/howtoe.html
  2. 12 0
      doc/html/howtor.html
  3. 1 1
      src/common.c
  4. 1 1
      src/dnspr.c
  5. 2 2
      src/ftppr.c
  6. 22 2
      src/log.c
  7. 2 2
      src/pop3p.c
  8. 1 1
      src/proxy.c
  9. 4 4
      src/proxy.h
  10. 36 25
      src/proxymain.c
  11. 2 2
      src/smtpp.c
  12. 583 498
      src/sockmap.c
  13. 1 1
      src/socks.c
  14. 1 1
      src/structures.h
  15. 1 1
      src/tcppm.c
  16. 3 3
      src/udppm.c
  17. 1 1
      src/webadmin.c

+ 10 - 0
doc/html/howtoe.html

@@ -870,6 +870,16 @@ You can control 3proxy service via "Services" administration ot via "net" comman
 		<li>50-69 - SOCKS5 PROXY REDIRECTION ERRORS
 		<li>70-79 PARENT PROXY CONNECTION ERRORS (identical to 1x)
 		<li>90-99 - established connection errors
+<li>since 0.9
+    <li>90 - unexpected system error (should not happen)
+    <li>91 - unexpected poll error (should not happen)
+    <li>92 - connection terminated by timeout
+    <li>93 - dirty connection termination by server or client (or network issue) with unsent data
+    <li>94 - clear connection termination by server or client with unsent data
+    <li>95 - dirty connection termination by client (or network issue)
+    <li>96 - dirty connection termination by server (or network issue)
+    <li>97 - dirty connection termination by both client and server (probably network issue)
+<li>prior to 0.9:
 		<li>90 - socket error or connection broken
 		<li>91 - TCP/IP common failure
 		<li>92 - connection timed out

+ 12 - 0
doc/html/howtor.html

@@ -1046,6 +1046,18 @@
     <li>50-69 - ошибки перенаправления SOCKS5
     <li>70-79 ошибки установки родительского соединения, аналогичны 1x
     <li>90-99 - ошибки разрыва соединения
+    <li>с версии 0.9
+    <li>90 - неожиданная системная ошибка (не должно происходить)
+    <li>91 - ошибка poll (не должно происходить)
+    <li>92 - соединение прервано по таймауту
+    <li>93 - клиент или сервер &quot;грязно&quot; закрыли соединение или произошла сетевая ошибка, остались неотправленные данные 
+    <li>94 - клиент или сервер &quot;чисто&quot; закрыли соединение или произошла сетевая ошибка, остались неотправленные данные
+    <li>95 - клиент "грязно" закрыл соединение или сетевая ошибка
+    <li>96 - сервер "грязно" закрыл соединение или сетевая ошибка
+    <li>97 - клиент и сервер "грязно" закрыли соединение или сетевая ошибка
+    <li>98 - исчерпан лимит данных сервера (не должно быть в журнале)
+    <li>99 - исчерпан лимит данных клиента (не должно быть в журнале)
+    <li>до версии 0.9
     <li>90 - ошибка сокета или соединение неожиданно прервано
     <li>91 - общий сбой стека TCP/IP
     <li>92 - соединение прервано по таймауту

+ 1 - 1
src/common.c

@@ -369,7 +369,7 @@ int connectwithpoll(SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to){
 		unsigned long ul = 1;
 		ioctlsocket(sock, FIONBIO, &ul);
 #else
-		fcntl(sock,F_SETFL,O_NONBLOCK);
+		fcntl(sock,F_SETFL, O_NONBLOCK | fcntl(sock,F_GETFL));
 #endif
 		if(so._connect(sock,sa,size)) {
 			if(errno != EAGAIN && errno != EINPROGRESS) return (13);

+ 1 - 1
src/dnspr.c

@@ -198,7 +198,7 @@ CLEANRET:
 	if((ip && type == 0x01) || type == 0x1c){
 		myinet_ntop(type == 0x01? AF_INET:AF_INET6, addr, (char *)buf+strlen((char *)buf), 64);
 	}
-	(*param->srv->logfunc)(param, buf);
+	dolog(param, buf);
  }
  if(bbuf)myfree(bbuf);
  if(host)myfree(host);

+ 2 - 2
src/ftppr.c

@@ -295,7 +295,7 @@ void * ftpprchild(struct clientparam* param) {
 	sasize = sizeof(param->sincr);
 	if(so._getpeername(param->ctrlsock, (struct sockaddr *)&param->sincr, &sasize)){RETURN(819);}
 	if(req && (param->statscli64 || param->statssrv64)){
-		(*param->srv->logfunc)(param, (unsigned char *)req);
+		dolog(param, (unsigned char *)req);
 	}
  }
 
@@ -316,7 +316,7 @@ CLEANRET:
  sasize = sizeof(param->sincr);
  so._getpeername(param->ctrlsock, (struct sockaddr *)&param->sincr, &sasize);
  if(param->res != 0 || param->statscli64 || param->statssrv64 ){
-	(*param->srv->logfunc)(param, (unsigned char *)((req && (param->res > 802))? req:NULL));
+	dolog(param, (unsigned char *)((req && (param->res > 802))? req:NULL));
  }
  if(req) myfree(req);
  if(buf) myfree(buf);

+ 22 - 2
src/log.c

@@ -1,18 +1,38 @@
 /*
    3APA3A simpliest proxy server
-   (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
+   (c) 2002-2020 by Vladimir Dubrovin <3proxy@3proxy.ru>
 
    please read License Agreement
 
 */
 
 
-pthread_mutex_t log_mutex;
 
 
 #include "proxy.h"
+pthread_mutex_t log_mutex;
 int havelog = 0;
 
+
+struct clientparam logparam;
+struct srvparam logsrv;
+
+
+
+void dolog(struct clientparam * param, const unsigned char *s){
+	static int init = 0;
+
+	if(param)param->srv->logfunc(param, s);
+	else {
+		if(!init){
+			srvinit(&logsrv, &logparam);
+			init = 1;
+		}
+		logstdout(&logparam, s);
+	}
+}
+
+
 void clearstat(struct clientparam * param) {
 
 #ifdef _WIN32

+ 2 - 2
src/pop3p.c

@@ -49,9 +49,9 @@ CLEANRET:
 
  if(param->hostname&&param->extusername) {
 	sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(&param->sinsr)==110)?0:':', ntohs(*SAPORT(&param->sinsr)));
-	 (*param->srv->logfunc)(param, buf);
+	dolog(param, buf);
  }
- else (*param->srv->logfunc)(param, NULL);
+ else dolog(param, NULL);
  if(param->clisock != INVALID_SOCKET) {
 	if ((param->res > 0 && param->res < 100) || (param->res > 611 && param->res <700)) socksend(param->clisock, (unsigned char *)"-ERR\r\n", 6,conf.timeouts[STRING_S]);
  }

+ 1 - 1
src/proxy.c

@@ -152,7 +152,7 @@ static void logurl(struct clientparam * param, char * buf, char * req, int ftp){
 		strcpy(se, sb);
 	}
  }
- if(param->res != 555 && param->res != 508)(*param->srv->logfunc)(param, (unsigned char *)(req?buf:NULL));
+ if(param->res != 555 && param->res != 508)dolog(param, (unsigned char *)(req?buf:NULL));
 }
 
 void decodeurl(unsigned char *s, int allowcr){

+ 4 - 4
src/proxy.h

@@ -151,8 +151,7 @@ extern int timetoexit;
 
 extern struct extparam conf;
 
-int sockmap(struct clientparam * param, int timeo);
-int splicemap(struct clientparam * param, int timeo);
+int sockmap(struct clientparam * param, int timeo, int usesplice);
 int socksend(SOCKET sock, unsigned char * buf, int bufsize, int to);
 int socksendto(SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to);
 int sockrecvfrom(SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to);
@@ -168,6 +167,7 @@ int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char *
 
 
 
+void dolog(struct clientparam * param, const unsigned char *s);
 int dobuf(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec);
 int dobuf2(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec, struct tm* tm, char * format);
 extern FILE * stdlog;
@@ -312,9 +312,9 @@ extern struct datatype datatypes[64];
 extern struct commands commandhandlers[];
 
 #ifdef WITHSPLICE
-#define mapsocket(a,b) (a->srv->usesplice && !a->ndatfilterssrv && !a->ndatfilterscli && !a->npredatfilters?splicemap(a,b):sockmap(a,b))
+#define mapsocket(a,b) ((a->srv->usesplice && !a->ndatfilterssrv && !a->ndatfilterscli)?sockmap(a,b,1):sockmap(a,b,0))
 #else
-#define mapsocket(a,b) sockmap(a,b)
+#define mapsocket(a,b) sockmap(a,b, 0)
 #endif
 
 

+ 36 - 25
src/proxymain.c

@@ -23,27 +23,27 @@ void * threadfunc (void *p) {
 	fds.revents = 0;
 	for(i=5+(param->srv->maxchild>>10); i; i--){
 		if(so._poll(&fds, 1, 1000*CONNBACK_TO)!=1){
-			param->srv->logfunc(param, (unsigned char *)"Connect back not received, check connback client");
+			dolog(param, (unsigned char *)"Connect back not received, check connback client");
 			i = 0;
 			break;
 		}
 		param->remsock = so._accept(param->srv->cbsock, (struct sockaddr*)&param->sinsr, &size);
 		if(param->remsock == INVALID_SOCKET) {
-			param->srv->logfunc(param, (unsigned char *)"Connect back accept() failed");
+			dolog(param, (unsigned char *)"Connect back accept() failed");
 			continue;
 		}
 #ifndef WITHMAIN
 		param->req = param->sinsr;
 		if(param->srv->acl) param->res = checkACL(param);
 		if(param->res){
-			param->srv->logfunc(param, (unsigned char *)"Connect back ACL failed");
+			dolog(param, (unsigned char *)"Connect back ACL failed");
 			so._closesocket(param->remsock);
 			param->remsock = INVALID_SOCKET;
 			continue;
 		}
 #endif
 		if(socksendto(param->remsock, (struct sockaddr*)&param->sinsr, (unsigned char *)"C", 1, CONNBACK_TO) != 1){
-			param->srv->logfunc(param, (unsigned char *)"Connect back sending command failed");
+			dolog(param, (unsigned char *)"Connect back sending command failed");
 			so._closesocket(param->remsock);
 			param->remsock = INVALID_SOCKET;
 			continue;
@@ -57,6 +57,13 @@ void * threadfunc (void *p) {
 	freeparam(param);
  }
  else {
+
+#ifndef _WIN32
+	sigset_t mask;
+	sigfillset(&mask);
+	pthread_sigmask(SIG_SETMASK, &mask, NULL);
+#endif
+
 	((struct clientparam *) p)->srv->pf((struct clientparam *)p);
  }
 #ifdef _WIN32
@@ -260,12 +267,8 @@ int MODULEMAINFUNC (int argc, char** argv){
  WSADATA wd;
  WSAStartup(MAKEWORD( 1, 1 ), &wd);
 
-
-
-#else
- signal(SIGPIPE, SIG_IGN);
-
 #endif
+
 #endif
 
  srvinit(&srv, &defparam);
@@ -288,6 +291,14 @@ int MODULEMAINFUNC (int argc, char** argv){
  pthread_mutex_init(&log_mutex, NULL);
 #endif
 
+#ifndef _WIN32
+ {
+	sigset_t mask;
+	sigfillset(&mask);
+	pthread_sigmask(SIG_SETMASK, &mask, NULL);
+ }
+#endif
+
  for (i=1; i<argc; i++) {
 	if(*argv[i]=='-') {
 		switch(argv[i][1]) {
@@ -513,7 +524,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 
 #ifndef _WIN32
  if(inetd) {
-	fcntl(0,F_SETFL,O_NONBLOCK);
+	fcntl(0,F_SETFL,O_NONBLOCK | fcntl(0,F_GETFL));
 	if(!isudp){
 		so._setsockopt(0, SOL_SOCKET, SO_LINGER, (unsigned char *)&lg, sizeof(lg));
 		so._setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (unsigned char *)&opt, sizeof(int));
@@ -571,7 +582,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 #ifdef _WIN32
 		ioctlsocket(sock, FIONBIO, &ul);
 #else
-		fcntl(sock,F_SETFL,O_NONBLOCK);
+		fcntl(sock,F_SETFL,O_NONBLOCK | fcntl(sock,F_GETFL));
 #endif
 		srv.srvsock = sock;
 		opt = 1;
@@ -587,7 +598,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 	size = sizeof(srv.intsa);
 	for(sleeptime = SLEEPTIME * 100; so._bind(sock, (struct sockaddr*)&srv.intsa, SASIZE(&srv.intsa))==-1; usleep(sleeptime)) {
 		sprintf((char *)buf, "bind(): %s", strerror(errno));
-		if(!srv.silent)(*srv.logfunc)(&defparam, buf);	
+		if(!srv.silent)dolog(&defparam, buf);	
 		sleeptime = (sleeptime<<1);	
 		if(!sleeptime) {
 			so._closesocket(sock);
@@ -597,7 +608,7 @@ int MODULEMAINFUNC (int argc, char** argv){
  	if(!isudp){
  		if(so._listen (sock, 1 + (srv.maxchild>>4))==-1) {
 			sprintf((char *)buf, "listen(): %s", strerror(errno));
-			if(!srv.silent)(*srv.logfunc)(&defparam, buf);
+			if(!srv.silent)dolog(&defparam, buf);
 			return -4;
 		}
 	}
@@ -606,13 +617,13 @@ int MODULEMAINFUNC (int argc, char** argv){
 
 	if(!srv.silent && !iscbc){
 		sprintf((char *)buf, "Accepting connections [%u/%u]", (unsigned)getpid(), (unsigned)pthread_self());
-		(*srv.logfunc)(&defparam, buf);
+		dolog(&defparam, buf);
 	}
  }
  if(iscbl){
 	parsehost(srv.family, cbl_string, (struct sockaddr *)&cbsa);
 	if((srv.cbsock=so._socket(SASOCK(&cbsa), SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET) {
-		(*srv.logfunc)(&defparam, (unsigned char *)"Failed to allocate connect back socket");
+		dolog(&defparam, (unsigned char *)"Failed to allocate connect back socket");
 		return -6;
 	}
 	opt = 1;
@@ -625,11 +636,11 @@ int MODULEMAINFUNC (int argc, char** argv){
 	setopts(srv.cbsock, srv.cbssockopts);
 
 	if(so._bind(srv.cbsock, (struct sockaddr*)&cbsa, SASIZE(&cbsa))==-1) {
-		(*srv.logfunc)(&defparam, (unsigned char *)"Failed to bind connect back socket");
+		dolog(&defparam, (unsigned char *)"Failed to bind connect back socket");
 		return -7;
 	}
 	if(so._listen(srv.cbsock, 1 + (srv.maxchild>>4))==-1) {
-		(*srv.logfunc)(&defparam, (unsigned char *)"Failed to listen connect back socket");
+		dolog(&defparam, (unsigned char *)"Failed to listen connect back socket");
 		return -8;
 	}
  }
@@ -649,7 +660,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 			nlog++;			
 			if(!srv.silent && nlog > 5000) {
 				sprintf((char *)buf, "Warning: too many connected clients (%d/%d)", srv.childcount, srv.maxchild);
-				(*srv.logfunc)(&defparam, buf);
+				dolog(&defparam, buf);
 				nlog = 0;
 			}
 			usleep(SLEEPTIME);
@@ -667,7 +678,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 		if (error == 0) continue;
 		if (errno != EAGAIN &&	errno != EINTR) {
 			sprintf((char *)buf, "poll(): %s/%d", strerror(errno), errno);
-			if(!srv.silent)(*srv.logfunc)(&defparam, buf);
+			if(!srv.silent)dolog(&defparam, buf);
 			break;
 		}
 	}
@@ -740,7 +751,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 				nlog++;			
 				if(!srv.silent && (error || nlog > 5000)) {
 					sprintf((char *)buf, "accept(): %s", strerror(errno));
-					(*srv.logfunc)(&defparam, buf);
+					dolog(&defparam, buf);
 					nlog = 0;
 				}
 				continue;
@@ -750,13 +761,13 @@ int MODULEMAINFUNC (int argc, char** argv){
 		size = sizeof(defparam.sincl);
 		if(so._getsockname(new_sock, (struct sockaddr *)&defparam.sincl, &size)){
 			sprintf((char *)buf, "getsockname(): %s", strerror(errno));
-			if(!srv.silent)(*srv.logfunc)(&defparam, buf);
+			if(!srv.silent)dolog(&defparam, buf);
 			continue;
 		}
 #ifdef _WIN32
 		ioctlsocket(new_sock, FIONBIO, &ul);
 #else
-		fcntl(new_sock,F_SETFL,O_NONBLOCK);
+		fcntl(new_sock,F_SETFL,O_NONBLOCK | fcntl(new_sock,F_GETFL));
 #endif
 		so._setsockopt(new_sock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
 		so._setsockopt(new_sock, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
@@ -767,7 +778,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 	if(! (newparam = myalloc (sizeof(defparam)))){
 		if(!isudp) so._closesocket(new_sock);
 		defparam.res = 21;
-		if(!srv.silent)(*srv.logfunc)(&defparam, (unsigned char *)"Memory Allocation Failed");
+		if(!srv.silent)dolog(&defparam, (unsigned char *)"Memory Allocation Failed");
 		usleep(SLEEPTIME);
 		continue;
 	};
@@ -804,7 +815,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 	}
 	else {
 		sprintf((char *)buf, "_beginthreadex(): %s", _strerror(NULL));
-		if(!srv.silent)(*srv.logfunc)(&defparam, buf);
+		if(!srv.silent)dolog(&defparam, buf);
 		error = 1;
 	}
 #else
@@ -813,7 +824,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 	srv.childcount++;
 	if(error){
 		sprintf((char *)buf, "pthread_create(): %s", strerror(error));
-		if(!srv.silent)(*srv.logfunc)(&defparam, buf);
+		if(!srv.silent)dolog(&defparam, buf);
 	}
 	else {
 		newparam->threadid = (unsigned)thread;

+ 2 - 2
src/smtpp.c

@@ -292,9 +292,9 @@ CLEANRET:
 
  if(param->hostname&&param->extusername) {
 	sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(&param->sinsr)==25?0:':',ntohs(*SAPORT(&param->sinsr)));
-	 (*param->srv->logfunc)(param, buf);
+	 dolog(param, buf);
  }
- else (*param->srv->logfunc)(param, NULL);
+ else dolog(param, NULL);
  if(param->clisock != INVALID_SOCKET) {
 	if ((param->res > 0 && param->res < 100) || (param->res > 661 && param->res <700)) socksend(param->clisock, (unsigned char *)"571 \r\n", 6,conf.timeouts[STRING_S]);
  }

+ 583 - 498
src/sockmap.c

@@ -1,6 +1,6 @@
 /*
    3APA3A simpliest proxy server
-   (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
+   (c) 2002-2020 by Vladimir Dubrovin <3proxy@3proxy.ru>
 
    please read License Agreement
 
@@ -8,6 +8,15 @@
 
 #include "proxy.h"
 
+#ifdef WITHLOG
+#if WITHLOG > 1
+char logbuf[1024];
+#endif
+#define log(X) dolog(param,X)
+#else
+#define log(X)
+#endif
+
 #ifdef WITHSPLICE
 
 #include <fcntl.h>
@@ -25,565 +34,641 @@ ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t le
 #define SPLICE_F_GIFT           0x08
 #endif
 
-#define RETURN(xxx) { res = xxx; goto CLEANRET; }
-#define MIN(a,b) ((a>b)?b:a)
 
 #define MAXSPLICE 65536
 
+#endif
+
+#define MIN(a,b) ((a>b)?b:a)
+#define RETURN(xxx) { res = xxx; goto CLEANRET; }
 
-int splicemap(struct clientparam * param, int timeo){
- struct pollfd fds[2];
+int sockmap(struct clientparam * param, int timeo, int usesplice){
+ uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
+ uint64_t inclientbuf = 0, inserverbuf = 0;
+ int FROMCLIENT = 1, TOCLIENTBUF = 1, FROMCLIENTBUF = 1, TOSERVER = 1, 
+	FROMSERVER = 1, TOSERVERBUF = 1, FROMSERVERBUF = 1, TOCLIENT = 1;
+ int HASERROR=0;
+ int CLIENTTERM = 0, SERVERTERM = 0;
+ int after = 0;
+ struct pollfd fds[6];
  struct pollfd *fdsp = fds;
- int fdsc = 2;
- int pipesrv[2] = {-1,-1};
- int pipecli[2] = {-1,-1};
- uint64_t sent=0, received=0;
- SASIZETYPE sasize;
- int res = 0, stop = 0;
- int srvstate = 0, clistate = 0;
- int srvsockstate = 0, clisockstate = 0;
- int insrvpipe = 0, inclipipe = 0;
- int rfromserver = 0, rfromclient = 0;
+ int fdsc = 0;
  int sleeptime = 0;
- int needcontinue;
- int tosend;
+ FILTER_ACTION action;
+ int res;
+ SASIZETYPE sasize;
 
+#ifdef WITHSPLICE
+ uint64_t inclientpipe = 0, inserverpipe = 0;
+ int TOCLIENTPIPE = 0, FROMCLIENTPIPE = 0, TOSERVERPIPE = 0, FROMSERVERPIPE = 0;
+ int pipesrv[2] = {-1,-1};
+ int pipecli[2] = {-1,-1};
 
- tosend = param->srvinbuf - param->srvoffset;
- if(!param->waitclient64 && tosend){
-	needcontinue = 1;
-	if(param->waitserver64 && param->waitserver64 <= tosend){
-		needcontinue = 0;
-		tosend = param->waitserver64;
-	}
-	if(socksend(param->clisock, param->srvbuf + param->srvoffset, tosend, conf.timeouts[STRING_S]) != tosend){
-		return 96;
-	}
-	if(!needcontinue){
-		param->srvoffset += tosend;
-		if(param->srvoffset == param->srvinbuf) param->srvoffset = param->srvinbuf = 0;
-		return 98;
-	}
-	received += tosend;
-	param->srvoffset = param->srvinbuf = 0;
+ if(param->operation == UDPASSOC) usesplice = 0;
+ if(usesplice){
+	TOCLIENTPIPE = FROMCLIENTPIPE = TOSERVERPIPE = FROMSERVERPIPE = 1;
+	TOCLIENTBUF = TOSERVERBUF = 0;
+	if(pipe2(pipecli, O_NONBLOCK) < 0) RETURN (21);
+	if(pipe2(pipesrv, O_NONBLOCK) < 0) RETURN (21);
  }
- tosend = param->cliinbuf - param->clioffset;
- if(!param->waitserver64 && tosend){
-	needcontinue = 1;
-	if(param->waitclient64 && param->waitclient64 <= tosend){
-		needcontinue = 0;
-		tosend = param->waitclient64;
-	}
-	if(socksend(param->remsock, param->clibuf + param->clioffset, tosend, conf.timeouts[STRING_S]) != tosend){
-		return 97;
-	}
-    	param->nwrites++;
-	param->statscli64 += tosend;
+#endif
 
-	if(!needcontinue){
-		param->clioffset += tosend;
-		if(param->clioffset == param->cliinbuf) param->clioffset = param->cliinbuf = 0;
-		return 99;
-	}
-	sent += tosend;
-	param->clioffset = param->cliinbuf = 0;
+ inserverbuf = param->srvinbuf - param->srvoffset;
+ inclientbuf = param->cliinbuf - param->clioffset;
+	
+ if(param->waitclient64) {
+	fromclient = param->waitclient64;
+	fromserver = 0;
+	inserverbuf = 0;
+	TOCLIENT = 0;
+	FROMSERVER = 0;
  }
-
- if(!param->waitserver64 && !param->waitclient64){
-	myfree(param->srvbuf);
-	param->srvbuf = NULL;
-	param->srvbufsize = 0;
-	myfree(param->clibuf);
-	param->clibuf = NULL;
-	param->clibufsize = 0;
-	param->srvinbuf = param->srvoffset = param->cliinbuf = param->clioffset = 0;
+ if(param->waitserver64) {
+	fromserver = param->waitserver64;
+	fromclient = 0;
+	inclientbuf = 0;
+	TOSERVER = 0;
+	FROMCLIENT = 0;
  }
-
- param->res = 0;
- if(pipe(pipecli) < 0) RETURN(21);
- if(pipe(pipesrv) < 0) RETURN(21);
-
- fds[0].fd = param->clisock;
- fds[1].fd = param->remsock;
-
- while((!stop || (inclipipe && !srvsockstate) || (insrvpipe && !clisockstate)) && !conf.timetoexit){
-
-    param->cycles++;
-#ifdef NOIPV6
-    sasize = sizeof(struct sockaddr_in);
-#else
-    sasize = sizeof(struct sockaddr_in6);
-#endif
-    fds[0].events = fds[1].events = 0;
-    fds[0].revents = fds[1].revents = 0;
-
-    if(srvstate && !clisockstate && !param->waitclient64 && param->clisock != INVALID_SOCKET){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: will send to client");
-#endif
-	fds[0].events |= POLLOUT;
-    }
-    rfromserver = MAXSPLICE - insrvpipe;
-    if(param->waitserver64) rfromserver = MIN(MAXSPLICE, param->waitserver64 - (received + insrvpipe));
-    if(srvstate < 2 && !srvsockstate && rfromserver > 0 && param->remsock != INVALID_SOCKET) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: will recv from server");
-#endif
-	fds[1].events |= (POLLIN|POLLRDHUP);
-    }
-    if(clistate && !srvsockstate && !param->waitserver64 && param->remsock != INVALID_SOCKET){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: will send to server");
-#endif
-	fds[1].events |= POLLOUT;
-    }
-    rfromclient = MAXSPLICE - inclipipe;
-    if(param->waitclient64) rfromclient = MIN(MAXSPLICE, param->waitclient64 - (sent + inclipipe));
-    if(clistate < 2 && !clisockstate && rfromclient > 0 && param->clisock != INVALID_SOCKET) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: will recv from client");
-#endif
-	fds[0].events |= (POLLIN|POLLRDHUP);
-    }
-    if(!fds[0].events && !fds[1].events) RETURN (666);
-    if(fds[0].fd == INVALID_SOCKET){
-	fdsp = fds +1;
-	fdsc = 1;
-    }
-    else if(fds[1].fd == INVALID_SOCKET){
-	fdsp = fds;
-	fdsc = 1;
-    }
-    else {
-	fdsp = fds;
-	fdsc = 2;
-    }
-    res = so._poll(fdsp, fdsc, timeo*1000);
-    if(res < 0){
-	if(errno == EINTR) so._poll(NULL, 0, 1);
-	else if(errno != EAGAIN) RETURN(91);
-        continue;
-    }
-    if(res < 1){
-	RETURN(92);
-    }
-    if( (fds[0].revents & (POLLERR|POLLNVAL)) || (fds[1].revents & (POLLERR|POLLNVAL))) {
-	RETURN(90);
-    }
-    if( (fds[0].revents & (POLLHUP|POLLRDHUP))) {
-	stop = clisockstate = 1;
-    }
-    if( (fds[1].revents & (POLLERR|POLLNVAL|POLLHUP|POLLRDHUP)) && !(fds[1].revents & POLLIN)){
-	stop = srvsockstate = 1;
-    }
-    if((fds[0].revents & POLLOUT)){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: spliced send to client");
-#endif
-	res = splice(pipesrv[0], NULL, param->clisock, NULL, MIN(MAXSPLICE, insrvpipe), SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
-	if(res <= 0) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: send to client error");
-#endif
-	    if(errno == EINTR) so._poll(NULL, 0, 1);
-	    else if(errno != EAGAIN) RETURN(96);
-	    continue;
-	}
-	if(res){
-	    insrvpipe -= res;
-	    received += res;
-
-	    if(param->bandlimfunc) {
-		    sleeptime = (*param->bandlimfunc)(param, res, 0);
-	    }
-	    srvstate = 0;
-	}
-	if(param->waitserver64 && param->waitserver64 <= received){
-	    RETURN (98);
-	}
-    }
-    if((fds[1].revents & POLLOUT)){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: spliced send to server");
-#endif
-	res = splice(pipecli[0], NULL, param->remsock, NULL, MIN(MAXSPLICE, inclipipe), SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
-	if(res <= 0) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: send to server error");
-#endif
-	    if(errno == EINTR) so._poll(NULL, 0, 1);
-	    else if(errno != EAGAIN) RETURN(97);
-	    continue;
-	}
-	if(res){
-	    inclipipe -= res;
-	    sent += res;
-    	    param->nwrites++;
-	    param->statscli64 += res;
-
-	    if(param->bandlimfunc) {
-		int sl1;
-		sl1 = (*param->bandlimfunc)(param, 0, res);
-		if(sl1 > sleeptime) sleeptime = sl1;
-	    }
-	    clistate = 0;
-	}
-	if(param->waitclient64 && param->waitclient64 <= sent){
-	    RETURN (99);
-	}
-    }
-    if ((fds[0].revents & POLLIN) || clisockstate == 1) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: recv from client");
-#endif
-	res = splice(param->clisock, NULL, pipecli[1], NULL, rfromclient, SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
-	if (res < 0){
-	    if(errno == EINTR) so._poll(NULL, 0, 1);
-	    else if(errno != EAGAIN) RETURN(94);
-	    continue;
-	}
-	if (res==0) {
-	    clisockstate = 2;
-	    stop = 1;
-	}
-	else {
-	    inclipipe += res;
-	    clistate = 1;
-	    if(insrvpipe >= MAXSPLICE) clistate = 2;
-	}
-    }
-    if ((fds[1].revents & POLLIN) || srvsockstate == 1) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: recv from server");
-#endif
-	res = splice(param->remsock, NULL, pipesrv[1], NULL, rfromserver, SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
-	if (res < 0){
-	    if(errno == EINTR) so._poll(NULL, 0, 1);
-	    else if(errno != EAGAIN) RETURN(93);
-	    continue;
-	}
-	if (res==0) {
-	    srvsockstate = 2;
-	    stop = 1;
-	}
-	else {
-	    insrvpipe += res;
-	    param->statssrv64 += res;
-	    param->nreads++;
-	    srvstate = 1;
-	    if(insrvpipe >= MAXSPLICE) srvstate = 2;
-	}
-    }
-    if(sleeptime > 0) {
-	if(sleeptime > (timeo * 1000)){RETURN (95);}
-	so._poll(NULL, 0, sleeptime);
-	sleeptime = 0;
-    }
+ if(param->operation == UDPASSOC && param->srv->singlepacket){
+	fromclient = inclientbuf;
+	FROMCLIENT = 0;
  }
-
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "splice: finished with mapping");
-#endif
-
-CLEANRET:
-
- if(pipecli[0] >= 0) close(pipecli[0]);
- if(pipecli[1] >= 0) close(pipecli[1]);
- if(pipesrv[0] >= 0) close(pipesrv[0]);
- if(pipesrv[1] >= 0) close(pipesrv[1]);
-
- return res;
-}
-
-#endif
-
-
-int sockmap(struct clientparam * param, int timeo){
- int res=0;
- uint64_t sent=0, received=0;
- SASIZETYPE sasize;
- struct pollfd fds[2];
- int sleeptime = 0, stop = 0;
- unsigned minsize;
- unsigned bufsize;
- FILTER_ACTION action;
- int retcode = 0;
-
- bufsize = SRVBUFSIZE; 
-
- minsize = (param->service == S_UDPPM || param->service == S_TCPPM)? bufsize - 1 : (bufsize>>2);
-
- fds[0].fd = param->clisock;
- fds[1].fd = param->remsock;
-
-
- if(param->cliinbuf == param->clioffset) param->cliinbuf = param->clioffset = 0;
- if(param->srvinbuf == param->srvoffset) param->srvinbuf = param->srvoffset = 0;
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "Starting sockets mapping");
+ if(inserverbuf >= fromserver) FROMSERVER = 0;
+ if(inclientbuf >= fromclient) FROMCLIENT = 0;
+#ifdef WITHSPLICE
+ if(!usesplice)
 #endif
- if(!param->waitclient64){
-	if(!param->srvbuf && (!(param->srvbuf=myalloc(bufsize)) || !(param->srvbufsize = bufsize))){
-		return (21);
+ {
+	if(fromserver && !param->srvbuf && (!(param->srvbuf=myalloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))){
+		RETURN (21);
 	}
- }
- if(!param->waitserver64){
-	if(!param->clibuf && (!(param->clibuf=myalloc(bufsize)) || !(param->clibufsize = bufsize))){
-		return (21);
+	if(fromclient && !param->clibuf && (!(param->clibuf=myalloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))){
+		RETURN (21);
 	}
+
  }
+ if(param->srvinbuf == param->srvoffset) param->srvinbuf =param->srvoffset = 0;
+ if(param->cliinbuf == param->clioffset) param->cliinbuf =param->clioffset = 0;
+ if(param->clibufsize == param->cliinbuf) TOCLIENTBUF = 0;
+ if(param->srvbufsize == param->srvinbuf) TOSERVERBUF = 0;
 
  action = handlepredatflt(param);
  if(action == HANDLED){
-	return 0;
- }
- if(action != PASS) return 19;
- if(!param->nolongdatfilter){
-	if(param->cliinbuf > param->clioffset){
-		action = handledatfltcli(param,  &param->clibuf, (int *)&param->clibufsize, param->clioffset, (int *)&param->cliinbuf);
-		if(action == HANDLED){
-			return 0;
-		}
-		if(action != PASS) return 19;
-	}
-	if(param->srvinbuf > param->srvoffset){
-		action = handledatfltsrv(param,  &param->srvbuf, (int *)&param->srvbufsize, param->srvoffset, (int *)&param->srvinbuf);
-		if(action == HANDLED){
-			return 0;
-		}
-		if(action != PASS) return 19;
-	}
+	RETURN(0);
  }
+ if(action != PASS) RETURN(19);
 
+ while(
+	((!CLIENTTERM) && (inserverbuf 
+#ifdef WITHSPLICE
+		|| inserverpipe 
+#endif
+		|| (!SERVERTERM && fromserver)))
+	||
+	((!SERVERTERM) && (inclientbuf 
+#ifdef WITHSPLICE
+		|| inclientpipe 
+#endif
+		|| (!CLIENTTERM && fromclient)))
+ ){
 
 
- while (!stop&&!conf.timetoexit){
-	param->cycles++;
-#ifdef NOIPV6
-	sasize = sizeof(struct sockaddr_in);
-#else
-	sasize = sizeof(struct sockaddr_in6);
+#if WITHLOG > 1
+sprintf(logbuf, "int FROMCLIENT = %d, TOCLIENTBUF = %d, FROMCLIENTBUF = %d, TOSERVER = %d, "
+	"FROMSERVER = %d, TOSERVERBUF = %d, FROMSERVERBUF = %d, TOCLIENT = %d; inclientbuf=%d; "
+	"inserverbuf=%d, CLIENTTERM = %d, SERVERTERM =%d, fromserver=%u, fromclient=%u"
+#ifdef WITHSPLICE
+	 ", inserverpipe=%d, inclentpipe=%d "
+	"TOCLIENTPIPE=%d FROMCLIENTPIPE==%d TOSERVERPIPE==%d FROMSERVERPIPE=%d"
+#endif
+	,
+ FROMCLIENT, TOCLIENTBUF, FROMCLIENTBUF, TOSERVER, 
+	FROMSERVER, TOSERVERBUF, FROMSERVERBUF, TOCLIENT, 
+	(int)inclientbuf, (int)inserverbuf, CLIENTTERM, SERVERTERM, 
+	(unsigned)fromserver, (unsigned)fromclient
+#ifdef WITHSPLICE
+	,(int)inserverpipe, (int)inclientpipe,
+	TOCLIENTPIPE, FROMCLIENTPIPE, TOSERVERPIPE, FROMSERVERPIPE
+#endif
+	);
+log(logbuf);
 #endif
+
+	if(sleeptime > 0) {
+		if(sleeptime > (timeo * 1000)){RETURN (92);}
+		memset(fds, 0, sizeof(fds));
+		fds[0].fd = param->clisock;
+		fds[1].fd = param->remsock;
+#ifdef POLLRDHUP
+		fds[0].events = POLLRDHUP;
+		fds[1].events = POLLRDHUP;
+#endif
+		so._poll(fds, 2, sleeptime);
+		sleeptime = 0;
+	}
+	if((param->srv->logdumpsrv && (param->statssrv64 > param->srv->logdumpsrv)) ||
+		(param->srv->logdumpcli && (param->statscli64 > param->srv->logdumpcli)))
+			dolog(param, NULL);
+
 	if(param->version < conf.version){
-		if((res = (*param->srv->authfunc)(param)) && res != 2 && !param->srv->noforce) {return(res);}
+		if(!param->srv->noforce && (res = (*param->srv->authfunc)(param)) && res != 2) {RETURN(res);}
 		param->paused = conf.paused;
 		param->version = conf.version;
 	}
+
 	if((param->maxtrafin64 && param->statssrv64 >= param->maxtrafin64) || (param->maxtrafout64 && param->statscli64 >= param->maxtrafout64)){
-		return (10);
-	}
-	if((param->srv->logdumpsrv && (param->statssrv64 > param->srv->logdumpsrv)) ||
-		(param->srv->logdumpcli && (param->statscli64 > param->srv->logdumpcli)))
-			(*param->srv->logfunc)(param, NULL);
-	fds[0].events = fds[1].events = 0;
-	if(param->srvinbuf > param->srvoffset && !param->waitclient64) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "will send to client");
-#endif
-		fds[0].events |= POLLOUT;
-	}
-	if((param->srvbufsize - param->srvinbuf) > minsize && !param->waitclient64 && (!param->waitserver64 ||(received + param->srvinbuf - param->srvoffset < param->waitserver64))) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "Will recv from server");
-#endif
-		fds[1].events |= POLLIN;
+		RETURN (10);
 	}
 
-	if(param->cliinbuf > param->clioffset && !param->waitserver64) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "Will send to server");
+	if(inclientbuf && TOSERVER){
+#ifdef WITHLOG
+log("send to server from buf");
 #endif
-		fds[1].events |= POLLOUT;
-	}
-    	if((param->clibufsize - param->cliinbuf) > minsize  && !param->waitserver64 &&(!param->srv->singlepacket || param->service != S_UDPPM) ) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "Will recv from client");
-#endif
-		fds[0].events |= POLLIN;
-	}
-	if(!fds[0].events && !fds[1].events) return 666;
-	res = so._poll(fds, 2, timeo*1000);
-	if(res < 0){
-		if(errno != EAGAIN && errno != EINTR) return 91;
-		if(errno == EINTR) usleep(SLEEPTIME);
-	 	continue;
-	}
-	if(res < 1){
-		return 92;
-	}
-	if( (fds[0].revents & (POLLERR|POLLNVAL
-#ifndef WITH_WSAPOLL
-					|POLLHUP
-#endif
-						)) && !(fds[0].revents & POLLIN)) {
-		fds[0].revents = 0;
-		stop = 1;
-		retcode = 90;
-	}
-	if( (fds[1].revents & (POLLERR|POLLNVAL
-#ifndef WITH_WSAPOLL
-					|POLLHUP
-#endif
-						)) && !(fds[1].revents & POLLIN)){
-		fds[1].revents = 0;
-		stop = 1;
-		retcode = 90;
-	}
-	if((fds[0].revents & POLLOUT)){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "send to client");
-#endif
-		if(param->bandlimfunc) {
-			sleeptime = (*param->bandlimfunc)(param, param->srvinbuf - param->srvoffset, 0);
-		}
-		res = so._sendto(param->clisock, (char *)param->srvbuf + param->srvoffset,(!param->waitserver64 || (param->waitserver64 - received) > (param->srvinbuf - param->srvoffset))? param->srvinbuf - param->srvoffset : (int)(param->waitserver64 - received), 0, (struct sockaddr*)&param->sincr, sasize);
-		if(res < 0) {
-			if(errno != EAGAIN && errno != EINTR) return 96;
-			if(errno == EINTR) usleep(SLEEPTIME);
-			continue;
+		if(!param->nolongdatfilter){
+			action = handledatfltcli(param,  &param->clibuf, (int *)&param->clibufsize, param->cliinbuf - res, (int *)&param->cliinbuf);
+			if(action == HANDLED){
+				RETURN(0);
+			}
+			if(action != PASS) RETURN(19);
+			inclientbuf=param->cliinbuf - param->clioffset;
 		}
-		param->srvoffset += res;
-		received += res;
-		if(param->srvoffset == param->srvinbuf) param->srvoffset = param->srvinbuf = 0;
-		if(param->waitserver64 && param->waitserver64<= received){
-			return (98);
+		if(!inclientbuf){
+			param->clioffset = param->cliinbuf = 0;
+			if(fromclient) TOCLIENTBUF = 1;
 		}
-		if(param->service == S_UDPPM && param->srv->singlepacket) {
-			stop = 1;
+		sasize = sizeof(param->sinsr);
+		res = so._sendto(param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, (struct sockaddr*)&param->sinsr, sasize);
+		if(res <= 0) TOSERVER = 0;
+		else {
+#ifdef WITHLOG
+log("done send to server from buf");
+#endif
+		    	param->nwrites++;
+			param->statscli64 += res;
+			inclientbuf -= res;
+			fromclient -= res;
+			param->clioffset += res;
+			if(param->clioffset == param->cliinbuf)param->clioffset = param->cliinbuf = 0;
+			if(param->cliinbuf < param->clibufsize) TOCLIENTBUF = 1;
+			if(param->bandlimfunc) {
+				int sl1;
+				sl1 = (*param->bandlimfunc)(param, 0, res);
+				if(sl1 > sleeptime) sleeptime = sl1;
+		    	}
+			continue;
 		}
 	}
-	if((fds[1].revents & POLLOUT)){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "send to server");
+	if(inserverbuf && TOCLIENT){
+#ifdef WITHLOG
+log("send to client from buf");
 #endif
-		if(param->bandlimfunc) {
-			int sl1;
-
-			sl1 = (*param->bandlimfunc)(param, 0, param->cliinbuf - param->clioffset);
-			if(sl1 > sleeptime) sleeptime = sl1;
+		if(!param->nolongdatfilter){
+			action = handledatfltsrv(param,  &param->srvbuf, (int *)&param->srvbufsize, param->srvinbuf - res, (int *)&param->srvinbuf);
+			if(action == HANDLED){
+				RETURN(0);
+			}
+			if(action != PASS) RETURN(19);
+			inserverbuf = param->srvinbuf - param->srvoffset;
 		}
-		res = so._sendto(param->remsock, (char *)param->clibuf + param->clioffset, (!param->waitclient64 || (param->waitclient64 - sent) > (param->cliinbuf - param->clioffset))? param->cliinbuf - param->clioffset : (int)(param->waitclient64 - sent), 0, (struct sockaddr*)&param->sinsr, sasize);
-		if(res < 0) {
-			if(errno != EAGAIN && errno != EINTR) return 97;
-			if(errno == EINTR) usleep(SLEEPTIME);
+		if(!inserverbuf){
+			param->srvinbuf = param->srvoffset = 0;
 			continue;
 		}
-		param->clioffset += res;
-		if(param->clioffset == param->cliinbuf) param->clioffset = param->cliinbuf = 0;
-		sent += res;
-		param->nwrites++;
-		param->statscli64 += res;
-		if(param->waitclient64 && param->waitclient64<= sent) {
-			return (99);
+		sasize = sizeof(param->sincr);
+		res = so._sendto(param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, (struct sockaddr*)&param->sincr, sasize);
+		if(res <= 0) TOCLIENT = 0;
+		else {
+#ifdef WITHLOG
+log("done send to client from buf");
+#endif
+			inserverbuf -= res;
+			fromserver -= res;
+			param->srvoffset += res;
+			if(param->srvoffset == param->srvinbuf)param->srvoffset = param->srvinbuf =0;
+			if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
+			continue;
 		}
 	}
-	if ((fds[0].revents & POLLIN)
-#ifdef WITH_WSAPOLL
-		||(fds[0].revents & POLLHUP)
-#endif
-					) {
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "recv from client");
-#endif
-		res = so._recvfrom(param->clisock, (char *)param->clibuf + param->cliinbuf, param->clibufsize - param->cliinbuf, 0, (struct sockaddr *)&param->sincr, &sasize);
-		if (res==0) {
-			so._shutdown(param->clisock, SHUT_RDWR);
-			so._closesocket(param->clisock);
-			fds[0].fd = param->clisock = INVALID_SOCKET;
-			stop = 1;
+#ifdef WITHSPLICE
+	if(usesplice){
+		if(inclientpipe && !inclientbuf && FROMCLIENTPIPE && TOSERVER){
+#ifdef WITHLOG
+log("send to server from pipe");
+#endif
+			res = splice(pipecli[0], NULL, param->remsock, NULL, MIN(MAXSPLICE, inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+			if(res >0) {
+#ifdef WITHLOG
+log("done send to server from pipe");
+#endif
+			    	param->nwrites++;
+				param->statscli64 += res;
+				inclientpipe -= res;
+				fromclient -= res;
+				if(param->bandlimfunc) {
+					int sl1;
+					sl1 = (*param->bandlimfunc)(param, 0, res);
+					if(sl1 > sleeptime) sleeptime = sl1;
+		    		}
+				continue;
+			}
+			else {
+				FROMCLIENTPIPE = TOSERVER = 0;
+			}
 		}
-		else {
-			if (res < 0){
-				if(errno != EAGAIN && errno != EINTR) return 94;
-				if(errno == EINTR) usleep(SLEEPTIME);
+		if(inserverpipe && !inserverbuf && FROMSERVERPIPE && TOCLIENT){
+#ifdef WITHLOG
+log("send to client from pipe");
+#endif
+			res = splice(pipesrv[0], NULL, param->clisock, NULL, MIN(MAXSPLICE, inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+			if(res > 0) {
+#ifdef WITHLOG
+log("done send to client from pipe");
+#endif
+				inserverpipe -= res;
+				fromserver -= res;
+				if(fromserver)TOSERVERPIPE = 1;
 				continue;
 			}
-			param->cliinbuf += res;
-			if(!param->nolongdatfilter){
-				action = handledatfltcli(param,  &param->clibuf, (int *)&param->clibufsize, param->cliinbuf - res, (int *)&param->cliinbuf);
-				if(action == HANDLED){
-					return 0;
+			else {
+				FROMSERVERPIPE = TOCLIENT = 0;
+			}
+		}
+		if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE){
+			int error;
+			socklen_t len=sizeof(error);
+#ifdef WITHLOG
+log("read from client to pipe");
+#endif
+			res = splice(param->clisock, NULL, pipecli[1], NULL, (int)MIN((uint64_t)MAXSPLICE - inclientpipe, (uint64_t)fromclient-inclientpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+			if(res <= 0) {
+#ifdef WITHLOG
+log("read failed");
+#endif
+				FROMCLIENT = TOCLIENTPIPE = 0;
+			}
+			else {
+#ifdef WITHLOG
+log("done read from client to pipe");
+#endif
+				inclientpipe += res;
+				if(inclientpipe >= MAXSPLICE) TOCLIENTPIPE = 0;
+				continue;
+			}
+		}
+		if(fromserver > inserverpipe && FROMSERVER && TOSERVERPIPE){
+			int error; 
+			socklen_t len=sizeof(error);
+#ifdef WITHLOG
+log("read from server to pipe\n");
+#endif
+			res = splice(param->remsock, NULL, pipesrv[1], NULL, MIN(MAXSPLICE - inclientpipe, fromserver - inserverpipe), SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+#ifdef WITHLOG
+log("splice finished\n");
+#endif
+			if(res <= 0) {
+				FROMSERVER = TOSERVERPIPE = 0;
+			}
+			else {
+#ifdef WITHLOG
+log("done read from server to pipe\n");
+#endif
+			    	param->nreads++;
+				param->statssrv64 += res;
+				inserverpipe += res;
+				if(inserverpipe >= MAXSPLICE) TOSERVERPIPE = 0;
+				if(param->bandlimfunc) {
+					int sl1;
+					sl1 = (*param->bandlimfunc)(param, 1, res);
+					if(sl1 > sleeptime) sleeptime = sl1;
+		    		}
+ 				if(param->operation == UDPASSOC && param->srv->singlepacket){
+					fromserver = inserverpipe;
+					FROMSERVER = 0;
 				}
-				if(action != PASS) return 19;
 			}
+			continue;
+		}
+	}
+	else
+#endif
+	{
+		if(fromclient > inclientbuf && FROMCLIENT && TOCLIENTBUF){
+#ifdef WITHLOG
+log("read from client to buf");
+#endif
+			sasize = sizeof(param->sincr);
+			res = so._recvfrom(param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, (struct sockaddr *)&param->sincr, &sasize);
+			if(res <= 0) {
+				if(!errno)CLIENTTERM = 1;
+				FROMCLIENT = 0;
+			}
+			else {
+#ifdef WITHLOG
+log("done read from client to buf");
+#endif
+				inclientbuf += res;
+				param->cliinbuf += res;
+				if(param->clibufsize == param->cliinbuf) TOCLIENTBUF = 0;
+				continue;
+			}
+		}
 
+		if(fromserver > inserverbuf && FROMSERVER && TOSERVERBUF){
+#ifdef WITHLOG
+log("read from server to buf");
+#endif
+			sasize = sizeof(param->sinsr);
+			res = so._recvfrom(param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, (struct sockaddr *)&param->sinsr, &sasize);
+			if(res <= 0) {
+				if(!errno) SERVERTERM = 1;
+				FROMSERVER = 0;
+			}
+			else {
+#ifdef WITHLOG
+log("done read from server to buf");
+#endif
+			    	param->nreads++;
+				param->statssrv64 += res;
+				inserverbuf += res;
+				param->srvinbuf += res;
+				if(param->bandlimfunc) {
+					int sl1;
+					sl1 = (*param->bandlimfunc)(param, 1, res);
+					if(sl1 > sleeptime) sleeptime = sl1;
+		    		}
+				if(param->srvbufsize == param->srvinbuf) TOSERVERBUF = 0;
+ 				if(param->operation == UDPASSOC && param->srv->singlepacket){
+					fromserver = inserverbuf;
+					FROMSERVER = 0;
+				}
+				continue;
+			}
 		}
 	}
-	if (!stop && ((fds[1].revents & POLLIN)
-#ifdef WITH_WSAPOLL
-		||(fds[1].revents & POLLHUP)
+	for(after = 0; after < 2; after ++){
+		fdsc = 0;
+		if(!after){
+			memset(fds, 0, sizeof(fds));
+		}
+		if(!CLIENTTERM){
+			if(!after){
+				fds[fdsc].fd = param->clisock;
+				if(fromclient && !FROMCLIENT && ((
+#ifdef WITHSPLICE
+					!usesplice && 
 #endif
-						)) {
-#ifdef NOIPV6
-		struct sockaddr_in sin;
-#else
-		struct sockaddr_in6 sin;
+					TOCLIENTBUF) 
+#ifdef WITHSPLICE
+					|| (usesplice)
+#endif
+						)){
+#ifdef WITHLOG
+log("wait reading from client");
+#endif
+							fds[fdsc].events |= (POLLIN
+#ifdef POLLRDHUP
+								|POLLRDHUP
+#endif
+							);
+						}
+				if(!TOCLIENT && (inserverbuf
+#ifdef WITHSPLICE
+					|| inserverpipe
+#endif
+						)){
+#ifdef WITHLOG
+log("wait writing to client");
+#endif
+							fds[fdsc].events |= POLLOUT;
+						}
+			}
+			else{
+				if(fds[fdsc].revents &  (POLLERR|POLLNVAL)) {
+					CLIENTTERM = 1;
+					HASERROR |= 1;
+				}
+				else if(fds[fdsc].revents &  (POLLHUP
+#ifdef POLLRDHUP
+					|POLLRDHUP
+#endif
+				)) {
+					CLIENTTERM = 1;
+				}
+				else {
+					if(fds[fdsc].revents & POLLIN) {
+#ifdef WITHLOG
+log("ready to read from client");
+#endif
+						FROMCLIENT = 1;
+					}
+					if(fds[fdsc].revents & POLLOUT) {
+#ifdef WITHLOG
+log("ready to write to client");
+#endif
+						TOCLIENT = 1;
+					}
+				}
+			}
+			fdsc++;
+		}
+		if(!SERVERTERM){
+			if(!after){
+				fds[fdsc].fd = param->remsock;
+				if(fromserver && !FROMSERVER && ((
+#ifdef WITHSPLICE
+					!usesplice && 
+#endif
+					TOSERVERBUF) 
+#ifdef WITHSPLICE
+					|| (usesplice)
+#endif
+						)){
+#ifdef WITHLOG
+log("wait reading from server");
+#endif
+							fds[fdsc].events |= (POLLIN
+#ifdef POLLRDHUP
+								|POLLRDHUP
 #endif
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "recv from server");
+							);
+						}
+				if(!TOSERVER && (inclientbuf
+#ifdef WITHSPLICE
+					|| inclientpipe
+#endif
+						)){
+#ifdef WITHLOG
+log("wait writing from server");
+#endif
+							fds[fdsc].events |= POLLOUT;
+						}
+			}
+			else{
+				if(fds[fdsc].revents &  (POLLERR|POLLNVAL)) {
+#ifdef WITHLOG
+log("poll from server failed");
 #endif
 
-		sasize = sizeof(sin);
-		res = so._recvfrom(param->remsock, (char *)param->srvbuf + param->srvinbuf, param->srvbufsize - param->srvinbuf, 0, (struct sockaddr *)&sin, &sasize);
-		if (res==0) {
-			so._shutdown(param->remsock, SHUT_RDWR);
-			so._closesocket(param->remsock);
-			fds[1].fd = param->remsock = INVALID_SOCKET;
-			stop = 2;
+					SERVERTERM = 1;
+					HASERROR |=2;
+				}
+				if(fds[fdsc].revents &  (POLLHUP
+#ifdef POLLRDHUP
+					|POLLRDHUP
+#endif
+					)) {
+#ifdef WITHLOG
+log("server terminated connection");
+#endif
+					SERVERTERM = 1;
+				}
+				else {
+					if(fds[fdsc].revents & POLLIN) {
+#ifdef WITHLOG
+log("ready to read from server");
+#endif
+						FROMSERVER = 1;
+					}
+					if(fds[fdsc].revents & POLLOUT) {
+#ifdef WITHLOG
+log("ready to write to server");
+#endif
+						TOSERVER = 1;
+					}
+				}
+			}
+			fdsc++;
 		}
-		else {
-			if (res < 0){
-				if(errno != EAGAIN && errno != EINTR) return 93;
-				if(errno == EINTR) usleep(SLEEPTIME);
-				continue;
+#ifdef WITHSPLICE
+		if(usesplice){
+			if(fromclient>inclientpipe && !TOCLIENTPIPE && inclientpipe < MAXSPLICE){
+				if(!after){
+#ifdef WITHLOG
+log("wait writing to client pipe");
+#endif
+					fds[fdsc].fd = pipecli[1];
+					fds[fdsc].events |= POLLOUT;
+				}
+				else {
+					if(fds[fdsc].revents &  (POLLHUP|POLLERR|POLLNVAL)){
+						RETURN(90);
+					}
+					if(fds[fdsc].revents & POLLOUT) {
+#ifdef WITHLOG
+log("ready to write to client pipe");
+#endif
+						TOCLIENTPIPE = 1;
+					}
+				}
+				fdsc++;
 			}
-			param->srvinbuf += res;
-			param->nreads++;
-			param->statssrv64 += res;
-			if(!param->nolongdatfilter){
-				action = handledatfltsrv(param,  &param->srvbuf, (int *)&param->srvbufsize, param->srvinbuf - res, (int *)&param->srvinbuf);
-				if(action == HANDLED){
-					return 0;
+			if(inclientpipe && !FROMCLIENTPIPE){
+				if(!after){
+#ifdef WITHLOG
+log("wait reading from client pipe");
+#endif
+					fds[fdsc].fd = pipecli[0];
+					fds[fdsc].events |= (POLLIN);
+				}
+				else {
+					if(fds[fdsc].revents &  (POLLHUP|POLLERR|POLLNVAL)){
+						RETURN(90);
+					}
+#ifdef WITHLOG
+log("ready reading from client pipe");
+#endif
+					if(fds[fdsc].revents & POLLIN) FROMCLIENTPIPE = 1;
+				}
+				fdsc++;
+			}
+			if(fromserver>inserverpipe && !TOSERVERPIPE && inserverpipe < MAXSPLICE){
+				if(!after){
+#ifdef WITHLOG
+log("wait writing to server pipe");
+#endif
+					fds[fdsc].fd = pipesrv[1];
+					fds[fdsc].events |= POLLOUT;
+				}
+				else {
+					if(fds[fdsc].revents &  (POLLHUP|POLLERR|POLLNVAL)){
+						RETURN(90);
+					}
+#ifdef WITHLOG
+log("ready writing to server pipe");
+#endif
+					if(fds[fdsc].revents & POLLOUT) TOSERVERPIPE = 1;
 				}
-				if(action != PASS) return 19;
+				fdsc++;
 			}
+			if(inserverpipe && !FROMSERVERPIPE){
+				if(!after){
+#ifdef WITHLOG
+log("wait reading from server pipe");
+#endif
+					fds[fdsc].fd = pipesrv[0];
+					fds[fdsc].events |= (POLLIN);
+				}
+				else {
+					if(fds[fdsc].revents &  (POLLHUP|POLLERR|POLLNVAL)){
+						RETURN(90);
+					}
+#ifdef WITHLOG
+log("ready reading from server pipe");
+#endif
+					if(fds[fdsc].revents & POLLIN) FROMSERVERPIPE = 1;
+				}
+				fdsc++;
+			}
+		}
+#endif
+		if(!after){
+			if(!fdsc) RETURN(90);
 
+
+
+
+#ifdef WITHLOG
+log("entering poll");
+#endif
+			res = so._poll(fds, fdsc, timeo*1000);
+#ifdef WITHLOG
+log("leaving poll");
+#endif
+			if(res < 0){
+#ifdef WITHLOG
+log("poll error");
+#endif
+				if(errno != EAGAIN && errno != EINTR) RETURN(91);
+				break;
+			}
+			if(res < 1){
+#ifdef WITHLOG
+log("timeout");
+#endif
+				RETURN (92);
+			}
 		}
 	}
 
-	if(sleeptime > 0) {
-		if(sleeptime > (timeo * 1000)){return (95);}
-		usleep(sleeptime * SLEEPTIME);
-		sleeptime = 0;
-	}
  }
- if(conf.timetoexit) return 89;
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "finished with mapping");
-#endif
- while(!param->waitclient64 && param->srvinbuf > param->srvoffset && param->clisock != INVALID_SOCKET){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "flushing buffer to client");
-#endif
-	res = socksendto(param->clisock, (struct sockaddr *)&param->sincr, param->srvbuf + param->srvoffset, param->srvinbuf - param->srvoffset, conf.timeouts[STRING_S] * 1000);
-	if(res > 0){
-		param->srvoffset += res;
-		param->statssrv64 += res;
-		if(param->srvoffset == param->srvinbuf) param->srvoffset = param->srvinbuf = 0;
-	}
-	else break;
- } 
- while(!param->waitserver64 && param->cliinbuf > param->clioffset && param->remsock != INVALID_SOCKET){
-#if DEBUGLEVEL > 2
-(*param->srv->logfunc)(param, "flushing buffer to server");
-#endif
-	res = socksendto(param->remsock, (struct sockaddr *)&param->sinsr, param->clibuf + param->clioffset, param->cliinbuf - param->clioffset, conf.timeouts[STRING_S] * 1000);
-	if(res > 0){
-		param->clioffset += res;
-		param->statscli64 += res;
-		if(param->cliinbuf == param->clioffset) param->cliinbuf = param->clioffset = 0;
-	}
-	else break;
- } 
- return retcode;
+ res = 0;
+ if(!fromserver) res = 98;
+ else if(!fromclient) res = 99;
+ else if((inclientbuf || inserverbuf)) res = HASERROR?93:94;
+#ifdef WITHSPLICE
+ else if(inclientpipe || inserverpipe) res = HASERROR?93:94;
+#endif
+ else if(HASERROR) res = 94+HASERROR;
+
+CLEANRET:
+
+#ifdef WITHSPLICE
+ if(pipecli[0] >= 0) close(pipecli[0]);
+ if(pipecli[1] >= 0) close(pipecli[1]);
+ if(pipesrv[0] >= 0) close(pipesrv[0]);
+ if(pipesrv[1] >= 0) close(pipesrv[1]);
+#endif
+
+ return res;
 }

+ 1 - 1
src/socks.c

@@ -448,7 +448,7 @@ fflush(stderr);
 	 else 
 		myinet_ntop(*SAFAMILY(&param->req), SAADDR(&param->req), (char *)buf + strlen((char *)buf), 64);
          sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(*SAPORT(&param->req)));
-	 (*param->srv->logfunc)(param, buf);
+	 dolog(param, buf);
 	 myfree(buf);
  }
  freeparam(param);

+ 1 - 1
src/structures.h

@@ -740,7 +740,7 @@ struct pluginlink {
 	int (*dobuf2)(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec, struct tm* tm, char * format);
 	int (*scanaddr)(const unsigned char *s, unsigned long * ip, unsigned long * mask);
 	unsigned long (*getip46)(int family, unsigned char *name,  struct sockaddr *sa);
-	int (*sockmap)(struct clientparam * param, int timeo);
+	int (*sockmap)(struct clientparam * param, int timeo, int usesplice);
 	int (*ACLMatches)(struct ace* acentry, struct clientparam * param);
 	int (*alwaysauth)(struct clientparam * param);
 	int (*checkACL)(struct clientparam * param);

+ 1 - 1
src/tcppm.c

@@ -23,7 +23,7 @@ void * tcppmchild(struct clientparam* param) {
  RETURN (mapsocket(param, conf.timeouts[CONNECTION_L]));
 CLEANRET:
  
- (*param->srv->logfunc)(param, param->hostname);
+ dolog(param, param->hostname);
  freeparam(param);
  return (NULL);
 }

+ 3 - 3
src/udppm.c

@@ -81,7 +81,7 @@ void * udppmchild(struct clientparam* param) {
 #ifdef _WIN32
 	ioctlsocket(param->remsock, FIONBIO, &ul);
 #else
-	fcntl(param->remsock,F_SETFL,O_NONBLOCK);
+	fcntl(param->remsock,F_SETFL,O_NONBLOCK | fcntl(param->remsock,F_GETFL));
 #endif
  memcpy(&param->sinsr, &param->req, sizeof(param->req));
 
@@ -91,7 +91,7 @@ void * udppmchild(struct clientparam* param) {
 	param->srv->fds.events = POLLIN;
  }
 
- param->res = sockmap(param, conf.timeouts[(param->srv->singlepacket)?SINGLEBYTE_L:STRING_L]);
+ param->res = mapsocket(param, conf.timeouts[(param->srv->singlepacket)?SINGLEBYTE_L:STRING_L]);
  if(!param->srv->singlepacket) {
 	param->srv->fds.events = POLLIN;
  }
@@ -99,7 +99,7 @@ void * udppmchild(struct clientparam* param) {
 CLEANRET:
 
  if(buf)myfree(buf);
- (*param->srv->logfunc)(param, NULL);
+ dolog(param, NULL);
 #ifndef _WIN32
  param->clisock = INVALID_SOCKET;
 #endif

+ 1 - 1
src/webadmin.c

@@ -576,7 +576,7 @@ CLEANRET:
 
  printstr(&pp, NULL);
  if(buf) myfree(buf);
- (*param->srv->logfunc)(param, (unsigned char *)req);
+ dolog(param, (unsigned char *)req);
  if(req)myfree(req);
  freeparam(param);
  return (NULL);