kike: asynchronous address resolution
As well as some refactoring and cleanup.
This commit is contained in:
		
							
								
								
									
										4
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								NEWS
									
									
									
									
									
								
							@@ -6,14 +6,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 * degesch: added autocomplete for /topic
 | 
					 * degesch: added autocomplete for /topic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * degesch: resolve remote addresses asynchronously
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 * degesch: Lua API was improved and extended
 | 
					 * degesch: Lua API was improved and extended
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * degesch: added a basic last.fm "now playing" plugin
 | 
					 * degesch: added a basic last.fm "now playing" plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * degesch: backlog limit was made configurable
 | 
					 * degesch: backlog limit was made configurable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Remote addresses are now resolved asynchronously
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * Various bugfixes
 | 
					 * Various bugfixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										196
									
								
								kike.c
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								kike.c
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * kike.c: the experimental IRC daemon
 | 
					 * kike.c: the experimental IRC daemon
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com>
 | 
					 * Copyright (c) 2014 - 2016, Přemysl Janouch <p.janouch@gmail.com>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Permission to use, copy, modify, and/or distribute this software for any
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 * purpose with or without fee is hereby granted, provided that the above
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
@@ -330,17 +330,17 @@ struct client
 | 
				
			|||||||
	struct poller_timer timeout_timer;  ///< Connection seems to be dead
 | 
						struct poller_timer timeout_timer;  ///< Connection seems to be dead
 | 
				
			||||||
	struct poller_timer kill_timer;     ///< Hard kill timeout
 | 
						struct poller_timer kill_timer;     ///< Hard kill timeout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool initialized;                   ///< Has any data been received yet?
 | 
					 | 
				
			||||||
	bool cap_negotiating;               ///< Negotiating capabilities
 | 
					 | 
				
			||||||
	bool registered;                    ///< The user has registered
 | 
					 | 
				
			||||||
	bool closing_link;                  ///< Closing link
 | 
					 | 
				
			||||||
	bool half_closed;                   ///< Closing link: conn. is half-closed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unsigned long cap_version;          ///< CAP protocol version
 | 
						unsigned long cap_version;          ///< CAP protocol version
 | 
				
			||||||
	unsigned caps_enabled;              ///< Enabled capabilities
 | 
						unsigned caps_enabled;              ///< Enabled capabilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool ssl_rx_want_tx;                ///< SSL_read() wants to write
 | 
						unsigned initialized     : 1;       ///< Has any data been received yet?
 | 
				
			||||||
	bool ssl_tx_want_rx;                ///< SSL_write() wants to read
 | 
						unsigned cap_negotiating : 1;       ///< Negotiating capabilities
 | 
				
			||||||
 | 
						unsigned registered      : 1;       ///< The user has registered
 | 
				
			||||||
 | 
						unsigned closing_link    : 1;       ///< Closing link
 | 
				
			||||||
 | 
						unsigned half_closed     : 1;       ///< Closing link: conn. is half-closed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned ssl_rx_want_tx  : 1;       ///< SSL_read() wants to write
 | 
				
			||||||
 | 
						unsigned ssl_tx_want_rx  : 1;       ///< SSL_write() wants to read
 | 
				
			||||||
	SSL *ssl;                           ///< SSL connection
 | 
						SSL *ssl;                           ///< SSL connection
 | 
				
			||||||
	char *ssl_cert_fingerprint;         ///< Client certificate fingerprint
 | 
						char *ssl_cert_fingerprint;         ///< Client certificate fingerprint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -349,20 +349,23 @@ struct client
 | 
				
			|||||||
	char *realname;                     ///< IRC realname (e-mail)
 | 
						char *realname;                     ///< IRC realname (e-mail)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *hostname;                     ///< Hostname shown to the network
 | 
						char *hostname;                     ///< Hostname shown to the network
 | 
				
			||||||
	char *address;                      ///< Full address including port
 | 
						char *port;                         ///< Port of the peer as a string
 | 
				
			||||||
 | 
						char *address;                      ///< Full address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned mode;                      ///< User's mode
 | 
						unsigned mode;                      ///< User's mode
 | 
				
			||||||
	char *away_message;                 ///< Away message
 | 
						char *away_message;                 ///< Away message
 | 
				
			||||||
	time_t last_active;                 ///< Last PRIVMSG, to get idle time
 | 
						time_t last_active;                 ///< Last PRIVMSG, to get idle time
 | 
				
			||||||
	struct str_map invites;             ///< Channel invitations by operators
 | 
						struct str_map invites;             ///< Channel invitations by operators
 | 
				
			||||||
	struct flood_detector antiflood;    ///< Flood detector
 | 
						struct flood_detector antiflood;    ///< Flood detector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct async_getnameinfo *gni;      ///< Backwards DNS resolution
 | 
				
			||||||
 | 
						struct poller_timer gni_timer;      ///< Backwards DNS resolution timeout
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static struct client *
 | 
				
			||||||
