int serv_loop() { int cs, ss = 0; struct sockaddr_storage cl; fd_set readable; int i, n, len; char cl_addr[NI_MAXHOST]; char cl_name[NI_MAXHOST]; int error; pid_t pid; #ifdef USE_THREAD if (threading) { blocksignal(SIGHUP); blocksignal(SIGINT); blocksignal(SIGUSR1); } #endif for (;;) { readable = allsock; MUTEX_LOCK(mutex_select); n = select(maxsock+1, &readable, 0, 0, 0); if (n <= 0) { if (n < 0 && errno != EINTR) { msg_out(warn, "select: %m"); } MUTEX_UNLOCK(mutex_select); continue; } #ifdef USE_THREAD if ( ! threading ) { #endif /* handle any queued signal flags */ if (FD_ISSET(sig_queue[0], &readable)) { if (ioctl(sig_queue[0], FIONREAD, &i) != 0) { msg_out(crit, "ioctl: %m"); exit(-1); } while (--i >= 0) { char c; if (read(sig_queue[0], &c, 1) != 1) { msg_out(crit, "read: %m"); exit(-1); } switch(c) { case 'H': /* sighup */ reload(); break; case 'C': /* sigchld */ reapchild(); break; case 'T': /* sigterm */ cleanup(); break; default: break; } } } #ifdef USE_THREAD } #endif for ( i = 0; i < serv_sock_ind; i++ ) { if (FD_ISSET(serv_sock[i], &readable)) { n--; break; } } if ( n < 0 || i >= serv_sock_ind ) { MUTEX_UNLOCK(mutex_select); continue; } len = sizeof(struct sockaddr_storage); cs = accept(serv_sock[i], (struct sockaddr *)&cl, (socklen_t *)&len); if (cs < 0) { if (errno == EINTR #ifdef SOLARIS || errno == EPROTO #endif || errno == EWOULDBLOCK || errno == ECONNABORTED) { ; /* ignore */ } else { /* real accept error */ msg_out(warn, "accept: %m"); } MUTEX_UNLOCK(mutex_select); continue; } MUTEX_UNLOCK(mutex_select); #ifdef USE_THREAD if ( !threading ) { #endif if (max_child > 0 && cur_child >= max_child) { msg_out(warn, "child: cur %d; exeedeing max(%d)", cur_child, max_child); close(cs); continue; } #ifdef USE_THREAD } #endif error = getnameinfo((struct sockaddr *)&cl, len, cl_addr, sizeof(cl_addr), NULL, 0, NI_NUMERICHOST); if (resolv_client) { error = getnameinfo((struct sockaddr *)&cl, len, cl_name, sizeof(cl_name), NULL, 0, 0); msg_out(norm, "%s[%s] connected", cl_name, cl_addr); } else { msg_out(norm, "%s connected", cl_addr); strncpy(cl_name, cl_addr, sizeof(cl_name)); } i = validate_access(cl_addr, cl_name); if (i < 1) { /* access denied */ close(cs); continue; } set_blocking(cs); #ifdef USE_THREAD if (!threading ) { #endif blocksignal(SIGHUP); blocksignal(SIGCHLD); pid = fork(); switch (pid) { case -1: /* fork child failed */ printf("\nfork failed\n"); break; case 0: /* i am child */ for ( i = 0; i < serv_sock_ind; i++ ) { close(serv_sock[i]); } setsignal(SIGCHLD, SIG_DFL); setsignal(SIGHUP, SIG_DFL); releasesignal(SIGCHLD); releasesignal(SIGHUP); ss = proto_socks(cs); if ( ss == -1 ) { close(cs); /* may already be closed */ exit(1); } printf("\nrelaying\n"); relay(cs, ss); exit(0); default: /* may be parent */ printf("\nadding proc\n"); proclist_add(pid); break; } close(cs); releasesignal(SIGHUP); releasesignal(SIGCHLD); #ifdef USE_THREAD } else { ss = proto_socks(cs); if ( ss == -1 ) { close(cs); /* may already be closed */ continue; } relay(cs, ss); } #endif } }
int serv_loop() { SOCKS_STATE state; SOCK_INFO si; CL_INFO client; int cs; fd_set readable; int i, n, len; int error; pid_t pid; memset(&state, 0, sizeof(state)); memset(&si, 0, sizeof(si)); memset(&client, 0, sizeof(client)); state.si = &si; #ifdef USE_THREAD if (threading) { blocksignal(SIGHUP); blocksignal(SIGINT); blocksignal(SIGUSR1); } #endif for (;;) { readable = allsock; MUTEX_LOCK(mutex_select); n = select(maxsock+1, &readable, 0, 0, 0); if (n <= 0) { if (n < 0 && errno != EINTR) { msg_out(warn, "select: %m"); } MUTEX_UNLOCK(mutex_select); continue; } #ifdef USE_THREAD if ( ! threading ) { #endif /* handle any queued signal flags */ if (FD_ISSET(sig_queue[0], &readable)) { if (ioctl(sig_queue[0], FIONREAD, &i) != 0) { msg_out(crit, "ioctl: %m"); exit(-1); } while (--i >= 0) { char c; if (read(sig_queue[0], &c, 1) != 1) { msg_out(crit, "read: %m"); exit(-1); } switch(c) { case 'H': /* sighup */ reload(); break; case 'C': /* sigchld */ reapchild(); break; case 'T': /* sigterm */ cleanup(); break; default: break; } } } #ifdef USE_THREAD } #endif for ( i = 0; i < serv_sock_ind; i++ ) { if (FD_ISSET(serv_sock[i], &readable)) { n--; break; } } if ( n < 0 || i >= serv_sock_ind ) { MUTEX_UNLOCK(mutex_select); continue; } len = SS_LEN; cs = accept(serv_sock[i], &si.prc.addr.sa, (socklen_t *)&len); si.prc.len = len; if (cs < 0) { if (errno == EINTR #ifdef SOLARIS || errno == EPROTO #endif || errno == EWOULDBLOCK || errno == ECONNABORTED) { ; /* ignore */ } else { /* real accept error */ msg_out(warn, "accept: %m"); } MUTEX_UNLOCK(mutex_select); continue; } MUTEX_UNLOCK(mutex_select); #ifdef USE_THREAD if ( !threading ) { #endif if (max_child > 0 && cur_child >= max_child) { msg_out(warn, "child: cur %d; exeedeing max(%d)", cur_child, max_child); close(cs); continue; } #ifdef USE_THREAD } #endif /* get downstream-side socket name */ len = SS_LEN; getsockname(cs, &si.myc.addr.sa, (socklen_t *)&len); si.myc.len = len; error = getnameinfo(&si.prc.addr.sa, si.prc.len, client.addr, sizeof(client.addr), NULL, 0, NI_NUMERICHOST); if (resolv_client) { error = getnameinfo(&si.prc.addr.sa, si.prc.len, client.name, sizeof(client.name), NULL, 0, 0); msg_out(norm, "%s[%s] connected", client.name, client.addr); } else { msg_out(norm, "%s connected", client.addr); strncpy(client.name, client.addr, sizeof(client.name)); } i = validate_access(&client); if (i < 1) { /* access denied */ close(cs); continue; } set_blocking(cs); state.s = cs; #ifdef USE_THREAD if (!threading ) { #endif blocksignal(SIGHUP); blocksignal(SIGCHLD); pid = fork(); switch (pid) { case -1: /* fork child failed */ break; case 0: /* i am child */ for ( i = 0; i < serv_sock_ind; i++ ) { close(serv_sock[i]); } setsignal(SIGCHLD, SIG_DFL); setsignal(SIGHUP, SIG_DFL); releasesignal(SIGCHLD); releasesignal(SIGHUP); error = proto_socks(&state); if ( error == -1 ) { close(state.s); /* may already be closed */ exit(1); } relay(&state); exit(0); default: /* may be parent */ proclist_add(pid); break; } close(state.s); releasesignal(SIGHUP); releasesignal(SIGCHLD); #ifdef USE_THREAD } else { error = proto_socks(&state); if ( error == -1 ) { close(state.s); /* may already be closed */ /* udp may be dynamically allocated */ if (state.sr.udp != NULL) free(state.sr.udp); continue; } relay(&state); } #endif } }