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.1 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
, NULL
))
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_source_tag (task
, g_proxy_address_enumerator_next_async
);
531 g_task_set_task_data (task
, priv
, NULL
);
533 if (priv
->proxies
== NULL
)
535 g_proxy_resolver_lookup_async (priv
->proxy_resolver
,
545 if (priv
->proxy_address
)
547 return_result (task
);
552 g_socket_address_enumerator_next_async (priv
->addr_enum
,
554 address_enumerate_cb
,
560 complete_async (task
);
563 static GSocketAddress
*
564 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator
*enumerator
,
565 GAsyncResult
*result
,
568 g_return_val_if_fail (g_task_is_valid (result
, enumerator
), NULL
);
570 return g_task_propagate_pointer (G_TASK (result
), error
);
574 g_proxy_address_enumerator_constructed (GObject
*object
)
576 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
577 GSocketConnectable
*conn
;
582 conn
= g_network_address_parse_uri (priv
->dest_uri
, priv
->default_port
, NULL
);
586 "hostname", &priv
->dest_hostname
,
589 priv
->dest_port
= port
;
591 g_object_unref (conn
);
594 g_warning ("Invalid URI '%s'", priv
->dest_uri
);
597 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class
)->constructed (object
);
601 g_proxy_address_enumerator_get_property (GObject
*object
,
606 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
610 g_value_set_string (value
, priv
->dest_uri
);
613 case PROP_DEFAULT_PORT
:
614 g_value_set_uint (value
, priv
->default_port
);
617 case PROP_CONNECTABLE
:
618 g_value_set_object (value
, priv
->connectable
);
621 case PROP_PROXY_RESOLVER
:
622 g_value_set_object (value
, priv
->proxy_resolver
);
626 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
631 g_proxy_address_enumerator_set_property (GObject
*object
,
636 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
640 priv
->dest_uri
= g_value_dup_string (value
);
643 case PROP_DEFAULT_PORT
:
644 priv
->default_port
= g_value_get_uint (value
);
647 case PROP_CONNECTABLE
:
648 priv
->connectable
= g_value_dup_object (value
);
651 case PROP_PROXY_RESOLVER
:
652 if (priv
->proxy_resolver
)
653 g_object_unref (priv
->proxy_resolver
);
654 priv
->proxy_resolver
= g_value_get_object (value
);
655 if (!priv
->proxy_resolver
)
656 priv
->proxy_resolver
= g_proxy_resolver_get_default ();
657 g_object_ref (priv
->proxy_resolver
);
661 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
666 g_proxy_address_enumerator_finalize (GObject
*object
)
668 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
670 if (priv
->connectable
)
671 g_object_unref (priv
->connectable
);
673 if (priv
->proxy_resolver
)
674 g_object_unref (priv
->proxy_resolver
);
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 g_clear_error (&priv
->last_error
);
693 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class
)->finalize (object
);
697 g_proxy_address_enumerator_init (GProxyAddressEnumerator
*self
)
699 self
->priv
= g_proxy_address_enumerator_get_instance_private (self
);
703 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass
*proxy_enumerator_class
)
705 GObjectClass
*object_class
= G_OBJECT_CLASS (proxy_enumerator_class
);
706 GSocketAddressEnumeratorClass
*enumerator_class
= G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class
);
708 object_class
->constructed
= g_proxy_address_enumerator_constructed
;
709 object_class
->set_property
= g_proxy_address_enumerator_set_property
;
710 object_class
->get_property
= g_proxy_address_enumerator_get_property
;
711 object_class
->finalize
= g_proxy_address_enumerator_finalize
;
713 enumerator_class
->next
= g_proxy_address_enumerator_next
;
714 enumerator_class
->next_async
= g_proxy_address_enumerator_next_async
;
715 enumerator_class
->next_finish
= g_proxy_address_enumerator_next_finish
;
717 g_object_class_install_property (object_class
,
719 g_param_spec_string ("uri",
721 P_("The destination URI, use none:// for generic socket"),
724 G_PARAM_CONSTRUCT_ONLY
|
725 G_PARAM_STATIC_STRINGS
));
728 * GProxyAddressEnumerator:default-port:
730 * The default port to use if #GProxyAddressEnumerator:uri does not
735 g_object_class_install_property (object_class
,
737 g_param_spec_uint ("default-port",
739 P_("The default port to use if uri does not specify one"),
742 G_PARAM_CONSTRUCT_ONLY
|
743 G_PARAM_STATIC_STRINGS
));
745 g_object_class_install_property (object_class
,
747 g_param_spec_object ("connectable",
749 P_("The connectable being enumerated."),
750 G_TYPE_SOCKET_CONNECTABLE
,
752 G_PARAM_CONSTRUCT_ONLY
|
753 G_PARAM_STATIC_STRINGS
));
756 * GProxyAddressEnumerator:proxy-resolver:
758 * The proxy resolver to use.
762 g_object_class_install_property (object_class
,
764 g_param_spec_object ("proxy-resolver",
765 P_("Proxy resolver"),
766 P_("The proxy resolver to use."),
767 G_TYPE_PROXY_RESOLVER
,
770 G_PARAM_STATIC_STRINGS
));