degesch: irc_{host,port} -> addresses
Now you can finally specify multiple addresses to connect to.
This commit is contained in:
		
							parent
							
								
									c5b38842bf
								
							
						
					
					
						commit
						a77ab689eb
					
				
							
								
								
									
										125
									
								
								degesch.c
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								degesch.c
									
									
									
									
									
								
							| @ -1249,6 +1249,29 @@ config_validate_nonjunk_string | ||||
| 	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 | ||||
| config_validate_nonnegative | ||||
| 	(const struct config_item_ *item, struct error **e) | ||||
| @ -1279,15 +1302,10 @@ static struct config_schema g_config_server[] = | ||||
| 	  .type      = CONFIG_ITEM_STRING, | ||||
| 	  .validate  = config_validate_nonjunk_string }, | ||||
| 
 | ||||
| 	{ .name      = "irc_host", | ||||
| 	  .comment   = "Address of the IRC server", | ||||
| 	  .type      = CONFIG_ITEM_STRING, | ||||
| 	  .validate  = config_validate_nonjunk_string }, | ||||
| 	{ .name      = "irc_port", | ||||
| 	  .comment   = "Port of the IRC server", | ||||
| 	  .type      = CONFIG_ITEM_INTEGER, | ||||
| 	  .validate  = config_validate_nonnegative, | ||||
| 	  .default_  = "6667" }, | ||||
| 	{ .name      = "addresses", | ||||
| 	  .comment   = "Addresses of the IRC network (e.g. \"irc.net:6667\")", | ||||
| 	  .type      = CONFIG_ITEM_STRING_ARRAY, | ||||
| 	  .validate  = config_validate_addresses }, | ||||
| 
 | ||||
| 	{ .name      = "ssl", | ||||
| 	  .comment   = "Whether to use SSL/TLS", | ||||
| @ -3303,9 +3321,24 @@ irc_on_connector_connected (void *user_data, int 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 | ||||
| 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); | ||||
| 	connector_init (connector, &s->ctx->poller); | ||||
| @ -3319,33 +3352,28 @@ irc_setup_connector (struct server *s, | ||||
| 	s->state = IRC_CONNECTING; | ||||
| 	s->connector = connector; | ||||
| 
 | ||||
| 	for (size_t i = 0; i < addresses->len; i++) | ||||
| 	{ | ||||
| 		char *host, *port; | ||||
| 		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); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| irc_initiate_connect (struct server *s) | ||||
| static bool | ||||
| 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; | ||||
| 
 | ||||
| 	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"); | ||||
| 	int64_t socks_port_int = get_config_integer (ctx, "server.socks_port"); | ||||
| 
 | ||||
| @ -3354,13 +3382,15 @@ irc_initiate_connect (struct server *s) | ||||
| 	const char *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); | ||||
| 
 | ||||
| 	// TODO: the SOCKS code needs a rewrite so that we don't block on it either
 | ||||
| 	struct error *e = NULL; | ||||
| 	if (socks_host) | ||||
| 	{ | ||||
| 	char *address = format_host_port_pair (irc_host, irc_port); | ||||
| 	char *socks_address = format_host_port_pair (socks_host, socks_port); | ||||
| 	buffer_send_status (ctx, s->buffer, | ||||
| @ -3368,22 +3398,49 @@ irc_initiate_connect (struct server *s) | ||||
| 	free (socks_address); | ||||
| 	free (address); | ||||
| 
 | ||||
| 	// TODO: the SOCKS code needs a rewrite so that we don't block on it either;
 | ||||
| 	//   perhaps it could act as a special kind of connector
 | ||||
| 	struct error *error = NULL; | ||||
| 	bool result = true; | ||||
| 	int fd = socks_connect (socks_host, socks_port, irc_host, irc_port, | ||||
| 		socks_username, socks_password, &error); | ||||
| 	if (fd != -1) | ||||
| 		irc_finish_connection (s, fd); | ||||
| 	else | ||||
| 	{ | ||||
| 			error_set (&e, "%s: %s", "SOCKS connection failed", error->message); | ||||
| 		error_set (e, "%s: %s", "SOCKS connection failed", error->message); | ||||
| 		error_free (error); | ||||
| 		result = false; | ||||
| 	} | ||||
| 	} | ||||
| 	else | ||||
| 		irc_setup_connector (s, irc_host, irc_port, &e); | ||||
| 
 | ||||
| 	free (irc_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) | ||||
| 	{ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user