kike: implement connection limit
Somehow I'm not sure whether this thing is useful in any sense.
This commit is contained in:
parent
2fe3c7ed45
commit
5bedd3918c
55
src/kike.c
55
src/kike.c
@ -37,7 +37,7 @@ static struct config_item g_config_table[] =
|
||||
{ "ssl_cert", NULL, "Server SSL certificate (PEM)" },
|
||||
{ "ssl_key", NULL, "Server SSL private key (PEM)" },
|
||||
|
||||
{ "max_connections", NULL, "Maximum client connections" },
|
||||
{ "max_connections", "0", "Global connection limit" },
|
||||
{ "ping_interval", "180", "Interval between PING's (sec)" },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
@ -365,6 +365,7 @@ struct server_context
|
||||
int listen_fd; ///< Listening socket FD
|
||||
struct client *clients; ///< Clients
|
||||
SSL_CTX *ssl_ctx; ///< SSL context
|
||||
unsigned n_clients; ///< Current number of connections
|
||||
|
||||
struct str_map users; ///< Maps nicknames to clients
|
||||
struct str_map channels; ///< Maps channel names to data
|
||||
@ -377,6 +378,7 @@ struct server_context
|
||||
struct str_map config; ///< Server configuration
|
||||
char *server_name; ///< Our server name
|
||||
unsigned ping_interval; ///< Ping interval in seconds
|
||||
unsigned max_connections; ///< Max. connections allowed or 0
|
||||
struct str_vector motd; ///< MOTD (none if empty)
|
||||
nl_catd catalog; ///< Message catalog for server msgs
|
||||
};
|
||||
@ -384,14 +386,10 @@ struct server_context
|
||||
static void
|
||||
server_context_init (struct server_context *self)
|
||||
{
|
||||
str_map_init (&self->config);
|
||||
self->config.free = free;
|
||||
load_config_defaults (&self->config, g_config_table);
|
||||
|
||||
self->listen_fd = -1;
|
||||
self->clients = NULL;
|
||||
self->n_clients = 0;
|
||||
|
||||
self->server_name = NULL;
|
||||
str_map_init (&self->users);
|
||||
self->users.key_xfrm = irc_strxfrm;
|
||||
// TODO: set channel_free() as the free function?
|
||||
@ -404,6 +402,13 @@ server_context_init (struct server_context *self)
|
||||
self->quitting = false;
|
||||
self->polling = false;
|
||||
|
||||
str_map_init (&self->config);
|
||||
self->config.free = free;
|
||||
load_config_defaults (&self->config, g_config_table);
|
||||
|
||||
self->server_name = NULL;
|
||||
self->ping_interval = 0;
|
||||
self->max_connections = 0;
|
||||
str_vector_init (&self->motd);
|
||||
self->catalog = (nl_catd) -1;
|
||||
}
|
||||
@ -476,6 +481,7 @@ client_kill (struct client *c, const char *reason)
|
||||
c->socket_fd = -1;
|
||||
client_free (c);
|
||||
LIST_UNLINK (ctx->clients, c);
|
||||
ctx->n_clients--;
|
||||
free (c);
|
||||
}
|
||||
|
||||
@ -1239,8 +1245,6 @@ on_irc_client_available (const struct pollfd *pfd, void *user_data)
|
||||
(void) pfd;
|
||||
struct server_context *ctx = user_data;
|
||||
|
||||
// TODO: stop accepting new connections when `max_connections' is reached
|
||||
|
||||
while (true)
|
||||
{
|
||||
// XXX: `struct sockaddr_storage' is not the most portable thing
|
||||
@ -1252,9 +1256,8 @@ on_irc_client_available (const struct pollfd *pfd, void *user_data)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
break;
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == ECONNABORTED)
|
||||
if (errno == EINTR
|
||||
|| errno == ECONNABORTED)
|
||||
continue;
|
||||
|
||||
// TODO: handle resource exhaustion (EMFILE, ENFILE) specially
|
||||
@ -1263,6 +1266,14 @@ on_irc_client_available (const struct pollfd *pfd, void *user_data)
|
||||
exit_fatal ("%s: %s", "accept", strerror (errno));
|
||||
}
|
||||
|
||||
if (ctx->max_connections != 0
|
||||
&& ctx->n_clients >= ctx->max_connections)
|
||||
{
|
||||
print_debug ("connection limit reached, refusing connection");
|
||||
close (fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -1276,6 +1287,7 @@ on_irc_client_available (const struct pollfd *pfd, void *user_data)
|
||||
c->socket_fd = fd;
|
||||
c->hostname = xstrdup (host);
|
||||
LIST_PREPEND (ctx->clients, c);
|
||||
ctx->n_clients++;
|
||||
|
||||
set_blocking (fd, false);
|
||||
poller_set (&ctx->poller, fd, POLLIN,
|
||||
@ -1434,16 +1446,19 @@ static bool
|
||||
irc_parse_config (struct server_context *ctx, struct error **e)
|
||||
{
|
||||
unsigned long ul;
|
||||
#define PARSE_UNSIGNED(name, min, max) \
|
||||
const char *name = str_map_find (&ctx->config, #name); \
|
||||
hard_assert (name != NULL); \
|
||||
if (!xstrtoul (&ul, name, 10) || ul > max || ul < min) \
|
||||
{ \
|
||||
error_set (e, "invalid configuration value for `%s': %s", \
|
||||
#name, "the number is invalid or out of range"); \
|
||||
return false; \
|
||||
} \
|
||||
ctx->name = ul
|
||||
|
||||
const char *ping_interval = str_map_find (&ctx->config, "ping_interval");
|
||||
hard_assert (ping_interval != NULL); // We have a default value for this
|
||||
if (!xstrtoul (&ul, ping_interval, 10) || ul > UINT_MAX)
|
||||
{
|
||||
error_set (e, "invalid configuration value for `%s': %s",
|
||||
"ping_interval", "the number is invalid or out of range");
|
||||
return false;
|
||||
}
|
||||
ctx->ping_interval = ul;
|
||||
PARSE_UNSIGNED (ping_interval, 1, UINT_MAX);
|
||||
PARSE_UNSIGNED (max_connections, 0, UINT_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user