client_init (struct client *self)
 | 
					client_new (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	memset (self, 0, sizeof *self);
 | 
						struct client *self = xcalloc (1, sizeof *self);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	self->socket_fd = -1;
 | 
						self->socket_fd = -1;
 | 
				
			||||||
	str_init (&self->read_buffer);
 | 
						str_init (&self->read_buffer);
 | 
				
			||||||
	str_init (&self->write_buffer);
 | 
						str_init (&self->write_buffer);
 | 
				
			||||||
@@ -371,10 +374,11 @@ client_init (struct client *self)
 | 
				
			|||||||
	flood_detector_init (&self->antiflood, 10, 20);
 | 
						flood_detector_init (&self->antiflood, 10, 20);
 | 
				
			||||||
	str_map_init (&self->invites);
 | 
						str_map_init (&self->invites);
 | 
				
			||||||
	self->invites.key_xfrm = irc_strxfrm;
 | 
						self->invites.key_xfrm = irc_strxfrm;
 | 
				
			||||||
 | 
						return self;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
client_free (struct client *self)
 | 
					client_destroy (struct client *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!soft_assert (self->socket_fd == -1))
 | 
						if (!soft_assert (self->socket_fd == -1))
 | 
				
			||||||
		xclose (self->socket_fd);
 | 
							xclose (self->socket_fd);
 | 
				
			||||||
@@ -389,10 +393,16 @@ client_free (struct client *self)
 | 
				
			|||||||
	free (self->realname);
 | 
						free (self->realname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free (self->hostname);
 | 
						free (self->hostname);
 | 
				
			||||||
 | 
						free (self->port);
 | 
				
			||||||
	free (self->address);
 | 
						free (self->address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free (self->away_message);
 | 
						free (self->away_message);
 | 
				
			||||||
	flood_detector_free (&self->antiflood);
 | 
						flood_detector_free (&self->antiflood);
 | 
				
			||||||
	str_map_free (&self->invites);
 | 
						str_map_free (&self->invites);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (self->gni)
 | 
				
			||||||
 | 
							async_cancel (&self->gni->async);
 | 
				
			||||||
 | 
						free (self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_close_link (struct client *c, const char *reason);
 | 
					static void client_close_link (struct client *c, const char *reason);
 | 
				
			||||||
@@ -891,9 +901,52 @@ client_unregister (struct client *c, const char *reason)
 | 
				
			|||||||
	c->registered = false;
 | 
						c->registered = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					client_kill (struct client *c, const char *reason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct server_context *ctx = c->ctx;
 | 
				
			||||||
 | 
						client_unregister (c, reason ? reason : "Client exited");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (c->address)
 | 
				
			||||||
 | 
							// Only log the event if address resolution has finished
 | 
				
			||||||
 | 
							print_debug ("closed connection to %s (%s)", c->address,
 | 
				
			||||||
 | 
								reason ? reason : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (c->ssl)
 | 
				
			||||||
 | 
							// Note that we might have already called this once, but that is fine
 | 
				
			||||||
 | 
							(void) SSL_shutdown (c->ssl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xclose (c->socket_fd);
 | 
				
			||||||
 | 
						c->socket_fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c->socket_event.closed = true;
 | 
				
			||||||
 | 
						poller_fd_reset (&c->socket_event);
 | 
				
			||||||
 | 
						client_cancel_timers (c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LIST_UNLINK (ctx->clients, c);
 | 
				
			||||||
 | 
						ctx->n_clients--;
 | 
				
			||||||
 | 
						client_destroy (c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irc_try_finish_quit (ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
client_close_link (struct client *c, const char *reason)
 | 
					client_close_link (struct client *c, const char *reason)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Cannot push data to a client whose protocol we don't even know,
 | 
				
			||||||
 | 
						// at least not with current code (client_send_str(), on_client_ready()),
 | 
				
			||||||
 | 
						// which could possibly be solved by client_update_poller() not setting
 | 
				
			||||||
 | 
						// POLLOUT when the protocol hasn't been initialized yet.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// We also want to avoid accidentally setting poller events before
 | 
				
			||||||
 | 
						// address resolution has finished.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Let's just cut the connection, the client can try again later.
 | 
				
			||||||
 | 
						if (!c->initialized)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							client_kill (c, reason);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (!soft_assert (!c->closing_link))
 | 
						if (!soft_assert (!c->closing_link))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -910,35 +963,6 @@ client_close_link (struct client *c, const char *reason)
 | 
				
			|||||||
	client_set_kill_timer (c);
 | 
						client_set_kill_timer (c);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
client_kill (struct client *c, const char *reason)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	client_unregister (c, reason ? reason : "Client exited");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct server_context *ctx = c->ctx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (c->ssl)
 | 
					 | 
				
			||||||
		// Note that we might have already called this once, but that is fine
 | 
					 | 
				
			||||||
		(void) SSL_shutdown (c->ssl);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	xclose (c->socket_fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	c->socket_event.closed = true;
 | 
					 | 
				
			||||||
	poller_fd_reset (&c->socket_event);
 | 
					 | 
				
			||||||
	client_cancel_timers (c);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	print_debug ("closed connection to %s (%s)",
 | 
					 | 
				
			||||||
		c->address, reason ? reason : "");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	c->socket_fd = -1;
 | 
					 | 
				
			||||||
	client_free (c);
 | 
					 | 
				
			||||||
	LIST_UNLINK (ctx->clients, c);
 | 
					 | 
				
			||||||
	ctx->n_clients--;
 | 
					 | 
				
			||||||
	free (c);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	irc_try_finish_quit (ctx);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
client_in_mask_list (const struct client *c, const struct str_vector *mask)
 | 
					client_in_mask_list (const struct client *c, const struct str_vector *mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -991,6 +1015,7 @@ client_cancel_timers (struct client *c)
 | 
				
			|||||||
	poller_timer_reset (&c->kill_timer);
 | 
						poller_timer_reset (&c->kill_timer);
 | 
				
			||||||
	poller_timer_reset (&c->timeout_timer);
 | 
						poller_timer_reset (&c->timeout_timer);
 | 
				
			||||||
	poller_timer_reset (&c->ping_timer);
 | 
						poller_timer_reset (&c->ping_timer);
 | 
				
			||||||
 | 
						poller_timer_reset (&c->gni_timer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -3211,6 +3236,8 @@ irc_try_write_tls (struct client *c)
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
irc_autodetect_tls (struct client *c)
 | 
					irc_autodetect_tls (struct client *c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -3281,6 +3308,8 @@ error_ssl_1:
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_client_ready (const struct pollfd *pfd, void *user_data)
 | 
					on_client_ready (const struct pollfd *pfd, void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -3354,6 +3383,44 @@ client_update_poller (struct client *c, const struct pollfd *pfd)
 | 
				
			|||||||
		poller_fd_set (&c->socket_event, new_events);
 | 
							poller_fd_set (&c->socket_event, new_events);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					client_finish_connection (struct client *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						c->gni = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c->address = format_host_port_pair (c->hostname, c->port);
 | 
				
			||||||
 | 
						print_debug ("accepted connection from %s", c->address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						client_update_poller (c, NULL);
 | 
				
			||||||
 | 
						client_set_kill_timer (c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_client_gni_resolved (int result, char *host, char *port, void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct client *c = user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (result)
 | 
				
			||||||
 | 
							print_debug ("%s: %s", "getnameinfo", gai_strerror (result));
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							free (c->hostname);
 | 
				
			||||||
 | 
							c->hostname = xstrdup (host);
 | 
				
			||||||
 | 
							(void) port;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						poller_timer_reset (&c->gni_timer);
 | 
				
			||||||
 | 
						client_finish_connection (c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_client_gni_timer (void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct client *c = user_data;
 | 
				
			||||||
 | 
						async_cancel (&c->gni->async);
 | 
				
			||||||
 | 
						client_finish_connection (c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
irc_try_fetch_client (struct server_context *ctx, int listen_fd)
 | 
					irc_try_fetch_client (struct server_context *ctx, int listen_fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -3378,6 +3445,15 @@ irc_try_fetch_client (struct server_context *ctx, int listen_fd)
 | 
				
			|||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_blocking (fd, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A little bit questionable once the traffic gets high enough (IMO),
 | 
				
			||||||
 | 
						// but it reduces silly latencies that we don't need because we already
 | 
				
			||||||
 | 
						// do buffer our output
 | 
				
			||||||
 | 
						int yes = 1;
 | 
				
			||||||
 | 
						soft_assert (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY,
 | 
				
			||||||
 | 
							&yes, sizeof yes) != -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ctx->max_connections != 0 && ctx->n_clients >= ctx->max_connections)
 | 
						if (ctx->max_connections != 0 && ctx->n_clients >= ctx->max_connections)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		print_debug ("connection limit reached, refusing connection");
 | 
							print_debug ("connection limit reached, refusing connection");
 | 
				
			||||||
@@ -3385,23 +3461,18 @@ irc_try_fetch_client (struct server_context *ctx, int listen_fd)
 | 
				
			|||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: use async_getnameinfo() so that we never ever block here
 | 
					 | 
				
			||||||
	char host[NI_MAXHOST] = "unknown", port[NI_MAXSERV] = "unknown";
 | 
						char host[NI_MAXHOST] = "unknown", port[NI_MAXSERV] = "unknown";
 | 
				
			||||||
	int err = getnameinfo ((struct sockaddr *) &peer, peer_len,
 | 
						int err = getnameinfo ((struct sockaddr *) &peer, peer_len,
 | 
				
			||||||
		host, sizeof host, port, sizeof port, NI_NUMERICSERV);
 | 
							host, sizeof host, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
 | 
							print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *address = format_host_port_pair (host, port);
 | 
						struct client *c = client_new ();
 | 
				
			||||||
	print_debug ("accepted connection from %s", address);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct client *c = xmalloc (sizeof *c);
 | 
					 | 
				
			||||||
	client_init (c);
 | 
					 | 
				
			||||||
	c->ctx = ctx;
 | 
						c->ctx = ctx;
 | 
				
			||||||
	c->opened = time (NULL);
 | 
						c->opened = time (NULL);
 | 
				
			||||||
	c->socket_fd = fd;
 | 
						c->socket_fd = fd;
 | 
				
			||||||
	c->hostname = xstrdup (host);
 | 
						c->hostname = xstrdup (host);
 | 
				
			||||||
	c->address = address;
 | 
						c->port = xstrdup (port);
 | 
				
			||||||
	c->last_active = time (NULL);
 | 
						c->last_active = time (NULL);
 | 
				
			||||||
	LIST_PREPEND (ctx->clients, c);
 | 
						LIST_PREPEND (ctx->clients, c);
 | 
				
			||||||
	ctx->n_clients++;
 | 
						ctx->n_clients++;
 | 
				
			||||||
@@ -3422,16 +3493,19 @@ irc_try_fetch_client (struct server_context *ctx, int listen_fd)
 | 
				
			|||||||
	c->ping_timer.dispatcher = on_client_ping_timer;
 | 
						c->ping_timer.dispatcher = on_client_ping_timer;
 | 
				
			||||||
	c->ping_timer.user_data = c;
 | 
						c->ping_timer.user_data = c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// A little bit questionable once the traffic gets high enough (IMO),
 | 
						// Resolve the client's hostname first; this is a blocking operation that
 | 
				
			||||||
	// but it reduces silly latencies that we don't need because we already
 | 
						// depends on the network, so run it asynchronously with some timeout
 | 
				
			||||||
	// do buffer our output
 | 
						// FIXME: we can run out of threads when there's a lot of connections
 | 
				
			||||||
	int yes = 1;
 | 
						c->gni = async_getnameinfo (&ctx->poller.common.async,
 | 
				
			||||||
	soft_assert (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY,
 | 
							(const struct sockaddr *) &peer, peer_len, NI_NUMERICSERV);
 | 
				
			||||||
		&yes, sizeof yes) != -1);
 | 
						c->gni->dispatcher = on_client_gni_resolved;
 | 
				
			||||||
 | 
						c->gni->user_data = c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_blocking (fd, false);
 | 
						poller_timer_init (&c->gni_timer, &c->ctx->poller);
 | 
				
			||||||
	client_update_poller (c, NULL);
 | 
						c->gni_timer.dispatcher = on_client_gni_timer;
 | 
				
			||||||
	client_set_kill_timer (c);
 | 
						c->gni_timer.user_data = c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						poller_timer_set (&c->gni_timer, 5000);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user