diff options
Diffstat (limited to 'src/child.c')
-rw-r--r-- | src/child.c | 119 |
1 files changed, 54 insertions, 65 deletions
diff --git a/src/child.c b/src/child.c index 15d4fe8..985357d 100644 --- a/src/child.c +++ b/src/child.c @@ -33,25 +33,27 @@ #include "conf.h" #include "sblist.h" #include "loop.h" +#include "conns.h" +#include "mypoll.h" #include <pthread.h> -static vector_t listen_fds; +static sblist* listen_fds; struct client { union sockaddr_union addr; - int fd; }; struct child { pthread_t thread; struct client client; + struct conn_s conn; volatile int done; }; static void* child_thread(void* data) { struct child *c = data; - handle_connection (c->client.fd, &c->client.addr); + handle_connection (&c->conn, &c->client.addr); c->done = 1; return NULL; } @@ -80,19 +82,24 @@ void child_main_loop (void) union sockaddr_union cliaddr_storage; struct sockaddr *cliaddr = (void*) &cliaddr_storage; socklen_t clilen = sizeof(cliaddr_storage); - fd_set rfds; + int nfds = sblist_getsize(listen_fds); + pollfd_struct *fds = safecalloc(nfds, sizeof *fds); ssize_t i; - int ret, listenfd, maxfd, was_full = 0; + int ret, listenfd, was_full = 0; pthread_attr_t *attrp, attr; struct child *child; childs = sblist_new(sizeof (struct child*), config->maxclients); - loop_records_init(); + for (i = 0; i < nfds; i++) { + int *fd = sblist_get(listen_fds, i); + fds[i].fd = *fd; + fds[i].events |= MYPOLL_READ; + } /* * We have to wait for connections on multiple fds, - * so use select. + * so use select/poll/whatever. */ while (!config->quit) { @@ -110,7 +117,6 @@ void child_main_loop (void) was_full = 0; listenfd = -1; - maxfd = 0; /* Handle log rotation if it was requested */ if (received_sighup) { @@ -124,62 +130,35 @@ void child_main_loop (void) received_sighup = FALSE; } + ret = mypoll(fds, nfds, -1); - FD_ZERO(&rfds); - - for (i = 0; i < vector_length(listen_fds); i++) { - int *fd = (int *) vector_getentry(listen_fds, i, NULL); - - ret = socket_nonblocking(*fd); - if (ret != 0) { - log_message(LOG_ERR, "Failed to set the listening " - "socket %d to non-blocking: %s", - fd, strerror(errno)); - continue; - } - - FD_SET(*fd, &rfds); - maxfd = max(maxfd, *fd); - } - - ret = select(maxfd + 1, &rfds, NULL, NULL, NULL); if (ret == -1) { if (errno == EINTR) { continue; } - log_message (LOG_ERR, "error calling select: %s", + log_message (LOG_ERR, "error calling " SELECT_OR_POLL ": %s", strerror(errno)); continue; } else if (ret == 0) { - log_message (LOG_WARNING, "Strange: select returned 0 " + log_message (LOG_WARNING, "Strange: " SELECT_OR_POLL " 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)) { + for (i = 0; i < nfds; i++) { + if (fds[i].revents & MYPOLL_READ) { /* * only accept the connection on the first * fd that we find readable. - fair? */ - listenfd = *fd; + listenfd = fds[i].fd; break; } } if (listenfd == -1) { log_message(LOG_WARNING, "Strange: None of our listen " - "fds was readable after select"); - continue; - } - - ret = socket_blocking(listenfd); - if (ret != 0) { - log_message(LOG_ERR, "Failed to set listening " - "socket %d to blocking for accept: %s", - listenfd, strerror(errno)); + "fds was readable after " SELECT_OR_POLL); continue; } @@ -201,7 +180,7 @@ void child_main_loop (void) continue; } - child = safemalloc(sizeof(struct child)); + child = safecalloc(1, sizeof(struct child)); if (!child) { oom: close(connfd); @@ -218,7 +197,9 @@ oom: goto oom; } - child->client.fd = connfd; + conn_struct_init(&child->conn); + child->conn.client_fd = connfd; + memcpy(&child->client.addr, &cliaddr_storage, sizeof(cliaddr_storage)); attrp = 0; @@ -233,6 +214,7 @@ oom: goto oom; } } + safefree(fds); } /* @@ -240,40 +222,48 @@ oom: */ void child_kill_children (int sig) { - size_t i; + size_t i, tries = 0; if (sig != SIGTERM) return; + log_message (LOG_INFO, + "trying to bring down %zu threads...", + sblist_getsize(childs) + ); + +again: for (i = 0; i < sblist_getsize(childs); i++) { struct child *c = *((struct child**)sblist_get(childs, i)); - if (!c->done) { - /* interrupt blocking operations. - this should cause the threads to shutdown orderly. */ - close(c->client.fd); - } + if (!c->done) pthread_kill(c->thread, SIGCHLD); } - usleep(16); + usleep(8192); collect_threads(); if (sblist_getsize(childs) != 0) + if(tries++ < 8) goto again; + if (sblist_getsize(childs) != 0) log_message (LOG_CRIT, "child_kill_children: %zu threads still alive!", sblist_getsize(childs) ); } +void child_free_children(void) { + sblist_free(childs); + childs = 0; +} /** * Listen on the various configured interfaces */ -int child_listening_sockets(vector_t listen_addrs, uint16_t port) +int child_listening_sockets(sblist *listen_addrs, uint16_t port) { int ret; - ssize_t i; + size_t i; assert (port > 0); if (listen_fds == NULL) { - listen_fds = vector_create(); + listen_fds = sblist_new(sizeof(int), 16); if (listen_fds == NULL) { log_message (LOG_ERR, "Could not create the list " "of listening fds"); @@ -281,8 +271,7 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port) } } - if ((listen_addrs == NULL) || - (vector_length(listen_addrs) == 0)) + if (!listen_addrs || !sblist_getsize(listen_addrs)) { /* * no Listen directive: @@ -292,17 +281,17 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port) return ret; } - for (i = 0; i < vector_length(listen_addrs); i++) { - const char *addr; + for (i = 0; i < sblist_getsize(listen_addrs); i++) { + char **addr; - addr = (char *)vector_getentry(listen_addrs, i, NULL); - if (addr == NULL) { + addr = sblist_get(listen_addrs, i); + if (!addr || !*addr) { log_message(LOG_WARNING, "got NULL from listen_addrs - skipping"); continue; } - ret = listen_sock(addr, port, listen_fds); + ret = listen_sock(*addr, port, listen_fds); if (ret != 0) { return ret; } @@ -313,14 +302,14 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port) void child_close_sock (void) { - ssize_t i; + size_t i; - for (i = 0; i < vector_length(listen_fds); i++) { - int *fd = (int *) vector_getentry(listen_fds, i, NULL); + for (i = 0; i < sblist_getsize(listen_fds); i++) { + int *fd = sblist_get(listen_fds, i); close (*fd); } - vector_delete(listen_fds); + sblist_free(listen_fds); listen_fds = NULL; } |