kike: preparation for multiple listening sockets

It should be only a matter of modifying irc_setup_listen_fds() now.
This commit is contained in:
Přemysl Eric Janouch 2014-08-09 00:01:33 +02:00
parent e3010f2d6d
commit a7ba1eb15f
1 changed files with 66 additions and 52 deletions

View File

@ -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);