diff -Naur stunnel-4.05/src/client.c stunnel-4.05.with.poll.steven/src/client.c --- stunnel-4.05/src/client.c 2004-02-10 20:17:54.000000000 +0100 +++ stunnel-4.05.with.poll.steven/src/client.c 2004-04-01 15:42:01.000000000 +0200 @@ -132,19 +132,29 @@ if(init_local(c)) return -1; + if(!options.option.client && !c->opt->protocol) { + /* Server mode and no protocol negotiation needed */ if(init_ssl(c)) + { return -1; + } if(init_remote(c)) + { return -1; + } + + } else { + if(init_remote(c)) return -1; if(negotiate(c)<0) { log(LOG_ERR, "Protocol negotiations failed"); return -1; } + if(init_ssl(c)) return -1; } @@ -213,6 +223,8 @@ free(c->resolved_addresses); } else /* NOT in remote mode */ fd=connect_local(c); + + if(fd<0) { log(LOG_ERR, "Failed to initialize remote connection"); return -1; @@ -230,16 +242,20 @@ c->remote_fd.is_socket=1; /* Always! */ if(set_socket_options(fd, 2)<0) return -1; + + return 0; /* OK */ } static int init_ssl(CLI *c) { int i, err; + if(!(c->ssl=SSL_new(ctx))) { sslerror("SSL_new"); return -1; } + #if SSLEAY_VERSION_NUMBER >= 0x0922 SSL_set_session_id_context(c->ssl, sid_ctx, strlen(sid_ctx)); #endif @@ -273,6 +289,7 @@ } while(1) { + if(options.option.client) i=SSL_connect(c->ssl); else @@ -307,6 +324,302 @@ return 0; /* OK */ } +#ifdef USE_POLL_NOT_SELECT + +static int transfer(CLI *c) { /* transfer data */ + struct poll_fdset rw_set; + int num, err; + int check_SSL_pending; + int ssl_closing; + /* 0=not closing SSL, 1=initiate SSL_shutdown, + * 2=retry SSL_shutdown, 3=SSL_shutdown done */ + int ready; + int timeout = 0; + + int returnvalue = -1; + + + POLL_FDSET_INIT(&rw_set); + + c->sock_ptr=c->ssl_ptr=0; + sock_rd=sock_wr=ssl_rd=ssl_wr=1; + c->sock_bytes=c->ssl_bytes=0; + ssl_closing=0; + + while(((sock_rd||c->sock_ptr)&&ssl_wr)||((ssl_rd||c->ssl_ptr)&&sock_wr)) { + + POLL_FD_ZERO(&rw_set); /* Setup rd_set */ + if(sock_rd && c->sock_ptrsock_rfd->fd, &rw_set, POLL_READ_FLAGS); + if(ssl_rd && ( + c->ssl_ptrsock_ptr||ssl_closing) && SSL_want_read(c->ssl)) + /* I want to SSL_write or SSL_shutdown but read from the + * underlying socket needed for the SSL protocol */ + )) { + POLL_FD_SET(c->ssl_rfd->fd, &rw_set, POLL_READ_FLAGS); + } + + if(sock_wr && c->ssl_ptr) /* SSL input buffer not empty */ + POLL_FD_SET(c->sock_wfd->fd, &rw_set, POLL_WRITE_FLAGS); + if (ssl_wr && ( + c->sock_ptr || /* socket input buffer not empty */ + ssl_closing==1 || /* initiate SSL_shutdown */ + ((c->ssl_ptrssl)) + /* I want to SSL_read or SSL_shutdown but write to the + * underlying socket needed for the SSL protocol */ + )) { + POLL_FD_SET(c->ssl_wfd->fd, &rw_set, POLL_WRITE_FLAGS); + } + + timeout = 1000 * (sock_rd || + (ssl_wr&&c->sock_ptr) || (sock_wr&&c->ssl_ptr) ? + c->opt->timeout_idle : c->opt->timeout_close); + + ready=spoll(&rw_set, timeout); + + if(ready<0) { /* Break the connection for others */ + sockerror("select"); + returnvalue = -1; goto cleanup; + } + if(!ready) { /* Timeout */ + if(sock_rd) { /* No traffic for a long time */ + log(LOG_DEBUG, "select timeout: connection reset"); + returnvalue = -1; goto cleanup; + } else { /* Timeout waiting for SSL close_notify */ + log(LOG_DEBUG, "select timeout waiting for SSL close_notify"); + break; /* Leave the while() loop */ + } + } + + if(ssl_closing==1 /* initiate SSL_shutdown */ || (ssl_closing==2 && ( + (SSL_want_read(c->ssl) && POLL_FD_ISSET(c->ssl_rfd->fd, &rw_set,POLL_READ_FLAGS)) || + (SSL_want_write(c->ssl) && POLL_FD_ISSET(c->ssl_wfd->fd, &rw_set, POLL_WRITE_FLAGS)) + ))) { + + switch(SSL_shutdown(c->ssl)) { /* Send close_notify */ + case 1: /* the shutdown was successfully completed */ + log(LOG_INFO, "SSL_shutdown successfully sent close_notify"); + ssl_wr=0; /* SSL write closed */ + /* TODO: It's not really closed. We need to distinguish + * closed SSL and closed underlying file descriptor */ + ssl_closing=3; /* done! */ + break; + case 0: /* the shutdown is not yet finished */ + log(LOG_DEBUG, "SSL_shutdown retrying"); + ssl_closing=2; /* next time just retry SSL_shutdown */ + break; + case -1: /* a fatal error occurred */ + sslerror("SSL_shutdown"); + returnvalue = -1; goto cleanup; + } + } + + /* Set flag to try and read any buffered SSL data if we made */ + /* room in the buffer by writing to the socket */ + check_SSL_pending = 0; + + if(sock_wr && POLL_FD_ISSET(c->sock_wfd->fd, &rw_set,POLL_WRITE_FLAGS)) { + switch(num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr)) { + case -1: /* error */ + switch(get_last_socket_error()) { + case EINTR: + log(LOG_DEBUG, + "writesocket interrupted by a signal: retrying"); + break; + case EWOULDBLOCK: + log(LOG_NOTICE, "writesocket would block: retrying"); + break; + default: + sockerror("writesocket"); + returnvalue = -1; goto cleanup; + } + break; + case 0: + log(LOG_DEBUG, "No data written to the socket: retrying"); + break; + default: + memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num); + if(c->ssl_ptr==BUFFSIZE) + check_SSL_pending=1; + c->ssl_ptr-=num; + c->sock_bytes+=num; + if(!ssl_rd && !c->ssl_ptr) { + shutdown(c->sock_wfd->fd, SHUT_WR); + log(LOG_DEBUG, + "Socket write shutdown (no more data to send)"); + sock_wr=0; + } + } + } + + if(ssl_wr && ( /* SSL sockets are still open */ + (c->sock_ptr && POLL_FD_ISSET(c->ssl_wfd->fd, &rw_set,POLL_WRITE_FLAGS)) || + /* See if application data can be written */ + (SSL_want_read(c->ssl) && POLL_FD_ISSET(c->ssl_rfd->fd, &rw_set,POLL_READ_FLAGS)) + /* I want to SSL_write but read from the underlying */ + /* socket needed for the SSL protocol */ + )) { + num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr); + + err=SSL_get_error(c->ssl, num); + switch(err) { + case SSL_ERROR_NONE: + memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num); + c->sock_ptr-=num; + c->ssl_bytes+=num; + if(!ssl_closing && !sock_rd && !c->sock_ptr && ssl_wr) { + log(LOG_DEBUG, + "SSL write shutdown (no more data to send)"); + ssl_closing=1; + } + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + log(LOG_DEBUG, "SSL_write returned WANT_: retrying"); + break; + case SSL_ERROR_SYSCALL: + if(num<0) { /* really an error */ + switch(get_last_socket_error()) { + case EINTR: + log(LOG_DEBUG, + "SSL_write interrupted by a signal: retrying"); + break; + case EAGAIN: + log(LOG_DEBUG, + "SSL_write returned EAGAIN: retrying"); + break; + default: + sockerror("SSL_write (ERROR_SYSCALL)"); + returnvalue = -1; goto cleanup; + } + } + break; + case SSL_ERROR_ZERO_RETURN: /* close_notify received */ + log(LOG_DEBUG, "SSL closed on SSL_write"); + ssl_rd=ssl_wr=0; + break; + case SSL_ERROR_SSL: + sslerror("SSL_write"); + returnvalue = -1; goto cleanup; + default: + log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); + returnvalue = -1; goto cleanup; + } + } + + if(sock_rd && POLL_FD_ISSET(c->sock_rfd->fd, &rw_set,POLL_READ_FLAGS)) { + switch(num=readsocket(c->sock_rfd->fd, + c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr)) { + case -1: + switch(get_last_socket_error()) { + case EINTR: + log(LOG_DEBUG, + "readsocket interrupted by a signal: retrying"); + break; + case EWOULDBLOCK: + log(LOG_NOTICE, "readsocket would block: retrying"); + break; + default: + sockerror("readsocket"); + returnvalue = -1; goto cleanup; + } + break; + case 0: /* close */ + log(LOG_DEBUG, "Socket closed on read"); + sock_rd=0; + if(!ssl_closing && !c->sock_ptr && ssl_wr) { + log(LOG_DEBUG, + "SSL write shutdown (output buffer empty)"); + ssl_closing=1; + } + break; + default: + c->sock_ptr+=num; + } + } + + if(ssl_rd && ( /* SSL sockets are still open */ + (c->ssl_ptrssl_rfd->fd, &rw_set,POLL_READ_FLAGS)) || + /* See if there's any application data coming in */ + (SSL_want_write(c->ssl) && POLL_FD_ISSET(c->ssl_wfd->fd, &rw_set,POLL_WRITE_FLAGS)) || + /* I want to SSL_read but write to the underlying */ + /* socket needed for the SSL protocol */ + (check_SSL_pending && SSL_pending(c->ssl)) + /* Write made space from full buffer */ + )) { + num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr); + + err=SSL_get_error(c->ssl, num); + switch(err) { + case SSL_ERROR_NONE: + c->ssl_ptr+=num; + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + log(LOG_DEBUG, "SSL_read returned WANT_: retrying"); + break; + case SSL_ERROR_SYSCALL: + if(num<0) { /* not EOF */ + switch(get_last_socket_error()) { + case EINTR: + log(LOG_DEBUG, + "SSL_read interrupted by a signal: retrying"); + break; + case EAGAIN: + log(LOG_DEBUG, + "SSL_read returned EAGAIN: retrying"); + break; + default: + sockerror("SSL_read (ERROR_SYSCALL)"); + returnvalue = -1; goto cleanup; + } + } else { /* EOF */ + log(LOG_DEBUG, "SSL socket closed on SSL_read"); + ssl_rd=ssl_wr=0; + } + break; + case SSL_ERROR_ZERO_RETURN: /* close_notify received */ + log(LOG_DEBUG, "SSL closed on SSL_read"); + ssl_rd=0; + if(!ssl_closing && !c->sock_ptr && ssl_wr) { + log(LOG_DEBUG, + "SSL write shutdown (output buffer empty)"); + ssl_closing=1; + } + if(!c->ssl_ptr && sock_wr) { + shutdown(c->sock_wfd->fd, SHUT_WR); + log(LOG_DEBUG, + "Socket write shutdown (output buffer empty)"); + sock_wr=0; + } + break; + case SSL_ERROR_SSL: + sslerror("SSL_read"); + returnvalue = -1; goto cleanup; + default: + log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); + returnvalue = -1; goto cleanup; + } + } + } + + returnvalue = 0; /* OK */ goto cleanup; + +cleanup: + + /* free the set */ + POLL_FD_ZERO(&rw_set); + + return returnvalue; +} + + +#else + static int transfer(CLI *c) { /* transfer data */ fd_set rd_set, wr_set; int num, err, fdno; @@ -592,6 +905,8 @@ return 0; /* OK */ } +#endif /* USE_POLL_NOT_SELECT */ + static void cleanup(CLI *c, int error) { /* Cleanup SSL */ if(c->ssl) { /* SSL initialized */ diff -Naur stunnel-4.05/src/common.h stunnel-4.05.with.poll.steven/src/common.h --- stunnel-4.05/src/common.h 2004-02-14 13:20:08.000000000 +0100 +++ stunnel-4.05.with.poll.steven/src/common.h 2004-04-05 18:04:24.000000000 +0200 @@ -266,6 +266,186 @@ #define safename(s) \ do {char *p; for(p=(s); *p; p++) if(!isalnum((int)*p)) *p='.';} while(0) + +#define USE_POLL_NOT_SELECT 1 + + +#ifdef USE_POLL_NOT_SELECT +# define __USE_XOPEN +# include + +struct poll_fdset +{ + struct pollfd *fds; + int count; +}; + +#include "prototypes.h" +#define POLL_READ_FLAGS (POLLIN)// | POLLPRI | POLLRDNORM | POLLRDBAND) +#define POLL_WRITE_FLAGS (POLLOUT)// | POLLWRNORM | POLLWRBAND) + +/* binary search */ +static int find_poll_fd_index(int fd,struct poll_fdset *set) +{ + int start, end, current; + + start = 0; + end = set->count - 1; + + if(!set->fds) + return -1; + + while(end - start > 0) + { + current = (start + end) / 2; + + if(set->fds[current].fd == fd) + { + return current; + } + else if (set->fds[current].fd < fd) + { + start = current + 1; + } + else + { + end = current - 1; + } + } + + if(set->fds[start].fd == fd) + return start; + + return -1; +} + +/* find the place where fd needs to be inserted */ +static int find_smallest_bigger_poll_fd_index(int fd,struct poll_fdset *set) +{ + int start, end, current; + + start = 0; + end = set->count - 1; + + if(!set->fds) + return 0; + + while(end - start > 0) + { + current = (start + end) / 2; + + if(set->fds[current].fd == fd) + { + return current + 1; + } + else if (set->fds[current].fd < fd) + { + start = current + 1; + } + else + { + end = current - 1; + } + } + + if(set->fds[start].fd < fd) + return start+1; + else + return start; +} + +static int POLL_FD_ISSET(int fd, struct poll_fdset *set, int flags) +{ + int i; + int result; + + if((i = find_poll_fd_index(fd,set)) < 0) + { + //printf("POLL_FD_SET(): testing fd %d for flag %d -> FD NOT FOUND !!!!!!!\n",fd,flags); + return 0; + } + + return (set->fds[i].revents & flags); +} + +static void POLL_FD_SET(int fd, struct poll_fdset *set, int flags) +{ + int i; + struct pollfd *tmp = NULL; + + if(!set) + return; + + if((i = find_poll_fd_index(fd,set)) >= 0) + { + set->fds[i].events |= flags; + return; + } + + /* fd not in set yet, add it */ + + i = find_smallest_bigger_poll_fd_index(fd,set); + + /* i is now the index of the slot where we have to insert this fd */ + + set->count++; + set->fds = (struct pollfd *)realloc(set->fds,set->count * sizeof(struct pollfd)); + tmp = (struct pollfd *)malloc(set->count * sizeof(struct pollfd)); + + if(!set->fds) + { + log(LOG_ERR, "POLL_FD_SET(): realloc failed!"); + return; + } + + if(i < set->count - 1) + { + /* move the old data */ + /* copy to temp buffer and back to the set, but shifted by 1 slot */ + memcpy(tmp, &(set->fds[i]), (set->count - i - 1) * sizeof(struct pollfd)); + memcpy(&(set->fds[i+1]), tmp, (set->count - i - 1) * sizeof(struct pollfd)); + } + + set->fds[i].fd = fd; + set->fds[i].events = flags; + set->fds[i].revents = 0; + + free(tmp); +} + +static void POLL_FDSET_INIT(struct poll_fdset *set) +{ + memset(set,0,sizeof(struct poll_fdset)); +} + +static void POLL_FD_ZERO(struct poll_fdset *set) +{ + if(!set) + return; + + if(set->fds) free(set->fds); + + set->fds = NULL; + set->count = 0; +} + +static void POLL_COPY_SET(struct poll_fdset *to,struct poll_fdset *from) +{ + POLL_FD_ZERO(to); + + to->fds = (struct pollfd *)malloc(from->count * sizeof(struct pollfd)); + if(!to->fds) + { + log(LOG_ERR, "POLL_COPY_SET(): malloc failed!"); + return; + } + + memcpy(to->fds,from->fds,from->count * sizeof(struct pollfd)); + to->count = from->count; +} + +#endif /* USE_POLL_NOT_SELECT */ + #endif /* defined COMMON_H */ /* End of common.h */ diff -Naur stunnel-4.05/src/protocol.c stunnel-4.05.with.poll.steven/src/protocol.c --- stunnel-4.05/src/protocol.c 2004-01-25 18:18:34.000000000 +0100 +++ stunnel-4.05.with.poll.steven/src/protocol.c 2004-04-01 15:42:20.000000000 +0200 @@ -260,6 +260,21 @@ } static int RFC2487(int fd) { + +#ifdef USE_POLL_NOT_SELECT + struct poll_fdset fdsRead; + int result; + + POLL_FDSET_INIT(&fdsRead); + POLL_FD_ZERO(&fdsRead); + POLL_FD_SET(fd, &fdsRead, POLL_READ_FLAGS); + + result = spoll(&fdsRead,0); + + POLL_FD_ZERO(&fdsRead); // free it + + switch(result) { +#else fd_set fdsRead; struct timeval timeout; @@ -268,6 +283,9 @@ timeout.tv_sec=timeout.tv_usec=0; /* don't wait */ switch(sselect(fd+1, &fdsRead, NULL, NULL, &timeout)) { + +#endif + case 0: /* fd not ready to read */ log(LOG_DEBUG, "RFC 2487 detected"); return 1; diff -Naur stunnel-4.05/src/prototypes.h stunnel-4.05.with.poll.steven/src/prototypes.h --- stunnel-4.05/src/prototypes.h 2004-02-10 20:15:05.000000000 +0100 +++ stunnel-4.05.with.poll.steven/src/prototypes.h 2004-04-01 15:13:53.000000000 +0200 @@ -256,12 +256,22 @@ /**************************************** Prototypes for select.c */ +#ifdef USE_POLL_NOT_SELECT +int spoll(struct poll_fdset *, int); +int waitforsocket(int, int, int); +#ifndef USE_WIN32 +void spoll_init(struct poll_fdset *); +void exec_status(void); +#endif +#else int sselect(int, fd_set *, fd_set *, fd_set *, struct timeval *); int waitforsocket(int, int, int); #ifndef USE_WIN32 void sselect_init(fd_set *, int *); void exec_status(void); #endif +#endif /* USE_POLL_NOT_SELECT */ + int write_blocking(CLI *, int fd, u8 *, int); int read_blocking(CLI *, int fd, u8 *, int); /* descriptor versions of fprintf/fscanf */ diff -Naur stunnel-4.05/src/sselect.c stunnel-4.05.with.poll.steven/src/sselect.c --- stunnel-4.05/src/sselect.c 2004-01-25 18:18:07.000000000 +0100 +++ stunnel-4.05.with.poll.steven/src/sselect.c 2004-04-01 15:43:35.000000000 +0200 @@ -52,6 +52,29 @@ #endif +#ifdef USE_POLL_NOT_SELECT +void spoll_init(struct poll_fdset *set) +{ + if(pipe(signal_pipe)) + { + ioerror("pipe"); + exit(1); + } + + alloc_fd(signal_pipe[0]); + alloc_fd(signal_pipe[1]); +#ifdef FD_CLOEXEC + /* close the pipe in child execvp */ + fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC); + fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC); +#endif + + POLL_FD_SET(signal_pipe[0], set, POLL_READ_FLAGS); + signal(SIGCHLD, sigchld_handler); +} + +#else + void sselect_init(fd_set *set, int *n) { if(pipe(signal_pipe)) { ioerror("pipe"); @@ -70,8 +93,34 @@ signal(SIGCHLD, sigchld_handler); } +#endif /* USE_POLL_NOT_SELECT */ #endif /* USE_WIN32 */ + +#ifdef USE_POLL_NOT_SELECT +int spoll(struct poll_fdset *set, int timeout) +{ + int retval; + + 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(set->fds, set->count, timeout); + } + while(retval<0 && get_last_socket_error()==EINTR); + return retval; +} + +#else int sselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int retval; @@ -99,9 +148,27 @@ } while(retval<0 && get_last_socket_error()==EINTR); return retval; } +#endif /* USE_POLL_NOT_SELECT */ int waitforsocket(int fd, int dir, int timeout) { /* dir: 0 for read, 1 for write */ + +#ifdef USE_POLL_NOT_SELECT + struct pollfd set; + int ready; + + log(LOG_DEBUG, "waitforsocket: FD=%d, DIR=%s", fd, dir ? "write" : "read"); + + set.fd = fd; + if(dir) /* write */ + set.events = POLL_WRITE_FLAGS; + else /* read */ + set.events = POLL_READ_FLAGS; + + set.revents = 0; + + ready = poll(&set, 1, 1000 * timeout); +#else struct timeval tv; fd_set set; int ready; @@ -112,6 +179,7 @@ tv.tv_sec=timeout; tv.tv_usec=0; ready=sselect(fd+1, dir ? NULL : &set, dir ? &set : NULL, NULL, &tv); +#endif /* USE_POLL_NOT_SELECT */ switch(ready) { case -1: sockerror("waitforsocket"); diff -Naur stunnel-4.05/src/stunnel.c stunnel-4.05.with.poll.steven/src/stunnel.c --- stunnel-4.05/src/stunnel.c 2004-02-14 15:12:27.000000000 +0100 +++ stunnel-4.05.with.poll.steven/src/stunnel.c 2004-04-05 15:46:48.000000000 +0200 @@ -116,6 +116,101 @@ log_close(); } +#ifdef USE_POLL_NOT_SELECT + +static void daemon_loop(void) { + struct sockaddr_in addr; + struct poll_fdset base_set, current_set; + LOCAL_OPTIONS *opt; + + get_limits(); + POLL_FDSET_INIT(&base_set); + POLL_FDSET_INIT(¤t_set); + + POLL_FD_ZERO(&base_set); + if(!local_options.next) { + log(LOG_ERR, "No connections defined in config file"); + exit(1); + } + + num_clients=0; + + + /* bind local ports */ + for(opt=local_options.next; opt; opt=opt->next) { + if(!opt->option.accept) /* no need to bind this service */ + continue; + if((opt->fd=socket(AF_INET, SOCK_STREAM, 0))<0) { + sockerror("local socket"); + exit(1); + } + if(alloc_fd(opt->fd)) + exit(1); + if(set_socket_options(opt->fd, 0)<0) + exit(1); + memset(&addr, 0, sizeof(addr)); + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=*opt->localnames; + addr.sin_port=opt->localport; + safe_ntoa(opt->local_address, addr.sin_addr); + if(bind(opt->fd, (struct sockaddr *)&addr, sizeof(addr))) { + log(LOG_ERR, "Error binding %s to %s:%d", opt->servname, + opt->local_address, ntohs(addr.sin_port)); + sockerror("bind"); + exit(1); + } + log(LOG_DEBUG, "%s bound to %s:%d", opt->servname, + opt->local_address, ntohs(addr.sin_port)); + if(listen(opt->fd, 5)) { + sockerror("listen"); + exit(1); + } +#ifdef FD_CLOEXEC + fcntl(opt->fd, F_SETFD, FD_CLOEXEC); /* close socket in child execvp */ +#endif + POLL_FD_SET(opt->fd, &base_set,POLL_READ_FLAGS); + } + +#ifndef USE_WIN32 + spoll_init(&base_set); +#endif + + +#if !defined (USE_WIN32) && !defined (__vms) + if(!(options.option.foreground)) + daemonize(); + drop_privileges(); + create_pid(); +#endif /* !defined USE_WIN32 && !defined (__vms) */ + + /* create exec+connect services */ + for(opt=local_options.next; opt; opt=opt->next) { + if(opt->option.accept) /* skip ordinary (accepting) services */ + continue; + enter_critical_section(CRIT_CLIENTS); /* for multi-cpu machines */ + num_clients++; + leave_critical_section(CRIT_CLIENTS); + create_client(-1, -1, alloc_client_session(opt, -1, -1), client); + } + + while(1) { + + POLL_COPY_SET(¤t_set, &base_set); + if(spoll(¤t_set, -1)<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(POLL_FD_ISSET(opt->fd, ¤t_set,POLL_READ_FLAGS)) + accept_connection(opt); + } + } + log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)"); +} + +#else + static void daemon_loop(void) { struct sockaddr_in addr; fd_set base_set, current_set; @@ -203,6 +298,8 @@ log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)"); } +#endif /* USE_POLL_NOT_SELECT */ + static void accept_connection(LOCAL_OPTIONS *opt) { struct sockaddr_in addr; int err, s, addrlen=sizeof(addr); @@ -272,7 +369,12 @@ if(fds_ulimit==RLIM_INFINITY) fds_ulimit=-1; #endif + +#ifdef USE_POLL_NOT_SELECT + max_fds=fds_ulimit; +#else max_fds=fds_ulimit=256 ? max_fds*125/256 : (max_fds-6)/2;