aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kike.c118
1 files changed, 66 insertions, 52 deletions
diff --git a/src/kike.c b/src/kike.c
index dde8d42..5a250b2 100644
--- a/src/kike.c
+++ b/src/kike.c
@@ -425,7 +425,9 @@ channel_get_mode (struct channel *self, bool disclose_secrets)
struct server_context
{
- int listen_fd; ///< Listening socket FD
+ int listen_fds[1]; ///< Listening socket FD's
+ size_t n_listen_fds; ///< Number of listening sockets
+
struct client *clients; ///< Clients
SSL_CTX *ssl_ctx; ///< SSL context
unsigned n_clients; ///< Current number of connections
@@ -450,7 +452,7 @@ struct server_context
static void
server_context_init (struct server_context *self)
{
- self->listen_fd = -1;
+ self->n_listen_fds = 0;
self->clients = NULL;
self->n_clients = 0;
@@ -485,8 +487,8 @@ server_context_free (struct server_context *self)
{
str_map_free (&self->config);
- if (self->listen_fd != -1)
- xclose (self->listen_fd);
+ for (size_t i = 0; i < self->n_listen_fds; i++)
+ xclose (self->listen_fds[i]);
if (self->ssl_ctx)
SSL_CTX_free (self->ssl_ctx);
@@ -763,12 +765,14 @@ irc_initiate_quit (struct server_context *ctx)
if (!iter->closing_link)
irc_close_link (iter, "Shutting down");
- ssize_t i = poller_find_by_fd (&ctx->poller, ctx->listen_fd);
- if (soft_assert (i != -1))
- poller_remove_at_index (&ctx->poller, i);
- if (ctx->listen_fd != -1)
- xclose (ctx->listen_fd);
- ctx->listen_fd = -1;
+ for (size_t i = 0; i < ctx->n_listen_fds; i++)
+ {
+ ssize_t index = poller_find_by_fd (&ctx->poller, ctx->listen_fds[i]);
+ if (soft_assert (index != -1))
+ poller_remove_at_index (&ctx->poller, index);
+ xclose (ctx->listen_fds[i]);
+ }
+ ctx->n_listen_fds = 0;
ctx->quitting = true;
irc_try_finish_quit (ctx);
@@ -2501,7 +2505,7 @@ on_irc_client_available (const struct pollfd *pfd, void *user_data)
struct sockaddr_storage peer;
socklen_t peer_len = sizeof peer;
- int fd = accept (ctx->listen_fd, (struct sockaddr *) &peer, &peer_len);
+ int fd = accept (pfd->fd, (struct sockaddr *) &peer, &peer_len);
if (fd == -1)
{
if (errno == EAGAIN)
@@ -2774,8 +2778,47 @@ irc_initialize_server_name (struct server_context *ctx, struct error **e)
return true;
}
+static int
+irc_listen (struct addrinfo *gai_iter)
+{
+ int fd = socket (gai_iter->ai_family,
+ gai_iter->ai_socktype, gai_iter->ai_protocol);
+ if (fd == -1)
+ return -1;
+ set_cloexec (fd);
+
+ int yes = 1;
+ soft_assert (setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE,
+ &yes, sizeof yes) != -1);
+ soft_assert (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
+ &yes, sizeof yes) != -1);
+
+ char real_host[NI_MAXHOST], real_port[NI_MAXSERV];
+ real_host[0] = real_port[0] = '\0';
+ int err = getnameinfo (gai_iter->ai_addr, gai_iter->ai_addrlen,
+ real_host, sizeof real_host, real_port, sizeof real_port,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (err)
+ print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
+
+ if (bind (fd, gai_iter->ai_addr, gai_iter->ai_addrlen))
+ print_error ("bind to %s:%s failed: %s",
+ real_host, real_port, strerror (errno));
+ else if (listen (fd, 16 /* arbitrary number */))
+ print_error ("listen at %s:%s failed: %s",
+ real_host, real_port, strerror (errno));
+ else
+ {
+ print_status ("listening at %s:%s", real_host, real_port);
+ return fd;
+ }
+
+ xclose (fd);
+ return -1;
+}
+
static bool
-irc_listen (struct server_context *ctx, struct error **e)
+irc_setup_listen_fds (struct server_context *ctx, struct error **e)
{
const char *bind_host = str_map_find (&ctx->config, "bind_host");
const char *bind_port = str_map_find (&ctx->config, "bind_port");
@@ -2795,56 +2838,27 @@ irc_listen (struct server_context *ctx, struct error **e)
return false;
}
- int sockfd;
- char real_host[NI_MAXHOST], real_port[NI_MAXSERV];
-
+ int fd;
for (gai_iter = gai_result; gai_iter; gai_iter = gai_iter->ai_next)
{
- sockfd = socket (gai_iter->ai_family,
- gai_iter->ai_socktype, gai_iter->ai_protocol);
- if (sockfd == -1)
- continue;
- set_cloexec (sockfd);
-
- int yes = 1;
- soft_assert (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
- &yes, sizeof yes) != -1);
- soft_assert (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
- &yes, sizeof yes) != -1);
-
- real_host[0] = real_port[0] = '\0';
- err = getnameinfo (gai_iter->ai_addr, gai_iter->ai_addrlen,
- real_host, sizeof real_host, real_port, sizeof real_port,
- NI_NUMERICHOST | NI_NUMERICSERV);
- if (err)
- print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
-
- if (bind (sockfd, gai_iter->ai_addr, gai_iter->ai_addrlen))
- print_error ("bind to %s:%s failed: %s",
- real_host, real_port, strerror (errno));
- else if (listen (sockfd, 16 /* arbitrary number */))
- print_error ("listen at %s:%s failed: %s",
- real_host, real_port, strerror (errno));
- else
+ if (ctx->n_listen_fds >= N_ELEMENTS (ctx->listen_fds))
break;
+ if ((fd = irc_listen (gai_iter)) == -1)
+ continue;
- xclose (sockfd);
+ ctx->listen_fds[ctx->n_listen_fds++] = fd;
+ set_blocking (fd, false);
+ poller_set (&ctx->poller, fd, POLLIN,
+ (poller_dispatcher_func) on_irc_client_available, ctx);
+ break;
}
-
freeaddrinfo (gai_result);
- if (!gai_iter)
+ if (!ctx->n_listen_fds)
{
error_set (e, "network setup failed");
return false;
}
-
- set_blocking (sockfd, false);
- ctx->listen_fd = sockfd;
- poller_set (&ctx->poller, ctx->listen_fd, POLLIN,
- (poller_dispatcher_func) on_irc_client_available, ctx);
-
- print_status ("listening at %s:%s", real_host, real_port);
return true;
}
@@ -2979,7 +2993,7 @@ main (int argc, char *argv[])
|| !irc_initialize_motd (&ctx, &e)
|| !irc_initialize_catalog (&ctx, &e)
|| !irc_parse_config (&ctx, &e)
- || !irc_listen (&ctx, &e))
+ || !irc_setup_listen_fds (&ctx, &e))
{
print_error ("%s", e->message);
error_free (e);