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_ptr<BUFFSIZE) /* socket input buffer not full*/
              FD_SET(c->sock_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_ptr<BUFFSIZE ? POLLIN : 0);
+         if(ssl_rd && (c->ssl_ptr<BUFFSIZE || /* SSL input buffer not full */
+                 (c->sock_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_ptr<BUFFSIZE && SSL_want_write(c->ssl))
+                 /* 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_ptr<BUFFSIZE && FD_ISSET(c->ssl_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_ptr<BUFFSIZE && (POLLIN & fds[2].revents)) ||
+                 /* See if there's any application data coming in */
+                 (SSL_want_write(c->ssl) && (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(&current_set, &base_set, sizeof(fd_set));
          if(sselect(n+1, &current_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, &current_set))
                      accept_connection(opt);
      }
      log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)");
  }
--- 211,238 ----
      }
  
      while(1) {
+ #ifndef PREFER_POLL
          memcpy(&current_set, &base_set, sizeof(fd_set));
          if(sselect(n+1, &current_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, &current_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<FD_SETSIZE)
          max_fds=fds_ulimit;
      else
          max_fds=FD_SETSIZE;
+ #else /* PREFER_POLL */
+     max_fds=fds_ulimit;
+ #endif /* PREFER_POLL */
      max_clients=max_fds>=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);
