degesch: irc_{host,port} -> addresses
Now you can finally specify multiple addresses to connect to.
This commit is contained in:
parent
c5b38842bf
commit
a77ab689eb
159
degesch.c
159
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue