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

代理服务器

开发平台:

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: socket.c,v 1.94.2.2.2.12 1998/10/05 21:34:51 wlu Exp $
  8.  */
  9. /* This file contains all of the socket creation and configuration functions */
  10. /* that are used by the daemon.  There are a couple of utility functions     */
  11. /* here becuase they deal with the sockets themselves...                     */
  12. #include "socks5p.h"
  13. #include "daemon.h"
  14. #include "validate.h"
  15. #include "msgids.h"
  16. #include "socket.h"
  17. #include "proxy.h"
  18. #include "sema.h"
  19. #include "log.h"
  20. #include "threads.h"
  21. #include "sigfix.h"
  22. #if defined(linux) && defined(USE_THREADS)
  23. #undef SIGUSR1
  24. #define SIGUSR1 SIGUNUSED
  25. #endif
  26. /* Two server modes (threading & preforking) work in a master/slave mode,    */
  27. /* these macros make decisions based on that status easier to read           */
  28. #define ISMASTER() (!iamachild && (servermode == PREFORKING || servermode == THREADED))
  29. #define ISSLAVE()  (iamachild  && (servermode == PREFORKING || servermode == THREADED))
  30. static int acceptor  = 0;  /* the pid of the accepting process if threaded   */
  31. static int nconns    = 0;  /* the number of proxies the daemon has had...    */
  32. static int nchildren = 0;  /* the number of children the daemon has had...   */
  33. static int iamachild = 0;  /* Am I a child, or the parent...                 */
  34. static void *asem = NULL;
  35. static S5IOHandle in = S5InvalidIOHandle;
  36. static sig_atomic_t hadfatalsig = 0;  /* Has a sighup/sigusr1 occured?       */
  37. static sig_atomic_t hadsigint   = 0;  /* Has a sigint         occured?       */
  38. static sig_atomic_t hadresetsig = 0;  /* Has a sigusr1        occured?       */
  39. /* A function to collect dead children before they become zombies...  Also,  */
  40. /* It keeps track of how many children are around for preforking...          */
  41. /*                                                                           */
  42. /* On a non-posix system, I suppose calling wait3 or waitpid in a signal     */
  43. /* handler (according to APUE) might not be cool.  Someone will have to      */
  44. /* tell me if this is ever the case, and I'll write code so that reaping is  */
  45. /* done elsewhere.                                                           */
  46. static RETSIGTYPE gravedigger(void) {
  47.     int oerrno = errno, wval, wstatus;
  48.     Sigset_t set = SigBlock(SIGCHLD);
  49.     for (;;) {
  50. #ifdef HAVE_WAITPID
  51. wval = waitpid(-1, &wstatus, WNOHANG);
  52. #else
  53.         wval = wait3(&wstatus, WNOHANG, NULL);
  54. #endif
  55. switch (wval) {
  56.     case -1:
  57. if (errno == EINTR) continue;
  58.     case 0:
  59. errno = oerrno;
  60. SigUnblock(set);
  61. return;
  62.     default:
  63. if (servermode == THREADED) acceptor = 0;
  64. if (nchildren > 0) nchildren--;
  65. }
  66.     }
  67. }
  68. /* Indicate that we had a sigint, so we exit & clean up later                */
  69. static RETSIGTYPE markdone(void) {
  70.     if (hadresetsig) hadresetsig = 0;
  71.     else hadsigint = 1;
  72. }
  73. /* Indicate that we had a sighup, so we can re-read the config file later.   */
  74. static RETSIGTYPE die(void) {
  75.     hadfatalsig = 1;
  76. }
  77. /* Indicate that we had a sigusr, so we start a new server.                  */
  78. static RETSIGTYPE reset(void) {
  79.     hadresetsig = 1;
  80. }
  81. /* fork(), and do the right thing...the right thing is...handle errors and   */
  82. /* incremenent nchildren...pretty simple...                                  */
  83. static int DoFork(void) {
  84.     int pid;
  85.   
  86.     if (nchildren >= nservers) {
  87. errno = EAGAIN;
  88.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Total number of children is %d", nchildren);
  89. return -1;
  90.     }
  91.   
  92.     switch (pid = fork()) {
  93. case 0:
  94.     Signal(SIGHUP,  SIG_DFL);
  95.     Signal(SIGUSR1, SIG_DFL);
  96.     Signal(SIGINT,  SIG_DFL);
  97.             Signal(SIGTERM, SIG_DFL);
  98.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "Child: Starting");
  99.     iamachild = 1;
  100.     return 0;
  101. case -1:
  102.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR,     0, "Fork failed: %m");
  103.     return -1;
  104. default:
  105.     nchildren++; 
  106.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "Parent: %d child%s", nchildren, (nchildren != 1)?"ren":"");
  107.     return pid;
  108.     }
  109. }
  110. static int GetBindIntfc(S5NetAddr *bndaddr) {
  111.     u_short bindport = 0;
  112.     char *tmp = NULL, *tmpaddr = NULL, *tmpport = NULL;
  113.     if (bindif) tmp = strdup(bindif);
  114.     else {
  115.         MUTEX_LOCK(env_mutex);
  116.         tmp = getenv("SOCKS5_BINDINTFC");
  117.         if (tmp) tmp = strdup(tmp);
  118.         MUTEX_UNLOCK(env_mutex);
  119.     }
  120.     if (tmp) {
  121.         if ((tmpport = strchr(tmp, ':'))) {
  122.             *tmpport++ = '';
  123.             if (*tmp) tmpaddr = tmp;
  124.         } else {
  125.             if (isdigit(*tmp) && !strchr(tmp, '.')) tmpport = tmp;
  126.             else tmpaddr = tmp;
  127.         }
  128.     }
  129.  
  130.     if (!tmpaddr) {
  131.        memset((char *)bndaddr, 0, sizeof(S5NetAddr));
  132.        bndaddr->sin.sin_family       = AF_INET;
  133.        bndaddr->sin.sin_addr.s_addr  = htonl(INADDR_ANY);
  134.     } else if (lsName2Addr(tmpaddr, bndaddr) < 0 || bndaddr->sin.sin_addr.s_addr == INVALIDADDR ) {
  135.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, " Invalid address %s specified", tmpaddr);
  136.         return -1;
  137.     }
  138.     if (tmpport) lsName2Port(tmpport, "tcp", &bindport);
  139.     else lsName2Port("socks", "tcp", &bindport);
  140.     if (bindport == INVALIDPORT) bindport = htons(SOCKS_DEFAULT_PORT);
  141.     lsAddrSetPort(bndaddr, bindport);
  142.     if (tmp) free(tmp);
  143.     return 0;
  144. }
  145. static void GetUdpPortRange(void) {
  146.     char *tmp = NULL, *tmpport = NULL;
  147.     tmp = getenv("SOCKS5_UDPPORTRANGE");
  148.     if (tmp) tmp = strdup(tmp);
  149.     if (tmp) {
  150. if ((tmpport = strchr(tmp, '-'))) *tmpport++ = '';
  151. if (*tmp && isdigit(*tmp)) ludpport = (u_short)atoi(tmp);
  152. else {
  153.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, " Invalid udp port range %s", tmp);
  154.     free(tmp);
  155.     return;
  156. }
  157. if (tmpport && *tmpport && isdigit(*tmpport)) hudpport = (u_short)atoi(tmpport);
  158. free(tmp);
  159.     }
  160. }
  161. /* Make a socket with the correct protocol (p), bind it to the right port    */
  162. /* (n, the name or port, the default), and set the function to be called the */
  163. /* socket becomes active (func)...store all this in an fdrec structure for   */
  164. /* convenience's sake...if for any reason something fails and this enry      */
  165. /* should become invalid, the r->fd should be set to -1, so other places     */
  166. /* know to ignore it...                                                      */
  167. static int MakeSocket(int start, S5IOHandle *infd) {
  168.     S5NetAddr bndaddr;
  169.     int on = 1;
  170.     if (!start) {
  171. time_t now = time(NULL);
  172. char tbuf[1024];
  173. MUTEX_LOCK(lt_mutex);
  174. strftime(tbuf, sizeof(tbuf), "%c", localtime(&now));
  175. MUTEX_UNLOCK(lt_mutex);
  176. S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_RESTART, "Socks5 restarting at %s", tbuf);
  177.     }
  178.     if (*infd != S5InvalidIOHandle) {
  179. return 0;
  180.     }
  181.     if (start) {
  182.         if (GetBindIntfc(&bndaddr) < 0) goto cleanup;
  183.     } 
  184.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Socks5 attempting to run on interface %s:%d", ADDRANDPORT(&bndaddr));
  185.     if ((*infd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) {
  186. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socket failed for %s:%d: %m", ADDRANDPORT(&bndaddr));
  187. goto cleanup;
  188.     }
  189.     if (setsockopt(*infd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0) {
  190. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0,  "Turning on address reuse failed for %s:%d: %m", ADDRANDPORT(&bndaddr));
  191. goto cleanup;
  192.     }
  193.   
  194.     if (bind(*infd, (ss *)&bndaddr, sizeof(ssi)) < 0) {
  195. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, MSGID_SERVER_SOCKS_BIND, "Bind failed for %s:%d: %m", ADDRANDPORT(&bndaddr));
  196. goto cleanup;
  197.     }
  198.   
  199.     if (listen(*infd, 5) < 0) {
  200. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Listen failed for %s:%d: %m", ADDRANDPORT(&bndaddr));
  201. goto cleanup;
  202.     }
  203.     /* If we bound, we're the owner, so put our pid in the pidfile.          */
  204. #ifndef DONT_STORE_PID
  205.     if (start) {
  206. char abuf[64], *myfl, *ofile = NULL;
  207. S5IOHandle fd = S5InvalidIOHandle;
  208. pid_t pid = getpid();
  209. struct stat sbuf;
  210.       
  211. MUTEX_LOCK(env_mutex);
  212. myfl = getenv("SOCKS5_PIDFILE");
  213. myfl = myfl?strdup(myfl):strdup(SRVPID_FILE);
  214. MUTEX_UNLOCK(env_mutex);
  215. if ((ofile = malloc(strlen(myfl)+7))) {
  216.     sprintf(ofile, "%s-%d", myfl, (int)ntohs(bndaddr.sin.sin_port));
  217.     free(myfl);
  218.     myfl = ofile;
  219. } else {
  220.     free(myfl);
  221.     myfl = NULL;
  222. }
  223.       
  224. if (myfl) {
  225.     int flags = O_WRONLY | O_CREAT | O_TRUNC;
  226.     /* Open exclusively if the file doesn't exist or if it does, it  */
  227.     /* is a link, and someone else owns it                           */
  228.     if (lstat(myfl, &sbuf) || (S_ISLNK(sbuf.st_mode) && geteuid() != sbuf.st_uid)) flags |= O_EXCL;
  229.     fd = open(myfl, flags, 0644);
  230. }
  231. if (fd == S5InvalidIOHandle) {
  232.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Error: Failed to open pid file: %s: %m", myfl?myfl:"(null)");
  233. } else {
  234.     sprintf(abuf, "%dn", (int)pid);
  235.     WRITEFILE(fd, abuf, strlen(abuf));
  236.     close(fd);
  237. }
  238. if (myfl) free(myfl);
  239.     }
  240. #endif
  241.     return 0;
  242.     
  243.   cleanup:
  244.     if (*infd != S5InvalidIOHandle) CLOSESOCKET(*infd);
  245.     *infd = S5InvalidIOHandle;
  246.     return -1;
  247. }
  248. /* This is called whenever an error occurs that requires a signal to fix.    */
  249. /* If the server is preforking or threaded, the parent begins in this state, */
  250. /* and only children come out of it... If it is normal, this state is        */
  251. /* reached by having a fatal call to accept...                               */
  252. /*                                                                           */
  253. /* Children come here sometimes when they've had fatal signals and need to   */
  254. /* be killed off...                                                          */
  255. static int GetSignals(void *asem, S5IOHandle *infd) {
  256.     Sigset_t set;
  257.     if (iamachild) {
  258.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Childs exiting");
  259.         exit(0);
  260.     }
  261.     /* Block appropriate signals here so that we don't get interrupted while */
  262.     /* we're forking or setting things up...                                 */
  263.     for (set = SigBlock(SIGHUP); ; ) {
  264. /* Do our thing if everything is ok...                               */
  265. if (*infd != S5InvalidIOHandle) {
  266.     switch (servermode) {
  267. case THREADED:
  268.     if (acceptor == 0) acceptor = DoFork();
  269.     if (iamachild) goto done;
  270.     break;
  271. case PREFORKING:
  272.     while (DoFork() > 0);
  273.     if (iamachild) goto done;
  274.     break;
  275.     }
  276. }
  277.         if (servermode == THREADED && (acceptor < 0 && errno != EAGAIN)) {
  278.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "server exiting: fork failed");
  279.             hadsigint = 1;
  280.         }
  281. /* Wait for any signal to arrive, esp SIGCHLD and SIGHUP.  SIGHUP    */
  282. /* will cause a re-read of the config file, everything else: loop.   */
  283. if (!hadfatalsig && !hadsigint && !hadresetsig && *infd != S5InvalidIOHandle) {
  284.     SigPause();
  285. }
  286. if (hadsigint) {
  287.     time_t now = time(NULL);
  288.     char tbuf[1024];
  289.     MUTEX_LOCK(lt_mutex);
  290.     strftime(tbuf, sizeof(tbuf), "%c", localtime(&now));
  291.     MUTEX_UNLOCK(lt_mutex);
  292.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_STOP, "Socks5 Exiting at: %s", tbuf);
  293.     hadresetsig = 0;
  294.             kill(-getpid(), SIGINT);
  295.     if (ISMASTER()) { semdestroy(asem); }
  296.     exit(0);
  297. }
  298. if (!hadfatalsig && !hadresetsig) {
  299.             /* SIGCHLD received...                                           */
  300.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "Parent reaped? (%d child%s)", nchildren, (nchildren != 1)?"ren":"");
  301.             continue;
  302. }
  303. if (hadfatalsig) {
  304.     char *tmp = NULL;
  305.     if (servermode == PREFORKING || servermode == THREADED) {
  306. /* Kill whoever is accepting (all of them if preforking) */
  307. /* and reset the semaphore...                            */
  308. hadresetsig = 1;
  309.                 kill(-getpid(), SIGINT);
  310. if (ISMASTER()) { semreset(asem, 1); } 
  311. acceptor = 0;
  312.     }
  313.     ReadConfig();
  314.     if ((tmp = getenv("SOCKS5_TIMEOUT")) && *tmp) idletimeout = atoi(tmp);
  315.     GetUdpPortRange();
  316. }
  317.  
  318. if (hadresetsig && servermode == THREADED) acceptor = 0;
  319. hadfatalsig = 0;
  320. hadresetsig = 0;
  321.         if (servermode == NORMAL) break;
  322.     }
  323.   done:
  324.     SigUnblock(set);
  325.     return 0;
  326. }
  327. static void DoWork(S5IOHandle sd) {
  328.     int eval;
  329.     if (servermode == NORMAL && (eval = DoFork()) != 0) {
  330. CLOSESOCKET(sd);
  331. if (eval > 0 || errno == EAGAIN) return;
  332. exit(-1);
  333.     }
  334.     eval = HandlePxyConnection(sd);
  335.     if (servermode == PREFORKING || servermode == THREADED) {
  336. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Accept: Done with connection...");
  337. return;
  338.     }
  339.     
  340.     exit(eval);
  341. }
  342. #if defined(USE_THREADS) && defined(HAVE_PTHREAD_H)
  343. static void DoThreadWork(S5IOHandle sd) {
  344.     int len;
  345.     S5NetAddr source;
  346.     S5IOHandle afd = sd;
  347.     for (;;) {
  348. DoWork(afd);
  349. MUTEX_LOCK(accept_mutex);
  350. if (semacquire(asem)) {
  351.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(2), 0, "DoThreadWork: Semaphore failure.");
  352.     MUTEX_UNLOCK(accept_mutex);
  353.     THREAD_EXIT(-1);
  354. }
  355. len = sizeof(source);
  356. memset(&source, 0, len);
  357. while ((afd = accept(in, &source.sa, &len)) == S5InvalidIOHandle && ((errno == EINTR)||(errno == EAGAIN)));
  358. semrelease(asem);
  359. MUTEX_UNLOCK(accept_mutex);
  360. if (afd == S5InvalidIOHandle) {
  361.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(2), 0, "DoThreadWork: accept failure.");
  362.     THREAD_EXIT(-1);
  363. }
  364.     }
  365. }
  366. #endif
  367. /* Get a connection from our input socket.  Then based on the socket's       */
  368. /* data, handle the connection correctly, and go on waiting for more         */
  369. /* connetions...                                                             */
  370. static void GetNetConnection(void) {
  371.     Sigset_t set = SigBlock(ISMASTER()?SIGUSR1:SIGHUP);
  372.     S5IOHandle afd;
  373.     S5NetAddr source;
  374.     int aerrno;
  375.     char *tmp = NULL;
  376. #if !defined(USE_THREADS) || !defined(HAVE_PTHREAD_H)
  377.     if (servermode == THREADED) {
  378. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Warning: Attempt to run server in threaded mode when threads were not a compile time option");
  379. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Warning: Running as a normal standalone server");
  380.         SigUnblock(set);
  381.         set = SigBlock(SIGHUP);
  382. servermode = NORMAL;
  383.     }
  384. #endif
  385.     Signal(SIGUSR1, reset);
  386.     Signal(SIGHUP,  die);
  387.     Signal(SIGCHLD, gravedigger);
  388.     ReadConfig();
  389.     if (MakeSocket(1, &in) < 0) {
  390.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Accept: Failed to make listening socket");
  391.         exit(-1);
  392.     }
  393.     if ((tmp = getenv("SOCKS5_TIMEOUT")) && *tmp) idletimeout = atoi(tmp);
  394.     GetUdpPortRange();
  395.     Signal(SIGINT,  markdone);
  396.     Signal(SIGTERM, markdone);
  397.     if (ISMASTER()) {
  398. asem = semcreate(1);
  399. GetSignals(asem, &in);
  400.     }
  401.     if (ISMASTER()) {
  402. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Error: Master reached slave code in GetNetConnection");
  403. exit(EXIT_ERR);
  404.     }
  405.     if (ISSLAVE()) {
  406. hadsigint = 0;
  407. hadresetsig = 0;
  408.     }
  409.     for (;;) {
  410. int len = sizeof(S5NetAddr);
  411. /* If an important signal has arrived or the acc fd is corrupted,    */
  412. /* got into the signal waiting state (and possibly exit - if child). */
  413. if (hadfatalsig || hadsigint || in == S5InvalidIOHandle) {
  414.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(2), 0, "Accept: Processing exception");
  415.     GetSignals(asem, &in);
  416.     hadfatalsig = 0;
  417. }
  418. if (SigPending(ISSLAVE()?SIGUSR1:SIGHUP)) {
  419.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(2), 0, "Accept: Waiting for a pending fatal signal...");
  420.     while (!hadfatalsig) SigPause();
  421.     continue;
  422. }
  423. /* Try to accept a connection.  We may receive a signal (HUP or      */
  424. /* USR1) here, if that happens, accept should return -1, with errno  */
  425. /* set to EINTR.  We'll handle that later, after we release the      */
  426. /* semaphore.  If we've already received a signal, don't bother      */
  427. /* accepting the connection, just set pri->in to -1 and errno to     */
  428. /* EINTR, to simulate having received the signal here.               */
  429. if (hadfatalsig) {
  430.     afd    = S5InvalidIOHandle;
  431.     aerrno = EINTR;
  432. } else {
  433.     /* For some reason (thanks to Rich Stevens for pointing this     */
  434.     /* out), System 5 is unhappy about a bunch of people calling     */
  435.     /* accept.  So we'll add some locks around it to synchronize     */
  436.     /* access...                                                     */
  437.     if (servermode == THREADED) MUTEX_LOCK(accept_mutex);
  438.     if (ISSLAVE()) {
  439. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "Accept: Acquiring semaphore");
  440. SigUnblock(set);
  441. if (semacquire(asem)) {
  442.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(2), 0, "Accept: Semaphore failure.");
  443.          if (servermode == THREADED) {
  444. MUTEX_UNLOCK(accept_mutex);
  445. if (nconns < nthreads) kill(getppid(), SIGUSR1);
  446. THREAD_EXIT(-1);
  447.     } else { 
  448. CLOSESOCKET(in);
  449. exit(-1);
  450.     }
  451. }
  452. set = SigBlock((servermode == NORMAL)?SIGHUP:SIGUSR1);
  453.     }
  454.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Accept: Waiting on accept or a signal");
  455.     SigUnblock(set);
  456.     while ((afd = accept(in, &source.sa, &len)) == S5InvalidIOHandle && errno == EAGAIN);
  457.     if (afd == S5InvalidIOHandle) aerrno = errno;
  458.     set = SigBlock((servermode == NORMAL)?SIGHUP:SIGUSR1);
  459. }
  460. /* Since we've got the connection, release the semaphore.            */
  461. /*                                                                   */
  462. /* We don't have to worry about releasing a reset semaphore, if we   */
  463. /* received a signal in the meantime, since semreset *should* create */
  464. /* a whole new semaphore, so we'll be releasing one which no one     */
  465. /* else looks at anymore.                                            */
  466. if (ISSLAVE()) {
  467.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "Accept: Releasing semaphore");
  468.     semrelease(asem);
  469.     if (servermode == THREADED) MUTEX_UNLOCK(accept_mutex);
  470. }
  471. /* Do the work according to the protocol to be passed on pri->in.    */
  472. /* When we're done, clean things up so we can do it all again...     */
  473. if (afd == S5InvalidIOHandle) {
  474.     /* We have to make sure the error wasn't too serious.  If it     */
  475.     /* was, quit, unless we are the parent, in which caes we we wait */
  476.     /* for a HUP to tell us things are fixed.                        */
  477.     if (aerrno == EINTR) continue;
  478.     errno = aerrno;
  479.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, MSGID_SERVER_SOCKS_ACCEPT, "Accept: Accept failed: %m");
  480.             if (ISSLAVE()) {
  481. if (servermode == THREADED) {
  482.     if (nconns < nthreads) kill(getppid(), SIGUSR1);
  483.     THREAD_EXIT(-1);
  484. } else {
  485.     CLOSESOCKET(in);
  486.     exit(-1);
  487. }
  488.     }
  489.             /* It is NORMAL mode and system resource is exhausted. sleep     */
  490.     /* while and continue...                                         */
  491.     sleep(180);
  492. } else if (servermode == THREADED) {
  493. #if defined(USE_THREADS) && defined(HAVE_PTHREAD_H)
  494.     THREAD_T tid;
  495.     ATTR_T attr;
  496.     sigset_t set, oset;
  497.     if ((nconns + 1) >= nthreads) {
  498. kill(getppid(), SIGUSR1);
  499. nconns++;
  500. DoThreadWork(afd);
  501.     }
  502.     sigemptyset(&set);
  503.             THREAD_ATTR_INIT(attr);
  504.             THREAD_ATTR_SETSTACKSIZE(&attr, 51200);
  505.             THREAD_ATTR_SETSCOPE(attr, PTHREAD_SCOPE_SYSTEM);
  506.             THREAD_ATTR_SETDETACHSTATE(attr, PTHREAD_CREATE_DETACHED);
  507.             THREAD_SIGMASK(SIG_BLOCK, set, oset);
  508.     
  509.             if (THREAD_CREATE(&tid, attr, (void *(*)P((void *)))DoThreadWork, (void *)afd) < 0) {
  510. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Accept: Thread creation failed: %m");
  511. kill(getppid(), SIGUSR1);
  512. nconns++;
  513. DoThreadWork(afd);
  514.     } else nconns++;
  515.             THREAD_DETACH(tid);
  516.     THREAD_SIGMASK(SIG_UNBLOCK, set, oset);
  517. #endif
  518.     afd = S5InvalidIOHandle;
  519. } else {
  520.     if (servermode == SINGLESHOT) CLOSESOCKET(in);
  521.          nconns++;
  522.     DoWork(afd);
  523. }
  524.     }
  525. }
  526. /* Setup a connection which has already been set up for us by inetd.         */
  527. /* Basically, we're just filling in the right structures and calling the     */
  528. /* work function, HandleProxyConnection...                                   */
  529. void GetStdioConnection(void) {
  530.     char *tmp = NULL;
  531.     ReadConfig();
  532.     if ((tmp = getenv("SOCKS5_TIMEOUT")) && *tmp) idletimeout = atoi(tmp);
  533.     GetUdpPortRange();
  534.     fclose(stdout);
  535.     fclose(stderr);
  536.     DoWork(STDIN_FILENO);
  537. }
  538. void GetConnection() {
  539.     Signal(SIGPIPE, SIG_IGN);
  540.     if (servermode == INETD) GetStdioConnection();
  541.     else                     GetNetConnection();
  542. }