diff options
Diffstat (limited to 'server.c')
| -rw-r--r-- | server.c | 163 |
1 files changed, 74 insertions, 89 deletions
@@ -1,11 +1,3 @@ -/* As of FreeBSD 13.2, sigaction(2) still conforms to IEEE Std - * 1003.1-1990 (POSIX.1), which did not define SA_RESTART. - * FreeBSD supports it as an extension, but then _POSIX_C_SOURCE must - * not be defined. */ -#ifndef __FreeBSD__ -#define _POSIX_C_SOURCE 200809L -#endif - #include "libweb/server.h" #include <fcntl.h> #include <sys/socket.h> @@ -13,7 +5,6 @@ #include <poll.h> #include <unistd.h> #include <errno.h> -#include <signal.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> @@ -22,7 +13,7 @@ struct server { - int fd; + int fd, cfds[2]; struct server_client { @@ -158,23 +149,6 @@ void server_client_write_pending(struct server_client *const c, c->write = write; } -static volatile sig_atomic_t do_exit; - -static void handle_signal(const int signum) -{ - switch (signum) - { - case SIGINT: - /* Fall through. */ - case SIGTERM: - do_exit = 1; - break; - - default: - break; - } -} - static size_t get_clients(const struct server *const s) { size_t ret = 0; @@ -185,12 +159,27 @@ static size_t get_clients(const struct server *const s) return ret; } +static int check_exit(const int fd) +{ + char exit; + const ssize_t n = read(fd, &exit, sizeof exit); + + if (n <= 0) + { + fprintf(stderr, "%s: read(2): %s\n", __func__, strerror(errno)); + return -1; + } + + return 0; +} + struct server_client *server_poll(struct server *const s, bool *const io, bool *const exit) { + enum {SERVER, PIPE, CLIENTS}; struct server_client *ret = NULL; const size_t n_clients = get_clients(s); - const nfds_t n = n_clients + 1; + const nfds_t n = n_clients + CLIENTS; struct pollfd *const fds = malloc(n * sizeof *fds); if (!fds) @@ -199,7 +188,7 @@ struct server_client *server_poll(struct server *const s, bool *const io, goto end; } - struct pollfd *const sfd = &fds[0]; + struct pollfd *const sfd = &fds[SERVER], *const pfd = &fds[PIPE]; *io = *exit = false; *sfd = (const struct pollfd) @@ -208,8 +197,14 @@ struct server_client *server_poll(struct server *const s, bool *const io, .events = POLLIN }; + *pfd = (const struct pollfd) + { + .fd = s->cfds[0], + .events = POLLIN + }; + for (struct {const struct server_client *c; size_t j;} - _ = {.c = s->c, .j = 1}; _.c; _.c = _.c->next, _.j++) + _ = {.c = s->c, .j = CLIENTS}; _.c; _.c = _.c->next, _.j++) { struct pollfd *const p = &fds[_.j]; const int fd = _.c->fd; @@ -230,14 +225,8 @@ again: res = poll(fds, n, -1); - if (do_exit) + if (res < 0) { - *exit = true; - goto end; - } - else if (res < 0) - { - switch (errno) { case EAGAIN: @@ -257,6 +246,15 @@ again: fprintf(stderr, "%s: poll(2) returned zero\n", __func__); goto end; } + else if (pfd->revents) + { + if (check_exit(pfd->fd)) + fprintf(stderr, "%s: check_exit failed\n", __func__); + else + *exit = true; + + goto end; + } else if (sfd->revents) { ret = alloc_client(s); @@ -264,7 +262,7 @@ again: } for (struct {struct server_client *c; size_t j;} - _ = {.c = s->c, .j = 1}; _.c; _.c = _.c->next, _.j++) + _ = {.c = s->c, .j = CLIENTS}; _.c; _.c = _.c->next, _.j++) { const struct pollfd *const p = &fds[_.j]; @@ -283,66 +281,25 @@ end: return ret; } -static int init_signals(void) -{ - struct sigaction sa = - { - .sa_handler = handle_signal, - .sa_flags = SA_RESTART - }; - - sigemptyset(&sa.sa_mask); - - static const struct signal - { - int signal; - const char *name; - } signals[] = - { - {.signal = SIGINT, .name = "SIGINT"}, - {.signal = SIGTERM, .name = "SIGTERM"}, - {.signal = SIGPIPE, .name = "SIGPIPE"} - }; - - for (size_t i = 0; i < sizeof signals / sizeof *signals; i++) - { - const struct signal *const s = &signals [i]; - - if (sigaction(s->signal, &sa, NULL)) - { - fprintf(stderr, "%s: sigaction(2) %s: %s\n", - __func__, s->name, strerror(errno)); - return -1; - } - } - - return 0; -} - struct server *server_init(const unsigned short port, unsigned short *const outport) { struct server *const s = malloc(sizeof *s); + int fds[2] = {-1, -1}, fd = -1; if (!s) { fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno)); goto failure; } - - *s = (const struct server) - { - .fd = socket(AF_INET, SOCK_STREAM, 0) - }; - - if (s->fd < 0) + else if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "%s: socket(2): %s\n", __func__, strerror(errno)); goto failure; } - else if (init_signals()) + else if (pipe(fds)) { - fprintf(stderr, "%s: init_signals failed\n", __func__); + fprintf(stderr, "%s: socketpair(2): %s\n", __func__, strerror(errno)); goto failure; } @@ -354,12 +311,12 @@ struct server *server_init(const unsigned short port, enum {QUEUE_LEN = 10}; - if (bind(s->fd, (const struct sockaddr *)&addr, sizeof addr)) + if (bind(fd, (const struct sockaddr *)&addr, sizeof addr)) { fprintf(stderr, "%s: bind(2): %s\n", __func__, strerror(errno)); goto failure; } - else if (listen(s->fd, QUEUE_LEN)) + else if (listen(fd, QUEUE_LEN)) { fprintf(stderr, "%s: listen(2): %s\n", __func__, strerror(errno)); goto failure; @@ -368,17 +325,45 @@ struct server *server_init(const unsigned short port, struct sockaddr_in in; socklen_t sz = sizeof in; - if (getsockname(s->fd, (struct sockaddr *)&in, &sz)) + if (getsockname(fd, (struct sockaddr *)&in, &sz)) { fprintf(stderr, "%s: getsockname(2): %s\n", __func__, strerror(errno)); goto failure; } - else if (outport) + + *s = (const struct server) + { + .fd = fd, + .cfds = { + [0] = fds[0], + [1] = fds[1] + } + }; + + if (outport) *outport = ntohs(in.sin_port); return s; -failure: - server_close(s); +failure:; + + const int a[] = {fd, fds[0], fds[1]}; + + for (size_t i = 0; sizeof a / sizeof *a; i++) + { + const int fd = a[i]; + + if (fd >= 0 && close(fd)) + fprintf(stderr, "%s: close(2)[%zu]: %s\n", + __func__, i, strerror(errno)); + } + return NULL; } + +int server_notify_close(struct server *const s) +{ + char exit = 0; + + return write(s->cfds[1], &exit, sizeof exit) <= 0 ? -1 : 0; +} |
