Rewrite socks to async

Not quite working yet, however it's a massive and important change.
This commit is contained in:
2015-07-20 23:31:26 +02:00
parent b750590f18
commit 318b7400d1
3 changed files with 769 additions and 362 deletions

138
degesch.c
View File

@@ -1116,6 +1116,7 @@ struct server
enum server_state state; ///< Connection state
struct connector *connector; ///< Connection establisher
struct socks_connector *socks_conn; ///< SOCKS connection establisher
unsigned reconnect_attempt; ///< Number of reconnect attempt
bool manual_disconnect; ///< Don't reconnect after disconnect
@@ -1265,6 +1266,11 @@ server_free (struct server *self)
connector_free (self->connector);
free (self->connector);
}
if (self->socks_conn)
{
socks_connector_free (self->socks_conn);
free (self->socks_conn);
}
if (self->transport
&& self->transport->cleanup)
@@ -3591,10 +3597,16 @@ irc_shutdown (struct server *s)
static void
irc_destroy_connector (struct server *s)
{
connector_free (s->connector);
if (s->connector)
connector_free (s->connector);
free (s->connector);
s->connector = NULL;
if (s->socks_conn)
socks_connector_free (s->socks_conn);
free (s->socks_conn);
s->socks_conn = NULL;
// Not connecting anymore
s->state = IRC_DISCONNECTED;
}
@@ -4352,6 +4364,28 @@ irc_finish_connection (struct server *s, int socket)
refresh_prompt (s->ctx);
}
static void
irc_split_host_port (char *s, char **host, char **port)
{
char *colon = strrchr (s, ':');
if (colon)
{
*colon = '\0';
*port = ++colon;
}
else
*port = "6667";
// Unwrap IPv6 addresses in format_host_port_pair() format
size_t host_end = strlen (s) - 1;
if (*s == '[' && s[host_end] == ']')
s++[host_end] = '\0';
*host = s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
irc_on_connector_connecting (void *user_data, const char *address)
{
@@ -4382,32 +4416,13 @@ 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 = strrchr (s, ':');
if (colon)
{
*colon = '\0';
*port = ++colon;
}
else
*port = "6667";
// Unwrap IPv6 addresses in format_host_port_pair() format
size_t host_end = strlen (s) - 1;
if (*s == '[' && s[host_end] == ']')
s++[host_end] = '\0';
*host = s;
}
static bool
irc_setup_connector (struct server *s,
const struct str_vector *addresses, struct error **e)
{
struct connector *connector = xmalloc (sizeof *connector);
connector_init (connector, &s->ctx->poller);
s->connector = connector;
connector->user_data = s;
connector->on_connecting = irc_on_connector_connecting;
@@ -4415,69 +4430,76 @@ irc_setup_connector (struct server *s,
connector->on_connected = irc_on_connector_connected;
connector->on_failure = irc_on_connector_failure;
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;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO: see if we can further merge code for the two connectors, for example
// by making SOCKS 4A and 5 mere plugins for the connector, or by using
// a virtual interface common to them both (seems more likely)
static void
irc_on_socks_connecting (void *user_data,
const char *address, const char *via, const char *version)
{
struct server *s = user_data;
log_server_status (s, s->buffer,
"Connecting to #s via #s (#s)...", address, via, version);
}
static bool
irc_initiate_connect_socks (struct server *s,
irc_setup_connector_socks (struct server *s,
const struct str_vector *addresses, struct error **e)
{
const char *socks_host = get_config_string (s->config, "socks_host");
int64_t socks_port_int = get_config_integer (s->config, "socks_port");
const char *socks_username =
get_config_string (s->config, "socks_username");
const char *socks_password =
get_config_string (s->config, "socks_password");
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);
struct socks_connector *connector = xmalloc (sizeof *connector);
socks_connector_init (connector, &s->ctx->poller);
s->socks_conn = connector;
char *socks_port = xstrdup_printf ("%" PRIi64, socks_port_int);
// FIXME: the SOCKS connector may outlive these values
connector->hostname = socks_host;
// FIXME: memory leak
connector->service = xstrdup_printf ("%" PRIi64, socks_port_int);
connector->username = get_config_string (s->config, "socks_username");
connector->password = get_config_string (s->config, "socks_password");
log_server_status (s, s->buffer, "Connecting to #&s via #&s...",
format_host_port_pair (irc_host, irc_port),
format_host_port_pair (socks_host, socks_port));
connector->user_data = s;
connector->on_connecting = irc_on_socks_connecting;
connector->on_error = irc_on_connector_error;
connector->on_connected = irc_on_connector_connected;
connector->on_failure = irc_on_connector_failure;
// 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
for (size_t i = 0; i < addresses->len; i++)
{
error_set (e, "%s: %s", "SOCKS connection failed", error->message);
error_free (error);
result = false;
char *host, *port;
irc_split_host_port (addresses->vector[i], &host, &port);
if (!socks_connector_add_target (connector, host, port, e))
return false;
}
free (socks_port);
return result;
socks_connector_run (connector);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
irc_initiate_connect (struct server *s)
{
@@ -4497,13 +4519,17 @@ irc_initiate_connect (struct server *s)
cstr_split_ignore_empty (addresses, ',', &servers);
struct error *e = NULL;
if (!irc_initiate_connect_socks (s, &servers, &e) && !e)
if (!irc_setup_connector_socks (s, &servers, &e) && !e)
irc_setup_connector (s, &servers, &e);
str_vector_free (&servers);
if (e)
if (!e)
s->state = IRC_CONNECTING;
else
{
irc_destroy_connector (s);
log_server_error (s, s->buffer, "#s", e->message);
error_free (e);
irc_queue_reconnect (s);