aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kike.c137
1 files changed, 70 insertions, 67 deletions
diff --git a/kike.c b/kike.c
index 15c31df..7bbfef4 100644
--- a/kike.c
+++ b/kike.c
@@ -2760,81 +2760,84 @@ client_update_poller (struct client *c, const struct pollfd *pfd)
poller_fd_set (&c->socket_event, new_events);
}
-static void
-on_irc_client_available (const struct pollfd *pfd, void *user_data)
+static bool
+irc_try_fetch_client (struct server_context *ctx, int listen_fd)
{
- (void) pfd;
- struct server_context *ctx = user_data;
+ // XXX: `struct sockaddr_storage' is not the most portable thing
+ struct sockaddr_storage peer;
+ socklen_t peer_len = sizeof peer;
- while (true)
+ int fd = accept (listen_fd, (struct sockaddr *) &peer, &peer_len);
+ if (fd == -1)
{
- // XXX: `struct sockaddr_storage' is not the most portable thing
- struct sockaddr_storage peer;
- socklen_t peer_len = sizeof peer;
+ if (errno == EAGAIN)
+ return false;
+ if (errno == EINTR
+ || errno == ECONNABORTED)
+ return true;
- int fd = accept (pfd->fd, (struct sockaddr *) &peer, &peer_len);
- if (fd == -1)
- {
- if (errno == EAGAIN)
- break;
- if (errno == EINTR
- || errno == ECONNABORTED)
- continue;
-
- // TODO: handle resource exhaustion (EMFILE, ENFILE) specially
- // (stop accepting new connections and wait until we close some;
- // also set a timer in case of ENFILE).
- print_fatal ("%s: %s", "accept", strerror (errno));
- irc_initiate_quit (ctx);
- break;
- }
+ // TODO: handle resource exhaustion (EMFILE, ENFILE) specially
+ // (stop accepting new connections and wait until we close some;
+ // also set a timer in case of ENFILE).
+ print_fatal ("%s: %s", "accept", strerror (errno));
+ irc_initiate_quit (ctx);
+ return false;
+ }
- if (ctx->max_connections != 0 && ctx->n_clients >= ctx->max_connections)
- {
- print_debug ("connection limit reached, refusing connection");
- close (fd);
- continue;
- }
+ if (ctx->max_connections != 0 && ctx->n_clients >= ctx->max_connections)
+ {
+ print_debug ("connection limit reached, refusing connection");
+ close (fd);
+ return true;
+ }
- char host[NI_MAXHOST] = "unknown", port[NI_MAXSERV] = "unknown";
- int err = getnameinfo ((struct sockaddr *) &peer, peer_len,
- host, sizeof host, port, sizeof port, NI_NUMERICSERV);
- if (err)
- print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
+ char host[NI_MAXHOST] = "unknown", port[NI_MAXSERV] = "unknown";
+ int err = getnameinfo ((struct sockaddr *) &peer, peer_len,
+ host, sizeof host, port, sizeof port, NI_NUMERICSERV);
+ if (err)
+ print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
- char *address = format_host_port_pair (host, port);
- print_debug ("accepted connection from %s", address);
-
- struct client *c = xmalloc (sizeof *c);
- client_init (c);
- c->ctx = ctx;
- c->socket_fd = fd;
- c->hostname = xstrdup (host);
- c->address = address;
- c->last_active = time (NULL);
- LIST_PREPEND (ctx->clients, c);
- ctx->n_clients++;
-
- poller_fd_init (&c->socket_event, &c->ctx->poller, c->socket_fd);
- c->socket_event.dispatcher = (poller_fd_fn) on_client_ready;
- c->socket_event.user_data = c;
-
- poller_timer_init (&c->kill_timer, &c->ctx->poller);
- c->kill_timer.dispatcher = on_client_kill_timer;
- c->kill_timer.user_data = c;
-
- poller_timer_init (&c->timeout_timer, &c->ctx->poller);
- c->timeout_timer.dispatcher = on_client_timeout_timer;
- c->timeout_timer.user_data = c;
-
- poller_timer_init (&c->ping_timer, &c->ctx->poller);
- c->ping_timer.dispatcher = on_client_ping_timer;
- c->ping_timer.user_data = c;
+ char *address = format_host_port_pair (host, port);
+ print_debug ("accepted connection from %s", address);
+
+ struct client *c = xmalloc (sizeof *c);
+ client_init (c);
+ c->ctx = ctx;
+ c->socket_fd = fd;
+ c->hostname = xstrdup (host);
+ c->address = address;
+ c->last_active = time (NULL);
+ LIST_PREPEND (ctx->clients, c);
+ ctx->n_clients++;
- set_blocking (fd, false);
- client_update_poller (c, NULL);
- client_set_kill_timer (c);
- }
+ poller_fd_init (&c->socket_event, &c->ctx->poller, c->socket_fd);
+ c->socket_event.dispatcher = (poller_fd_fn) on_client_ready;
+ c->socket_event.user_data = c;
+
+ poller_timer_init (&c->kill_timer, &c->ctx->poller);
+ c->kill_timer.dispatcher = on_client_kill_timer;
+ c->kill_timer.user_data = c;
+
+ poller_timer_init (&c->timeout_timer, &c->ctx->poller);
+ c->timeout_timer.dispatcher = on_client_timeout_timer;
+ c->timeout_timer.user_data = c;
+
+ poller_timer_init (&c->ping_timer, &c->ctx->poller);
+ c->ping_timer.dispatcher = on_client_ping_timer;
+ c->ping_timer.user_data = c;
+
+ set_blocking (fd, false);
+ client_update_poller (c, NULL);
+ client_set_kill_timer (c);
+ return true;
+}
+
+static void
+on_irc_client_available (const struct pollfd *pfd, void *user_data)
+{
+ struct server_context *ctx = user_data;
+ while (irc_try_fetch_client (ctx, pfd->fd))
+ ;
}
// --- Application setup -------------------------------------------------------