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

代理服务器

开发平台:

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: select.c,v 1.34.4.3 1998/02/13 23:12:12 wlu Exp $
  8.  */
  9. #define HIDEORIG
  10. #include "socks5p.h"
  11. #include "buffer.h"
  12. #include "wrap.h"
  13. #include "addr.h"
  14. #include "protocol.h"
  15. #include "libproto.h"
  16. #include "cache.h"
  17. #include "msg.h"
  18. #include "log.h"
  19. #define NBCONN(x)   (((x)->cmd == SOCKS_CONNECT) && ((x)->status == CON_INPROGRESS))
  20. #define BUFFERED(x) (((x)->cmd != SOCKS_UDP) && ((x)->pri) && ((x)->pri->cinfo.auth.encode))
  21. /* wrapper around the select system call.                                    */
  22. int LIBPREFIX(select)(S5IOHandle width, fd_set *rfdsp, fd_set *wfdsp, fd_set *efdsp, struct timeval *timeout) {
  23.     fd_set rfs, wfs, efs, w2rfs;
  24.     int n, nbc = 0, nours = 0, size = sizeof(fd_set);
  25.     struct timeval start, end;
  26.     lsSocksInfo *pcon;
  27. #ifdef FOR_SHARED_LIBRARY
  28.     if (lsInRLDFunctions || lsInWrapFunction) return REAL(select)(width, rfdsp, wfdsp, efdsp, timeout);
  29. #endif
  30.     lsInWrapFunction = 1;
  31.     LIBPREFIX2(init)("libsocks5");
  32.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "SOCKS select: FAKE");
  33.     /* If we're not looking at read or write readiness, we can't really do   */
  34.     /* anything, so just return the real select...                           */
  35.     if (!rfdsp && !wfdsp) {
  36. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "SCKS select: REAL: No read/write file descriptors");
  37.      lsInWrapFunction = 0;
  38. return REAL(select)(width, NULL, NULL, efdsp, timeout);
  39.     }
  40.     /* Setup the back up file descriptor sets in case we end up looping...   */
  41.     /* Make our best effort not to look at or modify *fdsp beyond size bytes */
  42.     /* out.                                                                  */
  43.     FD_ZERO(&rfs); 
  44.     FD_ZERO(&wfs); 
  45.     FD_ZERO(&efs);
  46.     FD_ZERO(&w2rfs);
  47.     if (rfdsp) memcpy(&rfs, rfdsp, size);
  48.     if (wfdsp) memcpy(&wfs, wfdsp, size);
  49.     if (efdsp) memcpy(&efs, efdsp, size);
  50.     for (pcon = lsConList; pcon; pcon = pcon->next) {
  51. if (pcon->fd >= width) continue;
  52. if (pcon->cmd == SOCKS_UDP) continue;
  53. if (!pcon->pri || pcon->pri->how == DIRECT) continue;
  54. /* The closest thing to anything that makes any sense for            */
  55. /* non-blocking connects is to connect to the server, and wait for   */
  56. /* it to connect to the end machine (presumably, thats where the     */
  57. /* time is spent).  So, we're really looking for read-readiness in   */
  58. /* the form of a response from the server, not write-readiness in    */
  59. /* the form of a connect...so, switch them.                          */
  60. if (wfdsp && FD_ISSET(pcon->fd, &wfs) && NBCONN(pcon)) {
  61.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Moving fd: %d from write to read set", pcon->fd);
  62.     FD_SET(pcon->fd, &rfs);
  63.     FD_SET(pcon->fd, &w2rfs);
  64.     FD_CLR(pcon->fd, &wfs);
  65.     nbc++;
  66. }
  67. /* Find out how many of "our" file descriptors we're going to be     */
  68. /* looking at.  If we find this number is 0, we can just return the  */
  69. /* real select.                                                      */
  70. if (FD_ISSET(pcon->fd, &rfs) || FD_ISSET(pcon->fd, &wfs)) {
  71.     nours++;
  72. }
  73.     }
  74.     /* If we didn't find any of our file descriptors being examined, just    */
  75.     /* return the real select, we won't be doing anything...                 */
  76.     if (nours == 0) {
  77. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "No file descriptors used by socks; calling real select");
  78.      lsInWrapFunction = 0;
  79. return REAL(select)(width, rfdsp, wfdsp, efdsp, timeout);
  80.     }
  81.     if (!rfdsp && nbc) {
  82. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Using back up read set because we weren't originally interested in reads");
  83. rfdsp = &rfs;
  84.     }
  85.     /* Before calling the select with timeout, we will check the readable    */
  86.     /* fdsets whether their buffer has something ready for them.             */
  87.     if (rfdsp && rfdsp != &rfs) {
  88.         n = 0;
  89.         FD_ZERO(rfdsp);
  90.         if (wfdsp) FD_ZERO(wfdsp);
  91.         if (efdsp) FD_ZERO(efdsp);
  92.         for (pcon = lsConList; pcon; pcon = pcon->next) {
  93.             if (pcon->fd >= width) continue;
  94.     if (pcon->cmd == SOCKS_UDP) continue;
  95.     if (!pcon->pri || pcon->pri->how == DIRECT) continue;
  96.             if (NBCONN(pcon)) continue;
  97.     if (!FD_ISSET(pcon->fd, &rfs)) continue;
  98.             if (BUFFERED(pcon) && S5BufCheckData(pcon->fd, &pcon->pri->cinfo)) {
  99.                 FD_SET(pcon->fd, rfdsp);
  100.                 n++;
  101.             }
  102.         }
  103.         if (n > 0) {
  104.             lsInWrapFunction = 0;
  105.             return n;
  106.         }
  107.     }
  108.     if (timeout) gettimeofday(&start, NULL);
  109.     for (;;) {
  110. if (rfdsp) memcpy(rfdsp, &rfs, size);
  111. if (wfdsp) memcpy(wfdsp, &wfs, size);
  112. if (efdsp) memcpy(efdsp, &efs, size);
  113. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Select: Selecting");
  114. if ((n = REAL(select)(width, rfdsp, wfdsp, efdsp, timeout)) <= 0) {
  115.          lsInWrapFunction = 0;
  116.     return n;
  117. }
  118. /* If we had a non-blocking connecting file descriptor which become  */
  119. /* read-ready, take care of it...If it didn't really become          */
  120. /* read-ready, mark it as an error...                                */
  121. /*                                                                   */
  122. /* For read file descriptors that became read-ready and have special */
  123. /* (i.e. buffered) read fucntions, we want to make sure that the     */
  124. /* whole message is there before we read.  We also don't want to     */
  125. /* spin forever, so we'll buffer the data that we do read...         */
  126. /*                                                                   */
  127. /* We also mark file descriptors which have previously buffered data */
  128. /* that was already ready to be read but hasn't been.                */
  129. /*                                                                   */
  130.         /* For non-blocking connecting file descriptor, we have to handle    */
  131.         /* the socks reply.                                                  */
  132. /*                                                                   */
  133.         /* For non-blocking bind/accept file descriptor, we also have to     */
  134.         /* the socks reply.                                                  */
  135. if (rfdsp) {
  136.     for (pcon = lsConList; pcon; pcon = pcon->next) {
  137. if (pcon->fd >= width) continue;
  138.         if (pcon->cmd == SOCKS_UDP) continue;
  139.         if (!pcon->pri || pcon->pri->how == DIRECT) continue;
  140. if (!FD_ISSET(pcon->fd, rfdsp)) continue;
  141. if (NBCONN(pcon)) {
  142.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Select: Nonblocking connect is read ready");
  143.     if (lsLibReadResponse(pcon) < 0) {
  144.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Select: Failed to read response: %m");
  145. SETSOCKETERROR(pcon->serrno);
  146.         pcon->status = CON_NOTESTABLISHED;
  147.                     } else {
  148.                         pcon->status = CON_ESTABLISHED;
  149.                         lsLastCon = pcon;
  150.                     }
  151.                     if (FD_ISSET(pcon->fd, &w2rfs)) {
  152.                         FD_CLR(pcon->fd, rfdsp);
  153.                         FD_SET(pcon->fd, wfdsp);
  154.                     }
  155. } else if (BUFFERED(pcon)) {
  156.     if (S5BufCheckPacket(pcon->fd, &pcon->pri->cinfo) == -2) {
  157. FD_CLR(pcon->fd, rfdsp);
  158. n--;
  159.     }
  160. }
  161.     }
  162. }
  163. if (n > 0) {
  164.          lsInWrapFunction = 0;
  165.     return n;
  166. }
  167. if (!timeout) continue;
  168. gettimeofday(&end, NULL);
  169. timeout->tv_sec  -= (end.tv_sec  - start.tv_sec);
  170. timeout->tv_usec -= (end.tv_usec - start.tv_usec);
  171. while (timeout->tv_usec < 0 && timeout->tv_sec > 0) {
  172.     timeout->tv_sec  -= 1;
  173.     timeout->tv_usec += 1000000;
  174. }
  175. if (timeout->tv_sec < 0 || timeout->tv_usec < 0) {
  176.          lsInWrapFunction = 0;
  177.     return 0;
  178. }
  179.     }
  180. }