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 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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
24 #include "gproxyaddressenumerator.h"
28 #include "gasyncresult.h"
29 #include "ginetaddress.h"
31 #include "gnetworkaddress.h"
32 #include "gnetworkingprivate.h"
34 #include "gproxyaddress.h"
35 #include "gproxyresolver.h"
37 #include "gresolver.h"
38 #include "gsocketaddress.h"
39 #include "gsocketaddressenumerator.h"
40 #include "gsocketconnectable.h"
42 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
53 struct _GProxyAddressEnumeratorPrivate
55 /* Destination address */
56 GSocketConnectable *connectable;
63 /* Proxy enumeration */
64 GProxyResolver *proxy_resolver;
67 GSocketAddressEnumerator *addr_enum;
68 GSocketAddress *proxy_address;
69 const gchar *proxy_uri;
71 gchar *proxy_username;
72 gchar *proxy_password;
73 gboolean supports_hostname;
78 G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
81 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
86 if (priv->proxy_username)
88 g_free (priv->proxy_username);
89 priv->proxy_username = NULL;
92 if (priv->proxy_password)
94 g_free (priv->proxy_password);
95 priv->proxy_password = NULL;
98 if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo))
102 gchar **split = g_strsplit (userinfo, ":", 2);
104 if (split[0] != NULL)
106 priv->proxy_username = g_uri_unescape_string (split[0], NULL);
107 if (split[1] != NULL)
108 priv->proxy_password = g_uri_unescape_string (split[1], NULL);
118 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
120 if (priv->proxy_address)
123 while (priv->addr_enum == NULL && *priv->next_proxy)
125 GSocketConnectable *connectable = NULL;
128 priv->proxy_uri = *priv->next_proxy++;
129 g_free (priv->proxy_type);
130 priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
132 if (priv->proxy_type == NULL)
135 /* Assumes hostnames are supported for unknown protocols */
136 priv->supports_hostname = TRUE;
137 proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
140 priv->supports_hostname = g_proxy_supports_hostname (proxy);
141 g_object_unref (proxy);
144 if (strcmp ("direct", priv->proxy_type) == 0)
146 if (priv->connectable)
147 connectable = g_object_ref (priv->connectable);
149 connectable = g_network_address_new (priv->dest_hostname,
154 GError *error = NULL;
156 connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
160 g_warning ("Invalid proxy URI '%s': %s",
161 priv->proxy_uri, error->message);
162 g_error_free (error);
165 save_userinfo (priv, priv->proxy_uri);
170 priv->addr_enum = g_socket_connectable_enumerate (connectable);
171 g_object_unref (connectable);
176 static GSocketAddress *
177 g_proxy_address_enumerator_next (GSocketAddressEnumerator *enumerator,
178 GCancellable *cancellable,
181 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
182 GSocketAddress *result = NULL;
183 GError *first_error = NULL;
185 if (priv->proxies == NULL)
187 priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
191 priv->next_proxy = priv->proxies;
193 if (priv->proxies == NULL)
197 while (result == NULL && (*priv->next_proxy || priv->addr_enum))
199 gchar *dest_hostname;
200 gchar *dest_protocol;
201 GInetSocketAddress *inetsaddr;
202 GInetAddress *inetaddr;
205 next_enumerator (priv);
207 if (!priv->addr_enum)
210 if (priv->proxy_address == NULL)
212 priv->proxy_address = g_socket_address_enumerator_next (
215 first_error ? NULL : &first_error);
218 if (priv->proxy_address == NULL)
220 g_object_unref (priv->addr_enum);
221 priv->addr_enum = NULL;
225 g_resolver_free_addresses (priv->dest_ips);
226 priv->dest_ips = NULL;
232 if (strcmp ("direct", priv->proxy_type) == 0)
234 result = priv->proxy_address;
235 priv->proxy_address = NULL;
239 if (!priv->supports_hostname)
241 GInetAddress *dest_ip;
247 resolver = g_resolver_get_default();
248 priv->dest_ips = g_resolver_lookup_by_name (resolver,
251 first_error ? NULL : &first_error);
252 g_object_unref (resolver);
256 g_object_unref (priv->proxy_address);
257 priv->proxy_address = NULL;
262 if (!priv->next_dest_ip)
263 priv->next_dest_ip = priv->dest_ips;
265 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
266 dest_hostname = g_inet_address_to_string (dest_ip);
268 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
272 dest_hostname = g_strdup (priv->dest_hostname);
274 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
276 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
279 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
280 inetaddr = g_inet_socket_address_get_address (inetsaddr);
281 port = g_inet_socket_address_get_port (inetsaddr);
283 result = g_object_new (G_TYPE_PROXY_ADDRESS,
286 "protocol", priv->proxy_type,
287 "destination-protocol", dest_protocol,
288 "destination-hostname", dest_hostname,
289 "destination-port", priv->dest_port,
290 "username", priv->proxy_username,
291 "password", priv->proxy_password,
292 "uri", priv->proxy_uri,
294 g_free (dest_hostname);
295 g_free (dest_protocol);
297 if (priv->supports_hostname || priv->next_dest_ip == NULL)
299 g_object_unref (priv->proxy_address);
300 priv->proxy_address = NULL;
304 if (result == NULL && first_error)
305 g_propagate_error (error, first_error);
306 else if (first_error)
307 g_error_free (first_error);
315 complete_async (GTask *task)
317 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
319 if (priv->last_error)
321 g_task_return_error (task, priv->last_error);
322 priv->last_error = NULL;
325 g_task_return_pointer (task, NULL, NULL);
327 g_object_unref (task);
331 return_result (GTask *task)
333 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
334 GSocketAddress *result;
336 if (strcmp ("direct", priv->proxy_type) == 0)
338 result = priv->proxy_address;
339 priv->proxy_address = NULL;
343 gchar *dest_hostname, *dest_protocol;
344 GInetSocketAddress *inetsaddr;
345 GInetAddress *inetaddr;
348 if (!priv->supports_hostname)
350 GInetAddress *dest_ip;
352 if (!priv->next_dest_ip)
353 priv->next_dest_ip = priv->dest_ips;
355 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
356 dest_hostname = g_inet_address_to_string (dest_ip);
358 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
362 dest_hostname = g_strdup (priv->dest_hostname);
364 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
366 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
368 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
369 inetaddr = g_inet_socket_address_get_address (inetsaddr);
370 port = g_inet_socket_address_get_port (inetsaddr);
372 result = g_object_new (G_TYPE_PROXY_ADDRESS,
375 "protocol", priv->proxy_type,
376 "destination-protocol", dest_protocol,
377 "destination-hostname", dest_hostname,
378 "destination-port", priv->dest_port,
379 "username", priv->proxy_username,
380 "password", priv->proxy_password,
381 "uri", priv->proxy_uri,
383 g_free (dest_hostname);
384 g_free (dest_protocol);
386 if (priv->supports_hostname || priv->next_dest_ip == NULL)
388 g_object_unref (priv->proxy_address);
389 priv->proxy_address = NULL;
393 g_task_return_pointer (task, result, g_object_unref);
394 g_object_unref (task);
397 static void address_enumerate_cb (GObject *object,
398 GAsyncResult *result,
402 next_proxy (GTask *task)
404 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
406 if (*priv->next_proxy)
408 g_object_unref (priv->addr_enum);
409 priv->addr_enum = NULL;
413 g_resolver_free_addresses (priv->dest_ips);
414 priv->dest_ips = NULL;
417 next_enumerator (priv);
421 g_socket_address_enumerator_next_async (priv->addr_enum,
422 g_task_get_cancellable (task),
423 address_enumerate_cb,
429 complete_async (task);
433 dest_hostname_lookup_cb (GObject *object,
434 GAsyncResult *result,
437 GTask *task = user_data;
438 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
440 g_clear_error (&priv->last_error);
441 priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
445 return_result (task);
448 g_clear_object (&priv->proxy_address);
454 address_enumerate_cb (GObject *object,
455 GAsyncResult *result,
458 GTask *task = user_data;
459 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
461 g_clear_error (&priv->last_error);
462 priv->proxy_address =
463 g_socket_address_enumerator_next_finish (priv->addr_enum,
466 if (priv->proxy_address)
468 if (!priv->supports_hostname && !priv->dest_ips)
471 resolver = g_resolver_get_default();
472 g_resolver_lookup_by_name_async (resolver,
474 g_task_get_cancellable (task),
475 dest_hostname_lookup_cb,
477 g_object_unref (resolver);
481 return_result (task);
488 proxy_lookup_cb (GObject *object,
489 GAsyncResult *result,
492 GTask *task = user_data;
493 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
495 g_clear_error (&priv->last_error);
496 priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
499 priv->next_proxy = priv->proxies;
501 if (priv->last_error)
503 complete_async (task);
508 next_enumerator (priv);
511 g_socket_address_enumerator_next_async (priv->addr_enum,
512 g_task_get_cancellable (task),
513 address_enumerate_cb,
519 complete_async (task);
523 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
524 GCancellable *cancellable,
525 GAsyncReadyCallback callback,
528 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
531 task = g_task_new (enumerator, cancellable, callback, user_data);
532 g_task_set_task_data (task, priv, NULL);
534 if (priv->proxies == NULL)
536 g_proxy_resolver_lookup_async (priv->proxy_resolver,
546 if (priv->proxy_address)
548 return_result (task);
553 g_socket_address_enumerator_next_async (priv->addr_enum,
555 address_enumerate_cb,
561 complete_async (task);
564 static GSocketAddress *
565 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
566 GAsyncResult *result,
569 g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
571 return g_task_propagate_pointer (G_TASK (result), error);
575 g_proxy_address_enumerator_constructed (GObject *object)
577 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
578 GSocketConnectable *conn;
583 conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
587 "hostname", &priv->dest_hostname,
590 priv->dest_port = port;
592 g_object_unref (conn);
595 g_warning ("Invalid URI '%s'", priv->dest_uri);
598 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
602 g_proxy_address_enumerator_get_property (GObject *object,
607 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
611 g_value_set_string (value, priv->dest_uri);
614 case PROP_DEFAULT_PORT:
615 g_value_set_uint (value, priv->default_port);
618 case PROP_CONNECTABLE:
619 g_value_set_object (value, priv->connectable);
622 case PROP_PROXY_RESOLVER:
623 g_value_set_object (value, priv->proxy_resolver);
627 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
632 g_proxy_address_enumerator_set_property (GObject *object,
637 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
641 priv->dest_uri = g_value_dup_string (value);
644 case PROP_DEFAULT_PORT:
645 priv->default_port = g_value_get_uint (value);
648 case PROP_CONNECTABLE:
649 priv->connectable = g_value_dup_object (value);
652 case PROP_PROXY_RESOLVER:
653 if (priv->proxy_resolver)
654 g_object_unref (priv->proxy_resolver);
655 priv->proxy_resolver = g_value_get_object (value);
656 if (!priv->proxy_resolver)
657 priv->proxy_resolver = g_proxy_resolver_get_default ();
658 g_object_ref (priv->proxy_resolver);
662 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
667 g_proxy_address_enumerator_finalize (GObject *object)
669 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
671 if (priv->connectable)
672 g_object_unref (priv->connectable);
674 if (priv->proxy_resolver)
675 g_object_unref (priv->proxy_resolver);
677 g_free (priv->dest_uri);
678 g_free (priv->dest_hostname);
681 g_resolver_free_addresses (priv->dest_ips);
683 g_strfreev (priv->proxies);
686 g_object_unref (priv->addr_enum);
688 g_free (priv->proxy_type);
689 g_free (priv->proxy_username);
690 g_free (priv->proxy_password);
692 g_clear_error (&priv->last_error);
694 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
698 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
700 self->priv = g_proxy_address_enumerator_get_instance_private (self);
704 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
706 GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
707 GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
709 object_class->constructed = g_proxy_address_enumerator_constructed;
710 object_class->set_property = g_proxy_address_enumerator_set_property;
711 object_class->get_property = g_proxy_address_enumerator_get_property;
712 object_class->finalize = g_proxy_address_enumerator_finalize;
714 enumerator_class->next = g_proxy_address_enumerator_next;
715 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
716 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
718 g_object_class_install_property (object_class,
720 g_param_spec_string ("uri",
722 P_("The destination URI, use none:// for generic socket"),
725 G_PARAM_CONSTRUCT_ONLY |
726 G_PARAM_STATIC_STRINGS));
729 * GProxyAddressEnumerator:default-port:
731 * The default port to use if #GProxyAddressEnumerator:uri does not
736 g_object_class_install_property (object_class,
738 g_param_spec_uint ("default-port",
740 P_("The default port to use if uri does not specify one"),
743 G_PARAM_CONSTRUCT_ONLY |
744 G_PARAM_STATIC_STRINGS));
746 g_object_class_install_property (object_class,
748 g_param_spec_object ("connectable",
750 P_("The connectable being enumerated."),
751 G_TYPE_SOCKET_CONNECTABLE,
753 G_PARAM_CONSTRUCT_ONLY |
754 G_PARAM_STATIC_STRINGS));
757 * GProxyAddressEnumerator:proxy-resolver:
759 * The proxy resolver to use.
763 g_object_class_install_property (object_class,
765 g_param_spec_object ("proxy-resolver",
766 P_("Proxy resolver"),
767 P_("The proxy resolver to use."),
768 G_TYPE_PROXY_RESOLVER,
771 G_PARAM_STATIC_STRINGS));