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
));