degesch: irc_{host,port} -> addresses
Now you can finally specify multiple addresses to connect to.
This commit is contained in:
		
							
								
								
									
										159
									
								
								degesch.c
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								degesch.c
									
									
									
									
									
								
							@@ -1249,6 +1249,29 @@ config_validate_nonjunk_string
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					config_validate_addresses
 | 
				
			||||||
 | 
						(const struct config_item_ *item, struct error **e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (item->type == CONFIG_ITEM_NULL)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						if (!config_validate_nonjunk_string (item, e))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Comma-separated list of "host[:port]" pairs
 | 
				
			||||||
 | 
						regex_t re;
 | 
				
			||||||
 | 
						int err = regcomp (&re, "^([^/:,]+(:[^/:,]+)?)?"
 | 
				
			||||||
 | 
							"(,([^/:,]+(:[^/:,]+)?)?)*$", REG_EXTENDED | REG_NOSUB);
 | 
				
			||||||
 | 
						hard_assert (!err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool result = !regexec (&re, item->value.string.str, 0, NULL, 0);
 | 
				
			||||||
 | 
						if (!result)
 | 
				
			||||||
 | 
							error_set (e, "invalid address list string");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						regfree (&re);
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
config_validate_nonnegative
 | 
					config_validate_nonnegative
 | 
				
			||||||
	(const struct config_item_ *item, struct error **e)
 | 
						(const struct config_item_ *item, struct error **e)
 | 
				
			||||||
@@ -1279,15 +1302,10 @@ static struct config_schema g_config_server[] =
 | 
				
			|||||||
	  .type      = CONFIG_ITEM_STRING,
 | 
						  .type      = CONFIG_ITEM_STRING,
 | 
				
			||||||
	  .validate  = config_validate_nonjunk_string },
 | 
						  .validate  = config_validate_nonjunk_string },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ .name      = "irc_host",
 | 
						{ .name      = "addresses",
 | 
				
			||||||
	  .comment   = "Address of the IRC server",
 | 
						  .comment   = "Addresses of the IRC network (e.g. \"irc.net:6667\")",
 | 
				
			||||||
	  .type      = CONFIG_ITEM_STRING,
 | 
						  .type      = CONFIG_ITEM_STRING_ARRAY,
 | 
				
			||||||
	  .validate  = config_validate_nonjunk_string },
 | 
						  .validate  = config_validate_addresses },
 | 
				
			||||||
	{ .name      = "irc_port",
 | 
					 | 
				
			||||||
	  .comment   = "Port of the IRC server",
 | 
					 | 
				
			||||||
	  .type      = CONFIG_ITEM_INTEGER,
 | 
					 | 
				
			||||||
	  .validate  = config_validate_nonnegative,
 | 
					 | 
				
			||||||
	  .default_  = "6667" },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ .name      = "ssl",
 | 
						{ .name      = "ssl",
 | 
				
			||||||
	  .comment   = "Whether to use SSL/TLS",
 | 
						  .comment   = "Whether to use SSL/TLS",
 | 
				
			||||||
@@ -3303,9 +3321,24 @@ irc_on_connector_connected (void *user_data, int socket)
 | 
				
			|||||||
	irc_finish_connection (s, socket);
 | 
						irc_finish_connection (s, socket);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					irc_split_host_port (char *s, char **host, char **port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *colon = strchr (s, ':');
 | 
				
			||||||
 | 
						if (colon)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							*colon = '\0';
 | 
				
			||||||
 | 
							*port = ++colon;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							*port = "6667";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*host = s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
irc_setup_connector (struct server *s,
 | 
					irc_setup_connector (struct server *s,
 | 
				
			||||||
	const char *host, const char *port, struct error **e)
 | 
						const struct str_vector *addresses, struct error **e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct connector *connector = xmalloc (sizeof *connector);
 | 
						struct connector *connector = xmalloc (sizeof *connector);
 | 
				
			||||||
	connector_init (connector, &s->ctx->poller);
 | 
						connector_init (connector, &s->ctx->poller);
 | 
				
			||||||
@@ -3319,33 +3352,28 @@ irc_setup_connector (struct server *s,
 | 
				
			|||||||
	s->state = IRC_CONNECTING;
 | 
						s->state = IRC_CONNECTING;
 | 
				
			||||||
	s->connector = connector;
 | 
						s->connector = connector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!connector_add_target (connector, host, port, e))
 | 
						for (size_t i = 0; i < addresses->len; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		irc_destroy_connector (s);
 | 
							char *host, *port;
 | 
				
			||||||
		return false;
 | 
							irc_split_host_port (addresses->vector[i], &host, &port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!connector_add_target (connector, host, port, e))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								irc_destroy_connector (s);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	connector_step (connector);
 | 
						connector_step (connector);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static bool
 | 
				
			||||||
irc_initiate_connect (struct server *s)
 | 
					irc_initiate_connect_socks (struct server *s,
 | 
				
			||||||
 | 
						const struct str_vector *addresses, struct error **e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	hard_assert (s->state == IRC_DISCONNECTED);
 | 
					 | 
				
			||||||
	struct app_context *ctx = s->ctx;
 | 
						struct app_context *ctx = s->ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *irc_host = get_config_string (ctx, "server.irc_host");
 | 
					 | 
				
			||||||
	int64_t irc_port_int = get_config_integer (ctx, "server.irc_port");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!get_config_string (ctx, "server.irc_host"))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// No sense in trying to reconnect
 | 
					 | 
				
			||||||
		buffer_send_error (ctx, s->buffer,
 | 
					 | 
				
			||||||
			"No hostname specified in configuration");
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const char *socks_host = get_config_string (ctx, "server.socks_host");
 | 
						const char *socks_host = get_config_string (ctx, "server.socks_host");
 | 
				
			||||||
	int64_t socks_port_int = get_config_integer (ctx, "server.socks_port");
 | 
						int64_t socks_port_int = get_config_integer (ctx, "server.socks_port");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3354,36 +3382,65 @@ irc_initiate_connect (struct server *s)
 | 
				
			|||||||
	const char *socks_password =
 | 
						const char *socks_password =
 | 
				
			||||||
		get_config_string (ctx, "server.socks_password");
 | 
							get_config_string (ctx, "server.socks_password");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *irc_port   = xstrdup_printf ("%" PRIi64, irc_port_int);
 | 
						if (!socks_host)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIXME: we only try the first address (still better than nothing)
 | 
				
			||||||
 | 
						char *irc_host, *irc_port;
 | 
				
			||||||
 | 
						irc_split_host_port (addresses->vector[0], &irc_host, &irc_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *socks_port = xstrdup_printf ("%" PRIi64, socks_port_int);
 | 
						char *socks_port = xstrdup_printf ("%" PRIi64, socks_port_int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: the SOCKS code needs a rewrite so that we don't block on it either
 | 
						char *address = format_host_port_pair (irc_host, irc_port);
 | 
				
			||||||
	struct error *e = NULL;
 | 
						char *socks_address = format_host_port_pair (socks_host, socks_port);
 | 
				
			||||||
	if (socks_host)
 | 
						buffer_send_status (ctx, s->buffer,
 | 
				
			||||||
	{
 | 
							"Connecting to %s via %s...", address, socks_address);
 | 
				
			||||||
		char *address = format_host_port_pair (irc_host, irc_port);
 | 
						free (socks_address);
 | 
				
			||||||
		char *socks_address = format_host_port_pair (socks_host, socks_port);
 | 
						free (address);
 | 
				
			||||||
		buffer_send_status (ctx, s->buffer,
 | 
					 | 
				
			||||||
			"Connecting to %s via %s...", address, socks_address);
 | 
					 | 
				
			||||||
		free (socks_address);
 | 
					 | 
				
			||||||
		free (address);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct error *error = NULL;
 | 
						// TODO: the SOCKS code needs a rewrite so that we don't block on it either;
 | 
				
			||||||
		int fd = socks_connect (socks_host, socks_port, irc_host, irc_port,
 | 
						//   perhaps it could act as a special kind of connector
 | 
				
			||||||
			socks_username, socks_password, &error);
 | 
						struct error *error = NULL;
 | 
				
			||||||
		if (fd != -1)
 | 
						bool result = true;
 | 
				
			||||||
			irc_finish_connection (s, fd);
 | 
						int fd = socks_connect (socks_host, socks_port, irc_host, irc_port,
 | 
				
			||||||
		else
 | 
							socks_username, socks_password, &error);
 | 
				
			||||||
		{
 | 
						if (fd != -1)
 | 
				
			||||||
			error_set (&e, "%s: %s", "SOCKS connection failed", error->message);
 | 
							irc_finish_connection (s, fd);
 | 
				
			||||||
			error_free (error);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		irc_setup_connector (s, irc_host, irc_port, &e);
 | 
						{
 | 
				
			||||||
 | 
							error_set (e, "%s: %s", "SOCKS connection failed", error->message);
 | 
				
			||||||
 | 
							error_free (error);
 | 
				
			||||||
 | 
							result = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free (irc_port);
 | 
					 | 
				
			||||||
	free (socks_port);
 | 
						free (socks_port);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					irc_initiate_connect (struct server *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						hard_assert (s->state == IRC_DISCONNECTED);
 | 
				
			||||||
 | 
						struct app_context *ctx = s->ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *addresses = get_config_string (ctx, "server.addresses");
 | 
				
			||||||
 | 
						if (!addresses || !addresses[strspn (addresses, ",")])
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// No sense in trying to reconnect
 | 
				
			||||||
 | 
							buffer_send_error (ctx, s->buffer,
 | 
				
			||||||
 | 
								"No addresses specified in configuration");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct str_vector servers;
 | 
				
			||||||
 | 
						str_vector_init (&servers);
 | 
				
			||||||
 | 
						split_str_ignore_empty (addresses, ',', &servers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct error *e = NULL;
 | 
				
			||||||
 | 
						if (!irc_initiate_connect_socks (s, &servers, &e) && !e)
 | 
				
			||||||
 | 
							irc_setup_connector (s, &servers, &e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str_vector_free (&servers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (e)
 | 
						if (e)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								test
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								test
									
									
									
									
									
								
							@@ -20,7 +20,7 @@ expect_after {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Connect to the daemon
 | 
					# Connect to the daemon
 | 
				
			||||||
send "/set server.irc_host = \"localhost\"\n"
 | 
					send "/set server.addresses = \"localhost\"\n"
 | 
				
			||||||
expect "Option changed"
 | 
					expect "Option changed"
 | 
				
			||||||
send "/disconnect\n"
 | 
					send "/disconnect\n"
 | 
				
			||||||
expect "]"
 | 
					expect "]"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user