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)
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;
77 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
82 if (priv->proxy_username)
84 g_free (priv->proxy_username);
85 priv->proxy_username = NULL;
88 if (priv->proxy_password)
90 g_free (priv->proxy_password);
91 priv->proxy_password = NULL;
94 if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo))
98 gchar **split = g_strsplit (userinfo, ":", 2);
100 if (split[0] != NULL)
102 priv->proxy_username = g_uri_unescape_string (split[0], NULL);
103 if (split[1] != NULL)
104 priv->proxy_password = g_uri_unescape_string (split[1], NULL);
114 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
116 if (priv->proxy_address)
119 while (priv->addr_enum == NULL && *priv->next_proxy)
121 GSocketConnectable *connectable = NULL;
124 priv->proxy_uri = *priv->next_proxy++;
125 g_free (priv->proxy_type);
126 priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
128 if (priv->proxy_type == NULL)
131 /* Assumes hostnames are supported for unknown protocols */
132 priv->supports_hostname = TRUE;
133 proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
136 priv->supports_hostname = g_proxy_supports_hostname (proxy);
137 g_object_unref (proxy);
140 if (strcmp ("direct", priv->proxy_type) == 0)
142 if (priv->connectable)
143 connectable = g_object_ref (priv->connectable);
145 connectable = g_network_address_new (priv->dest_hostname,
150 GError *error = NULL;
152 connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
156 g_warning ("Invalid proxy URI '%s': %s",
157 priv->proxy_uri, error->message);
158 g_error_free (error);
161 save_userinfo (priv, priv->proxy_uri);
166 priv->addr_enum = g_socket_connectable_enumerate (connectable);
167 g_object_unref (connectable);
172 static GSocketAddress *
173 g_proxy_address_enumerator_next (GSocketAddressEnumerator *enumerator,
174 GCancellable *cancellable,
177 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
178 GSocketAddress *result = NULL;
179 GError *first_error = NULL;
181 if (priv->proxies == NULL)
183 GProxyResolver *resolver = g_proxy_resolver_get_default ();
184 priv->proxies = g_proxy_resolver_lookup (resolver,
188 priv->next_proxy = priv->proxies;
190 if (priv->proxies == NULL)
194 while (result == NULL && (*priv->next_proxy || priv->addr_enum))
196 gchar *dest_hostname;
197 gchar *dest_protocol;
198 GInetSocketAddress *inetsaddr;
199 GInetAddress *inetaddr;
202 next_enumerator (priv);
204 if (!priv->addr_enum)
207 if (priv->proxy_address == NULL)
209 priv->proxy_address = g_socket_address_enumerator_next (
212 first_error ? NULL : &first_error);
215 if (priv->proxy_address == NULL)
217 g_object_unref (priv->addr_enum);
218 priv->addr_enum = NULL;
222 g_resolver_free_addresses (priv->dest_ips);
223 priv->dest_ips = NULL;
229 if (strcmp ("direct", priv->proxy_type) == 0)
231 result = priv->proxy_address;
232 priv->proxy_address = NULL;
236 if (!priv->supports_hostname)
238 GInetAddress *dest_ip;
244 resolver = g_resolver_get_default();
245 priv->dest_ips = g_resolver_lookup_by_name (resolver,
248 first_error ? NULL : &first_error);
249 g_object_unref (resolver);
253 g_object_unref (priv->proxy_address);
254 priv->proxy_address = NULL;
259 if (!priv->next_dest_ip)
260 priv->next_dest_ip = priv->dest_ips;
262 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
263 dest_hostname = g_inet_address_to_string (dest_ip);
265 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
269 dest_hostname = g_strdup (priv->dest_hostname);
271 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
273 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
276 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
277 inetaddr = g_inet_socket_address_get_address (inetsaddr);
278 port = g_inet_socket_address_get_port (inetsaddr);
280 result = g_object_new (G_TYPE_PROXY_ADDRESS,
283 "protocol", priv->proxy_type,
284 "destination-protocol", dest_protocol,
285 "destination-hostname", dest_hostname,
286 "destination-port", priv->dest_port,
287 "username", priv->proxy_username,
288 "password", priv->proxy_password,
289 "uri", priv->proxy_uri,
291 g_free (dest_hostname);
292 g_free (dest_protocol);
294 if (priv->supports_hostname || priv->next_dest_ip == NULL)
296 g_object_unref (priv->proxy_address);
297 priv->proxy_address = NULL;
301 if (result == NULL && first_error)
302 g_propagate_error (error, first_error);
303 else if (first_error)
304 g_error_free (first_error);
312 complete_async (GTask *task)
314 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
316 if (priv->last_error)
318 g_task_return_error (task, priv->last_error);
319 priv->last_error = NULL;
322 g_task_return_pointer (task, NULL, NULL);
324 g_object_unref (task);
328 return_result (GTask *task)
330 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
331 GSocketAddress *result;
333 if (strcmp ("direct", priv->proxy_type) == 0)
335 result = priv->proxy_address;
336 priv->proxy_address = NULL;
340 gchar *dest_hostname, *dest_protocol;
341 GInetSocketAddress *inetsaddr;
342 GInetAddress *inetaddr;
345 if (!priv->supports_hostname)
347 GInetAddress *dest_ip;
349 if (!priv->next_dest_ip)
350 priv->next_dest_ip = priv->dest_ips;
352 dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
353 dest_hostname = g_inet_address_to_string (dest_ip);
355 priv->next_dest_ip = g_list_next (priv->next_dest_ip);
359 dest_hostname = g_strdup (priv->dest_hostname);
361 dest_protocol = g_uri_parse_scheme (priv->dest_uri);
363 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
365 inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
366 inetaddr = g_inet_socket_address_get_address (inetsaddr);
367 port = g_inet_socket_address_get_port (inetsaddr);
369 result = g_object_new (G_TYPE_PROXY_ADDRESS,
372 "protocol", priv->proxy_type,
373 "destination-protocol", dest_protocol,
374 "destination-hostname", dest_hostname,
375 "destination-port", priv->dest_port,
376 "username", priv->proxy_username,
377 "password", priv->proxy_password,
378 "uri", priv->proxy_uri,
380 g_free (dest_hostname);
381 g_free (dest_protocol);
383 if (priv->supports_hostname || priv->next_dest_ip == NULL)
385 g_object_unref (priv->proxy_address);
386 priv->proxy_address = NULL;
390 g_task_return_pointer (task, result, g_object_unref);
391 g_object_unref (task);
394 static void address_enumerate_cb (GObject *object,
395 GAsyncResult *result,
399 next_proxy (GTask *task)
401 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
403 if (*priv->next_proxy)
405 g_object_unref (priv->addr_enum);
406 priv->addr_enum = NULL;
410 g_resolver_free_addresses (priv->dest_ips);
411 priv->dest_ips = NULL;
414 next_enumerator (priv);
418 g_socket_address_enumerator_next_async (priv->addr_enum,
419 g_task_get_cancellable (task),
420 address_enumerate_cb,
426 complete_async (task);
430 dest_hostname_lookup_cb (GObject *object,
431 GAsyncResult *result,
434 GTask *task = user_data;
435 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
437 g_clear_error (&priv->last_error);
438 priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
442 return_result (task);
445 g_clear_object (&priv->proxy_address);
451 address_enumerate_cb (GObject *object,
452 GAsyncResult *result,
455 GTask *task = user_data;
456 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
458 g_clear_error (&priv->last_error);
459 priv->proxy_address =
460 g_socket_address_enumerator_next_finish (priv->addr_enum,
463 if (priv->proxy_address)
465 if (!priv->supports_hostname && !priv->dest_ips)
468 resolver = g_resolver_get_default();
469 g_resolver_lookup_by_name_async (resolver,
471 g_task_get_cancellable (task),
472 dest_hostname_lookup_cb,
474 g_object_unref (resolver);
478 return_result (task);
485 proxy_lookup_cb (GObject *object,
486 GAsyncResult *result,
489 GTask *task = user_data;
490 GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
492 g_clear_error (&priv->last_error);
493 priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
496 priv->next_proxy = priv->proxies;
498 if (priv->last_error)
500 complete_async (task);
505 next_enumerator (priv);
508 g_socket_address_enumerator_next_async (priv->addr_enum,
509 g_task_get_cancellable (task),
510 address_enumerate_cb,
516 complete_async (task);
520 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
521 GCancellable *cancellable,
522 GAsyncReadyCallback callback,
525 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
528 task = g_task_new (enumerator, cancellable, callback, user_data);
529 g_task_set_task_data (task, priv, NULL);
531 if (priv->proxies == NULL)
533 GProxyResolver *resolver = g_proxy_resolver_get_default ();
534 g_proxy_resolver_lookup_async (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);
590 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
595 g_proxy_address_enumerator_set_property (GObject *object,
600 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
607 g_free (priv->dest_hostname);
608 priv->dest_hostname = NULL;
611 g_free (priv->dest_uri);
612 priv->dest_uri = NULL;
614 uri = g_value_get_string (value);
618 GSocketConnectable *conn;
620 conn = g_network_address_parse_uri (uri, 0, NULL);
625 priv->dest_uri = g_strdup (uri);
628 "hostname", &priv->dest_hostname,
632 priv->dest_port = port;
633 g_object_unref (conn);
636 g_warning ("Invalid URI '%s'", uri);
642 case PROP_CONNECTABLE:
643 priv->connectable = g_value_dup_object (value);
647 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
652 g_proxy_address_enumerator_finalize (GObject *object)
654 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
656 if (priv->connectable)
657 g_object_unref (priv->connectable);
659 g_free (priv->dest_uri);
660 g_free (priv->dest_hostname);
663 g_resolver_free_addresses (priv->dest_ips);
665 g_strfreev (priv->proxies);
668 g_object_unref (priv->addr_enum);
670 g_free (priv->proxy_type);
671 g_free (priv->proxy_username);
672 g_free (priv->proxy_password);
674 g_clear_error (&priv->last_error);
676 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
680 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
682 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
683 G_TYPE_PROXY_ADDRESS_ENUMERATOR,
684 GProxyAddressEnumeratorPrivate);
688 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
690 GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
691 GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
693 g_type_class_add_private (enumerator_class,
694 sizeof (GProxyAddressEnumeratorPrivate));
696 object_class->set_property = g_proxy_address_enumerator_set_property;
697 object_class->get_property = g_proxy_address_enumerator_get_property;
698 object_class->finalize = g_proxy_address_enumerator_finalize;
700 enumerator_class->next = g_proxy_address_enumerator_next;
701 enumerator_class->next_async = g_proxy_address_enumerator_next_async;
702 enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
704 g_object_class_install_property (object_class,
706 g_param_spec_string ("uri",
708 P_("The destination URI, use none:// for generic socket"),
711 G_PARAM_CONSTRUCT_ONLY |
712 G_PARAM_STATIC_STRINGS));
714 g_object_class_install_property (object_class,
716 g_param_spec_object ("connectable",
718 P_("The connectable being enumerated."),
719 G_TYPE_SOCKET_CONNECTABLE,
721 G_PARAM_CONSTRUCT_ONLY |
722 G_PARAM_STATIC_STRINGS));