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, 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"
40 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
51 struct _GProxyAddressEnumeratorPrivate
53 /* Destination address */
54 GSocketConnectable *connectable;
61 /* Proxy enumeration */
62 GProxyResolver *proxy_resolver;
65 GSocketAddressEnumerator *addr_enum;
66 GSocketAddress *proxy_address;
67 const gchar *proxy_uri;
69 gchar *proxy_username;
70 gchar *proxy_password;
71 gboolean supports_hostname;
76 G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
79 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
84 if (priv->proxy_username)
86 g_free (priv->proxy_username);
87 priv->proxy_username = NULL;
90 if (priv->proxy_password)
92 g_free (priv->proxy_password);
93 priv->proxy_password = NULL;
96 if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo))
100 gchar **split = g_strsplit (userinfo, ":", 2);
102 if (split[0] != NULL)
104 priv->proxy_username = g_uri_unescape_string (split[0], NULL);
105 if (split[1] != NULL)
106 priv->proxy_password = g_uri_unescape_string (split[1], NULL);
116 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
118 if (priv->proxy_address)
121 while (priv->addr_enum == NULL && *priv->next_proxy)
123 GSocketConnectable *connectable = NULL;
126 priv->proxy_uri = *priv->next_proxy++;
127 g_free (priv->proxy_type);
128 priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
130 if (priv->proxy_type == NULL)
133 /* Assumes hostnames are supported for unknown protocols */
134 priv->supports_hostname = TRUE;
135 proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
138 priv->supports_hostname = g_proxy_supports_hostname (proxy);
139 g_object_unref (proxy);
142 if (strcmp ("direct", priv->proxy_type) == 0)
144 if (priv->connectable)
145 connectable = g_object_ref (priv->connectable);
147 connectable = g_network_address_new (priv->dest_hostname,
152 GError *error = NULL;
154 connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
158 g_warning ("Invalid proxy URI '%s': %s",
159 priv->proxy_uri, error->message);
160 g_error_free (error);
163 save_userinfo (priv, priv->proxy_uri);
168 priv->addr_enum = g_socket_connectable_enumerate (connectable);
169 g_object_unref (connectable);
174 static GSocketAddress *
175 g_proxy_address_enumerator_next (GSocketAddressEnumerator *enumerator,
176 GCancellable *cancellable,
179 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
180 GSocketAddress *result = NULL;
181 GError *first_error = NULL;
183 if (priv->proxies == NULL)
185 priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
189 priv->next_proxy = priv->proxies;
191 if (priv->proxies == NULL)
195 while (result == NULL && (*priv->next_proxy || priv->addr_enum))
197 gchar *dest_hostname;
198 gchar *dest_protocol;
199 GInetSocketAddress *inetsaddr;
200 GInetAddress *inetaddr;
203 next_enumerator (priv);
205 if (!priv->addr_enum)
208 if (priv->proxy_address == NULL)
210 priv->proxy_address = g_socket_address_enumerator_next (
213 first_error ? NULL : &first_error);
216 if (priv->proxy_address == NULL)
218 g_object_unref (priv->addr_enum);
219 priv->addr_enum = NULL;
223 g_resolver_free_addresses (priv->dest_ips);
224 priv->dest_ips = NULL;
230 if (strcmp ("direct", priv->proxy_type) == 0)
232 result = priv->proxy_address;
233 priv->proxy_address = NULL;
237 if (!priv->supports_hostname)
239 GInetAddress *dest_ip;
245 resolver = g_resolver_get_default();
246 priv->dest_ips = g_resolver_lookup_by_name (resolver,
249 first_error ? NULL : &first_error);
250 g_object_unref (resolver);
254 g_object_unref (priv->proxy_address);
255 priv->proxy_address = NULL;
260 if (!priv->next_dest_ip)
261 priv->next_dest_ip = priv->dest_ips;
263 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
264 dest_hostname = g_inet_address_to_string (dest_ip);
266 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
270 dest_hostname = g_strdup (priv->dest_hostname);
272 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
274 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
277 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
278 inetaddr = g_inet_socket_address_get_address (inetsaddr);
279 port = g_inet_socket_address_get_port (inetsaddr);
281 result = g_object_new (G_TYPE_PROXY_ADDRESS,
284 "protocol", priv->proxy_type,
285 "destination-protocol", dest_protocol,
286 "destination-hostname", dest_hostname,
287 "destination-port", priv->dest_port,
288 "username", priv->proxy_username,
289 "password", priv->proxy_password,
290 "uri", priv->proxy_uri,
292 g_free (dest_hostname);
293 g_free (dest_protocol);
295 if (priv->supports_hostname || priv->next_dest_ip == NULL)
297 g_object_unref (priv->proxy_address);
298 priv->proxy_address = NULL;
302 if (result == NULL && first_error)
303 g_propagate_error (error, first_error);
304 else if (first_error)
305 g_error_free (first_error);
313 complete_async (GTask *task)
315 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
317 if (priv->last_error)
319 g_task_return_error (task, priv->last_error);
320 priv->last_error = NULL;
323 g_task_return_pointer (task, NULL, NULL);
325 g_object_unref (task);
329 return_result (GTask *task)
331 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
332 GSocketAddress *result;
334 if (strcmp ("direct", priv->proxy_type) == 0)
336 result = priv->proxy_address;
337 priv->proxy_address = NULL;
341 gchar *dest_hostname, *dest_protocol;
342 GInetSocketAddress *inetsaddr;
343 GInetAddress *inetaddr;
346 if (!priv->supports_hostname)
348 GInetAddress *dest_ip;
350 if (!priv->next_dest_ip)
351 priv->next_dest_ip = priv->dest_ips;
353 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
354 dest_hostname = g_inet_address_to_string (dest_ip);
356 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
360 dest_hostname = g_strdup (priv->dest_hostname);
362 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
364 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
366 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
367 inetaddr = g_inet_socket_address_get_address (inetsaddr);
368 port = g_inet_socket_address_get_port (inetsaddr);
370 result = g_object_new (G_TYPE_PROXY_ADDRESS,
373 "protocol", priv->proxy_type,
374 "destination-protocol", dest_protocol,
375 "destination-hostname", dest_hostname,
376 "destination-port", priv->dest_port,
377 "username", priv->proxy_username,
378 "password", priv->proxy_password,
379 "uri", priv->proxy_uri,
381 g_free (dest_hostname);
382 g_free (dest_protocol);
384 if (priv->supports_hostname || priv->next_dest_ip == NULL)
386 g_object_unref (priv->proxy_address);
387 priv->proxy_address = NULL;
391 g_task_return_pointer (task, result, g_object_unref);
392 g_object_unref (task);
395 static void address_enumerate_cb (GObject *object,
396 GAsyncResult *result,
400 next_proxy (GTask *task)
402 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
404 if (*priv->next_proxy)
406 g_object_unref (priv->addr_enum);
407 priv->addr_enum = NULL;
411 g_resolver_free_addresses (priv->dest_ips);
412 priv->dest_ips = NULL;
415 next_enumerator (priv);
419 g_socket_address_enumerator_next_async (priv->addr_enum,
420 g_task_get_cancellable (task),
421 address_enumerate_cb,
427 complete_async (task);
431 dest_hostname_lookup_cb (GObject *object,
432 GAsyncResult *result,
435 GTask *task = user_data;
436 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
438 g_clear_error (&priv->last_error);
439 priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
443 return_result (task);
446 g_clear_object (&priv->proxy_address);
452 address_enumerate_cb (GObject *object,
453 GAsyncResult *result,
456 GTask *task = user_data;
457 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
459 g_clear_error (&priv->last_error);
460 priv->proxy_address =
461 g_socket_address_enumerator_next_finish (priv->addr_enum,
464 if (priv->proxy_address)
466 if (!priv->supports_hostname && !priv->dest_ips)
469 resolver = g_resolver_get_default();
470 g_resolver_lookup_by_name_async (resolver,
472 g_task_get_cancellable (task),
473 dest_hostname_lookup_cb,
475 g_object_unref (resolver);
479 return_result (task);
486 proxy_lookup_cb (GObject *object,
487 GAsyncResult *result,
490 GTask *task = user_data;
491 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
493 g_clear_error (&priv->last_error);
494 priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
497 priv->next_proxy = priv->proxies;
499 if (priv->last_error)
501 complete_async (task);
506 next_enumerator (priv);
509 g_socket_address_enumerator_next_async (priv->addr_enum,
510 g_task_get_cancellable (task),
511 address_enumerate_cb,
517 complete_async (task);
521 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
522 GCancellable *cancellable,
523 GAsyncReadyCallback callback,
526 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
529 task = g_task_new (enumerator, cancellable, callback, user_data);
530 g_task_set_task_data (task, priv, NULL);
532 if (priv->proxies == NULL)
534 g_proxy_resolver_lookup_async (priv->proxy_resolver,
544 if (priv->proxy_address)
546 return_result (task);
551 g_socket_address_enumerator_next_async (priv->addr_enum,
553 address_enumerate_cb,
559 complete_async (task);
562 static GSocketAddress *
563 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
564 GAsyncResult *result,
567 g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
569 return g_task_propagate_pointer (G_TASK (result), error);
573 g_proxy_address_enumerator_constructed (GObject *object)
575 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
576 GSocketConnectable *conn;
581 conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
585 "hostname", &priv->dest_hostname,
588 priv->dest_port = port;
590 g_object_unref (conn);
593 g_warning ("Invalid URI '%s'", priv->dest_uri);
596 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
600 g_proxy_address_enumerator_get_property (GObject *object,
605 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
609 g_value_set_string (value, priv->dest_uri);
612 case PROP_DEFAULT_PORT:
613 g_value_set_uint (value, priv->default_port);
616 case PROP_CONNECTABLE:
617 g_value_set_object (value, priv->connectable);
620 case PROP_PROXY_RESOLVER:
621 g_value_set_object (value, priv->proxy_resolver);
625 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
630 g_proxy_address_enumerator_set_property (GObject *object,
635 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
639 priv->dest_uri = g_value_dup_string (value);
642 case PROP_DEFAULT_PORT:
643 priv->default_port = g_value_get_uint (value);
646 case PROP_CONNECTABLE:
647 priv->connectable = g_value_dup_object (value);
650 case PROP_PROXY_RESOLVER:
651 if (priv->proxy_resolver)
652 g_object_unref (priv->proxy_resolver);
653 priv->proxy_resolver = g_value_get_object (value);
654 if (!priv->proxy_resolver)
655 priv->proxy_resolver = g_proxy_resolver_get_default ();
656 g_object_ref (priv->proxy_resolver);
660 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
665 g_proxy_address_enumerator_finalize (GObject *object)
667 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
669 if (priv->connectable)
670 g_object_unref (priv->connectable);
672 if (priv->proxy_resolver)
673 g_object_unref (priv->proxy_resolver);
675 g_free (priv->dest_uri);
676 g_free (priv->dest_hostname);
679 g_resolver_free_addresses (priv->dest_ips);
681 g_strfreev (priv->proxies);
684 g_object_unref (priv->addr_enum);
686 g_free (priv->proxy_type);
687 g_free (priv->proxy_username);
688 g_free (priv->proxy_password);
690 g_clear_error (&priv->last_error);
692 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
696 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
698 self->priv = g_proxy_address_enumerator_get_instance_private (self);
702 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
704 GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
705 GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
707 object_class->constructed = g_proxy_address_enumerator_constructed;
708 object_class->set_property = g_proxy_address_enumerator_set_property;
709 object_class->get_property = g_proxy_address_enumerator_get_property;
710 object_class->finalize = g_proxy_address_enumerator_finalize;
712 enumerator_class->next = g_proxy_address_enumerator_next;
713 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
714 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
716 g_object_class_install_property (object_class,
718 g_param_spec_string ("uri",
720 P_("The destination URI, use none:// for generic socket"),
723 G_PARAM_CONSTRUCT_ONLY |
724 G_PARAM_STATIC_STRINGS));
727 * GProxyAddressEnumerator:default-port:
729 * The default port to use if #GProxyAddressEnumerator:uri does not
734 g_object_class_install_property (object_class,
736 g_param_spec_uint ("default-port",
738 P_("The default port to use if uri does not specify one"),
741 G_PARAM_CONSTRUCT_ONLY |
742 G_PARAM_STATIC_STRINGS));
744 g_object_class_install_property (object_class,
746 g_param_spec_object ("connectable",
748 P_("The connectable being enumerated."),
749 G_TYPE_SOCKET_CONNECTABLE,
751 G_PARAM_CONSTRUCT_ONLY |
752 G_PARAM_STATIC_STRINGS));
755 * GProxyAddressEnumerator:proxy-resolver:
757 * The proxy resolver to use.
761 g_object_class_install_property (object_class,
763 g_param_spec_object ("proxy-resolver",
764 P_("Proxy resolver"),
765 P_("The proxy resolver to use."),
766 G_TYPE_PROXY_RESOLVER,
769 G_PARAM_STATIC_STRINGS));