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 G_DEFINE_TYPE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR);
44 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
54 struct _GProxyAddressEnumeratorPrivate
56 /* Destination address */
57 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;
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_get_property (GObject *object,
578 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
582 g_value_set_string (value, priv->dest_uri);
585 case PROP_CONNECTABLE:
586 g_value_set_object (value, priv->connectable);
589 case PROP_PROXY_RESOLVER:
590 g_value_set_object (value, priv->proxy_resolver);
594 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
599 g_proxy_address_enumerator_set_property (GObject *object,
604 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
611 g_free (priv->dest_hostname);
612 priv->dest_hostname = NULL;
615 g_free (priv->dest_uri);
616 priv->dest_uri = NULL;
618 uri = g_value_get_string (value);
622 GSocketConnectable *conn;
624 conn = g_network_address_parse_uri (uri, 0, NULL);
629 priv->dest_uri = g_strdup (uri);
632 "hostname", &priv->dest_hostname,
636 priv->dest_port = port;
637 g_object_unref (conn);
640 g_warning ("Invalid URI '%s'", uri);
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_TYPE_INSTANCE_GET_PRIVATE (self,
699 G_TYPE_PROXY_ADDRESS_ENUMERATOR,
700 GProxyAddressEnumeratorPrivate);
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 g_type_class_add_private (enumerator_class,
710 sizeof (GProxyAddressEnumeratorPrivate));
712 object_class->set_property = g_proxy_address_enumerator_set_property;
713 object_class->get_property = g_proxy_address_enumerator_get_property;
714 object_class->finalize = g_proxy_address_enumerator_finalize;
716 enumerator_class->next = g_proxy_address_enumerator_next;
717 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
718 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
720 g_object_class_install_property (object_class,
722 g_param_spec_string ("uri",
724 P_("The destination URI, use none:// for generic socket"),
727 G_PARAM_CONSTRUCT_ONLY |
728 G_PARAM_STATIC_STRINGS));
730 g_object_class_install_property (object_class,
732 g_param_spec_object ("connectable",
734 P_("The connectable being enumerated."),
735 G_TYPE_SOCKET_CONNECTABLE,
737 G_PARAM_CONSTRUCT_ONLY |
738 G_PARAM_STATIC_STRINGS));
741 * GProxyAddressEnumerator:proxy-resolver:
743 * The proxy resolver to use.
747 g_object_class_install_property (object_class,
749 g_param_spec_object ("proxy-resolver",
750 P_("Proxy resolver"),
751 P_("The proxy resolver to use."),
752 G_TYPE_PROXY_RESOLVER,
755 G_PARAM_STATIC_STRINGS));