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;
|
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 "]"
|
||||||
|
|
Loading…
Reference in New Issue