GIcon: add g_icon_[de]serialize()
[glib.git] / gio / gproxyaddressenumerator.c
blob32a684fc2499640c9a67988e615a4dc4ec48dc41
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 "gtask.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,
51 PROP_PROXY_RESOLVER
54 struct _GProxyAddressEnumeratorPrivate
56 /* Destination address */
57 GSocketConnectable *connectable;
58 gchar *dest_uri;
59 gchar *dest_hostname;
60 guint16 dest_port;
61 GList *dest_ips;
63 /* Proxy enumeration */
64 GProxyResolver *proxy_resolver;
65 gchar **proxies;
66 gchar **next_proxy;
67 GSocketAddressEnumerator *addr_enum;
68 GSocketAddress *proxy_address;
69 const gchar *proxy_uri;
70 gchar *proxy_type;
71 gchar *proxy_username;
72 gchar *proxy_password;
73 gboolean supports_hostname;
74 GList *next_dest_ip;
75 GError *last_error;
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 GProxy *proxy;
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)
131 continue;
133 /* Assumes hostnames are supported for unknown protocols */
134 priv->supports_hostname = TRUE;
135 proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
136 if (proxy)
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);
146 else
147 connectable = g_network_address_new (priv->dest_hostname,
148 priv->dest_port);
150 else
152 GError *error = NULL;
154 connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
156 if (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);
166 if (connectable)
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,
177 GError **error)
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,
186 priv->dest_uri,
187 cancellable,
188 error);
189 priv->next_proxy = priv->proxies;
191 if (priv->proxies == NULL)
192 return 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;
201 guint16 port;
203 next_enumerator (priv);
205 if (!priv->addr_enum)
206 continue;
208 if (priv->proxy_address == NULL)
210 priv->proxy_address = g_socket_address_enumerator_next (
211 priv->addr_enum,
212 cancellable,
213 first_error ? NULL : &first_error);
216 if (priv->proxy_address == NULL)
218 g_object_unref (priv->addr_enum);
219 priv->addr_enum = NULL;
221 if (priv->dest_ips)
223 g_resolver_free_addresses (priv->dest_ips);
224 priv->dest_ips = NULL;
227 continue;
230 if (strcmp ("direct", priv->proxy_type) == 0)
232 result = priv->proxy_address;
233 priv->proxy_address = NULL;
234 continue;
237 if (!priv->supports_hostname)
239 GInetAddress *dest_ip;
241 if (!priv->dest_ips)
243 GResolver *resolver;
245 resolver = g_resolver_get_default();
246 priv->dest_ips = g_resolver_lookup_by_name (resolver,
247 priv->dest_hostname,
248 cancellable,
249 first_error ? NULL : &first_error);
250 g_object_unref (resolver);
252 if (!priv->dest_ips)
254 g_object_unref (priv->proxy_address);
255 priv->proxy_address = NULL;
256 continue;
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);
268 else
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),
275 NULL);
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,
282 "address", inetaddr,
283 "port", port,
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,
291 NULL);
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);
307 return result;
312 static void
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;
322 else
323 g_task_return_pointer (task, NULL, NULL);
325 g_object_unref (task);
328 static void
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;
339 else
341 gchar *dest_hostname, *dest_protocol;
342 GInetSocketAddress *inetsaddr;
343 GInetAddress *inetaddr;
344 guint16 port;
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);
358 else
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,
371 "address", inetaddr,
372 "port", port,
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,
380 NULL);
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,
397 gpointer user_data);
399 static void
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;
409 if (priv->dest_ips)
411 g_resolver_free_addresses (priv->dest_ips);
412 priv->dest_ips = NULL;
415 next_enumerator (priv);
417 if (priv->addr_enum)
419 g_socket_address_enumerator_next_async (priv->addr_enum,
420 g_task_get_cancellable (task),
421 address_enumerate_cb,
422 task);
423 return;
427 complete_async (task);
430 static void
431 dest_hostname_lookup_cb (GObject *object,
432 GAsyncResult *result,
433 gpointer user_data)
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),
440 result,
441 &priv->last_error);
442 if (priv->dest_ips)
443 return_result (task);
444 else
446 g_clear_object (&priv->proxy_address);
447 next_proxy (task);
451 static void
452 address_enumerate_cb (GObject *object,
453 GAsyncResult *result,
454 gpointer user_data)
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,
462 result,
463 &priv->last_error);
464 if (priv->proxy_address)
466 if (!priv->supports_hostname && !priv->dest_ips)
468 GResolver *resolver;
469 resolver = g_resolver_get_default();
470 g_resolver_lookup_by_name_async (resolver,
471 priv->dest_hostname,
472 g_task_get_cancellable (task),
473 dest_hostname_lookup_cb,
474 task);
475 g_object_unref (resolver);
476 return;
479 return_result (task);
481 else
482 next_proxy (task);
485 static void
486 proxy_lookup_cb (GObject *object,
487 GAsyncResult *result,
488 gpointer user_data)
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),
495 result,
496 &priv->last_error);
497 priv->next_proxy = priv->proxies;
499 if (priv->last_error)
501 complete_async (task);
502 return;
504 else
506 next_enumerator (priv);
507 if (priv->addr_enum)
509 g_socket_address_enumerator_next_async (priv->addr_enum,
510 g_task_get_cancellable (task),
511 address_enumerate_cb,
512 task);
513 return;
517 complete_async (task);
520 static void
521 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
522 GCancellable *cancellable,
523 GAsyncReadyCallback callback,
524 gpointer user_data)
526 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
527 GTask *task;
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,
535 priv->dest_uri,
536 cancellable,
537 proxy_lookup_cb,
538 task);
539 return;
542 if (priv->addr_enum)
544 if (priv->proxy_address)
546 return_result (task);
547 return;
549 else
551 g_socket_address_enumerator_next_async (priv->addr_enum,
552 cancellable,
553 address_enumerate_cb,
554 task);
555 return;
559 complete_async (task);
562 static GSocketAddress *
563 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
564 GAsyncResult *result,
565 GError **error)
567 g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
569 return g_task_propagate_pointer (G_TASK (result), error);
572 static void
573 g_proxy_address_enumerator_get_property (GObject *object,
574 guint property_id,
575 GValue *value,
576 GParamSpec *pspec)
578 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
579 switch (property_id)
581 case PROP_URI:
582 g_value_set_string (value, priv->dest_uri);
583 break;
585 case PROP_CONNECTABLE:
586 g_value_set_object (value, priv->connectable);
587 break;
589 case PROP_PROXY_RESOLVER:
590 g_value_set_object (value, priv->proxy_resolver);
591 break;
593 default:
594 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
598 static void
599 g_proxy_address_enumerator_set_property (GObject *object,
600 guint property_id,
601 const GValue *value,
602 GParamSpec *pspec)
604 GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
605 switch (property_id)
607 case PROP_URI:
609 const gchar *uri;
611 g_free (priv->dest_hostname);
612 priv->dest_hostname = NULL;
613 priv->dest_port = 0;
615 g_free (priv->dest_uri);
616 priv->dest_uri = NULL;
618 uri = g_value_get_string (value);
620 if (uri)
622 GSocketConnectable *conn;
624 conn = g_network_address_parse_uri (uri, 0, NULL);
625 if (conn)
627 guint port;
629 priv->dest_uri = g_strdup (uri);
631 g_object_get (conn,
632 "hostname", &priv->dest_hostname,
633 "port", &port,
634 NULL);
636 priv->dest_port = port;
637 g_object_unref (conn);
639 else
640 g_warning ("Invalid URI '%s'", uri);
643 break;
646 case PROP_CONNECTABLE:
647 priv->connectable = g_value_dup_object (value);
648 break;
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);
657 break;
659 default:
660 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
664 static void
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);
678 if (priv->dest_ips)
679 g_resolver_free_addresses (priv->dest_ips);
681 g_strfreev (priv->proxies);
683 if (priv->addr_enum)
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);
695 static void
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);
703 static void
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,
721 PROP_URI,
722 g_param_spec_string ("uri",
723 P_("URI"),
724 P_("The destination URI, use none:// for generic socket"),
725 NULL,
726 G_PARAM_READWRITE |
727 G_PARAM_CONSTRUCT_ONLY |
728 G_PARAM_STATIC_STRINGS));
730 g_object_class_install_property (object_class,
731 PROP_CONNECTABLE,
732 g_param_spec_object ("connectable",
733 P_("Connectable"),
734 P_("The connectable being enumerated."),
735 G_TYPE_SOCKET_CONNECTABLE,
736 G_PARAM_READWRITE |
737 G_PARAM_CONSTRUCT_ONLY |
738 G_PARAM_STATIC_STRINGS));
741 * GProxyAddressEnumerator:proxy-resolver:
743 * The proxy resolver to use.
745 * Since: 2.36
747 g_object_class_install_property (object_class,
748 PROP_PROXY_RESOLVER,
749 g_param_spec_object ("proxy-resolver",
750 P_("Proxy resolver"),
751 P_("The proxy resolver to use."),
752 G_TYPE_PROXY_RESOLVER,
753 G_PARAM_READWRITE |
754 G_PARAM_CONSTRUCT |
755 G_PARAM_STATIC_STRINGS));