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
;
68 gchar
*proxy_username
;
69 gchar
*proxy_password
;
70 gboolean supports_hostname
;
73 /* Async attributes */
74 GSimpleAsyncResult
*simple
;
75 GCancellable
*cancellable
;
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
;
124 const gchar
*proxy_uri
;
127 proxy_uri
= *priv
->next_proxy
++;
128 g_free (priv
->proxy_type
);
129 priv
->proxy_type
= g_uri_parse_scheme (proxy_uri
);
131 if (priv
->proxy_type
== NULL
)
134 /* Assumes hostnames are supported for unknown protocols */
135 priv
->supports_hostname
= TRUE
;
136 proxy
= g_proxy_get_default_for_protocol (priv
->proxy_type
);
139 priv
->supports_hostname
= g_proxy_supports_hostname (proxy
);
140 g_object_unref (proxy
);
143 if (strcmp ("direct", priv
->proxy_type
) == 0)
145 if (priv
->connectable
)
146 connectable
= g_object_ref (priv
->connectable
);
148 connectable
= g_network_address_new (priv
->dest_hostname
,
153 GError
*error
= NULL
;
155 connectable
= g_network_address_parse_uri (proxy_uri
, 0, &error
);
159 g_warning ("Invalid proxy URI '%s': %s",
160 proxy_uri
, error
->message
);
161 g_error_free (error
);
164 save_userinfo (priv
, proxy_uri
);
169 priv
->addr_enum
= g_socket_connectable_enumerate (connectable
);
170 g_object_unref (connectable
);
175 static GSocketAddress
*
176 g_proxy_address_enumerator_next (GSocketAddressEnumerator
*enumerator
,
177 GCancellable
*cancellable
,
180 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (enumerator
);
181 GSocketAddress
*result
= NULL
;
182 GError
*first_error
= NULL
;
184 if (priv
->proxies
== NULL
)
186 GProxyResolver
*resolver
= g_proxy_resolver_get_default ();
187 priv
->proxies
= g_proxy_resolver_lookup (resolver
,
191 priv
->next_proxy
= priv
->proxies
;
193 if (priv
->proxies
== NULL
)
197 while (result
== NULL
&& (*priv
->next_proxy
|| priv
->addr_enum
))
199 gchar
*dest_hostname
;
200 GInetSocketAddress
*inetsaddr
;
201 GInetAddress
*inetaddr
;
204 next_enumerator (priv
);
206 if (!priv
->addr_enum
)
209 if (priv
->proxy_address
== NULL
)
211 priv
->proxy_address
= g_socket_address_enumerator_next (
214 first_error
? NULL
: &first_error
);
217 if (priv
->proxy_address
== NULL
)
219 g_object_unref (priv
->addr_enum
);
220 priv
->addr_enum
= NULL
;
224 g_resolver_free_addresses (priv
->dest_ips
);
225 priv
->dest_ips
= NULL
;
231 if (strcmp ("direct", priv
->proxy_type
) == 0)
233 result
= priv
->proxy_address
;
234 priv
->proxy_address
= NULL
;
238 if (!priv
->supports_hostname
)
240 GInetAddress
*dest_ip
;
246 resolver
= g_resolver_get_default();
247 priv
->dest_ips
= g_resolver_lookup_by_name (resolver
,
250 first_error
? NULL
: &first_error
);
251 g_object_unref (resolver
);
255 g_object_unref (priv
->proxy_address
);
256 priv
->proxy_address
= NULL
;
261 if (!priv
->next_dest_ip
)
262 priv
->next_dest_ip
= priv
->dest_ips
;
264 dest_ip
= G_INET_ADDRESS (priv
->next_dest_ip
->data
);
265 dest_hostname
= g_inet_address_to_string (dest_ip
);
267 priv
->next_dest_ip
= g_list_next (priv
->next_dest_ip
);
271 dest_hostname
= g_strdup (priv
->dest_hostname
);
275 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv
->proxy_address
),
278 inetsaddr
= G_INET_SOCKET_ADDRESS (priv
->proxy_address
);
279 inetaddr
= g_inet_socket_address_get_address (inetsaddr
);
280 port
= g_inet_socket_address_get_port (inetsaddr
);
282 result
= g_proxy_address_new (inetaddr
, port
,
284 dest_hostname
, priv
->dest_port
,
285 priv
->proxy_username
,
286 priv
->proxy_password
);
288 g_free (dest_hostname
);
290 if (priv
->supports_hostname
|| priv
->next_dest_ip
== NULL
)
292 g_object_unref (priv
->proxy_address
);
293 priv
->proxy_address
= NULL
;
297 if (result
== NULL
&& first_error
)
298 g_propagate_error (error
, first_error
);
299 else if (first_error
)
300 g_error_free (first_error
);
308 complete_async (GProxyAddressEnumeratorPrivate
*priv
)
310 GSimpleAsyncResult
*simple
= priv
->simple
;
312 if (priv
->cancellable
)
314 g_object_unref (priv
->cancellable
);
315 priv
->cancellable
= NULL
;
319 g_simple_async_result_complete (simple
);
320 g_object_unref (simple
);
324 save_result (GProxyAddressEnumeratorPrivate
*priv
)
326 GSocketAddress
*result
;
328 if (strcmp ("direct", priv
->proxy_type
) == 0)
330 result
= priv
->proxy_address
;
331 priv
->proxy_address
= NULL
;
335 gchar
*dest_hostname
;
336 GInetSocketAddress
*inetsaddr
;
337 GInetAddress
*inetaddr
;
340 if (!priv
->supports_hostname
)
342 GInetAddress
*dest_ip
;
344 if (!priv
->next_dest_ip
)
345 priv
->next_dest_ip
= priv
->dest_ips
;
347 dest_ip
= G_INET_ADDRESS (priv
->next_dest_ip
->data
);
348 dest_hostname
= g_inet_address_to_string (dest_ip
);
350 priv
->next_dest_ip
= g_list_next (priv
->next_dest_ip
);
354 dest_hostname
= g_strdup (priv
->dest_hostname
);
357 g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv
->proxy_address
));
359 inetsaddr
= G_INET_SOCKET_ADDRESS (priv
->proxy_address
);
360 inetaddr
= g_inet_socket_address_get_address (inetsaddr
);
361 port
= g_inet_socket_address_get_port (inetsaddr
);
363 result
= g_proxy_address_new (inetaddr
, port
,
365 dest_hostname
, priv
->dest_port
,
366 priv
->proxy_username
,
367 priv
->proxy_password
);
369 g_free (dest_hostname
);
371 if (priv
->supports_hostname
|| priv
->next_dest_ip
== NULL
)
373 g_object_unref (priv
->proxy_address
);
374 priv
->proxy_address
= NULL
;
378 g_simple_async_result_set_op_res_gpointer (priv
->simple
,
384 dest_hostname_lookup_cb (GObject
*object
,
385 GAsyncResult
*result
,
388 GError
*error
= NULL
;
389 GProxyAddressEnumeratorPrivate
*priv
= user_data
;
390 GSimpleAsyncResult
*simple
= priv
->simple
;
392 priv
->dest_ips
= g_resolver_lookup_by_name_finish (G_RESOLVER (object
),
398 g_simple_async_result_take_error (simple
, error
);
400 complete_async (priv
);
404 address_enumerate_cb (GObject
*object
,
405 GAsyncResult
*result
,
408 GError
*error
= NULL
;
409 GProxyAddressEnumeratorPrivate
*priv
= user_data
;
410 GSimpleAsyncResult
*simple
= priv
->simple
;
412 priv
->proxy_address
=
413 g_socket_address_enumerator_next_finish (priv
->addr_enum
,
416 if (priv
->proxy_address
)
418 if (!priv
->supports_hostname
&& !priv
->dest_ips
)
421 resolver
= g_resolver_get_default();
422 g_resolver_lookup_by_name_async (resolver
,
425 dest_hostname_lookup_cb
,
427 g_object_unref (resolver
);
433 else if (*priv
->next_proxy
)
435 g_object_unref (priv
->addr_enum
);
436 priv
->addr_enum
= NULL
;
440 g_resolver_free_addresses (priv
->dest_ips
);
441 priv
->dest_ips
= NULL
;
444 next_enumerator (priv
);
448 g_socket_address_enumerator_next_async (priv
->addr_enum
,
450 address_enumerate_cb
,
457 g_simple_async_result_take_error (simple
, error
);
459 complete_async (priv
);
463 proxy_lookup_cb (GObject
*object
,
464 GAsyncResult
*result
,
467 GError
*error
= NULL
;
468 GProxyAddressEnumeratorPrivate
*priv
= user_data
;
469 GSimpleAsyncResult
*simple
= priv
->simple
;
471 priv
->proxies
= g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object
),
474 priv
->next_proxy
= priv
->proxies
;
478 g_simple_async_result_take_error (simple
, error
);
482 next_enumerator (priv
);
485 g_socket_address_enumerator_next_async (priv
->addr_enum
,
487 address_enumerate_cb
,
493 complete_async (priv
);
497 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator
*enumerator
,
498 GCancellable
*cancellable
,
499 GAsyncReadyCallback callback
,
502 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (enumerator
);
504 g_return_if_fail (priv
->simple
== NULL
);
505 g_return_if_fail (priv
->cancellable
== NULL
);
507 priv
->simple
= g_simple_async_result_new (G_OBJECT (enumerator
),
509 g_proxy_address_enumerator_next_async
);
511 priv
->cancellable
= cancellable
? g_object_ref (cancellable
) : NULL
;
513 if (priv
->proxies
== NULL
)
515 GProxyResolver
*resolver
= g_proxy_resolver_get_default ();
516 g_proxy_resolver_lookup_async (resolver
,
526 if (priv
->proxy_address
)
532 g_socket_address_enumerator_next_async (priv
->addr_enum
,
534 address_enumerate_cb
,
540 g_simple_async_result_complete_in_idle (priv
->simple
);
542 g_object_unref (priv
->simple
);
545 if (priv
->cancellable
)
547 g_object_unref (priv
->cancellable
);
548 priv
->cancellable
= NULL
;
552 static GSocketAddress
*
553 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator
*enumerator
,
554 GAsyncResult
*result
,
557 GSimpleAsyncResult
*simple
= G_SIMPLE_ASYNC_RESULT (result
);
558 GSocketAddress
*address
;
560 if (g_simple_async_result_propagate_error (simple
, error
))
563 address
= g_simple_async_result_get_op_res_gpointer (simple
);
565 g_object_ref (address
);
571 g_proxy_address_enumerator_get_property (GObject
*object
,
576 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
580 g_value_set_string (value
, priv
->dest_uri
);
583 case PROP_CONNECTABLE
:
584 g_value_set_object (value
, priv
->connectable
);
588 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
593 g_proxy_address_enumerator_set_property (GObject
*object
,
598 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
605 g_free (priv
->dest_hostname
);
606 priv
->dest_hostname
= NULL
;
609 g_free (priv
->dest_uri
);
610 priv
->dest_uri
= NULL
;
612 uri
= g_value_get_string (value
);
616 GSocketConnectable
*conn
;
618 conn
= g_network_address_parse_uri (uri
, 0, NULL
);
623 priv
->dest_uri
= g_strdup (uri
);
626 "hostname", &priv
->dest_hostname
,
630 priv
->dest_port
= port
;
631 g_object_unref (conn
);
634 g_warning ("Invalid URI '%s'", uri
);
640 case PROP_CONNECTABLE
:
641 priv
->connectable
= g_value_dup_object (value
);
645 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
650 g_proxy_address_enumerator_finalize (GObject
*object
)
652 GProxyAddressEnumeratorPrivate
*priv
= GET_PRIVATE (object
);
654 if (priv
->connectable
)
655 g_object_unref (priv
->connectable
);
657 g_free (priv
->dest_uri
);
658 g_free (priv
->dest_hostname
);
661 g_resolver_free_addresses (priv
->dest_ips
);
663 g_strfreev (priv
->proxies
);
666 g_object_unref (priv
->addr_enum
);
668 g_free (priv
->proxy_type
);
669 g_free (priv
->proxy_username
);
670 g_free (priv
->proxy_password
);
672 if (priv
->cancellable
)
673 g_object_unref (priv
->cancellable
);
675 G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class
)->finalize (object
);
679 g_proxy_address_enumerator_init (GProxyAddressEnumerator
*self
)
681 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
682 G_TYPE_PROXY_ADDRESS_ENUMERATOR
,
683 GProxyAddressEnumeratorPrivate
);
687 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass
*proxy_enumerator_class
)
689 GObjectClass
*object_class
= G_OBJECT_CLASS (proxy_enumerator_class
);
690 GSocketAddressEnumeratorClass
*enumerator_class
= G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class
);
692 g_type_class_add_private (enumerator_class
,
693 sizeof (GProxyAddressEnumeratorPrivate
));
695 object_class
->set_property
= g_proxy_address_enumerator_set_property
;
696 object_class
->get_property
= g_proxy_address_enumerator_get_property
;
697 object_class
->finalize
= g_proxy_address_enumerator_finalize
;
699 enumerator_class
->next
= g_proxy_address_enumerator_next
;
700 enumerator_class
->next_async
= g_proxy_address_enumerator_next_async
;
701 enumerator_class
->next_finish
= g_proxy_address_enumerator_next_finish
;
703 g_object_class_install_property (object_class
,
705 g_param_spec_string ("uri",
707 P_("The destination URI, use none:// for generic socket"),
710 G_PARAM_CONSTRUCT_ONLY
|
711 G_PARAM_STATIC_STRINGS
));
713 g_object_class_install_property (object_class
,
715 g_param_spec_object ("connectable",
717 P_("The connectable being enumerated."),
718 G_TYPE_SOCKET_CONNECTABLE
,
720 G_PARAM_CONSTRUCT_ONLY
|
721 G_PARAM_STATIC_STRINGS
));