diff options
| -rw-r--r-- | src/kike.c | 118 | 
1 files changed, 66 insertions, 52 deletions
| @@ -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); | 
