sockmap.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*
  2. 3APA3A simpliest proxy server
  3. (c) 2002-2008 by ZARAZA <3APA3A@security.nnov.ru>
  4. please read License Agreement
  5. */
  6. #include "proxy.h"
  7. #define BUFSIZE (param->srv->bufsize?param->srv->bufsize:((param->service == S_UDPPM)?UDPBUFSIZE:TCPBUFSIZE))
  8. #ifdef WITHSPLICE
  9. #include <fcntl.h>
  10. ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
  11. #ifndef SPLICE_F_MOVE
  12. #define SPLICE_F_MOVE 0x01
  13. #endif
  14. #ifndef SPLICE_F_NONBLOCK
  15. #define SPLICE_F_NONBLOCK 0x02
  16. #endif
  17. #ifndef SPLICE_F_MORE
  18. #define SPLICE_F_MORE 0x04
  19. #endif
  20. #ifndef SPLICE_F_GIFT
  21. #define SPLICE_F_GIFT 0x08
  22. #endif
  23. #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
  24. #define MIN(a,b) ((a>b)?b:a)
  25. #define MAXSPLICE 65536
  26. int splicemap(struct clientparam * param, int timeo){
  27. struct pollfd fds[2];
  28. int pipesrv[2] = {-1,-1};
  29. int pipecli[2] = {-1,-1};
  30. uint64_t sent=0, received=0;
  31. SASIZETYPE sasize;
  32. int res = 0, stop = 0;
  33. int srvstate = 0, clistate = 0;
  34. int insrvpipe = 0, inclipipe = 0;
  35. int rfromserver = 0, rfromclient = 0;
  36. int sleeptime = 0;
  37. if(param->srv->usesplice > 1 && !param->waitserver64 && !param->waitclient64){
  38. if(param->clioffset == param->cliinbuf){
  39. param->clioffset = param->cliinbuf = 0;
  40. if(param->clibuf){
  41. myfree(param->clibuf);
  42. param->clibuf = NULL;
  43. }
  44. }
  45. if(param->srvoffset == param->srvinbuf){
  46. param->srvoffset = param->srvinbuf = 0;
  47. if(param->srvbuf){
  48. myfree(param->srvbuf);
  49. param->srvbuf = NULL;
  50. }
  51. }
  52. }
  53. param->res = 0;
  54. if(pipe(pipecli) < 0) RETURN(21);
  55. if(pipe(pipesrv) < 0) RETURN(21);
  56. fds[0].fd = param->clisock;
  57. fds[1].fd = param->remsock;
  58. while(!stop && !conf.timetoexit){
  59. #ifdef NOIPV6
  60. sasize = sizeof(struct sockaddr_in);
  61. #else
  62. sasize = sizeof(struct sockaddr_in6);
  63. #endif
  64. fds[0].events = fds[1].events = 0;
  65. if((srvstate || param->srvinbuf > param->srvoffset) && !param->waitclient64){
  66. #if DEBUGLEVEL > 2
  67. (*param->srv->logfunc)(param, "splice: will send to client");
  68. #endif
  69. fds[0].events |= POLLOUT;
  70. }
  71. rfromserver = MAXSPLICE;
  72. if(param->srvinbuf > param->srvoffset) rfromserver = 0;
  73. else if(param->waitserver64) rfromserver = MIN(MAXSPLICE, param->waitserver64 - (received + insrvpipe));
  74. if(srvstate < 2 && rfromserver > 0) {
  75. #if DEBUGLEVEL > 2
  76. (*param->srv->logfunc)(param, "splice: will recv from server");
  77. #endif
  78. fds[1].events |= POLLIN;
  79. }
  80. if((clistate || param->cliinbuf > param->clioffset)&& !param->waitserver64){
  81. #if DEBUGLEVEL > 2
  82. (*param->srv->logfunc)(param, "splice: will send to server");
  83. #endif
  84. fds[1].events |= POLLOUT;
  85. }
  86. rfromclient = MAXSPLICE;
  87. if(param->cliinbuf > param->clioffset) rfromclient = 0;
  88. else if(param->waitclient64) rfromclient = MIN(MAXSPLICE, param->waitclient64 - (sent + inclipipe));
  89. if(clistate < 2 && rfromclient > 0) {
  90. #if DEBUGLEVEL > 2
  91. (*param->srv->logfunc)(param, "splice :will recv from client");
  92. #endif
  93. fds[0].events |= POLLIN;
  94. }
  95. if(!fds[0].events && !fds[1].events) RETURN (666);
  96. res = so._poll(fds, 2, timeo*1000);
  97. if(res < 0){
  98. if(errno != EAGAIN && errno != EINTR) RETURN(91);
  99. if(errno == EINTR) usleep(SLEEPTIME);
  100. continue;
  101. }
  102. if(res < 1){
  103. RETURN(92);
  104. }
  105. if( (fds[0].revents & (POLLERR|POLLHUP|POLLNVAL)) && !(fds[0].revents & POLLIN)) {
  106. fds[0].revents = 0;
  107. stop = 1;
  108. param->res = 90;
  109. }
  110. if( (fds[1].revents & (POLLERR|POLLHUP|POLLNVAL)) && !(fds[1].revents & POLLIN)){
  111. fds[1].revents = 0;
  112. stop = 1;
  113. param->res = 90;
  114. }
  115. if((fds[0].revents & POLLOUT)){
  116. if (param->srvinbuf > param->srvoffset) {
  117. #if DEBUGLEVEL > 2
  118. (*param->srv->logfunc)(param, "splice: non-spliced send to client");
  119. #endif
  120. 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);
  121. }
  122. else {
  123. #if DEBUGLEVEL > 2
  124. (*param->srv->logfunc)(param, "splice: spliced send to client");
  125. #endif
  126. res = splice(pipesrv[0], NULL, param->clisock, NULL, MIN(MAXSPLICE, insrvpipe), SPLICE_F_NONBLOCK | SPLICE_F_MORE | SPLICE_F_MOVE);
  127. }
  128. if(res < 0) {
  129. #if DEBUGLEVEL > 2
  130. (*param->srv->logfunc)(param, "splice: send to client error");
  131. #endif
  132. if(errno != EAGAIN && errno != EINTR) RETURN(96);
  133. if(errno == EINTR) usleep(SLEEPTIME);
  134. continue;
  135. }
  136. if(res){
  137. if (param->srvinbuf > param->srvoffset){
  138. param->srvinbuf = param->srvoffset = 0;
  139. if(param->srv->usesplice > 1 && !param->waitclient64 && !param->waitserver64){
  140. if(param->srvbuf){
  141. myfree(param->srvbuf);
  142. param->srvbuf = NULL;
  143. }
  144. }
  145. }
  146. else insrvpipe -= res;
  147. received += res;
  148. if(param->bandlimfunc) {
  149. sleeptime = (*param->bandlimfunc)(param, res, 0);
  150. }
  151. srvstate = 0;
  152. }
  153. else srvstate = 2;
  154. if(param->waitserver64 && param->waitserver64 <= received){
  155. RETURN (98);
  156. }
  157. }
  158. if((fds[1].revents & POLLOUT)){
  159. if(param->cliinbuf > param->clioffset){
  160. #if DEBUGLEVEL > 2
  161. (*param->srv->logfunc)(param, "splice: non-spliced send to server");
  162. #endif
  163. 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);
  164. }
  165. else {
  166. #if DEBUGLEVEL > 2
  167. (*param->srv->logfunc)(param, "splice: spliced send to server");
  168. #endif
  169. res = splice(pipecli[0], NULL, param->remsock, NULL, MIN(MAXSPLICE, inclipipe), SPLICE_F_NONBLOCK | SPLICE_F_MORE | SPLICE_F_MOVE);
  170. }
  171. if(res < 0) {
  172. #if DEBUGLEVEL > 2
  173. (*param->srv->logfunc)(param, "splice: send to server error");
  174. #endif
  175. if(errno != EAGAIN && errno != EINTR) RETURN(97);
  176. if(errno == EINTR) usleep(SLEEPTIME);
  177. continue;
  178. }
  179. if(res){
  180. if(param->cliinbuf > param->clioffset){
  181. param->clioffset += res;
  182. if(param->clioffset == param->cliinbuf){
  183. param->clioffset = param->cliinbuf = 0;
  184. if(param->srv->usesplice > 1 && !param->waitclient64 && !param->waitserver64){
  185. if(param->clibuf){
  186. myfree(param->clibuf);
  187. param->clibuf = NULL;
  188. }
  189. }
  190. }
  191. }
  192. else inclipipe -= res;
  193. sent += res;
  194. param->nwrites++;
  195. param->statscli64 += res;
  196. if(param->bandlimfunc) {
  197. int sl1;
  198. sl1 = (*param->bandlimfunc)(param, 0, res);
  199. if(sl1 > sleeptime) sleeptime = sl1;
  200. }
  201. clistate = 0;
  202. }
  203. if(param->waitclient64 && param->waitclient64 <= sent){
  204. RETURN (99);
  205. }
  206. }
  207. if ((fds[0].revents & POLLIN)) {
  208. #if DEBUGLEVEL > 2
  209. (*param->srv->logfunc)(param, "splice: recv from client");
  210. #endif
  211. res = splice(param->clisock, NULL, pipecli[1], NULL, rfromclient, SPLICE_F_NONBLOCK | SPLICE_F_MORE | SPLICE_F_MOVE);
  212. if (res < 0){
  213. if(errno != EAGAIN && errno != EINTR) RETURN(94);
  214. if(errno == EINTR) usleep(SLEEPTIME);
  215. continue;
  216. }
  217. if (res==0) {
  218. so._shutdown(param->clisock, SHUT_RDWR);
  219. so._closesocket(param->clisock);
  220. fds[0].fd = param->clisock = INVALID_SOCKET;
  221. stop = 1;
  222. }
  223. else {
  224. inclipipe += res;
  225. clistate = 1;
  226. if(insrvpipe >= MAXSPLICE) clistate = 2;
  227. }
  228. }
  229. if ((fds[1].revents & POLLIN)) {
  230. #if DEBUGLEVEL > 2
  231. (*param->srv->logfunc)(param, "splice: recv from server");
  232. #endif
  233. res = splice(param->remsock, NULL, pipesrv[1], NULL, rfromserver, SPLICE_F_NONBLOCK | SPLICE_F_MORE | SPLICE_F_MOVE);
  234. if (res < 0){
  235. if(errno != EAGAIN && errno != EINTR) RETURN(93);
  236. if(errno == EINTR) usleep(SLEEPTIME);
  237. continue;
  238. }
  239. if (res==0) {
  240. so._shutdown(param->remsock, SHUT_RDWR);
  241. so._closesocket(param->remsock);
  242. fds[1].fd = param->remsock = INVALID_SOCKET;
  243. stop = 2;
  244. }
  245. else {
  246. insrvpipe += res;
  247. param->statssrv64 += res;
  248. param->nreads++;
  249. srvstate = 1;
  250. if(insrvpipe >= MAXSPLICE) srvstate = 2;
  251. }
  252. }
  253. if(sleeptime > 0) {
  254. if(sleeptime > (timeo * 1000)){RETURN (95);}
  255. usleep(sleeptime * SLEEPTIME);
  256. sleeptime = 0;
  257. }
  258. }
  259. #if DEBUGLEVEL > 2
  260. (*param->srv->logfunc)(param, "splice: finished with mapping");
  261. #endif
  262. CLEANRET:
  263. if(pipecli[0] >= 0) close(pipecli[0]);
  264. if(pipecli[1] >= 0) close(pipecli[1]);
  265. if(pipesrv[0] >= 0) close(pipesrv[0]);
  266. if(pipesrv[1] >= 0) close(pipesrv[1]);
  267. return param->res;
  268. }
  269. #endif
  270. int sockmap(struct clientparam * param, int timeo){
  271. int res=0;
  272. uint64_t sent=0, received=0;
  273. SASIZETYPE sasize;
  274. struct pollfd fds[2];
  275. int sleeptime = 0, stop = 0;
  276. unsigned minsize;
  277. unsigned bufsize;
  278. FILTER_ACTION action;
  279. int retcode = 0;
  280. bufsize = BUFSIZE;
  281. minsize = (param->service == S_UDPPM || param->service == S_TCPPM)? bufsize - 1 : (bufsize>>2);
  282. fds[0].fd = param->clisock;
  283. fds[1].fd = param->remsock;
  284. #if DEBUGLEVEL > 2
  285. (*param->srv->logfunc)(param, "Starting sockets mapping");
  286. #endif
  287. if(!param->waitclient64){
  288. if(!param->srvbuf && (!(param->srvbuf=myalloc(bufsize)) || !(param->srvbufsize = bufsize))){
  289. return (21);
  290. }
  291. }
  292. if(!param->waitserver64){
  293. if(!param->clibuf && (!(param->clibuf=myalloc(bufsize)) || !(param->clibufsize = bufsize))){
  294. return (21);
  295. }
  296. }
  297. action = handlepredatflt(param);
  298. if(action == HANDLED){
  299. return 0;
  300. }
  301. if(action != PASS) return 19;
  302. if(!param->nolongdatfilter){
  303. if(param->cliinbuf > param->clioffset){
  304. action = handledatfltcli(param, &param->clibuf, (int *)&param->clibufsize, param->clioffset, (int *)&param->cliinbuf);
  305. if(action == HANDLED){
  306. return 0;
  307. }
  308. if(action != PASS) return 19;
  309. }
  310. if(param->srvinbuf > param->srvoffset){
  311. action = handledatfltsrv(param, &param->srvbuf, (int *)&param->srvbufsize, param->srvoffset, (int *)&param->srvinbuf);
  312. if(action == HANDLED){
  313. return 0;
  314. }
  315. if(action != PASS) return 19;
  316. }
  317. }
  318. while (!stop&&!conf.timetoexit){
  319. #ifdef NOIPV6
  320. sasize = sizeof(struct sockaddr_in);
  321. #else
  322. sasize = sizeof(struct sockaddr_in6);
  323. #endif
  324. if(param->version < conf.version){
  325. if((res = (*param->srv->authfunc)(param)) && res != 2 && !param->srv->noforce) {return(res);}
  326. param->paused = conf.paused;
  327. param->version = conf.version;
  328. }
  329. if((param->maxtrafin64 && param->statssrv64 >= param->maxtrafin64) || (param->maxtrafout64 && param->statscli64 >= param->maxtrafout64)){
  330. return (10);
  331. }
  332. if((param->srv->logdumpsrv && (param->statssrv64 > param->srv->logdumpsrv)) ||
  333. (param->srv->logdumpcli && (param->statscli64 > param->srv->logdumpcli)))
  334. (*param->srv->logfunc)(param, NULL);
  335. fds[0].events = fds[1].events = 0;
  336. if(param->srvinbuf > param->srvoffset && !param->waitclient64) {
  337. #if DEBUGLEVEL > 2
  338. (*param->srv->logfunc)(param, "will send to client");
  339. #endif
  340. fds[0].events |= POLLOUT;
  341. }
  342. if((param->srvbufsize - param->srvinbuf) > minsize && !param->waitclient64 && (!param->waitserver64 ||(received + param->srvinbuf - param->srvoffset < param->waitserver64))) {
  343. #if DEBUGLEVEL > 2
  344. (*param->srv->logfunc)(param, "Will recv from server");
  345. #endif
  346. fds[1].events |= POLLIN;
  347. }
  348. if(param->cliinbuf > param->clioffset && !param->waitserver64) {
  349. #if DEBUGLEVEL > 2
  350. (*param->srv->logfunc)(param, "Will send to server");
  351. #endif
  352. fds[1].events |= POLLOUT;
  353. }
  354. if((param->clibufsize - param->cliinbuf) > minsize && !param->waitserver64 &&(!param->srv->singlepacket || param->service != S_UDPPM) ) {
  355. #if DEBUGLEVEL > 2
  356. (*param->srv->logfunc)(param, "Will recv from client");
  357. #endif
  358. fds[0].events |= POLLIN;
  359. }
  360. if(!fds[0].events && !fds[1].events) return 666;
  361. res = so._poll(fds, 2, timeo*1000);
  362. if(res < 0){
  363. if(errno != EAGAIN && errno != EINTR) return 91;
  364. if(errno == EINTR) usleep(SLEEPTIME);
  365. continue;
  366. }
  367. if(res < 1){
  368. return 92;
  369. }
  370. if( (fds[0].revents & (POLLERR|POLLHUP|POLLNVAL)) && !(fds[0].revents & POLLIN)) {
  371. fds[0].revents = 0;
  372. stop = 1;
  373. retcode = 90;
  374. }
  375. if( (fds[1].revents & (POLLERR|POLLHUP|POLLNVAL)) && !(fds[1].revents & POLLIN)){
  376. fds[1].revents = 0;
  377. stop = 1;
  378. retcode = 90;
  379. }
  380. if((fds[0].revents & POLLOUT)){
  381. #if DEBUGLEVEL > 2
  382. (*param->srv->logfunc)(param, "send to client");
  383. #endif
  384. if(param->bandlimfunc) {
  385. sleeptime = (*param->bandlimfunc)(param, param->srvinbuf - param->srvoffset, 0);
  386. }
  387. 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);
  388. if(res < 0) {
  389. if(errno != EAGAIN && errno != EINTR) return 96;
  390. if(errno == EINTR) usleep(SLEEPTIME);
  391. continue;
  392. }
  393. param->srvoffset += res;
  394. received += res;
  395. if(param->srvoffset == param->srvinbuf) param->srvoffset = param->srvinbuf = 0;
  396. if(param->waitserver64 && param->waitserver64<= received){
  397. return (98);
  398. }
  399. if(param->service == S_UDPPM && param->srv->singlepacket) {
  400. stop = 1;
  401. }
  402. }
  403. if((fds[1].revents & POLLOUT)){
  404. #if DEBUGLEVEL > 2
  405. (*param->srv->logfunc)(param, "send to server");
  406. #endif
  407. if(param->bandlimfunc) {
  408. int sl1;
  409. sl1 = (*param->bandlimfunc)(param, 0, param->cliinbuf - param->clioffset);
  410. if(sl1 > sleeptime) sleeptime = sl1;
  411. }
  412. 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);
  413. if(res < 0) {
  414. if(errno != EAGAIN && errno != EINTR) return 97;
  415. if(errno == EINTR) usleep(SLEEPTIME);
  416. continue;
  417. }
  418. param->clioffset += res;
  419. if(param->clioffset == param->cliinbuf) param->clioffset = param->cliinbuf = 0;
  420. sent += res;
  421. param->nwrites++;
  422. param->statscli64 += res;
  423. if(param->waitclient64 && param->waitclient64<= sent) {
  424. return (99);
  425. }
  426. }
  427. if ((fds[0].revents & POLLIN)) {
  428. #if DEBUGLEVEL > 2
  429. (*param->srv->logfunc)(param, "recv from client");
  430. #endif
  431. res = so._recvfrom(param->clisock, (char *)param->clibuf + param->cliinbuf, param->clibufsize - param->cliinbuf, 0, (struct sockaddr *)&param->sincr, &sasize);
  432. if (res==0) {
  433. so._shutdown(param->clisock, SHUT_RDWR);
  434. so._closesocket(param->clisock);
  435. fds[0].fd = param->clisock = INVALID_SOCKET;
  436. stop = 1;
  437. }
  438. else {
  439. if (res < 0){
  440. if(errno != EAGAIN && errno != EINTR) return 94;
  441. if(errno == EINTR) usleep(SLEEPTIME);
  442. continue;
  443. }
  444. param->cliinbuf += res;
  445. if(!param->nolongdatfilter){
  446. action = handledatfltcli(param, &param->clibuf, (int *)&param->clibufsize, param->cliinbuf - res, (int *)&param->cliinbuf);
  447. if(action == HANDLED){
  448. return 0;
  449. }
  450. if(action != PASS) return 19;
  451. }
  452. }
  453. }
  454. if (!stop && (fds[1].revents & POLLIN)) {
  455. #ifdef NOIPV6
  456. struct sockaddr_in sin;
  457. #else
  458. struct sockaddr_in6 sin;
  459. #endif
  460. #if DEBUGLEVEL > 2
  461. (*param->srv->logfunc)(param, "recv from server");
  462. #endif
  463. sasize = sizeof(sin);
  464. res = so._recvfrom(param->remsock, (char *)param->srvbuf + param->srvinbuf, param->srvbufsize - param->srvinbuf, 0, (struct sockaddr *)&sin, &sasize);
  465. if (res==0) {
  466. so._shutdown(param->remsock, SHUT_RDWR);
  467. so._closesocket(param->remsock);
  468. fds[1].fd = param->remsock = INVALID_SOCKET;
  469. stop = 2;
  470. }
  471. else {
  472. if (res < 0){
  473. if(errno != EAGAIN && errno != EINTR) return 93;
  474. if(errno == EINTR) usleep(SLEEPTIME);
  475. continue;
  476. }
  477. param->srvinbuf += res;
  478. param->nreads++;
  479. param->statssrv64 += res;
  480. if(!param->nolongdatfilter){
  481. action = handledatfltsrv(param, &param->srvbuf, (int *)&param->srvbufsize, param->srvinbuf - res, (int *)&param->srvinbuf);
  482. if(action == HANDLED){
  483. return 0;
  484. }
  485. if(action != PASS) return 19;
  486. }
  487. }
  488. }
  489. if(sleeptime > 0) {
  490. if(sleeptime > (timeo * 1000)){return (95);}
  491. usleep(sleeptime * SLEEPTIME);
  492. sleeptime = 0;
  493. }
  494. }
  495. if(conf.timetoexit) return 89;
  496. #if DEBUGLEVEL > 2
  497. (*param->srv->logfunc)(param, "finished with mapping");
  498. #endif
  499. while(!param->waitclient64 && param->srvinbuf > param->srvoffset && param->clisock != INVALID_SOCKET){
  500. #if DEBUGLEVEL > 2
  501. (*param->srv->logfunc)(param, "flushing buffer to client");
  502. #endif
  503. res = socksendto(param->clisock, (struct sockaddr *)&param->sincr, param->srvbuf + param->srvoffset, param->srvinbuf - param->srvoffset, conf.timeouts[STRING_S] * 1000);
  504. if(res > 0){
  505. param->srvoffset += res;
  506. param->statssrv64 += res;
  507. if(param->srvoffset == param->srvinbuf) param->srvoffset = param->srvinbuf = 0;
  508. }
  509. else break;
  510. }
  511. while(!param->waitserver64 && param->cliinbuf > param->clioffset && param->remsock != INVALID_SOCKET){
  512. #if DEBUGLEVEL > 2
  513. (*param->srv->logfunc)(param, "flushing buffer to server");
  514. #endif
  515. res = socksendto(param->remsock, (struct sockaddr *)&param->sinsr, param->clibuf + param->clioffset, param->cliinbuf - param->clioffset, conf.timeouts[STRING_S] * 1000);
  516. if(res > 0){
  517. param->clioffset += res;
  518. param->statscli64 += res;
  519. if(param->cliinbuf == param->clioffset) param->cliinbuf = param->clioffset = 0;
  520. }
  521. else break;
  522. }
  523. return retcode;
  524. }