More clearly define 'named menu' in the XML parser
[glib.git] / gio / gproxyaddressenumerator.c
blobb7bc04d457373d7d6ed89c09364d5f5ef78153af
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>
23 #include "config.h"
24 #include "gproxyaddressenumerator.h"
26 #include <string.h>
28 #include "gasyncresult.h"
29 #include "ginetaddress.h"
30 #include "glibintl.h"
31 #include "gnetworkaddress.h"
32 #include "gnetworkingprivate.h"
33 #include "gproxy.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)
46 enum
48 PROP_0,
49 PROP_URI,
50 PROP_CONNECTABLE
53 struct _GProxyAddressEnumeratorPrivate
55 /* Destination address */
56 GSocketConnectable *connectable;
57 gchar *dest_uri;
58 gchar *dest_hostname;
59 guint16 dest_port;
60 GList *dest_ips;
62 /* Proxy enumeration */
63 gchar **proxies;
64 gchar **next_proxy;
65 GSocketAddressEnumerator *addr_enum;
66 GSocketAddress *proxy_address;
67 gchar *proxy_type;
68 gchar *proxy_username;
69 gchar *proxy_password;
70 gboolean supports_hostname;
71 GList *next_dest_ip;
73 /* Async attributes */
74 GSimpleAsyncResult *simple;
75 GCancellable *cancellable;
78 static void
79 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
80 const gchar *proxy)
82 gchar *userinfo;
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))
98 if (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);
109 g_strfreev (split);
110 g_free (userinfo);
115 static void
116 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
118 if (priv->proxy_address)
119 return;
121 while (priv->addr_enum == NULL && *priv->next_proxy)
123 GSocketConnectable *connectable = NULL;
124 const gchar *proxy_uri;
125 GProxy *proxy;
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)
132 continue;
134 /* Assumes hostnames are supported for unknown protocols */
135 priv->supports_hostname = TRUE;
136 proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
137 if (proxy)
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);
147 else
148 connectable = g_network_address_new (priv->dest_hostname,
149 priv->dest_port);
151 else
153 GError *error = NULL;
155 connectable = g_network_address_parse_uri (proxy_uri, 0, &error);
157 if (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);
167 if (connectable)
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,
178 GError **error)
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,
188 priv->dest_uri,
189 cancellable,
190 error);
191 priv->next_proxy = priv->proxies;
193 if (priv->proxies == NULL)
194 return NULL;
197 while (result == NULL && (*priv->next_proxy || priv->addr_enum))
199 gchar *dest_hostname;
200 GInetSocketAddress *inetsaddr;
201 GInetAddress *inetaddr;
202 guint16 port;
204 next_enumerator (priv);
206 if (!priv->addr_enum)
207 continue;
209 if (priv->proxy_address == NULL)
211 priv->proxy_address = g_socket_address_enumerator_next (
212 priv->addr_enum,
213 cancellable,
214 first_error ? NULL : &first_error);
217 if (priv->proxy_address == NULL)
219 g_object_unref (priv->addr_enum);
220 priv->addr_enum = NULL;
222 if (priv->dest_ips)
224 g_resolver_free_addresses (priv->dest_ips);
225 priv->dest_ips = NULL;
228 continue;
231 if (strcmp ("direct", priv->proxy_type) == 0)
233 result = priv->proxy_address;
234 priv->proxy_address = NULL;
235 continue;
238 if (!priv->supports_hostname)
240 GInetAddress *dest_ip;
242 if (!priv->dest_ips)
244 GResolver *resolver;
246 resolver = g_resolver_get_default();
247 priv->dest_ips = g_resolver_lookup_by_name (resolver,
248 priv->dest_hostname,
249 cancellable,
250 first_error ? NULL : &first_error);
251 g_object_unref (resolver);
253 if (!priv->dest_ips)
255 g_object_unref (priv->proxy_address);
256 priv->proxy_address = NULL;
257 continue;
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);
269 else
271 dest_hostname = g_strdup (priv->dest_hostname);
275 g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
276 NULL);
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,
283 priv->proxy_type,
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);
302 return result;
307 static void
308 complete_async (GProxyAddressEnumeratorPrivate *priv)
310 GSimpleAsyncResult *simple = priv->simple;
312 if (priv->cancellable)
314 g_object_unref (priv->cancellable);
315 priv->cancellable = NULL;
318 priv->simple = NULL;
319 g_simple_async_result_complete (simple);
320 g_object_unref (simple);
323 static void
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;
333 else
335 gchar *dest_hostname;
336 GInetSocketAddress *inetsaddr;
337 GInetAddress *inetaddr;
338 guint16 port;
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);
352 else
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,
364 priv->proxy_type,
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,
379 result,
380 g_object_unref);
383 static void
384 dest_hostname_lookup_cb (GObject *object,
385 GAsyncResult *result,
386 gpointer user_data)
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),
393 result,
394 &error);
395 if (priv->dest_ips)
396 save_result (priv);
397 else
398 g_simple_async_result_take_error (simple, error);
400 complete_async (priv);
403 static void
404 address_enumerate_cb (GObject *object,
405 GAsyncResult *result,
406 gpointer user_data)
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,
414 result,
415 &error);
416 if (priv->proxy_address)
418 if (!priv->supports_hostname && !priv->dest_ips)
420 GResolver *resolver;
421 resolver = g_resolver_get_default();
422 g_resolver_lookup_by_name_async (resolver,
423 priv->dest_hostname,
424 priv->cancellable,
425 dest_hostname_lookup_cb,
426 priv);
427 g_object_unref (resolver);
428 return;
431 save_result (priv);
433 else if (*priv->next_proxy)
435 g_object_unref (priv->addr_enum);
436 priv->addr_enum = NULL;
438 if (priv->dest_ips)
440 g_resolver_free_addresses (priv->dest_ips);
441 priv->dest_ips = NULL;
444 next_enumerator (priv);
446 if (priv->addr_enum)
448 g_socket_address_enumerator_next_async (priv->addr_enum,
449 priv->cancellable,
450 address_enumerate_cb,
451 priv);
452 return;
456 if (error)
457 g_simple_async_result_take_error (simple, error);
459 complete_async (priv);
462 static void
463 proxy_lookup_cb (GObject *object,
464 GAsyncResult *result,
465 gpointer user_data)
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),
472 result,
473 &error);
474 priv->next_proxy = priv->proxies;
476 if (error)
478 g_simple_async_result_take_error (simple, error);
480 else
482 next_enumerator (priv);
483 if (priv->addr_enum)
485 g_socket_address_enumerator_next_async (priv->addr_enum,
486 priv->cancellable,
487 address_enumerate_cb,
488 priv);
489 return;
493 complete_async (priv);
496 static void
497 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
498 GCancellable *cancellable,
499 GAsyncReadyCallback callback,
500 gpointer user_data)
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),
508 callback, user_data,
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,
517 priv->dest_uri,
518 cancellable,
519 proxy_lookup_cb,
520 priv);
521 return;
524 if (priv->addr_enum)
526 if (priv->proxy_address)
528 save_result (priv);
530 else
532 g_socket_address_enumerator_next_async (priv->addr_enum,
533 cancellable,
534 address_enumerate_cb,
535 priv);
536 return;
540 g_simple_async_result_complete_in_idle (priv->simple);
542 g_object_unref (priv->simple);
543 priv->simple = NULL;
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,
555 GError **error)
557 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
558 GSocketAddress *address;
560 if (g_simple_async_result_propagate_error (simple, error))
561 return NULL;
563 address = g_simple_async_result_get_op_res_gpointer (simple);
564 if (address)
565 g_object_ref (address);
567 return address;
570 static void
571 g_proxy_address_enumerator_get_property (GObject *object,
572 guint property_id,
573 GValue *value,
574 GParamSpec *pspec)
576 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
577 switch (property_id)
579 case PROP_URI:
580 g_value_set_string (value, priv->dest_uri);
581 break;
583 case PROP_CONNECTABLE:
584 g_value_set_object (value, priv->connectable);
585 break;
587 default:
588 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
592 static void
593 g_proxy_address_enumerator_set_property (GObject *object,
594 guint property_id,
595 const GValue *value,
596 GParamSpec *pspec)
598 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
599 switch (property_id)
601 case PROP_URI:
603 const gchar *uri;
605 g_free (priv->dest_hostname);
606 priv->dest_hostname = NULL;
607 priv->dest_port = 0;
609 g_free (priv->dest_uri);
610 priv->dest_uri = NULL;
612 uri = g_value_get_string (value);
614 if (uri)
616 GSocketConnectable *conn;
618 conn = g_network_address_parse_uri (uri, 0, NULL);
619 if (conn)
621 guint port;
623 priv->dest_uri = g_strdup (uri);
625 g_object_get (conn,
626 "hostname", &priv->dest_hostname,
627 "port", &port,
628 NULL);
630 priv->dest_port = port;
631 g_object_unref (conn);
633 else
634 g_warning ("Invalid URI '%s'", uri);
637 break;
640 case PROP_CONNECTABLE:
641 priv->connectable = g_value_dup_object (value);
642 break;
644 default:
645 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
649 static void
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);
660 if (priv->dest_ips)
661 g_resolver_free_addresses (priv->dest_ips);
663 g_strfreev (priv->proxies);
665 if (priv->addr_enum)
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);
678 static void
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);
686 static void
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,
704 PROP_URI,
705 g_param_spec_string ("uri",
706 P_("URI"),
707 P_("The destination URI, use none:// for generic socket"),
708 NULL,
709 G_PARAM_READWRITE |
710 G_PARAM_CONSTRUCT_ONLY |
711 G_PARAM_STATIC_STRINGS));
713 g_object_class_install_property (object_class,
714 PROP_CONNECTABLE,
715 g_param_spec_object ("connectable",
716 P_("Connectable"),
717 P_("The connectable being enumerated."),
718 G_TYPE_SOCKET_CONNECTABLE,
719 G_PARAM_READWRITE |
720 G_PARAM_CONSTRUCT_ONLY |
721 G_PARAM_STATIC_STRINGS));