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

代理服务器

开发平台:

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: msg.c,v 1.30.2.1.2.3 1998/07/17 19:57:01 wlu Exp $
  8.  */
  9. /* This file contains functions support reliable message transport under any */
  10. /* (UDP or TCP) protocol.                                                    */
  11. #include "socks5p.h"
  12. #include "buffer.h"
  13. #include "block.h"
  14. #include "msg.h"
  15. #include "log.h"
  16. int S5IORecv(S5IOHandle fd, S5IOInfo *info, char *buf, int size, int ioflags, int libflags, double *timerm) {
  17.     int nr, sval, rlen = size;
  18.     struct timeval sv, *svpt;
  19.     fd_set fds, b;
  20.     
  21. #ifdef STRICT_TIMEOUT
  22.     struct timeval ts, te;
  23. #endif
  24.     if (libflags & S5_IOFLAGS_TIMED && !timerm) {
  25. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: NULL timeout pointer passed");
  26. SETSOCKETERROR(ETIMEDOUT);
  27. return -1;
  28.     }
  29.     
  30.     if ((libflags & S5_IOFLAGS_NBYTES) && !(libflags & S5_IOFLAGS_RESTART)) {
  31. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: Warning: Cannot reliably read n bytes and not handle restarts");
  32.     }
  33.     
  34.     /* We may have read in some stuff and buffered it.  Rather than replace  */
  35.     /* select, lets just read the stuff *out* of the buffer first...         */
  36.     while (1) {
  37. if ((sval = S5BufCheckData(fd, info)) < 0) return -1;
  38. if (sval == 0) break;
  39. if ((nr = S5BufReadPacket(fd, info, buf, rlen, ioflags)) < 0) return -1;
  40. if (nr == 0) return (size - rlen);
  41. rlen -= nr; buf += nr;
  42. if (!(libflags & S5_IOFLAGS_NBYTES)) return nr;
  43. if (rlen == 0) return size;
  44.     }
  45.     /* Read again and again until we have an error, we run out of time, or   */
  46.     /* we just read all that we wanted to.  If STRICT_TIMEOUT is defined,    */
  47.     /* subtract the amount of time we've spent at each point form the time   */
  48.     /* we are allowing *total*...This is kind of expensive...An alternative, */
  49.     /* which has nearly the same consequences is is to spend that amount of  */
  50.     /* time *each* read.  If the data is too interspersed, it will die...    */
  51.     FD_ZERO(&b);
  52.     FD_SET(fd, &b);
  53.     
  54.     for (fds = b; rlen > 0; fds = b) {
  55. if (libflags & S5_IOFLAGS_TIMED) {
  56.     sv.tv_sec  = (int)*timerm;
  57.     sv.tv_usec = (int)((*timerm - (double)sv.tv_sec) * 1000000.0);
  58. #ifdef STRICT_TIMEOUT
  59.     if (gettimeofday(&ts, NULL) < 0) {
  60. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: gettimeofday failed: %m");
  61. SETSOCKETERROR(ETIMEDOUT);
  62. goto interrupted;
  63.     }
  64. #endif
  65. } else {
  66.     sv.tv_sec = 0;
  67.     sv.tv_usec = 0;
  68. }
  69. if (libflags & S5_IOFLAGS_TIMED) svpt = &sv;
  70. else if (ISNBLOCK(fd) && !(libflags & S5_IOFLAGS_NBYTES)) svpt = &sv;
  71. else svpt = NULL;
  72. if ((sval = REAL(select)(fd + 1, &fds, NULL, NULL, svpt)) == 0) {
  73.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "S5IORecv: select failed: Timed out");
  74.     if (libflags & S5_IOFLAGS_TIMED) SETSOCKETERROR(ETIMEDOUT);
  75. #if defined(sun) && !defined(__svr4__)
  76.             else SETSOCKETERROR(EWOULDBLOCK);
  77. #else
  78.             else SETSOCKETERROR(EAGAIN);
  79. #endif
  80.     sval = -1;
  81.     goto interrupted;
  82. }
  83. #ifdef STRICT_TIMEOUT
  84. if (libflags & S5_IOFLAGS_TIMED) {
  85.     if (gettimeofday(&te, NULL) < 0) {
  86. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: gettimeofday failed: %m");
  87. SETSOCKETERROR(ETIMEDOUT);
  88.         sval = -1;
  89. goto interrupted;
  90.     }
  91.     *timerm -= (te.tv_sec  - ts.tv_sec);
  92.     *timerm -= (te.tv_usec - ts.tv_usec)/1000000.0;
  93.     if (*timerm < 0.0) *timerm = 0.0;
  94. }
  95. #endif
  96. if (sval < 0) {
  97.     if (ISSOCKETERROR(EINTR) && libflags & S5_IOFLAGS_RESTART) continue;
  98.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: Select failed: %m");
  99.     goto interrupted;
  100. }
  101. while (rlen > 0) {
  102.     switch ((sval = S5BufCheckPacket(fd, info))) {
  103. case 0:
  104. case -1: goto interrupted;
  105. default: break;
  106.     }
  107.             /* packet is not available...                                    */
  108.     if (sval < 0) break;
  109.       if ((nr = S5BufReadPacket(fd, info, buf, rlen, ioflags)) <= 0) {
  110. sval = nr;
  111.   goto interrupted;
  112.     }
  113.     if (!(libflags & S5_IOFLAGS_NBYTES)) return nr;
  114.          rlen -= nr;
  115.     buf  += nr;
  116.         }
  117.         if (sval < 0 && !(libflags & S5_IOFLAGS_NBYTES)) {
  118.     sval = -1;
  119.     goto interrupted;
  120. }
  121.     }
  122.     
  123.     return size;
  124. interrupted:
  125.     /* We read some data in, but we were interrupted and we aren't supposed  */
  126.     /* to restart... So we have to store what we've read so far in info...   */
  127.     if (S5BufUnreadPacket(info, buf-(size-rlen), size-rlen)) {
  128.         /* Nowhere to store what we've read... Bummer...                     */
  129.     }
  130.     return sval;
  131. }
  132. int S5IOSend(S5IOHandle fd, S5IOInfo *info, char *buf, int size, int flags, int libflags, double *timerm) {
  133.     struct timeval sv, *svpt;
  134.     int nw, wlen, sval;
  135.     fd_set fds, b;
  136.     
  137. #ifdef STRICT_TIMEOUT
  138.     struct timeval ts, te;
  139. #endif
  140.     if (libflags & S5_IOFLAGS_TIMED && !timerm) {
  141. SETSOCKETERROR(ETIMEDOUT);
  142. return -1;
  143.     }
  144.     
  145.     if ((libflags & S5_IOFLAGS_NBYTES) && !(libflags & S5_IOFLAGS_RESTART)) {
  146. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: Warning: Cannot reliably write n bytes and not handle restarts");
  147.     }
  148.     
  149.     FD_ZERO(&b);
  150.     FD_SET(fd, &b);
  151.     
  152.     for (fds = b, wlen = size; wlen > 0; fds = b) {
  153. if (libflags & S5_IOFLAGS_TIMED) {
  154.     sv.tv_sec  = (int)*timerm;
  155.     sv.tv_usec = (int)((*timerm - (double)sv.tv_sec) * 1000000.0);
  156.     
  157. #ifdef STRICT_TIMEOUT
  158.     if (gettimeofday(&ts, NULL) < 0) {
  159. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: gettimeofday failed: %m");
  160. SETSOCKETERROR(ETIMEDOUT);
  161. return -1;
  162.     }
  163. #endif
  164. } else {
  165.     sv.tv_sec = 0;
  166.     sv.tv_usec = 0;
  167. }
  168. if (libflags & S5_IOFLAGS_TIMED) svpt = &sv;
  169. else if (ISNBLOCK(fd) && !(libflags & S5_IOFLAGS_NBYTES)) svpt = &sv;
  170. else svpt = NULL;
  171. if ((sval = REAL(select)(fd + 1, NULL, &fds, NULL, svpt)) == 0) {
  172.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "S5IOSend: select failed: Timed out");
  173.     if (libflags & S5_IOFLAGS_TIMED) SETSOCKETERROR(ETIMEDOUT);
  174. #if defined(sun) && !defined(__svr4__)
  175.             else SETSOCKETERROR(EWOULDBLOCK);
  176. #else
  177.             else SETSOCKETERROR(EAGAIN);
  178. #endif
  179.     return -1;
  180. }
  181. #ifdef STRICT_TIMEOUT
  182. if (libflags & S5_IOFLAGS_TIMED) {
  183.     if (gettimeofday(&te, NULL) < 0) {
  184. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: gettimeofday failed: %m");
  185. SETSOCKETERROR(ETIMEDOUT);
  186. return -1;
  187.     }
  188.     
  189.     *timerm -= (te.tv_sec  - ts.tv_sec);
  190.     *timerm -= (te.tv_usec - ts.tv_usec)/1000000.0;
  191.     if (*timerm < 0.0) *timerm = 0.0;
  192. }
  193. #endif
  194. if (sval < 0) {
  195.     if (ISSOCKETERROR(EINTR) && libflags & S5_IOFLAGS_RESTART) continue;
  196.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: Select failed: %m");
  197.     return -1;
  198. }
  199. do {
  200.     if ((nw = S5BufWritePacket(fd, info, buf, wlen, flags)) > 0) break;
  201.             if (ISSOCKETERROR(EINTR) && !(libflags & S5_IOFLAGS_RESTART)) break;
  202.             if ((ISSOCKETERROR(EWOULDBLOCK) || ISSOCKETERROR(EAGAIN)) && !(libflags & S5_IOFLAGS_NBYTES)) break;
  203.     nw = 0;
  204.         } while (S5IOCheck(fd) >= 0);
  205. if (nw < 0) {
  206.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING,  0, "S5IOSend: failed: %m");
  207.     return nw;
  208. }
  209. if (nw == 0) {
  210.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING,  0, "S5IOSend: peer closed");
  211.     SETSOCKETERROR(EPIPE);
  212.     return -1;
  213. }
  214. if (!(libflags & S5_IOFLAGS_NBYTES)) return nw;
  215. wlen -= nw;
  216. buf  += nw;
  217.     }
  218.     
  219.     return size;
  220. }
  221. /* See what's going on with a socket -- is the connection still valid?       */
  222. int S5IOCheck(S5IOHandle fd) {
  223.     struct timeval tv = { 0, 0 };
  224.     fd_set rfds, b;
  225.     char dummy;
  226.     int sv, n;
  227.     FD_ZERO(&b);
  228.     FD_SET(fd, &b);
  229.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5IOCheck: Checking socket status");
  230.     /* Poll the file descriptor real quick, and see what comes back...       */
  231.     while (1) {
  232. rfds = b; 
  233.         switch ((sv = REAL(select)(fd+1, &rfds, NULL, NULL, &tv))) {
  234.     case 1:
  235.         /* Something happened -- either an error or data, ok to recv */
  236.         n = RECVSOCKET(fd, &dummy, 1, MSG_PEEK);
  237.         if (n < 0 && ISSOCKETERROR(EINTR)) continue;
  238. else if (n <= 0) {
  239.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(1), 0, "S5IOCheck: recv failed: %m");
  240.     return -1;
  241.         }
  242.         /* fallthrough -- there is real data there...                */
  243.     case 0:
  244.         /* Nothing's happening -- no error, all's ok.                */
  245.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5IOCheck: ok");
  246.         return sv;
  247.     default:
  248.         /* Not a valid socket (?).                                   */
  249.                 if (ISSOCKETERROR(EINTR)) continue;
  250.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOCheck: select failed: %m");
  251.         return -1;
  252.         }
  253.     }
  254. }