diff -rc stunnel-4.04/src/client.c stunnel-4.04.with_poll/src/client.c *** stunnel-4.04/src/client.c Wed Jan 1 14:04:39 2003 --- stunnel-4.04.with_poll/src/client.c Fri Mar 28 13:43:07 2003 *************** *** 302,318 **** } static int transfer(CLI *c) { /* transfer data */ fd_set rd_set, wr_set; ! int num, err, fdno; int check_SSL_pending; int ready; - struct timeval tv; fdno=c->sock_rfd->fd; if(c->sock_wfd->fd>fdno) fdno=c->sock_wfd->fd; if(c->ssl_rfd->fd>fdno) fdno=c->ssl_rfd->fd; if(c->ssl_wfd->fd>fdno) fdno=c->ssl_wfd->fd; fdno+=1; c->sock_ptr=c->ssl_ptr=0; sock_rd=sock_wr=ssl_rd=ssl_wr=1; --- 302,334 ---- } static int transfer(CLI *c) { /* transfer data */ + #ifndef PREFER_POLL fd_set rd_set, wr_set; ! int fdno; ! struct timeval tv; ! #else /* PREFER_POLL */ ! struct pollfd fds[4]; /* add one for signal pipe */ ! unsigned int nfds; ! int timeout; ! #endif /* PREFER_POLL */ ! int num, err; int check_SSL_pending; int ready; + #ifndef PREFER_POLL fdno=c->sock_rfd->fd; if(c->sock_wfd->fd>fdno) fdno=c->sock_wfd->fd; if(c->ssl_rfd->fd>fdno) fdno=c->ssl_rfd->fd; if(c->ssl_wfd->fd>fdno) fdno=c->ssl_wfd->fd; fdno+=1; + #else /* PREFER_POLL */ + /* TODO - set it up once, not once per call */ + fds[0].fd = c->sock_rfd->fd; + fds[1].fd = c->sock_wfd->fd; + fds[2].fd = c->ssl_rfd->fd; + fds[3].fd = c->ssl_wfd->fd; + nfds = 4; /* add one for signal pipe */ + #endif /* PREFER_POLL */ c->sock_ptr=c->ssl_ptr=0; sock_rd=sock_wr=ssl_rd=ssl_wr=1; *************** *** 320,325 **** --- 336,342 ---- while(((sock_rd||c->sock_ptr)&&ssl_wr)||((ssl_rd||c->ssl_ptr)&&sock_wr)) { + #ifndef PREFER_POLL FD_ZERO(&rd_set); /* Setup rd_set */ if(sock_rd && c->sock_ptrsock_rfd->fd, &rd_set); *************** *** 346,352 **** --- 363,410 ---- (ssl_wr&&c->sock_ptr) || (sock_wr&&c->ssl_ptr) ? c->opt->timeout_idle : c->opt->timeout_close; tv.tv_usec=0; + /* TODO: why not an error set too? */ ready=sselect(fdno, &rd_set, &wr_set, NULL, &tv); + #else /* PREFER_POLL */ + /* socket input buffer not full*/ + fds[0].events = (sock_rd && c->sock_ptrssl_ptrsock_ptr && SSL_want_read(c->ssl)) + /* I want to SSL_write but read from the underlying */ + /* socket needed for the SSL protocol */ + )) { + fds[2].events = POLLIN; + } + else { + fds[2].events = 0; + } + + /* SSL input buffer not empty */ + fds[1].events = (sock_wr && c->ssl_ptr ? POLLOUT : 0); + if (ssl_wr && (c->sock_ptr || /* socket input buffer not empty */ + (c->ssl_ptrssl)) + /* I want to SSL_read but write to the underlying */ + /* socket needed for the SSL protocol */ + )) { + fds[3].events = POLLOUT; + } + else { + fds[3].events = 0; + } + + timeout = 1000 * (sock_rd || + (ssl_wr&&c->sock_ptr) || (sock_wr&&c->ssl_ptr) ? + c->opt->timeout_idle : c->opt->timeout_close); + + ready=spoll(fds, nfds, timeout); + /* FIXME on any errors, give up this connection + if ((fds[0].revents | fds[1].revents | fds[2].revents | fds[3].revents) + & (POLLERR | POLLHUP)) { + log(LOG_INFO, "pollerr or pollhup"); + return -1; + } */ + #endif /* PREFER_POLL */ + if(ready<0) { /* Break the connection for others */ sockerror("select"); return -1; *************** *** 365,371 **** /* room in the buffer by writing to the socket */ check_SSL_pending = 0; ! if(sock_wr && FD_ISSET(c->sock_wfd->fd, &wr_set)) { switch(num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr)) { case -1: /* error */ switch(get_last_socket_error()) { --- 423,434 ---- /* room in the buffer by writing to the socket */ check_SSL_pending = 0; ! #ifndef PREFER_POLL ! if(sock_wr && c->ssl_ptr && FD_ISSET(c->sock_wfd->fd, &wr_set)) ! #else /* PREFER POLL */ ! if(sock_wr && c->ssl_ptr && (POLLOUT & fds[1].revents)) ! #endif /* PREFER POLL */ ! { switch(num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr)) { case -1: /* error */ switch(get_last_socket_error()) { *************** *** 400,408 **** --- 463,477 ---- } if(ssl_wr && ( /* SSL sockets are still open */ + #ifndef PREFER_POLL (c->sock_ptr && FD_ISSET(c->ssl_wfd->fd, &wr_set)) || /* See if application data can be written */ (SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set)) + #else /* PREFER_POLL */ + (c->sock_ptr && (POLLOUT & fds[3].revents)) || + /* See if application data can be written */ + (SSL_want_read(c->ssl) && (POLLIN & fds[2].revents)) + #endif /* PREFER_POLL */ /* I want to SSL_write but read from the underlying */ /* socket needed for the SSL protocol */ )) { *************** *** 449,455 **** --- 518,528 ---- } } + #ifndef PREFER_POLL if(sock_rd && FD_ISSET(c->sock_rfd->fd, &rd_set)) { + #else /* PREFER_POLL */ + if(sock_rd && (POLLIN & fds[0].revents)) { + #endif /* PREFER_POLL */ switch(num=readsocket(c->sock_rfd->fd, c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr)) { case -1: switch(get_last_socket_error()) { *************** *** 481,489 **** --- 554,568 ---- } if(ssl_rd && ( /* SSL sockets are still open */ + #ifndef PREFER_POLL (c->ssl_ptrssl_rfd->fd, &rd_set)) || /* See if there's any application data coming in */ (SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set)) || + #else /* PREFER_POLL */ + (c->ssl_ptrssl) && (POLLOUT & fds[3].revents)) || + #endif /* PREFER_POLL */ /* I want to SSL_read but write to the underlying */ /* socket needed for the SSL protocol */ (check_SSL_pending && SSL_pending(c->ssl)) diff -rc stunnel-4.04/src/protocol.c stunnel-4.04.with_poll/src/protocol.c *** stunnel-4.04/src/protocol.c Wed Jan 1 14:07:10 2003 --- stunnel-4.04.with_poll/src/protocol.c Fri Mar 28 13:29:30 2003 *************** *** 242,247 **** --- 242,248 ---- } static int RFC2487(int fd) { + #ifndef PREFER_POLL fd_set fdsRead; struct timeval timeout; *************** *** 250,255 **** --- 251,265 ---- timeout.tv_sec=timeout.tv_usec=0; /* don't wait */ switch(sselect(fd+1, &fdsRead, NULL, NULL, &timeout)) { + #else /* PREFER_POLL */ + struct pollfd fds[1]; /* add one for signal pipe */ + + /* TODO - do this once */ + fds[0].fd = fd; + fds[0].events = POLLIN; + + switch(spoll(fds, 1, 0)) { + #endif /* PREFER_POLL */ case 0: /* fd not ready to read */ log(LOG_DEBUG, "RFC 2487 detected"); return 1; diff -rc stunnel-4.04/src/prototypes.h stunnel-4.04.with_poll/src/prototypes.h *** stunnel-4.04/src/prototypes.h Wed Jan 1 09:33:54 2003 --- stunnel-4.04.with_poll/src/prototypes.h Fri Mar 28 13:31:23 2003 *************** *** 23,28 **** --- 23,32 ---- #include "common.h" + #ifdef PREFER_POLL + #include "poll.h" + #endif /* PREFER POLL */ + /**************************************** Prototypes for stunnel.c */ extern int num_clients; *************** *** 249,255 **** --- 253,263 ---- /**************************************** Prototypes for select.c */ + #ifndef PREFER_POLL int sselect(int, fd_set *, fd_set *, fd_set *, struct timeval *); + #else /* PREFER_POLL */ + int spoll(struct pollfd *, unsigned int, int); + #endif /* PREFER_POLL */ int waitforsocket(int, int, int); #ifndef USE_WIN32 void sselect_init(fd_set *, int *); diff -rc stunnel-4.04/src/sselect.c stunnel-4.04.with_poll/src/sselect.c *** stunnel-4.04/src/sselect.c Wed Jan 1 10:16:52 2003 --- stunnel-4.04.with_poll/src/sselect.c Fri Mar 28 13:46:14 2003 *************** *** 34,42 **** #ifdef USE_FORK static void client_status(void); /* dead children detected */ #endif - - #ifndef USE_WIN32 static int signal_pipe[2]; static char signal_buffer[16]; --- 34,41 ---- #ifdef USE_FORK static void client_status(void); /* dead children detected */ #endif + #ifndef USE_WIN32 static int signal_pipe[2]; static char signal_buffer[16]; *************** *** 64,77 **** --- 63,79 ---- fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC); fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC); #endif + #ifndef PREFER_POLL FD_SET(signal_pipe[0], set); if(signal_pipe[0]>*n) *n=signal_pipe[0]; + #endif /* !PREFER_POLL */ signal(SIGCHLD, sigchld_handler); } #endif /* USE_WIN32 */ + #ifndef PREFER_POLL int sselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int retval; *************** *** 100,117 **** --- 102,153 ---- return retval; } + #else /* PREFER_POLL */ + + int spoll(struct pollfd * fds, unsigned int nfds, int timeout) + { + int retval; + + /* poll will always be true for signal_pipe, try a non-blocking read */ + /* Empty the pipe */ + if (0 > read(signal_pipe[0], signal_buffer, sizeof(signal_buffer))) { + #ifdef USE_PTHREAD + exec_status(); /* Report status of 'exec' process */ + #endif /* USE_PTHREAD */ + #ifdef USE_FORK + client_status(); /* Report status of client process */ + #endif /* USE_FORK */ + } + do { /* Skip "Interrupted system call" errors */ + retval=poll(fds, nfds, timeout); + } while(retval<0 && get_last_socket_error()==EINTR); + return retval; + } + + #endif /* PREFER_POLL */ + int waitforsocket(int fd, int dir, int timeout) { /* dir: 0 for read, 1 for write */ + #ifndef PREFER_POLL struct timeval tv; fd_set set; + #else /* PREFER_POLL */ + struct pollfd fds[1]; + #endif /* PREFER_POLL */ int ready; log(LOG_DEBUG, "waitforsocket: FD=%d, DIR=%s", fd, dir ? "write" : "read"); + #ifndef PREFER_POLL FD_ZERO(&set); FD_SET(fd, &set); tv.tv_sec=timeout; tv.tv_usec=0; ready=sselect(fd+1, dir ? NULL : &set, dir ? &set : NULL, NULL, &tv); + #else /* PREFER_POLL */ + fds[0].fd = fd; + fds[0].events = (0 == dir ? POLLIN : POLLOUT); + ready=spoll(fds, 1, 1000*timeout); + #endif /* PREFER_POLL */ switch(ready) { case -1: sockerror("waitforsocket"); diff -rc stunnel-4.04/src/stunnel.c stunnel-4.04.with_poll/src/stunnel.c *** stunnel-4.04/src/stunnel.c Sun Jan 12 10:46:55 2003 --- stunnel-4.04.with_poll/src/stunnel.c Fri Mar 28 13:49:32 2003 *************** *** 118,129 **** static void daemon_loop(void) { struct sockaddr_in addr; ! fd_set base_set, current_set; int n; LOCAL_OPTIONS *opt; get_limits(); FD_ZERO(&base_set); if(!local_options.next) { log(LOG_ERR, "No connections defined in config file"); exit(1); --- 118,138 ---- static void daemon_loop(void) { struct sockaddr_in addr; ! fd_set base_set; int n; + #ifndef PREFER_POLL + fd_set current_set; + #else /* PREFER_POLL */ + struct pollfd fds[1024]; /* TODO: use malloc instead? */ + unsigned int nfds; + unsigned int fdi[1024]; + #endif /* PREFER_POLL */ LOCAL_OPTIONS *opt; get_limits(); + #ifndef PREFER_POLL FD_ZERO(&base_set); + #endif /* !PREFER_POLL */ if(!local_options.next) { log(LOG_ERR, "No connections defined in config file"); exit(1); *************** *** 132,138 **** --- 141,151 ---- num_clients=0; /* bind local ports */ + #ifndef PREFER_POLL n=0; + #else /* PREFER_POLL */ + nfds = 0; + #endif /* PREFER_POLL */ for(opt=local_options.next; opt; opt=opt->next) { if(!opt->option.accept) /* no need to bind this service */ continue; *************** *** 164,172 **** --- 177,192 ---- #ifdef FD_CLOEXEC fcntl(opt->fd, F_SETFD, FD_CLOEXEC); /* close socket in child execvp */ #endif + #ifndef PREFER_POLL FD_SET(opt->fd, &base_set); if(opt->fd > n) n=opt->fd; + #else /* PREFER_POLL */ + fds[nfds].fd = opt->fd; + fds[nfds].events = POLLIN; + fdi[opt->fd] = nfds; + nfds++; + #endif /* PREFER_POLL */ } #ifndef USE_WIN32 *************** *** 191,204 **** } while(1) { memcpy(¤t_set, &base_set, sizeof(fd_set)); if(sselect(n+1, ¤t_set, NULL, NULL, NULL)<0) /* non-critical error */ log_error(LOG_INFO, get_last_socket_error(), "main loop select"); ! else ! for(opt=local_options.next; opt; opt=opt->next) if(FD_ISSET(opt->fd, ¤t_set)) accept_connection(opt); } log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)"); } --- 211,238 ---- } while(1) { + #ifndef PREFER_POLL memcpy(¤t_set, &base_set, sizeof(fd_set)); if(sselect(n+1, ¤t_set, NULL, NULL, NULL)<0) + #else /* PREFER_POLL */ + if(spoll(fds, nfds, -1)<0) + #endif /* PREFER_POLL */ + { /* non-critical error */ log_error(LOG_INFO, get_last_socket_error(), "main loop select"); ! } ! else { ! for(opt=local_options.next; opt; opt=opt->next) { ! #ifndef PREFER_POLL if(FD_ISSET(opt->fd, ¤t_set)) + #else /* PREFER_POLL */ + if(POLLIN & fds[fdi[opt->fd]].revents) + #endif /* PREFER_POLL */ + { accept_connection(opt); + } + } + } } log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)"); } *************** *** 259,268 **** --- 293,306 ---- if(fds_ulimit==RLIM_INFINITY) fds_ulimit=-1; #endif + #ifndef PREFER_POLL if(fds_ulimit>=16 && fds_ulimit=256 ? max_fds*125/256 : (max_fds-6)/2; log(LOG_NOTICE, "FD_SETSIZE=%d, file ulimit=%d%s -> %d clients allowed", FD_SETSIZE, fds_ulimit, fds_ulimit<0?" (unlimited)":"", max_clients);