buffer.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: buffer.c,v 1.51.4.3 1998/07/17 19:56:20 wlu Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "buffer.h"
  11. #include "block.h"
  12. #include "addr.h"
  13. #include "log.h"
  14. #include "msg.h"
  15. #define DATAHEAD(b) ((b)->data + (b)->off)
  16. #define DATASIZE(b) ((b)->len  - (b)->off)
  17. static int S5BufFillPacket(S5Packet *ebuf, char *buffer, int buflen, int ioflags) {
  18.     int len = DATASIZE(ebuf);
  19.     if (len <= 0) return 0;
  20.     if (len > buflen) len = buflen;
  21.     
  22.     memcpy(buffer, DATAHEAD(ebuf), len);
  23.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufFill: Filled in %d bytes out of buffer", len);
  24.     if (ioflags & MSG_PEEK) return len;
  25.     ebuf->off += len;
  26.     if (DATASIZE(ebuf) > 0) {
  27. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufFill: Leaving %d bytes in buffer", DATASIZE(ebuf));
  28.     } else {
  29. free(ebuf->data);
  30. ebuf->data = NULL;
  31. ebuf->off  = 0;
  32. ebuf->len  = 0;
  33.     }
  34.     return len;
  35. }
  36. static int S5BufPutPacket(S5IOHandle fd, char *buffer, int buflen, int ioflags) {
  37.     int n, m = buflen;
  38.     fd_set fds, wfs;
  39.     struct timeval *stm, tm = { 0, 0 };
  40.     FD_ZERO(&wfs);
  41.     FD_SET(fd, &wfs);
  42.     if (ISNBLOCK(fd)) stm = &tm;
  43.     else       stm = NULL;
  44.     while (m > 0) {
  45. fds = wfs;
  46. switch (REAL(select)(fd + 1, NULL, &fds, NULL, stm)) {
  47.     case -1:
  48.      if (ISSOCKETERROR(EINTR)) continue;
  49. else {
  50.                     SETSOCKETERROR(EBADF);
  51.     return -1;
  52.         }
  53.     case 0:
  54. if (m == buflen) {
  55. #if defined(sun) && !defined(__svr4__)
  56.                     SETSOCKETERROR(EWOULDBLOCK);
  57. #else
  58.                     SETSOCKETERROR(EAGAIN);
  59. #endif
  60.     return -1;
  61.   }
  62. stm = NULL;
  63. continue;
  64. }
  65. if ((n = SENDSOCKET(fd, buffer, m, ioflags)) < 0) {
  66.             if (S5IOCheck(fd) >= 0) continue;
  67.             else {
  68.                 SETSOCKETERROR(EBADF);
  69.                 return -1;
  70.             }
  71. }
  72. m -= n;
  73. buffer += n;
  74.     }
  75.     return 0;
  76. }
  77. static int S5BufGetPacket(S5IOHandle fd, S5IOInfo *cinfo, int block) {
  78.     int nlen, nr;
  79.     S5Packet buf;
  80.     char *nbuf;
  81.     
  82.     if (cinfo->ibuf.data == NULL) {
  83. cinfo->ibuf.off = 0;
  84. cinfo->ibuf.len = 0;
  85.     }
  86.     while (1) {
  87. /* As long as we haven't read in the whole packet, read in more...   */
  88. buf.data = cinfo->ibuf.data;
  89. buf.len  = cinfo->ibuf.off;
  90. if (!(nlen = cinfo->auth.check(&buf, cinfo->auth.context))) {
  91.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufGet: Whole packet available...");
  92.     return 1;
  93. }
  94. /* Grow the buffer if necessary...                                   */
  95. if (cinfo->ibuf.len < cinfo->ibuf.off + nlen) {
  96.     if (!cinfo->ibuf.data) nbuf = (char *)malloc(cinfo->ibuf.off + nlen);
  97.     else                   nbuf = (char *)realloc(cinfo->ibuf.data, cinfo->ibuf.off + nlen);
  98.     if (!nbuf) {
  99. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5BufGet: Out of memory enlarging packet buffer");
  100. SETSOCKETERROR(EBADF);
  101. return -1;
  102.     }
  103.     cinfo->ibuf.len  = cinfo->ibuf.off + nlen;
  104.     cinfo->ibuf.data = nbuf;
  105. }
  106.         if (!block) {
  107.             int na = 0;
  108.             if (S5IOCheck(fd) < 0) return 0;
  109. #ifdef FIONREAD
  110.             if ((nr = IOCTLSOCKET(fd, FIONREAD, &na)) < 0) {
  111.                 SETSOCKETERROR(EBADF);
  112.                 return -1;
  113.             }
  114.             if (na < nlen) {
  115.                 S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufGet: Not enough data");
  116. #if defined(sun) && !defined(__svr4__)
  117.                 SETSOCKETERROR(EWOULDBLOCK);
  118. #else
  119.                 SETSOCKETERROR(EAGAIN);
  120. #endif
  121.                 return -2;
  122.     }
  123. #endif
  124.         }
  125. switch (nr = RECVSOCKET(fd, cinfo->ibuf.data + cinfo->ibuf.off, nlen, 0)) {
  126.     case -1:
  127.   if (ISSOCKETERROR(EINTR)) continue;
  128.     case 0:
  129. return nr;
  130. }
  131. /* Update counters...                                                */
  132. cinfo->ibuf.off += nr;
  133.     }
  134.     SETSOCKETERROR(EBADF);
  135.     return -1;
  136. }
  137.     
  138. /* Check if whole packet is available including data in the I/O buffer       */
  139. /* Return 1 if packet is available, -2 if not available and 0/-1 if I/O      */
  140. /* fails...                                                                  */
  141. int S5BufCheckPacket(S5IOHandle fd, S5IOInfo *cinfo) {
  142.     /* If there's no buffering, or if we've read the whole thing, we're done */
  143.     if (!cinfo || !cinfo->auth.check) return 1;
  144.     return S5BufGetPacket(fd, cinfo, 0);
  145. }
  146. /* Check if whole packet is available in the buffer. Return 1 if packet is   */
  147. /* available, 0 if not.                                                      */
  148. int S5BufCheckData(S5IOHandle fd, S5IOInfo *cinfo) {
  149.     if (cinfo && cinfo->obuf.data) return 1;
  150.     return 0;
  151. }
  152. int S5BufUnreadPacket(S5IOInfo *cinfo, char *ibuf, int ilen) {
  153.     S5Packet nbuf;
  154.     
  155.     if (!cinfo || ilen < 0) return -1;
  156.     if (ilen == 0) return 0;
  157.     if (!cinfo->obuf.data) {
  158. cinfo->obuf.len  = 0;
  159. cinfo->obuf.off  = 0;
  160.     }
  161.     /* Try to put the data back into the buffer...                           */
  162.     if (cinfo->obuf.off >= ilen) {
  163. memcpy(DATAHEAD(&cinfo->obuf) - ilen, ibuf, ilen);
  164. cinfo->obuf.off -= ilen;
  165. return 0;
  166.     }
  167.     /* Make a new buffer which can hold what was already there and this.     */
  168.     nbuf.len  = DATASIZE(&cinfo->obuf) + ilen;
  169.     nbuf.off  = 0;
  170.     
  171.     if (!(nbuf.data = (char *)malloc(nbuf.len * sizeof(char)))) {
  172. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "S5BufUnread: Couldn't allocate buffer");
  173. return -1;
  174.     }
  175.     /* Put the already read data at the beginning of the buffer...           */
  176.     memcpy(DATAHEAD(&nbuf), ibuf, ilen);
  177.     nbuf.off  = ilen;
  178.     /* There was already some data there, so copy it in...                   */
  179.     if (cinfo->obuf.data) {
  180. memcpy(DATAHEAD(&nbuf), DATAHEAD(&cinfo->obuf), DATASIZE(&cinfo->obuf));
  181. nbuf.off += DATASIZE(&cinfo->obuf);
  182.     }
  183.     free(cinfo->obuf.data);
  184.     cinfo->obuf = nbuf;
  185.     return 0;
  186. }
  187. int S5BufReadPacket(S5IOHandle fd, S5IOInfo *cinfo, char *ibuf, int ilen, int ioflags) {
  188.     int rval;
  189.     int block = (ISNBLOCK(fd))?0:1;
  190.     if (!cinfo || !cinfo->auth.encode || ilen <= 0) {
  191. return (int)RECVSOCKET(fd, ibuf, ilen, ioflags);
  192.     }
  193.     
  194.     /* Find out if there was a prior message we had read in an decoded, but  */
  195.     /* couldn't fit into the requested buffer...(this would be typical of a  */
  196.     /* program that calls do (read(fd, buf, 1) while (*buf++ != ''), or    */
  197.     /* the like... Also could occur if EINTR occured and restarting wasn't   */
  198.     /* set in S5IORecv...                                                    */
  199.     if (cinfo && cinfo->obuf.data != NULL) {
  200. return S5BufFillPacket(&cinfo->obuf, (char *)ibuf, ilen, ioflags);
  201.     }
  202.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufRead: encapsulated...");
  203.     
  204.     switch ((rval = S5BufGetPacket(fd, cinfo, block))) {
  205. case -2: rval = -1;
  206. case -1:
  207. case  0: return rval;
  208. default: break;
  209.     }
  210.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufRead: Decoding message...");
  211.     /* Decode message.  Again, if something goes wrong, we have no choice    */
  212.     /* but tho close the file descriptor (since its state is screwed up),    */
  213.     /* and return EBADF.                                                     */
  214.     if (cinfo->auth.encode(&cinfo->ibuf, &cinfo->obuf, S5_DECODE, cinfo->auth.context) < 0) {
  215. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5BufRead: Decoding failed.");
  216. SETSOCKETERROR(EBADF);
  217. return -1;
  218.     }
  219.     cinfo->obuf.off = 0;
  220.     free(cinfo->ibuf.data);
  221.     cinfo->ibuf.data = NULL;
  222.     
  223.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufRead: Done");
  224.     return S5BufFillPacket(&cinfo->obuf, ibuf, ilen, ioflags);
  225. }
  226. int S5BufWritePacket(S5IOHandle fd, S5IOInfo *cinfo, char *obuf, int olen, int ioflags) {
  227.     S5Packet buf[2];
  228.     int elen;
  229.     if (!cinfo || !cinfo->auth.encode || olen <= 0) {
  230. return SENDSOCKET(fd, obuf, olen, ioflags);
  231.     }
  232.     
  233.     buf[0].data = obuf; buf[0].len = olen; buf[0].off = olen;
  234.     buf[1].data = NULL; buf[1].len = 0;    buf[1].off = 0;
  235.     
  236.     if ((elen = cinfo->auth.encode(&buf[0], &buf[1], S5_ENCODE, cinfo->auth.context)) < 0) {
  237. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: encapsulating packet failed");
  238. SETSOCKETERROR(EBADF);
  239. return -1;
  240.     }
  241.     
  242.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: Sending encapsulated packet");
  243.     /* An easy thing to do is make sure we can write the whole message by    */
  244.     /* making the file descriptor blocking...ugh.                            */
  245.     elen = S5BufPutPacket(fd, buf[1].data, buf[1].len, ioflags);
  246.     free(buf[1].data);
  247.     if (elen < 0) {
  248.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: Network failure");
  249. return -1;
  250.     } else {
  251. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: Done");
  252.         return olen;
  253.     }
  254. }
  255. void S5BufSetupContext(S5IOInfo *cinfo) {
  256.     cinfo->fd           = S5InvalidIOHandle;
  257.     cinfo->ibuf.data    = NULL;
  258.     cinfo->obuf.data    = NULL;
  259.     cinfo->auth.context = NULL;
  260.     cinfo->auth.clean   = NULL;
  261.     cinfo->auth.encode  = NULL;
  262.     cinfo->auth.check   = NULL;
  263. }
  264. void S5BufCleanContext(S5IOInfo *cinfo) {
  265.     if (!cinfo) return;
  266.     
  267.     if (cinfo->auth.clean) cinfo->auth.clean(cinfo->auth.context);
  268.     if (cinfo->fd != S5InvalidIOHandle) CLOSESOCKET(cinfo->fd);
  269.     if (cinfo->ibuf.data) free(cinfo->ibuf.data);
  270.     if (cinfo->obuf.data) free(cinfo->obuf.data);
  271.     S5BufSetupContext(cinfo);
  272. }