diff --git a/src/child.c b/src/child.c index 144b032..c7490fd 100644 --- a/src/child.c +++ b/src/child.c @@ -32,7 +32,7 @@ #include "utils.h" #include "conf.h" -static int listenfd; +static vector_t listen_fds; /* * Stores the internal data needed for each child (connection) @@ -186,6 +186,10 @@ static void child_main (struct child_s *ptr) int connfd; struct sockaddr *cliaddr; socklen_t clilen; + fd_set rfds; + int maxfd = 0; + ssize_t i; + int ret; cliaddr = (struct sockaddr *) safemalloc (sizeof(struct sockaddr_storage)); @@ -197,11 +201,65 @@ static void child_main (struct child_s *ptr) ptr->connects = 0; + /* + * We have to wait for connections on multiple fds, + * so use select. + */ + + FD_ZERO(&rfds); + + for (i = 0; i < vector_length(listen_fds); i++) { + int *fd = (int *) vector_getentry(listen_fds, i, NULL); + + socket_nonblocking(*fd); + FD_SET(*fd, &rfds); + maxfd = max(maxfd, *fd); + } + while (!config.quit) { + int listenfd = -1; + ptr->status = T_WAITING; clilen = sizeof(struct sockaddr_storage); + ret = select(maxfd + 1, &rfds, NULL, NULL, NULL); + if (ret == -1) { + log_message (LOG_ERR, "error calling select: %s", + strerror(errno)); + exit(1); + } else if (ret == 0) { + log_message (LOG_WARNING, "Strange: select returned 0 " + "but we did not specify a timeout..."); + continue; + } + + for (i = 0; i < vector_length(listen_fds); i++) { + int *fd = (int *) vector_getentry(listen_fds, i, NULL); + + if (FD_ISSET(*fd, &rfds)) { + /* + * only accept the connection on the first + * fd that we find readable. - fair? + */ + listenfd = *fd; + break; + } + } + + if (listenfd == -1) { + log_message(LOG_WARNING, "Strange: None of our listen " + "fds was readable after select"); + continue; + } + + socket_blocking(listenfd); + + /* + * We have a socket that is readable. + * Continue handling this connection. + */ + connfd = accept (listenfd, cliaddr, &clilen); #ifndef NDEBUG @@ -466,11 +524,31 @@ void child_kill_children (int sig) int child_listening_sock (const char *addr, uint16_t port) { - listenfd = listen_sock (addr, port); - return listenfd; + int ret; + + if (listen_fds == NULL) { + listen_fds = vector_create(); + if (listen_fds == NULL) { + log_message (LOG_ERR, "Could not create the list " + "of listening fds"); + return -1; + } + } + + ret = listen_sock (addr, port, listen_fds); + return ret; } void child_close_sock (void) { - close (listenfd); + ssize_t i; + + for (i = 0; i < vector_length(listen_fds); i++) { + int *fd = (int *) vector_getentry(listen_fds, i, NULL); + close (*fd); + } + + vector_delete(listen_fds); + + listen_fds = NULL; } diff --git a/src/sock.c b/src/sock.c index fe28de6..d2db37b 100644 --- a/src/sock.c +++ b/src/sock.c @@ -166,7 +166,7 @@ int socket_blocking (int sock) * Start listening on a socket. Create a socket with the selected port. * The socket fd is returned upon success, -1 upon error. */ -int listen_sock (const char *addr, uint16_t port) +int listen_sock (const char *addr, uint16_t port, vector_t listen_fds) { struct addrinfo hints, *result, *rp; char portstr[6]; @@ -174,6 +174,7 @@ int listen_sock (const char *addr, uint16_t port) const int on = 1; assert (port > 0); + assert (listen_fds != NULL); memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -224,9 +225,11 @@ int listen_sock (const char *addr, uint16_t port) return -1; } + vector_append(listen_fds, &listenfd, sizeof(int)); + freeaddrinfo (result); - return listenfd; + return 0; } /* diff --git a/src/sock.h b/src/sock.h index 5cca744..f1225ea 100644 --- a/src/sock.h +++ b/src/sock.h @@ -28,8 +28,10 @@ #define MAXLINE (1024 * 4) +#include "vector.h" + extern int opensock (const char *host, int port, const char *bind_to); -extern int listen_sock (const char *addr, uint16_t port); +extern int listen_sock (const char *addr, uint16_t port, vector_t listen_fds); extern int socket_nonblocking (int sock); extern int socket_blocking (int sock);