* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
* Alexander Larsson <alexl@redhat.com>
#include <gio/gsocketaddressenumerator.h>
#include <gio/gsocketconnectable.h>
#include <gio/gsocketconnection.h>
+#include <gio/gioprivate.h>
#include <gio/gproxyaddressenumerator.h>
#include <gio/gproxyaddress.h>
#include <gio/gtask.h>
#include <gio/gnetworkaddress.h>
#include <gio/gnetworkservice.h>
#include <gio/gproxy.h>
+#include <gio/gproxyresolver.h>
#include <gio/gsocketaddress.h>
#include <gio/gtcpconnection.h>
#include <gio/gtcpwrapperconnection.h>
*/
-G_DEFINE_TYPE (GSocketClient, g_socket_client, G_TYPE_OBJECT);
-
enum
{
EVENT,
PROP_TIMEOUT,
PROP_ENABLE_PROXY,
PROP_TLS,
- PROP_TLS_VALIDATION_FLAGS
+ PROP_TLS_VALIDATION_FLAGS,
+ PROP_PROXY_RESOLVER
};
struct _GSocketClientPrivate
GHashTable *app_proxies;
gboolean tls;
GTlsCertificateFlags tls_validation_flags;
+ GProxyResolver *proxy_resolver;
};
+G_DEFINE_TYPE_WITH_PRIVATE (GSocketClient, g_socket_client, G_TYPE_OBJECT)
+
static GSocket *
create_socket (GSocketClient *client,
GSocketAddress *dest_address,
static void
g_socket_client_init (GSocketClient *client)
{
- client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
- G_TYPE_SOCKET_CLIENT,
- GSocketClientPrivate);
+ client->priv = g_socket_client_get_instance_private (client);
client->priv->type = G_SOCKET_TYPE_STREAM;
client->priv->app_proxies = g_hash_table_new_full (g_str_hash,
g_str_equal,
{
GSocketClient *client = G_SOCKET_CLIENT (object);
- if (client->priv->local_address)
- g_object_unref (client->priv->local_address);
+ g_clear_object (&client->priv->local_address);
+ g_clear_object (&client->priv->proxy_resolver);
- if (G_OBJECT_CLASS (g_socket_client_parent_class)->finalize)
- (*G_OBJECT_CLASS (g_socket_client_parent_class)->finalize) (object);
+ G_OBJECT_CLASS (g_socket_client_parent_class)->finalize (object);
g_hash_table_unref (client->priv->app_proxies);
}
g_value_set_flags (value, g_socket_client_get_tls_validation_flags (client));
break;
+ case PROP_PROXY_RESOLVER:
+ g_value_set_object (value, g_socket_client_get_proxy_resolver (client));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
g_socket_client_set_tls_validation_flags (client, g_value_get_flags (value));
break;
+ case PROP_PROXY_RESOLVER:
+ g_socket_client_set_proxy_resolver (client, g_value_get_object (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
* #GProxyResolver to determine if a proxy protocol such as SOCKS is
* needed, and automatically do the necessary proxy negotiation.
*
+ * See also g_socket_client_set_proxy_resolver().
+ *
* Since: 2.26
*/
void
}
}
+/**
+ * g_socket_client_get_proxy_resolver:
+ * @client: a #GSocketClient.
+ *
+ * Gets the #GProxyResolver being used by @client. Normally, this will
+ * be the resolver returned by g_proxy_resolver_get_default(), but you
+ * can override it with g_socket_client_set_proxy_resolver().
+ *
+ * Returns: (transfer none): The #GProxyResolver being used by
+ * @client.
+ *
+ * Since: 2.36
+ */
+GProxyResolver *
+g_socket_client_get_proxy_resolver (GSocketClient *client)
+{
+ if (client->priv->proxy_resolver)
+ return client->priv->proxy_resolver;
+ else
+ return g_proxy_resolver_get_default ();
+}
+
+/**
+ * g_socket_client_set_proxy_resolver:
+ * @client: a #GSocketClient.
+ * @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL for the
+ * default.
+ *
+ * Overrides the #GProxyResolver used by @client. You can call this if
+ * you want to use specific proxies, rather than using the system
+ * default proxy settings.
+ *
+ * Note that whether or not the proxy resolver is actually used
+ * depends on the setting of #GSocketClient:enable-proxy, which is not
+ * changed by this function (but which is %TRUE by default)
+ *
+ * Since: 2.36
+ */
+void
+g_socket_client_set_proxy_resolver (GSocketClient *client,
+ GProxyResolver *proxy_resolver)
+{
+ /* We have to be careful to avoid calling
+ * g_proxy_resolver_get_default() until we're sure we need it,
+ * because trying to load the default proxy resolver module will
+ * break some test programs that aren't expecting it (eg,
+ * tests/gsettings).
+ */
+
+ if (client->priv->proxy_resolver)
+ g_object_unref (client->priv->proxy_resolver);
+
+ client->priv->proxy_resolver = proxy_resolver;
+
+ if (client->priv->proxy_resolver)
+ g_object_ref (client->priv->proxy_resolver);
+}
+
static void
g_socket_client_class_init (GSocketClientClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
- g_type_class_add_private (class, sizeof (GSocketClientPrivate));
-
gobject_class->finalize = g_socket_client_finalize;
gobject_class->set_property = g_socket_client_set_property;
gobject_class->get_property = g_socket_client_get_property;
* information about a network connection in the UI. The meanings of
* the different @event values are as follows:
*
- * <variablelist>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_RESOLVING:</term>
- * <listitem><para>
- * @client is about to look up @connectable in DNS.
- * @connection will be %NULL.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_RESOLVED:</term>
- * <listitem><para>
- * @client has successfully resolved @connectable in DNS.
- * @connection will be %NULL.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_CONNECTING:</term>
- * <listitem><para>
- * @client is about to make a connection to a remote host;
- * either a proxy server or the destination server itself.
- * @connection is the #GSocketConnection, which is not yet
- * connected.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_CONNECTED:</term>
- * <listitem><para>
- * @client has successfully connected to a remote host.
- * @connection is the connected #GSocketConnection.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_PROXY_NEGOTIATING:</term>
- * <listitem><para>
- * @client is about to negotiate with a proxy to get it to
- * connect to @connectable. @connection is the
- * #GSocketConnection to the proxy server.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_PROXY_NEGOTIATED:</term>
- * <listitem><para>
- * @client has negotiated a connection to @connectable through
- * a proxy server. @connection is the stream returned from
- * g_proxy_connect(), which may or may not be a
- * #GSocketConnection.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_TLS_HANDSHAKING:</term>
- * <listitem><para>
- * @client is about to begin a TLS handshake. @connection is a
- * #GTlsClientConnection.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_TLS_HANDSHAKED:</term>
- * <listitem><para>
- * @client has successfully completed the TLS handshake.
- * @connection is a #GTlsClientConnection.
- * </para></listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>%G_SOCKET_CLIENT_COMPLETE:</term>
- * <listitem><para>
- * @client has either successfully connected to @connectable
- * (in which case @connection is the #GSocketConnection that
- * it will be returning to the caller) or has failed (in which
- * case @connection is %NULL and the client is about to return
- * an error).
- * </para></listitem>
- * </varlistentry>
- * </variablelist>
+ * - %G_SOCKET_CLIENT_RESOLVING: @client is about to look up @connectable
+ * in DNS. @connection will be %NULL.
+ *
+ * - %G_SOCKET_CLIENT_RESOLVED: @client has successfully resolved
+ * @connectable in DNS. @connection will be %NULL.
+ *
+ * - %G_SOCKET_CLIENT_CONNECTING: @client is about to make a connection
+ * to a remote host; either a proxy server or the destination server
+ * itself. @connection is the #GSocketConnection, which is not yet
+ * connected. Since GLib 2.40, you can access the remote
+ * address via g_socket_connection_get_remote_address().
+ *
+ * - %G_SOCKET_CLIENT_CONNECTED: @client has successfully connected
+ * to a remote host. @connection is the connected #GSocketConnection.
+ *
+ * - %G_SOCKET_CLIENT_PROXY_NEGOTIATING: @client is about to negotiate
+ * with a proxy to get it to connect to @connectable. @connection is
+ * the #GSocketConnection to the proxy server.
+ *
+ * - %G_SOCKET_CLIENT_PROXY_NEGOTIATED: @client has negotiated a
+ * connection to @connectable through a proxy server. @connection is
+ * the stream returned from g_proxy_connect(), which may or may not
+ * be a #GSocketConnection.
+ *
+ * - %G_SOCKET_CLIENT_TLS_HANDSHAKING: @client is about to begin a TLS
+ * handshake. @connection is a #GTlsClientConnection.
+ *
+ * - %G_SOCKET_CLIENT_TLS_HANDSHAKED: @client has successfully completed
+ * the TLS handshake. @connection is a #GTlsClientConnection.
+ *
+ * - %G_SOCKET_CLIENT_COMPLETE: @client has either successfully connected
+ * to @connectable (in which case @connection is the #GSocketConnection
+ * that it will be returning to the caller) or has failed (in which
+ * case @connection is %NULL and the client is about to return an error).
*
* Each event except %G_SOCKET_CLIENT_COMPLETE may be emitted
* multiple times (or not at all) for a given connectable (in
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GSocketClient:proxy-resolver:
+ *
+ * The proxy resolver to use
+ *
+ * Since: 2.36
+ */
+ g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
+ g_param_spec_object ("proxy-resolver",
+ P_("Proxy resolver"),
+ P_("The proxy resolver to use"),
+ G_TYPE_PROXY_RESOLVER,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
}
static void
last_error = NULL;
if (can_use_proxy (client))
- enumerator = g_socket_connectable_proxy_enumerate (connectable);
+ {
+ enumerator = g_socket_connectable_proxy_enumerate (connectable);
+ if (client->priv->proxy_resolver &&
+ G_IS_PROXY_ADDRESS_ENUMERATOR (enumerator))
+ {
+ g_object_set (G_OBJECT (enumerator),
+ "proxy-resolver", client->priv->proxy_resolver,
+ NULL);
+ }
+ }
else
enumerator = g_socket_connectable_enumerate (connectable);
}
connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
+ g_socket_connection_set_cached_remote_address ((GSocketConnection*)connection, address);
g_socket_client_emit_event (client, G_SOCKET_CLIENT_CONNECTING, connectable, connection);
if (g_socket_connection_connect (G_SOCKET_CONNECTION (connection),
address, cancellable, &last_error))
{
+ g_socket_connection_set_cached_remote_address ((GSocketConnection*)connection, NULL);
g_socket_client_emit_event (client, G_SOCKET_CLIENT_CONNECTED, connectable, connection);
}
else
GProxy *proxy;
const gchar *protocol;
+ if (g_task_return_error_if_cancelled (data->task))
+ {
+ g_object_unref (data->task);
+ return;
+ }
+
if (!g_socket_connection_connect_finish (G_SOCKET_CONNECTION (source),
result, &error))
{
return;
}
+ g_socket_connection_set_cached_remote_address ((GSocketConnection*)data->connection, NULL);
g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTED, data->connectable, data->connection);
/* wrong, but backward compatible */
GError *error = NULL;
if (g_task_return_error_if_cancelled (data->task))
- return;
+ {
+ g_object_unref (data->task);
+ return;
+ }
address = g_socket_address_enumerator_next_finish (data->enumerator,
result, &error);
data->current_addr = address;
data->connection = (GIOStream *) g_socket_connection_factory_create_connection (socket);
+ g_socket_connection_set_cached_remote_address ((GSocketConnection*)data->connection, address);
g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTING, data->connectable, data->connection);
g_socket_connection_connect_async (G_SOCKET_CONNECTION (data->connection),
address,
data->connectable = g_object_ref (connectable);
if (can_use_proxy (client))
+ {
data->enumerator = g_socket_connectable_proxy_enumerate (connectable);
+ if (client->priv->proxy_resolver &&
+ G_IS_PROXY_ADDRESS_ENUMERATOR (data->enumerator))
+ {
+ g_object_set (G_OBJECT (data->enumerator),
+ "proxy-resolver", client->priv->proxy_resolver,
+ NULL);
+ }
+ }
else
- data->enumerator = g_socket_connectable_enumerate (connectable);
+ data->enumerator = g_socket_connectable_enumerate (connectable);
data->task = g_task_new (client, cancellable, callback, user_data);
g_task_set_task_data (data->task, data, (GDestroyNotify)g_socket_client_async_connect_data_free);