SOCKS: finishing touches

Making sure that I handle all corner cases appropriately.
This commit is contained in:
Přemysl Eric Janouch 2015-07-22 00:34:27 +02:00
parent 7d9b05eb9a
commit c34bb483ca
1 changed files with 48 additions and 32 deletions

View File

@ -383,23 +383,20 @@ struct socks_connector
// Negotiation:
struct poller_timer timeout; ///< Timeout timer
int socket_fd; ///< Current socket file descriptor
struct poller_fd socket_event; ///< Socket can be read from/written to
struct str read_buffer; ///< Read buffer
struct str write_buffer; ///< Write buffer
struct poller_timer timeout; ///< Timeout timer
bool done; ///< We're connected
bool done; ///< Tunnel succesfully established
uint8_t bound_address_len; ///< Length of domain name
struct socks_addr bound_address; ///< Bound address at the server
uint16_t bound_port; ///< Bound port at the server
size_t data_needed; ///< How much data "on_data" needs
/// Process incoming data if there's enough of it available
bool (*on_data) (struct socks_connector *, struct msg_unpacker *);
size_t data_needed; ///< How much data the callback needs
// Configuration:
const char *hostname; ///< SOCKS server hostname
@ -413,6 +410,11 @@ struct socks_connector
void *user_data; ///< User data for callbacks
// Additional results:
struct socks_addr bound_address; ///< Bound address at the server
uint16_t bound_port; ///< Bound port at the server
// You may destroy the connector object in these two main callbacks:
/// Connection has been successfully established
@ -429,6 +431,8 @@ struct socks_connector
void (*on_error) (void *user_data, const char *error);
};
// I've tried to make the actual protocol handlers as simple as possible
#define SOCKS_FAIL(...) \
BLOCK_START \
char *error = xstrdup_printf (__VA_ARGS__); \
@ -712,18 +716,38 @@ socks_5_auth_start (struct socks_connector *self)
static void socks_connector_start (struct socks_connector *self);
static void
socks_connector_destroy_connector (struct socks_connector *self)
{
if (self->connector)
{
connector_free (self->connector);
free (self->connector);
self->connector = NULL;
}
}
static void
socks_connector_cancel_events (struct socks_connector *self)
{
// Before calling the final callbacks, we should cancel events that
// could potentially fire; caller should destroy us immediately, though
poller_fd_reset (&self->socket_event);
poller_timer_reset (&self->timeout);
}
static void
socks_connector_fail (struct socks_connector *self)
{
poller_fd_reset (&self->socket_event);
socks_connector_cancel_events (self);
self->on_failure (self->user_data);
}
static bool
socks_connector_step_iterators (struct socks_connector *self)
{
// At the lowest level we iterate over all addresses for the SOCKS server;
// this is done automatically by the connector
// At the lowest level we iterate over all addresses for the SOCKS server
// and just try to connect; this is done automatically by the connector
// Then we iterate over available protocols
if (++self->protocol_iter != SOCKS_MAX)
@ -747,13 +771,7 @@ socks_connector_step (struct socks_connector *self)
self->socket_fd = -1;
}
if (self->connector)
{
connector_free (self->connector);
free (self->connector);
self->connector = NULL;
}
socks_connector_destroy_connector (self);
if (socks_connector_step_iterators (self))
socks_connector_start (self);
else
@ -766,6 +784,7 @@ socks_connector_on_timeout (struct socks_connector *self)
if (self->on_error)
self->on_error (self->user_data, "timeout");
socks_connector_destroy_connector (self);
socks_connector_fail (self);
}
@ -783,11 +802,9 @@ socks_connector_on_connected (void *user_data, int socket_fd)
str_reset (&self->read_buffer);
str_reset (&self->write_buffer);
if ((self->protocol_iter == SOCKS_5 && socks_5_auth_start (self))
|| (self->protocol_iter == SOCKS_4A && socks_4a_start (self)))
return;
socks_connector_fail (self);
if (!(self->protocol_iter == SOCKS_5 && socks_5_auth_start (self))
&& !(self->protocol_iter == SOCKS_4A && socks_4a_start (self)))
socks_connector_fail (self);
}
static void
@ -838,9 +855,13 @@ socks_connector_start (struct socks_connector *self)
hard_assert (connector_add_target (connector,
self->hostname, self->service, NULL));
connector_step (connector);
poller_timer_set (&self->timeout, 60 * 1000);
connector_step (connector);
self->done = false;
self->bound_port = 0;
socks_addr_free (&self->bound_address);
memset (&self->bound_address, 0, sizeof self->bound_address);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -923,8 +944,9 @@ socks_connector_on_ready
}
else if (self->done)
{
socks_connector_cancel_events (self);
int fd = self->socket_fd;
poller_fd_reset (&self->socket_event);
self->socket_fd = -1;
set_blocking (fd, true);
self->on_connected (self->user_data, fd);
@ -956,14 +978,8 @@ socks_connector_init (struct socks_connector *self, struct poller *poller)
static void
socks_connector_free (struct socks_connector *self)
{
if (self->connector)
{
connector_free (self->connector);
free (self->connector);
}
poller_fd_reset (&self->socket_event);
poller_timer_reset (&self->timeout);
socks_connector_destroy_connector (self);
socks_connector_cancel_events (self);
if (self->socket_fd != -1)
xclose (self->socket_fd);