From a77ab689eb1d6ba15f3f2195d70bcdc464b0c74c Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Thu, 14 May 2015 06:22:58 +0200
Subject: degesch: irc_{host,port} -> addresses
Now you can finally specify multiple addresses to connect to.
---
degesch.c | 161 ++++++++++++++++++++++++++++++++++++++++++--------------------
test | 2 +-
2 files changed, 110 insertions(+), 53 deletions(-)
diff --git a/degesch.c b/degesch.c
index f3ad894..5b54e0d 100644
--- a/degesch.c
+++ b/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;
- if (!connector_add_target (connector, host, port, e))
+ for (size_t i = 0; i < addresses->len; i++)
{
- irc_destroy_connector (s);
- return false;
+ 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,36 +3382,65 @@ 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,
- "Connecting to %s via %s...", address, socks_address);
- free (socks_address);
- free (address);
-
- struct error *error = NULL;
- 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_free (error);
- }
- }
+ 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,
+ "Connecting to %s via %s...", address, socks_address);
+ 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
- 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);
+ 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)
{
diff --git a/test b/test
index 38227aa..daef9f8 100755
--- a/test
+++ b/test
@@ -20,7 +20,7 @@ expect_after {
}
# Connect to the daemon
-send "/set server.irc_host = \"localhost\"\n"
+send "/set server.addresses = \"localhost\"\n"
expect "Option changed"
send "/disconnect\n"
expect "]"
--
cgit v1.2.3-70-g09d2