1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2010 Collabora, Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
22 #include "gproxyaddressenumerator.h"
26 #include "gasyncresult.h"
27 #include "ginetaddress.h"
29 #include "gnetworkaddress.h"
30 #include "gnetworkingprivate.h"
32 #include "gproxyaddress.h"
33 #include "gproxyresolver.h"
35 #include "gresolver.h"
36 #include "gsocketaddress.h"
37 #include "gsocketaddressenumerator.h"
38 #include "gsocketconnectable.h"
41 * SECTION:gproxyaddressenumerator
42 * @short_description: Proxy wrapper enumerator for socket addresses
45 * #GProxyAddressEnumerator is a wrapper around #GSocketAddressEnumerator which
46 * takes the #GSocketAddress instances returned by the #GSocketAddressEnumerator
47 * and wraps them in #GProxyAddress instances, using the given
48 * #GProxyAddressEnumerator:proxy-resolver.
50 * This enumerator will be returned (for example, by
51 * g_socket_connectable_enumerate()) as appropriate when a proxy is configured;
52 * there should be no need to manually wrap a #GSocketAddressEnumerator instance
56 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
67 struct _GProxyAddressEnumeratorPrivate
69 /* Destination address */
70 GSocketConnectable *connectable;
77 /* Proxy enumeration */
78 GProxyResolver *proxy_resolver;
81 GSocketAddressEnumerator *addr_enum;
82 GSocketAddress *proxy_address;
83 const gchar *proxy_uri;
85 gchar *proxy_username;
86 gchar *proxy_password;
87 gboolean supports_hostname;
92 G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
95 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
100 if (priv->proxy_username)
102 g_free (priv->proxy_username);
103 priv->proxy_username = NULL;
106 if (priv->proxy_password)
108 g_free (priv->proxy_password);
109 priv->proxy_password = NULL;
112 if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo, NULL))
116 gchar **split = g_strsplit (userinfo, ":", 2);
118 if (split[0] != NULL)
120 priv->proxy_username = g_uri_unescape_string (split[0], NULL);
121 if (split[1] != NULL)
122 priv->proxy_password = g_uri_unescape_string (split[1], NULL);
132 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
134 if (priv->proxy_address)
137 while (priv->addr_enum == NULL && *priv->next_proxy)
139 GSocketConnectable *connectable = NULL;
142 priv->proxy_uri = *priv->next_proxy++;
143 g_free (priv->proxy_type);
144 priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
146 if (priv->proxy_type == NULL)
149 /* Assumes hostnames are supported for unknown protocols */
150 priv->supports_hostname = TRUE;
151 proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
154 priv->supports_hostname = g_proxy_supports_hostname (proxy);
155 g_object_unref (proxy);
158 if (strcmp ("direct", priv->proxy_type) == 0)
160 if (priv->connectable)
161 connectable = g_object_ref (priv->connectable);
163 connectable = g_network_address_new (priv->dest_hostname,
168 GError *error = NULL;
170 connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
174 g_warning ("Invalid proxy URI '%s': %s",
175 priv->proxy_uri, error->message);
176 g_error_free (error);
179 save_userinfo (priv, priv->proxy_uri);
184 priv->addr_enum = g_socket_connectable_enumerate (connectable);
185 g_object_unref (connectable);
190 static GSocketAddress *
191 g_proxy_address_enumerator_next (GSocketAddressEnumerator *enumerator,
192 GCancellable *cancellable,
195 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
196 GSocketAddress *result = NULL;
197 GError *first_error = NULL;
199 if (priv->proxies == NULL)
201 priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
205 priv->next_proxy = priv->proxies;
207 if (priv->proxies == NULL)
211 while (result == NULL && (*priv->next_proxy || priv->addr_enum))
213 gchar *dest_hostname;
214 gchar *dest_protocol;
215 GInetSocketAddress *inetsaddr;
216 GInetAddress *inetaddr;
219 next_enumerator (priv);
221 if (!priv->addr_enum)
224 if (priv->proxy_address == NULL)
226 priv->proxy_address = g_socket_address_enumerator_next (
229 first_error ? NULL : &first_error);
232 if (priv->proxy_address == NULL)
234 g_object_unref (priv->addr_enum);
235 priv->addr_enum = NULL;
239 g_resolver_free_addresses (priv->dest_ips);
240 priv->dest_ips = NULL;
246 if (strcmp ("direct", priv->proxy_type) == 0)
248 result = priv->proxy_address;
249 priv->proxy_address = NULL;
253 if (!priv->supports_hostname)
255 GInetAddress *dest_ip;
261 resolver = g_resolver_get_default();
262 priv->dest_ips = g_resolver_lookup_by_name (resolver,
265 first_error ? NULL : &first_error);
266 g_object_unref (resolver);
270 g_object_unref (priv->proxy_address);
271 priv->proxy_address = NULL;
276 if (!priv->next_dest_ip)
277 priv->next_dest_ip = priv->dest_ips;
279 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
280 dest_hostname = g_inet_address_to_string (dest_ip);
282 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
286 dest_hostname = g_strdup (priv->dest_hostname);
288 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
290 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
293 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
294 inetaddr = g_inet_socket_address_get_address (inetsaddr);
295 port = g_inet_socket_address_get_port (inetsaddr);
297 result = g_object_new (G_TYPE_PROXY_ADDRESS,
300 "protocol", priv->proxy_type,
301 "destination-protocol", dest_protocol,
302 "destination-hostname", dest_hostname,
303 "destination-port", priv->dest_port,
304 "username", priv->proxy_username,
305 "password", priv->proxy_password,
306 "uri", priv->proxy_uri,
308 g_free (dest_hostname);
309 g_free (dest_protocol);
311 if (priv->supports_hostname || priv->next_dest_ip == NULL)
313 g_object_unref (priv->proxy_address);
314 priv->proxy_address = NULL;
318 if (result == NULL && first_error)
319 g_propagate_error (error, first_error);
320 else if (first_error)
321 g_error_free (first_error);
329 complete_async (GTask *task)
331 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
333 if (priv->last_error)
335 g_task_return_error (task, priv->last_error);
336 priv->last_error = NULL;
339 g_task_return_pointer (task, NULL, NULL);
341 g_object_unref (task);
345 return_result (GTask *task)
347 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
348 GSocketAddress *result;
350 if (strcmp ("direct", priv->proxy_type) == 0)
352 result = priv->proxy_address;
353 priv->proxy_address = NULL;
357 gchar *dest_hostname, *dest_protocol;
358 GInetSocketAddress *inetsaddr;
359 GInetAddress *inetaddr;
362 if (!priv->supports_hostname)
364 GInetAddress *dest_ip;
366 if (!priv->next_dest_ip)
367 priv->next_dest_ip = priv->dest_ips;
369 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
370 dest_hostname = g_inet_address_to_string (dest_ip);
372 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
376 dest_hostname = g_strdup (priv->dest_hostname);
378 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
380 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
382 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
383 inetaddr = g_inet_socket_address_get_address (inetsaddr);
384 port = g_inet_socket_address_get_port (inetsaddr);
386 result = g_object_new (G_TYPE_PROXY_ADDRESS,
389 "protocol", priv->proxy_type,
390 "destination-protocol", dest_protocol,
391 "destination-hostname", dest_hostname,
392 "destination-port", priv->dest_port,
393 "username", priv->proxy_username,
394 "password", priv->proxy_password,
395 "uri", priv->proxy_uri,
397 g_free (dest_hostname);
398 g_free (dest_protocol);
400 if (priv->supports_hostname || priv->next_dest_ip == NULL)
402 g_object_unref (priv->proxy_address);
403 priv->proxy_address = NULL;
407 g_task_return_pointer (task, result, g_object_unref);
408 g_object_unref (task);
411 static void address_enumerate_cb (GObject *object,
412 GAsyncResult *result,
416 next_proxy (GTask *task)
418 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
420 if (*priv->next_proxy)
422 g_object_unref (priv->addr_enum);
423 priv->addr_enum = NULL;
427 g_resolver_free_addresses (priv->dest_ips);
428 priv->dest_ips = NULL;
431 next_enumerator (priv);
435 g_socket_address_enumerator_next_async (priv->addr_enum,
436 g_task_get_cancellable (task),
437 address_enumerate_cb,
443 complete_async (task);
447 dest_hostname_lookup_cb (GObject *object,
448 GAsyncResult *result,
451 GTask *task = user_data;
452 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
454 g_clear_error (&priv->last_error);
455 priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
459 return_result (task);
462 g_clear_object (&priv->proxy_address);
468 address_enumerate_cb (GObject *object,
469 GAsyncResult *result,
472 GTask *task = user_data;
473 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
475 g_clear_error (&priv->last_error);
476 priv->proxy_address =
477 g_socket_address_enumerator_next_finish (priv->addr_enum,
480 if (priv->proxy_address)
482 if (!priv->supports_hostname && !priv->dest_ips)
485 resolver = g_resolver_get_default();
486 g_resolver_lookup_by_name_async (resolver,
488 g_task_get_cancellable (task),
489 dest_hostname_lookup_cb,
491 g_object_unref (resolver);
495 return_result (task);
502 proxy_lookup_cb (GObject *object,
503 GAsyncResult *result,
506 GTask *task = user_data;
507 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
509 g_clear_error (&priv->last_error);
510 priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
513 priv->next_proxy = priv->proxies;
515 if (priv->last_error)
517 complete_async (task);
522 next_enumerator (priv);
525 g_socket_address_enumerator_next_async (priv->addr_enum,
526 g_task_get_cancellable (task),
527 address_enumerate_cb,
533 complete_async (task);
537 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
538 GCancellable *cancellable,
539 GAsyncReadyCallback callback,
542 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
545 task = g_task_new (enumerator, cancellable, callback, user_data);
546 g_task_set_source_tag (task, g_proxy_address_enumerator_next_async);
547 g_task_set_task_data (task, priv, NULL);
549 if (priv->proxies == NULL)
551 g_proxy_resolver_lookup_async (priv->proxy_resolver,
561 if (priv->proxy_address)
563 return_result (task);
568 g_socket_address_enumerator_next_async (priv->addr_enum,
570 address_enumerate_cb,
576 complete_async (task);
579 static GSocketAddress *
580 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
581 GAsyncResult *result,
584 g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
586 return g_task_propagate_pointer (G_TASK (result), error);
590 g_proxy_address_enumerator_constructed (GObject *object)
592 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
593 GSocketConnectable *conn;
598 conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
602 "hostname", &priv->dest_hostname,
605 priv->dest_port = port;
607 g_object_unref (conn);
610 g_warning ("Invalid URI '%s'", priv->dest_uri);
613 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
617 g_proxy_address_enumerator_get_property (GObject *object,
622 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
626 g_value_set_string (value, priv->dest_uri);
629 case PROP_DEFAULT_PORT:
630 g_value_set_uint (value, priv->default_port);
633 case PROP_CONNECTABLE:
634 g_value_set_object (value, priv->connectable);
637 case PROP_PROXY_RESOLVER:
638 g_value_set_object (value, priv->proxy_resolver);
642 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
647 g_proxy_address_enumerator_set_property (GObject *object,
652 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
656 priv->dest_uri = g_value_dup_string (value);
659 case PROP_DEFAULT_PORT:
660 priv->default_port = g_value_get_uint (value);
663 case PROP_CONNECTABLE:
664 priv->connectable = g_value_dup_object (value);
667 case PROP_PROXY_RESOLVER:
668 if (priv->proxy_resolver)
669 g_object_unref (priv->proxy_resolver);
670 priv->proxy_resolver = g_value_get_object (value);
671 if (!priv->proxy_resolver)
672 priv->proxy_resolver = g_proxy_resolver_get_default ();
673 g_object_ref (priv->proxy_resolver);
677 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
682 g_proxy_address_enumerator_finalize (GObject *object)
684 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
686 if (priv->connectable)
687 g_object_unref (priv->connectable);
689 if (priv->proxy_resolver)
690 g_object_unref (priv->proxy_resolver);
692 g_free (priv->dest_uri);
693 g_free (priv->dest_hostname);
696 g_resolver_free_addresses (priv->dest_ips);
698 g_strfreev (priv->proxies);
701 g_object_unref (priv->addr_enum);
703 g_free (priv->proxy_type);
704 g_free (priv->proxy_username);
705 g_free (priv->proxy_password);
707 g_clear_error (&priv->last_error);
709 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
713 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
715 self->priv = g_proxy_address_enumerator_get_instance_private (self);
719 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
721 GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
722 GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
724 object_class->constructed = g_proxy_address_enumerator_constructed;
725 object_class->set_property = g_proxy_address_enumerator_set_property;
726 object_class->get_property = g_proxy_address_enumerator_get_property;
727 object_class->finalize = g_proxy_address_enumerator_finalize;
729 enumerator_class->next = g_proxy_address_enumerator_next;
730 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
731 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
733 g_object_class_install_property (object_class,
735 g_param_spec_string ("uri",
737 P_("The destination URI, use none:// for generic socket"),
740 G_PARAM_CONSTRUCT_ONLY |
741 G_PARAM_STATIC_STRINGS));
744 * GProxyAddressEnumerator:default-port:
746 * The default port to use if #GProxyAddressEnumerator:uri does not
751 g_object_class_install_property (object_class,
753 g_param_spec_uint ("default-port",
755 P_("The default port to use if uri does not specify one"),
758 G_PARAM_CONSTRUCT_ONLY |
759 G_PARAM_STATIC_STRINGS));
761 g_object_class_install_property (object_class,
763 g_param_spec_object ("connectable",
765 P_("The connectable being enumerated."),
766 G_TYPE_SOCKET_CONNECTABLE,
768 G_PARAM_CONSTRUCT_ONLY |
769 G_PARAM_STATIC_STRINGS));
772 * GProxyAddressEnumerator:proxy-resolver:
774 * The proxy resolver to use.
778 g_object_class_install_property (object_class,
780 g_param_spec_object ("proxy-resolver",
781 P_("Proxy resolver"),
782 P_("The proxy resolver to use."),
783 G_TYPE_PROXY_RESOLVER,
786 G_PARAM_STATIC_STRINGS));