summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/child.c86
-rw-r--r--src/sock.c7
-rw-r--r--src/sock.h4
3 files changed, 90 insertions, 7 deletions
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);