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"
36 #include "gsimpleasyncresult.h"
37 #include "gresolver.h"
38 #include "gsocketaddress.h"
39 #include "gsocketaddressenumerator.h"
40 #include "gsocketconnectable.h"
42 G_DEFINE_TYPE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR);
44 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
53 struct _GProxyAddressEnumeratorPrivate
55 /* Destination address */
56 GSocketConnectable *connectable;
62 /* Proxy enumeration */
65 GSocketAddressEnumerator *addr_enum;
66 GSocketAddress *proxy_address;
68 gchar *proxy_username;
69 gchar *proxy_password;
70 gboolean supports_hostname;
74 /* Async attributes */
75 GSimpleAsyncResult *simple;
76 GCancellable *cancellable;
80 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
85 if (priv->proxy_username)
87 g_free (priv->proxy_username);
88 priv->proxy_username = NULL;
91 if (priv->proxy_password)
93 g_free (priv->proxy_password);
94 priv->proxy_password = NULL;
97 if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo))
101 gchar **split = g_strsplit (userinfo, ":", 2);
103 if (split[0] != NULL)
105 priv->proxy_username = g_uri_unescape_string (split[0], NULL);
106 if (split[1] != NULL)
107 priv->proxy_password = g_uri_unescape_string (split[1], NULL);
117 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
119 if (priv->proxy_address)
122 while (priv->addr_enum == NULL && *priv->next_proxy)
124 GSocketConnectable *connectable = NULL;
125 const gchar *proxy_uri;
128 proxy_uri = *priv->next_proxy++;
129 g_free (priv->proxy_type);
130 priv->proxy_type = g_uri_parse_scheme (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 (proxy_uri, 0, &error);
160 g_warning ("Invalid proxy URI '%s': %s",
161 proxy_uri, error->message);
162 g_error_free (error);
165 save_userinfo (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 GProxyResolver *resolver = g_proxy_resolver_get_default ();
188 priv->proxies = g_proxy_resolver_lookup (resolver,
192 priv->next_proxy = priv->proxies;
194 if (priv->proxies == NULL)
198 while (result == NULL && (*priv->next_proxy || priv->addr_enum))
200 gchar *dest_hostname;
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);
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_proxy_address_new (inetaddr, port,
285 dest_hostname, priv->dest_port,
286 priv->proxy_username,
287 priv->proxy_password);
289 g_free (dest_hostname);
291 if (priv->supports_hostname || priv->next_dest_ip == NULL)
293 g_object_unref (priv->proxy_address);
294 priv->proxy_address = NULL;
298 if (result == NULL && first_error)
299 g_propagate_error (error, first_error);
300 else if (first_error)
301 g_error_free (first_error);
309 complete_async (GProxyAddressEnumeratorPrivate *priv)
311 GSimpleAsyncResult *simple = priv->simple;
313 if (priv->cancellable)
315 g_object_unref (priv->cancellable);
316 priv->cancellable = NULL;
321 if (priv->last_error)
323 g_simple_async_result_take_error (simple, priv->last_error);
324 priv->last_error = NULL;
327 g_simple_async_result_complete (simple);
328 g_object_unref (simple);
332 save_result (GProxyAddressEnumeratorPrivate *priv)
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;
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);
365 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
367 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
368 inetaddr = g_inet_socket_address_get_address (inetsaddr);
369 port = g_inet_socket_address_get_port (inetsaddr);
371 result = g_proxy_address_new (inetaddr, port,
373 dest_hostname, priv->dest_port,
374 priv->proxy_username,
375 priv->proxy_password);
377 g_free (dest_hostname);
379 if (priv->supports_hostname || priv->next_dest_ip == NULL)
381 g_object_unref (priv->proxy_address);
382 priv->proxy_address = NULL;
386 g_simple_async_result_set_op_res_gpointer (priv->simple,
391 static void address_enumerate_cb (GObject *object,
392 GAsyncResult *result,
396 next_proxy (GProxyAddressEnumeratorPrivate *priv)
398 if (*priv->next_proxy)
400 g_object_unref (priv->addr_enum);
401 priv->addr_enum = NULL;
405 g_resolver_free_addresses (priv->dest_ips);
406 priv->dest_ips = NULL;
409 next_enumerator (priv);
413 g_socket_address_enumerator_next_async (priv->addr_enum,
415 address_enumerate_cb,
421 complete_async (priv);
425 dest_hostname_lookup_cb (GObject *object,
426 GAsyncResult *result,
429 GProxyAddressEnumeratorPrivate *priv = user_data;
431 g_clear_error (&priv->last_error);
432 priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
438 complete_async (priv);
442 g_clear_object (&priv->proxy_address);
448 address_enumerate_cb (GObject *object,
449 GAsyncResult *result,
452 GProxyAddressEnumeratorPrivate *priv = user_data;
454 g_clear_error (&priv->last_error);
455 priv->proxy_address =
456 g_socket_address_enumerator_next_finish (priv->addr_enum,
459 if (priv->proxy_address)
461 if (!priv->supports_hostname && !priv->dest_ips)
464 resolver = g_resolver_get_default();
465 g_resolver_lookup_by_name_async (resolver,
468 dest_hostname_lookup_cb,
470 g_object_unref (resolver);
475 complete_async (priv);
482 proxy_lookup_cb (GObject *object,
483 GAsyncResult *result,
486 GError *error = NULL;
487 GProxyAddressEnumeratorPrivate *priv = user_data;
488 GSimpleAsyncResult *simple = priv->simple;
490 priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
493 priv->next_proxy = priv->proxies;
497 g_simple_async_result_take_error (simple, error);
501 next_enumerator (priv);
504 g_socket_address_enumerator_next_async (priv->addr_enum,
506 address_enumerate_cb,
512 complete_async (priv);
516 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
517 GCancellable *cancellable,
518 GAsyncReadyCallback callback,
521 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
523 g_return_if_fail (priv->simple == NULL);
524 g_return_if_fail (priv->cancellable == NULL);
526 priv->simple = g_simple_async_result_new (G_OBJECT (enumerator),
528 g_proxy_address_enumerator_next_async);
530 priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
532 if (priv->proxies == NULL)
534 GProxyResolver *resolver = g_proxy_resolver_get_default ();
535 g_proxy_resolver_lookup_async (resolver,
545 if (priv->proxy_address)
551 g_socket_address_enumerator_next_async (priv->addr_enum,
553 address_enumerate_cb,
559 g_simple_async_result_complete_in_idle (priv->simple);
561 g_object_unref (priv->simple);
564 if (priv->cancellable)
566 g_object_unref (priv->cancellable);
567 priv->cancellable = NULL;
571 static GSocketAddress *
572 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
573 GAsyncResult *result,
576 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
577 GSocketAddress *address;
579 if (g_simple_async_result_propagate_error (simple, error))
582 address = g_simple_async_result_get_op_res_gpointer (simple);
584 g_object_ref (address);
590 g_proxy_address_enumerator_get_property (GObject *object,
595 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
599 g_value_set_string (value, priv->dest_uri);
602 case PROP_CONNECTABLE:
603 g_value_set_object (value, priv->connectable);
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
612 g_proxy_address_enumerator_set_property (GObject *object,
617 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
624 g_free (priv->dest_hostname);
625 priv->dest_hostname = NULL;
628 g_free (priv->dest_uri);
629 priv->dest_uri = NULL;
631 uri = g_value_get_string (value);
635 GSocketConnectable *conn;
637 conn = g_network_address_parse_uri (uri, 0, NULL);
642 priv->dest_uri = g_strdup (uri);
645 "hostname", &priv->dest_hostname,
649 priv->dest_port = port;
650 g_object_unref (conn);
653 g_warning ("Invalid URI '%s'", uri);
659 case PROP_CONNECTABLE:
660 priv->connectable = g_value_dup_object (value);
664 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
669 g_proxy_address_enumerator_finalize (GObject *object)
671 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
673 if (priv->connectable)
674 g_object_unref (priv->connectable);
676 g_free (priv->dest_uri);
677 g_free (priv->dest_hostname);
680 g_resolver_free_addresses (priv->dest_ips);
682 g_strfreev (priv->proxies);
685 g_object_unref (priv->addr_enum);
687 g_free (priv->proxy_type);
688 g_free (priv->proxy_username);
689 g_free (priv->proxy_password);
691 if (priv->cancellable)
692 g_object_unref (priv->cancellable);
694 g_clear_error (&priv->last_error);
696 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
700 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
702 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
703 G_TYPE_PROXY_ADDRESS_ENUMERATOR,
704 GProxyAddressEnumeratorPrivate);
708 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
710 GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
711 GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
713 g_type_class_add_private (enumerator_class,
714 sizeof (GProxyAddressEnumeratorPrivate));
716 object_class->set_property = g_proxy_address_enumerator_set_property;
717 object_class->get_property = g_proxy_address_enumerator_get_property;
718 object_class->finalize = g_proxy_address_enumerator_finalize;
720 enumerator_class->next = g_proxy_address_enumerator_next;
721 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
722 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
724 g_object_class_install_property (object_class,
726 g_param_spec_string ("uri",
728 P_("The destination URI, use none:// for generic socket"),
731 G_PARAM_CONSTRUCT_ONLY |
732 G_PARAM_STATIC_STRINGS));
734 g_object_class_install_property (object_class,
736 g_param_spec_object ("connectable",
738 P_("The connectable being enumerated."),
739 G_TYPE_SOCKET_CONNECTABLE,
741 G_PARAM_CONSTRUCT_ONLY |
742 G_PARAM_STATIC_STRINGS));