aboutsummaryrefslogtreecommitdiff
path: root/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'server.c')
-rw-r--r--server.c163
1 files changed, 74 insertions, 89 deletions
diff --git a/server.c b/server.c
index 6167db3..11e2af0 100644
--- a/server.c
+++ b/server.c
@@ -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;
+}