mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-09 19:06:15 +01:00
Hooked proxy enumeration into GSocketClient
This functionnallity can be disabled using property enable-proxy. It enumerates addresses using GSocketConnectable::proxy_enumerate() instead of enumerate(). When the returned address is of type GProxyAddress (a type based on GInetSocketAddress), it gets the proxy protocol handler using g_proxy_get_default_for_protocol() and call connect() on it. Reviewed-by: Dan Winship <danw@gnome.org>
This commit is contained in:
parent
ee3dbf747e
commit
a6c3820f46
@ -1798,6 +1798,8 @@ g_socket_client_get_local_address
|
||||
g_socket_client_get_protocol
|
||||
g_socket_client_get_socket_type
|
||||
g_socket_client_get_timeout
|
||||
g_socket_client_get_enable_proxy
|
||||
g_socket_client_set_enable_proxy
|
||||
<SUBSECTION Standard>
|
||||
GSocketClientClass
|
||||
G_IS_SOCKET_CLIENT
|
||||
|
@ -1359,12 +1359,14 @@ g_socket_client_get_local_address
|
||||
g_socket_client_get_protocol
|
||||
g_socket_client_get_socket_type
|
||||
g_socket_client_get_timeout
|
||||
g_socket_client_get_enable_proxy
|
||||
g_socket_client_new
|
||||
g_socket_client_set_family
|
||||
g_socket_client_set_local_address
|
||||
g_socket_client_set_protocol
|
||||
g_socket_client_set_socket_type
|
||||
g_socket_client_set_timeout
|
||||
g_socket_client_set_enable_proxy
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -26,18 +26,24 @@
|
||||
#include "gsocketclient.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gio/gioenumtypes.h>
|
||||
#include <gio/gsocketaddressenumerator.h>
|
||||
#include <gio/gsocketconnectable.h>
|
||||
#include <gio/gsocketconnection.h>
|
||||
#include <gio/gproxyaddressenumerator.h>
|
||||
#include <gio/gproxyaddress.h>
|
||||
#include <gio/gproxyconnection.h>
|
||||
#include <gio/gsimpleasyncresult.h>
|
||||
#include <gio/gcancellable.h>
|
||||
#include <gio/gioerror.h>
|
||||
#include <gio/gsocket.h>
|
||||
#include <gio/gnetworkaddress.h>
|
||||
#include <gio/gnetworkservice.h>
|
||||
#include <gio/gproxy.h>
|
||||
#include <gio/gsocketaddress.h>
|
||||
#include <gio/gtcpconnection.h>
|
||||
#include "glibintl.h"
|
||||
|
||||
|
||||
@ -71,7 +77,8 @@ enum
|
||||
PROP_TYPE,
|
||||
PROP_PROTOCOL,
|
||||
PROP_LOCAL_ADDRESS,
|
||||
PROP_TIMEOUT
|
||||
PROP_TIMEOUT,
|
||||
PROP_ENABLE_PROXY,
|
||||
};
|
||||
|
||||
struct _GSocketClientPrivate
|
||||
@ -81,6 +88,7 @@ struct _GSocketClientPrivate
|
||||
GSocketProtocol protocol;
|
||||
GSocketAddress *local_address;
|
||||
guint timeout;
|
||||
gboolean enable_proxy;
|
||||
};
|
||||
|
||||
static GSocket *
|
||||
@ -123,6 +131,15 @@ create_socket (GSocketClient *client,
|
||||
return socket;
|
||||
}
|
||||
|
||||
gboolean
|
||||
can_use_proxy (GSocketClient *client)
|
||||
{
|
||||
GSocketClientPrivate *priv = client->priv;
|
||||
|
||||
return priv->enable_proxy
|
||||
&& priv->type == G_SOCKET_TYPE_STREAM;
|
||||
}
|
||||
|
||||
static void
|
||||
g_socket_client_init (GSocketClient *client)
|
||||
{
|
||||
@ -190,6 +207,10 @@ g_socket_client_get_property (GObject *object,
|
||||
g_value_set_uint (value, client->priv->timeout);
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_PROXY:
|
||||
g_value_set_boolean (value, client->priv->enable_proxy);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@ -225,6 +246,10 @@ g_socket_client_set_property (GObject *object,
|
||||
g_socket_client_set_timeout (client, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_PROXY:
|
||||
g_socket_client_set_enable_proxy (client, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@ -399,7 +424,7 @@ g_socket_client_set_local_address (GSocketClient *client,
|
||||
GSocketAddress *address)
|
||||
{
|
||||
if (address)
|
||||
g_object_ref (address);
|
||||
g_object_ref (address);
|
||||
|
||||
if (client->priv->local_address)
|
||||
{
|
||||
@ -453,6 +478,46 @@ g_socket_client_set_timeout (GSocketClient *client,
|
||||
g_object_notify (G_OBJECT (client), "timeout");
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_client_get_enable_proxy:
|
||||
* @client: a #GSocketClient.
|
||||
*
|
||||
* Gets the proxy enable state; see g_socket_client_set_enable_proxy()
|
||||
*
|
||||
* Returns: whether proxying is enabled
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_socket_client_get_enable_proxy (GSocketClient *client)
|
||||
{
|
||||
return client->priv->enable_proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_client_set_enable_proxy:
|
||||
* @client: a #GSocketClient.
|
||||
* @enable: whether to enable proxies
|
||||
*
|
||||
* Sets whether or not @client attempts to make connections via a
|
||||
* proxy server. When enabled (the default), #GSocketClient will use a
|
||||
* #GProxyResolver to determine if a proxy protocol such as SOCKS is
|
||||
* needed, and automatically do the necessary proxy negotiation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_socket_client_set_enable_proxy (GSocketClient *client,
|
||||
gboolean enable)
|
||||
{
|
||||
enable = !!enable;
|
||||
if (client->priv->enable_proxy == enable)
|
||||
return;
|
||||
|
||||
client->priv->enable_proxy = enable;
|
||||
g_object_notify (G_OBJECT (client), "enable-proxy");
|
||||
}
|
||||
|
||||
static void
|
||||
g_socket_client_class_init (GSocketClientClass *class)
|
||||
{
|
||||
@ -512,6 +577,15 @@ g_socket_client_class_init (GSocketClientClass *class)
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_ENABLE_PROXY,
|
||||
g_param_spec_boolean ("enable-proxy",
|
||||
P_("Enable proxy"),
|
||||
P_("Enable proxy support"),
|
||||
TRUE,
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -551,14 +625,19 @@ g_socket_client_connect (GSocketClient *client,
|
||||
GError **error)
|
||||
{
|
||||
GSocketConnection *connection = NULL;
|
||||
GSocketAddressEnumerator *enumerator;
|
||||
GSocketAddressEnumerator *enumerator = NULL;
|
||||
GError *last_error, *tmp_error;
|
||||
|
||||
last_error = NULL;
|
||||
enumerator = g_socket_connectable_enumerate (connectable);
|
||||
|
||||
if (can_use_proxy (client))
|
||||
enumerator = g_socket_connectable_proxy_enumerate (connectable);
|
||||
else
|
||||
enumerator = g_socket_connectable_enumerate (connectable);
|
||||
|
||||
while (connection == NULL)
|
||||
{
|
||||
GSocketAddress *address;
|
||||
GSocketAddress *address = NULL;
|
||||
GSocket *socket;
|
||||
|
||||
if (g_cancellable_is_cancelled (cancellable))
|
||||
@ -570,7 +649,8 @@ g_socket_client_connect (GSocketClient *client,
|
||||
|
||||
tmp_error = NULL;
|
||||
address = g_socket_address_enumerator_next (enumerator, cancellable,
|
||||
&tmp_error);
|
||||
&tmp_error);
|
||||
|
||||
if (address == NULL)
|
||||
{
|
||||
if (tmp_error)
|
||||
@ -600,6 +680,71 @@ g_socket_client_connect (GSocketClient *client,
|
||||
g_object_unref (socket);
|
||||
}
|
||||
|
||||
if (connection &&
|
||||
G_IS_PROXY_ADDRESS (address) &&
|
||||
client->priv->enable_proxy)
|
||||
{
|
||||
GProxyAddress *proxy_addr = G_PROXY_ADDRESS (address);
|
||||
const gchar *protocol;
|
||||
GProxy *proxy;
|
||||
|
||||
protocol = g_proxy_address_get_protocol (proxy_addr);
|
||||
proxy = g_proxy_get_default_for_protocol (protocol);
|
||||
|
||||
/* The connection should not be anything else then TCP Connection,
|
||||
* but let's put a safety guard in case
|
||||
*/
|
||||
if (!G_IS_TCP_CONNECTION (connection))
|
||||
{
|
||||
g_critical ("Trying to proxy over non-TCP connection, this is "
|
||||
"most likely a bug in GLib IO library.");
|
||||
|
||||
g_set_error_literal (&last_error,
|
||||
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Trying to proxy over non-TCP connection is not supported."));
|
||||
|
||||
g_object_unref (connection);
|
||||
connection = NULL;
|
||||
}
|
||||
else if (proxy)
|
||||
{
|
||||
GIOStream *io_stream;
|
||||
GTcpConnection *old_connection = G_TCP_CONNECTION (connection);
|
||||
|
||||
io_stream = g_proxy_connect (proxy,
|
||||
G_IO_STREAM (old_connection),
|
||||
proxy_addr,
|
||||
cancellable,
|
||||
&last_error);
|
||||
|
||||
if (io_stream)
|
||||
{
|
||||
if (G_IS_SOCKET_CONNECTION (io_stream))
|
||||
connection = G_SOCKET_CONNECTION (g_object_ref (io_stream));
|
||||
else
|
||||
connection = _g_proxy_connection_new (old_connection,
|
||||
io_stream);
|
||||
|
||||
g_object_unref (io_stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = NULL;
|
||||
}
|
||||
|
||||
g_object_unref (old_connection);
|
||||
g_object_unref (proxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (&last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Proxy protocol '%s' is not supported."),
|
||||
protocol);
|
||||
g_object_unref (connection);
|
||||
connection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (address);
|
||||
}
|
||||
g_object_unref (enumerator);
|
||||
@ -720,7 +865,9 @@ typedef struct
|
||||
GSocketClient *client;
|
||||
|
||||
GSocketAddressEnumerator *enumerator;
|
||||
GProxyAddress *proxy_addr;
|
||||
GSocket *current_socket;
|
||||
GSocketConnection *connection;
|
||||
|
||||
GError *last_error;
|
||||
} GSocketClientAsyncConnectData;
|
||||
@ -728,8 +875,6 @@ typedef struct
|
||||
static void
|
||||
g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
|
||||
{
|
||||
GSocketConnection *connection;
|
||||
|
||||
if (data->last_error)
|
||||
{
|
||||
g_simple_async_result_set_from_error (data->result, data->last_error);
|
||||
@ -737,14 +882,10 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (data->current_socket);
|
||||
g_assert (data->connection);
|
||||
|
||||
g_socket_set_blocking (data->current_socket, TRUE);
|
||||
|
||||
connection = g_socket_connection_factory_create_connection (data->current_socket);
|
||||
g_object_unref (data->current_socket);
|
||||
g_simple_async_result_set_op_res_gpointer (data->result,
|
||||
connection,
|
||||
data->connection,
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
@ -753,6 +894,10 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
|
||||
g_object_unref (data->enumerator);
|
||||
if (data->cancellable)
|
||||
g_object_unref (data->cancellable);
|
||||
if (data->current_socket)
|
||||
g_object_unref (data->current_socket);
|
||||
if (data->proxy_addr)
|
||||
g_object_unref (data->proxy_addr);
|
||||
g_slice_free (GSocketClientAsyncConnectData, data);
|
||||
}
|
||||
|
||||
@ -770,6 +915,97 @@ set_last_error (GSocketClientAsyncConnectData *data,
|
||||
data->last_error = error;
|
||||
}
|
||||
|
||||
static void
|
||||
enumerator_next_async (GSocketClientAsyncConnectData *data)
|
||||
{
|
||||
g_socket_address_enumerator_next_async (data->enumerator,
|
||||
data->cancellable,
|
||||
g_socket_client_enumerator_callback,
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
g_socket_client_proxy_connect_callback (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSocketClientAsyncConnectData *data = user_data;
|
||||
GIOStream *io_stream;
|
||||
GTcpConnection *old_connection = G_TCP_CONNECTION (data->connection);
|
||||
|
||||
io_stream = g_proxy_connect_finish (G_PROXY (object),
|
||||
result,
|
||||
&data->last_error);
|
||||
|
||||
if (io_stream)
|
||||
{
|
||||
if (G_IS_SOCKET_CONNECTION (io_stream))
|
||||
data->connection = G_SOCKET_CONNECTION (g_object_ref (io_stream));
|
||||
else
|
||||
data->connection = _g_proxy_connection_new (old_connection,
|
||||
io_stream);
|
||||
g_object_unref (io_stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
data->connection = NULL;
|
||||
}
|
||||
|
||||
g_object_unref (old_connection);
|
||||
|
||||
g_socket_client_async_connect_complete (data);
|
||||
}
|
||||
|
||||
static void
|
||||
g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
|
||||
{
|
||||
GProxy *proxy;
|
||||
const gchar *protocol = g_proxy_address_get_protocol (data->proxy_addr);
|
||||
|
||||
proxy = g_proxy_get_default_for_protocol (protocol);
|
||||
|
||||
/* The connection should not be anything else then TCP Connection,
|
||||
* but let's put a safety guard in case
|
||||
*/
|
||||
if (!G_IS_TCP_CONNECTION (data->connection))
|
||||
{
|
||||
g_critical ("Trying to proxy over non-TCP connection, this is "
|
||||
"most likely a bug in GLib IO library.");
|
||||
|
||||
g_set_error_literal (&data->last_error,
|
||||
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Trying to proxy over non-TCP connection is not supported."));
|
||||
|
||||
g_object_unref (data->connection);
|
||||
data->connection = NULL;
|
||||
|
||||
enumerator_next_async (data);
|
||||
}
|
||||
else if (proxy)
|
||||
{
|
||||
g_proxy_connect_async (proxy,
|
||||
G_IO_STREAM (data->connection),
|
||||
data->proxy_addr,
|
||||
data->cancellable,
|
||||
g_socket_client_proxy_connect_callback,
|
||||
data);
|
||||
g_object_unref (proxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error (&data->last_error);
|
||||
|
||||
g_set_error (&data->last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Proxy protocol '%s' is not supported."),
|
||||
protocol);
|
||||
|
||||
g_object_unref (data->connection);
|
||||
data->connection = NULL;
|
||||
|
||||
enumerator_next_async (data);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_socket_client_socket_callback (GSocket *socket,
|
||||
GIOCondition condition,
|
||||
@ -796,16 +1032,23 @@ g_socket_client_socket_callback (GSocket *socket,
|
||||
data->current_socket = NULL;
|
||||
|
||||
/* try next one */
|
||||
g_socket_address_enumerator_next_async (data->enumerator,
|
||||
data->cancellable,
|
||||
g_socket_client_enumerator_callback,
|
||||
data);
|
||||
enumerator_next_async (data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_socket_client_async_connect_complete (data);
|
||||
g_socket_set_blocking (data->current_socket, TRUE);
|
||||
|
||||
data->connection =
|
||||
g_socket_connection_factory_create_connection (data->current_socket);
|
||||
g_object_unref (data->current_socket);
|
||||
data->current_socket = NULL;
|
||||
|
||||
if (data->proxy_addr)
|
||||
g_socket_client_proxy_connect (data);
|
||||
else
|
||||
g_socket_client_async_connect_complete (data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -816,7 +1059,7 @@ g_socket_client_enumerator_callback (GObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSocketClientAsyncConnectData *data = user_data;
|
||||
GSocketAddress *address;
|
||||
GSocketAddress *address = NULL;
|
||||
GSocket *socket;
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
@ -843,6 +1086,10 @@ g_socket_client_enumerator_callback (GObject *object,
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_IS_PROXY_ADDRESS (address) &&
|
||||
data->client->priv->enable_proxy)
|
||||
data->proxy_addr = g_object_ref (G_PROXY_ADDRESS (address));
|
||||
|
||||
g_clear_error (&data->last_error);
|
||||
|
||||
socket = create_socket (data->client, address, &data->last_error);
|
||||
@ -880,13 +1127,10 @@ g_socket_client_enumerator_callback (GObject *object,
|
||||
data->last_error = tmp_error;
|
||||
g_object_unref (socket);
|
||||
}
|
||||
g_object_unref (address);
|
||||
}
|
||||
|
||||
g_socket_address_enumerator_next_async (data->enumerator,
|
||||
data->cancellable,
|
||||
g_socket_client_enumerator_callback,
|
||||
data);
|
||||
g_object_unref (address);
|
||||
enumerator_next_async (data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -916,7 +1160,7 @@ g_socket_client_connect_async (GSocketClient *client,
|
||||
|
||||
g_return_if_fail (G_IS_SOCKET_CLIENT (client));
|
||||
|
||||
data = g_slice_new (GSocketClientAsyncConnectData);
|
||||
data = g_slice_new0 (GSocketClientAsyncConnectData);
|
||||
|
||||
data->result = g_simple_async_result_new (G_OBJECT (client),
|
||||
callback, user_data,
|
||||
@ -924,14 +1168,13 @@ g_socket_client_connect_async (GSocketClient *client,
|
||||
data->client = client;
|
||||
if (cancellable)
|
||||
data->cancellable = g_object_ref (cancellable);
|
||||
else
|
||||
data->cancellable = NULL;
|
||||
data->last_error = NULL;
|
||||
data->enumerator = g_socket_connectable_enumerate (connectable);
|
||||
|
||||
g_socket_address_enumerator_next_async (data->enumerator, cancellable,
|
||||
g_socket_client_enumerator_callback,
|
||||
data);
|
||||
if (can_use_proxy (client))
|
||||
data->enumerator = g_socket_connectable_proxy_enumerate (connectable);
|
||||
else
|
||||
data->enumerator = g_socket_connectable_enumerate (connectable);
|
||||
|
||||
enumerator_next_async (data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,6 +85,9 @@ void g_socket_client_set_local_address (GSocket
|
||||
guint g_socket_client_get_timeout (GSocketClient *client);
|
||||
void g_socket_client_set_timeout (GSocketClient *client,
|
||||
guint timeout);
|
||||
gboolean g_socket_client_get_enable_proxy (GSocketClient *client);
|
||||
void g_socket_client_set_enable_proxy (GSocketClient *client,
|
||||
gboolean enable);
|
||||
|
||||
GSocketConnection * g_socket_client_connect (GSocketClient *client,
|
||||
GSocketConnectable *connectable,
|
||||
|
Loading…
Reference in New Issue
Block a user