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;
67 const gchar *proxy_uri;
69 gchar *proxy_username;
70 gchar *proxy_password;
71 gboolean supports_hostname;
75 /* Async attributes */
76 GSimpleAsyncResult *simple;
77 GCancellable *cancellable;
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 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 gchar *dest_protocol;
202 GInetSocketAddress *inetsaddr;
203 GInetAddress *inetaddr;
206 next_enumerator (priv);
208 if (!priv->addr_enum)
211 if (priv->proxy_address == NULL)
213 priv->proxy_address = g_socket_address_enumerator_next (
216 first_error ? NULL : &first_error);
219 if (priv->proxy_address == NULL)
221 g_object_unref (priv->addr_enum);
222 priv->addr_enum = NULL;
226 g_resolver_free_addresses (priv->dest_ips);
227 priv->dest_ips = NULL;
233 if (strcmp ("direct", priv->proxy_type) == 0)
235 result = priv->proxy_address;
236 priv->proxy_address = NULL;
240 if (!priv->supports_hostname)
242 GInetAddress *dest_ip;
248 resolver = g_resolver_get_default();
249 priv->dest_ips = g_resolver_lookup_by_name (resolver,
252 first_error ? NULL : &first_error);
253 g_object_unref (resolver);
257 g_object_unref (priv->proxy_address);
258 priv->proxy_address = NULL;
263 if (!priv->next_dest_ip)
264 priv->next_dest_ip = priv->dest_ips;
266 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
267 dest_hostname = g_inet_address_to_string (dest_ip);
269 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
273 dest_hostname = g_strdup (priv->dest_hostname);
275 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
277 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
280 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
281 inetaddr = g_inet_socket_address_get_address (inetsaddr);
282 port = g_inet_socket_address_get_port (inetsaddr);
284 result = g_object_new (G_TYPE_PROXY_ADDRESS,
287 "protocol", priv->proxy_type,
288 "destination-protocol", dest_protocol,
289 "destination-hostname", dest_hostname,
290 "destination-port", priv->dest_port,
291 "username", priv->proxy_username,
292 "password", priv->proxy_password,
293 "uri", priv->proxy_uri,
295 g_free (dest_hostname);
296 g_free (dest_protocol);
298 if (priv->supports_hostname || priv->next_dest_ip == NULL)
300 g_object_unref (priv->proxy_address);
301 priv->proxy_address = NULL;
305 if (result == NULL && first_error)
306 g_propagate_error (error, first_error);
307 else if (first_error)
308 g_error_free (first_error);
316 complete_async (GProxyAddressEnumeratorPrivate *priv)
318 GSimpleAsyncResult *simple = priv->simple;
320 if (priv->cancellable)
322 g_object_unref (priv->cancellable);
323 priv->cancellable = NULL;
328 if (priv->last_error)
330 g_simple_async_result_take_error (simple, priv->last_error);
331 priv->last_error = NULL;
334 g_simple_async_result_complete (simple);
335 g_object_unref (simple);
339 save_result (GProxyAddressEnumeratorPrivate *priv)
341 GSocketAddress *result;
343 if (strcmp ("direct", priv->proxy_type) == 0)
345 result = priv->proxy_address;
346 priv->proxy_address = NULL;
350 gchar *dest_hostname, *dest_protocol;
351 GInetSocketAddress *inetsaddr;
352 GInetAddress *inetaddr;
355 if (!priv->supports_hostname)
357 GInetAddress *dest_ip;
359 if (!priv->next_dest_ip)
360 priv->next_dest_ip = priv->dest_ips;
362 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
363 dest_hostname = g_inet_address_to_string (dest_ip);
365 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
369 dest_hostname = g_strdup (priv->dest_hostname);
371 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
373 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
375 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
376 inetaddr = g_inet_socket_address_get_address (inetsaddr);
377 port = g_inet_socket_address_get_port (inetsaddr);
379 result = g_object_new (G_TYPE_PROXY_ADDRESS,
382 "protocol", priv->proxy_type,
383 "destination-protocol", dest_protocol,
384 "destination-hostname", dest_hostname,
385 "destination-port", priv->dest_port,
386 "username", priv->proxy_username,
387 "password", priv->proxy_password,
388 "uri", priv->proxy_uri,
390 g_free (dest_hostname);
391 g_free (dest_protocol);
393 if (priv->supports_hostname || priv->next_dest_ip == NULL)
395 g_object_unref (priv->proxy_address);
396 priv->proxy_address = NULL;
400 g_simple_async_result_set_op_res_gpointer (priv->simple,
405 static void address_enumerate_cb (GObject *object,
406 GAsyncResult *result,
410 next_proxy (GProxyAddressEnumeratorPrivate *priv)
412 if (*priv->next_proxy)
414 g_object_unref (priv->addr_enum);
415 priv->addr_enum = NULL;
419 g_resolver_free_addresses (priv->dest_ips);
420 priv->dest_ips = NULL;
423 next_enumerator (priv);
427 g_socket_address_enumerator_next_async (priv->addr_enum,
429 address_enumerate_cb,
435 complete_async (priv);
439 dest_hostname_lookup_cb (GObject *object,
440 GAsyncResult *result,
443 GProxyAddressEnumeratorPrivate *priv = user_data;
445 g_clear_error (&priv->last_error);
446 priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
452 complete_async (priv);
456 g_clear_object (&priv->proxy_address);
462 address_enumerate_cb (GObject *object,
463 GAsyncResult *result,
466 GProxyAddressEnumeratorPrivate *priv = user_data;
468 g_clear_error (&priv->last_error);
469 priv->proxy_address =
470 g_socket_address_enumerator_next_finish (priv->addr_enum,
473 if (priv->proxy_address)
475 if (!priv->supports_hostname && !priv->dest_ips)
478 resolver = g_resolver_get_default();
479 g_resolver_lookup_by_name_async (resolver,
482 dest_hostname_lookup_cb,
484 g_object_unref (resolver);
489 complete_async (priv);
496 proxy_lookup_cb (GObject *object,
497 GAsyncResult *result,
500 GError *error = NULL;
501 GProxyAddressEnumeratorPrivate *priv = user_data;
502 GSimpleAsyncResult *simple = priv->simple;
504 priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
507 priv->next_proxy = priv->proxies;
511 g_simple_async_result_take_error (simple, error);
515 next_enumerator (priv);
518 g_socket_address_enumerator_next_async (priv->addr_enum,
520 address_enumerate_cb,
526 complete_async (priv);
530 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
531 GCancellable *cancellable,
532 GAsyncReadyCallback callback,
535 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
537 g_return_if_fail (priv->simple == NULL);
538 g_return_if_fail (priv->cancellable == NULL);
540 priv->simple = g_simple_async_result_new (G_OBJECT (enumerator),
542 g_proxy_address_enumerator_next_async);
544 priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
546 if (priv->proxies == NULL)
548 GProxyResolver *resolver = g_proxy_resolver_get_default ();
549 g_proxy_resolver_lookup_async (resolver,
559 if (priv->proxy_address)
565 g_socket_address_enumerator_next_async (priv->addr_enum,
567 address_enumerate_cb,
573 g_simple_async_result_complete_in_idle (priv->simple);
575 g_object_unref (priv->simple);
578 if (priv->cancellable)
580 g_object_unref (priv->cancellable);
581 priv->cancellable = NULL;
585 static GSocketAddress *
586 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
587 GAsyncResult *result,
590 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
591 GSocketAddress *address;
593 if (g_simple_async_result_propagate_error (simple, error))
596 address = g_simple_async_result_get_op_res_gpointer (simple);
598 g_object_ref (address);
604 g_proxy_address_enumerator_get_property (GObject *object,
609 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
613 g_value_set_string (value, priv->dest_uri);
616 case PROP_CONNECTABLE:
617 g_value_set_object (value, priv->connectable);
621 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
626 g_proxy_address_enumerator_set_property (GObject *object,
631 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
638 g_free (priv->dest_hostname);
639 priv->dest_hostname = NULL;
642 g_free (priv->dest_uri);
643 priv->dest_uri = NULL;
645 uri = g_value_get_string (value);
649 GSocketConnectable *conn;
651 conn = g_network_address_parse_uri (uri, 0, NULL);
656 priv->dest_uri = g_strdup (uri);
659 "hostname", &priv->dest_hostname,
663 priv->dest_port = port;
664 g_object_unref (conn);
667 g_warning ("Invalid URI '%s'", uri);
673 case PROP_CONNECTABLE:
674 priv->connectable = g_value_dup_object (value);
678 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
683 g_proxy_address_enumerator_finalize (GObject *object)
685 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
687 if (priv->connectable)
688 g_object_unref (priv->connectable);
690 g_free (priv->dest_uri);
691 g_free (priv->dest_hostname);
694 g_resolver_free_addresses (priv->dest_ips);
696 g_strfreev (priv->proxies);
699 g_object_unref (priv->addr_enum);
701 g_free (priv->proxy_type);
702 g_free (priv->proxy_username);
703 g_free (priv->proxy_password);
705 if (priv->cancellable)
706 g_object_unref (priv->cancellable);
708 g_clear_error (&priv->last_error);
710 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
714 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
716 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
717 G_TYPE_PROXY_ADDRESS_ENUMERATOR,
718 GProxyAddressEnumeratorPrivate);
722 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
724 GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
725 GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
727 g_type_class_add_private (enumerator_class,
728 sizeof (GProxyAddressEnumeratorPrivate));
730 object_class->set_property = g_proxy_address_enumerator_set_property;
731 object_class->get_property = g_proxy_address_enumerator_get_property;
732 object_class->finalize = g_proxy_address_enumerator_finalize;
734 enumerator_class->next = g_proxy_address_enumerator_next;
735 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
736 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
738 g_object_class_install_property (object_class,
740 g_param_spec_string ("uri",
742 P_("The destination URI, use none:// for generic socket"),
745 G_PARAM_CONSTRUCT_ONLY |
746 G_PARAM_STATIC_STRINGS));
748 g_object_class_install_property (object_class,
750 g_param_spec_object ("connectable",
752 P_("The connectable being enumerated."),
753 G_TYPE_SOCKET_CONNECTABLE,
755 G_PARAM_CONSTRUCT_ONLY |
756 G_PARAM_STATIC_STRINGS));