[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / gproxyaddressenumerator.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2010 Collabora, Ltd.
4  *
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.
9  *
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.
14  *
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/>.
17  *
18  * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
19  */
20
21 #include "config.h"
22 #include "gproxyaddressenumerator.h"
23
24 #include <string.h>
25
26 #include "gasyncresult.h"
27 #include "ginetaddress.h"
28 #include "glibintl.h"
29 #include "gnetworkaddress.h"
30 #include "gnetworkingprivate.h"
31 #include "gproxy.h"
32 #include "gproxyaddress.h"
33 #include "gproxyresolver.h"
34 #include "gtask.h"
35 #include "gresolver.h"
36 #include "gsocketaddress.h"
37 #include "gsocketaddressenumerator.h"
38 #include "gsocketconnectable.h"
39
40 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
41
42 enum
43 {
44   PROP_0,
45   PROP_URI,
46   PROP_DEFAULT_PORT,
47   PROP_CONNECTABLE,
48   PROP_PROXY_RESOLVER
49 };
50
51 struct _GProxyAddressEnumeratorPrivate
52 {
53   /* Destination address */
54   GSocketConnectable *connectable;
55   gchar              *dest_uri;
56   guint16             default_port;
57   gchar              *dest_hostname;
58   guint16             dest_port;
59   GList              *dest_ips;
60
61   /* Proxy enumeration */
62   GProxyResolver           *proxy_resolver;
63   gchar                   **proxies;
64   gchar                   **next_proxy;
65   GSocketAddressEnumerator *addr_enum;
66   GSocketAddress           *proxy_address;
67   const gchar              *proxy_uri;
68   gchar                    *proxy_type;
69   gchar                    *proxy_username;
70   gchar                    *proxy_password;
71   gboolean                  supports_hostname;
72   GList                    *next_dest_ip;
73   GError                   *last_error;
74 };
75
76 G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
77
78 static void
79 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
80                const gchar *proxy)
81 {
82   gchar *userinfo;
83
84   if (priv->proxy_username)
85     {
86       g_free (priv->proxy_username);
87       priv->proxy_username = NULL;
88     }
89
90   if (priv->proxy_password)
91     {
92       g_free (priv->proxy_password);
93       priv->proxy_password = NULL;
94     }
95   
96   if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo))
97     {
98       if (userinfo)
99         {
100           gchar **split = g_strsplit (userinfo, ":", 2);
101
102           if (split[0] != NULL)
103             {
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);
107             }
108
109           g_strfreev (split);
110           g_free (userinfo);
111         }
112     }
113 }
114
115 static void
116 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
117 {
118   if (priv->proxy_address)
119     return;
120
121   while (priv->addr_enum == NULL && *priv->next_proxy)
122     {
123       GSocketConnectable *connectable = NULL;
124       GProxy *proxy;
125
126       priv->proxy_uri = *priv->next_proxy++;
127       g_free (priv->proxy_type);
128       priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
129
130       if (priv->proxy_type == NULL)
131         continue;
132
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)
137         {
138           priv->supports_hostname = g_proxy_supports_hostname (proxy);
139           g_object_unref (proxy);
140         }
141
142       if (strcmp ("direct", priv->proxy_type) == 0)
143         {
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);
149         }
150       else
151         {
152           GError *error = NULL;
153
154           connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
155
156           if (error)
157             {
158               g_warning ("Invalid proxy URI '%s': %s",
159                          priv->proxy_uri, error->message);
160               g_error_free (error);
161             }
162
163           save_userinfo (priv, priv->proxy_uri);
164         }
165
166       if (connectable)
167         {
168           priv->addr_enum = g_socket_connectable_enumerate (connectable);
169           g_object_unref (connectable);
170         }
171     }
172 }
173
174 static GSocketAddress *
175 g_proxy_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
176                                  GCancellable              *cancellable,
177                                  GError                   **error)
178 {
179   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
180   GSocketAddress *result = NULL;
181   GError *first_error = NULL;
182
183   if (priv->proxies == NULL)
184     {
185       priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
186                                                priv->dest_uri,
187                                                cancellable,
188                                                error);
189       priv->next_proxy = priv->proxies;
190
191       if (priv->proxies == NULL)
192         return NULL;
193     }
194
195   while (result == NULL && (*priv->next_proxy || priv->addr_enum))
196     {
197       gchar *dest_hostname;
198       gchar *dest_protocol;
199       GInetSocketAddress *inetsaddr;
200       GInetAddress *inetaddr;
201       guint16 port;
202
203       next_enumerator (priv);
204
205       if (!priv->addr_enum)
206         continue;
207
208       if (priv->proxy_address == NULL)
209         {
210           priv->proxy_address = g_socket_address_enumerator_next (
211                                     priv->addr_enum,
212                                     cancellable,
213                                     first_error ? NULL : &first_error);
214         }
215
216       if (priv->proxy_address == NULL)
217         {
218           g_object_unref (priv->addr_enum);
219           priv->addr_enum = NULL;
220
221           if (priv->dest_ips)
222             {
223               g_resolver_free_addresses (priv->dest_ips);
224               priv->dest_ips = NULL;
225             }
226
227           continue;
228         }
229
230       if (strcmp ("direct", priv->proxy_type) == 0)
231         {
232           result = priv->proxy_address;
233           priv->proxy_address = NULL;
234           continue;
235         }
236
237       if (!priv->supports_hostname)
238         {
239           GInetAddress *dest_ip;
240
241           if (!priv->dest_ips)
242             {
243               GResolver *resolver;
244
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);
251
252               if (!priv->dest_ips)
253                 {
254                   g_object_unref (priv->proxy_address);
255                   priv->proxy_address = NULL;
256                   continue;
257                 }
258             }
259
260           if (!priv->next_dest_ip)
261             priv->next_dest_ip = priv->dest_ips;
262         
263           dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
264           dest_hostname = g_inet_address_to_string (dest_ip);
265
266           priv->next_dest_ip = g_list_next (priv->next_dest_ip);
267         }
268       else
269         {
270           dest_hostname = g_strdup (priv->dest_hostname);
271         }
272       dest_protocol = g_uri_parse_scheme (priv->dest_uri);
273                                   
274       g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
275                             NULL);
276
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);
280
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);
294
295       if (priv->supports_hostname || priv->next_dest_ip == NULL)
296         {
297           g_object_unref (priv->proxy_address);
298           priv->proxy_address = NULL;
299         }
300     }
301
302   if (result == NULL && first_error)
303     g_propagate_error (error, first_error);
304   else if (first_error)
305     g_error_free (first_error);
306
307   return result;
308 }
309
310
311
312 static void
313 complete_async (GTask *task)
314 {
315   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
316
317   if (priv->last_error)
318     {
319       g_task_return_error (task, priv->last_error);
320       priv->last_error = NULL;
321     }
322   else
323     g_task_return_pointer (task, NULL, NULL);
324
325   g_object_unref (task);
326 }
327
328 static void
329 return_result (GTask *task)
330 {
331   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
332   GSocketAddress *result;
333
334   if (strcmp ("direct", priv->proxy_type) == 0)
335     {
336       result = priv->proxy_address;
337       priv->proxy_address = NULL;
338     }
339   else
340     {
341       gchar *dest_hostname, *dest_protocol;
342       GInetSocketAddress *inetsaddr;
343       GInetAddress *inetaddr;
344       guint16 port;
345
346       if (!priv->supports_hostname)
347         {
348           GInetAddress *dest_ip;
349
350           if (!priv->next_dest_ip)
351             priv->next_dest_ip = priv->dest_ips;
352
353           dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
354           dest_hostname = g_inet_address_to_string (dest_ip);
355
356           priv->next_dest_ip = g_list_next (priv->next_dest_ip);
357         }
358       else
359         {
360           dest_hostname = g_strdup (priv->dest_hostname);
361         }
362       dest_protocol = g_uri_parse_scheme (priv->dest_uri);
363
364       g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
365
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);
369
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);
383
384       if (priv->supports_hostname || priv->next_dest_ip == NULL)
385         {
386           g_object_unref (priv->proxy_address);
387           priv->proxy_address = NULL;
388         }
389     }
390
391   g_task_return_pointer (task, result, g_object_unref);
392   g_object_unref (task);
393 }
394
395 static void address_enumerate_cb (GObject      *object,
396                                   GAsyncResult *result,
397                                   gpointer      user_data);
398
399 static void
400 next_proxy (GTask *task)
401 {
402   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
403
404   if (*priv->next_proxy)
405     {
406       g_object_unref (priv->addr_enum);
407       priv->addr_enum = NULL;
408
409       if (priv->dest_ips)
410         {
411           g_resolver_free_addresses (priv->dest_ips);
412           priv->dest_ips = NULL;
413         }
414
415       next_enumerator (priv);
416
417       if (priv->addr_enum)
418         {
419           g_socket_address_enumerator_next_async (priv->addr_enum,
420                                                   g_task_get_cancellable (task),
421                                                   address_enumerate_cb,
422                                                   task);
423           return;
424         }
425     }
426
427   complete_async (task);
428 }
429
430 static void
431 dest_hostname_lookup_cb (GObject           *object,
432                          GAsyncResult      *result,
433                          gpointer           user_data)
434 {
435   GTask *task = user_data;
436   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
437
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
445     {
446       g_clear_object (&priv->proxy_address);
447       next_proxy (task);
448     }
449 }
450
451 static void
452 address_enumerate_cb (GObject      *object,
453                       GAsyncResult *result,
454                       gpointer      user_data)
455 {
456   GTask *task = user_data;
457   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
458
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)
465     {
466       if (!priv->supports_hostname && !priv->dest_ips)
467         {
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;
477         }
478
479       return_result (task);
480     }
481   else
482     next_proxy (task);
483 }
484
485 static void
486 proxy_lookup_cb (GObject      *object,
487                  GAsyncResult *result,
488                  gpointer      user_data)
489 {
490   GTask *task = user_data;
491   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
492
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;
498
499   if (priv->last_error)
500     {
501       complete_async (task);
502       return;
503     }
504   else
505     {
506       next_enumerator (priv);
507       if (priv->addr_enum)
508         {
509           g_socket_address_enumerator_next_async (priv->addr_enum,
510                                                   g_task_get_cancellable (task),
511                                                   address_enumerate_cb,
512                                                   task);
513           return;
514         }
515     }
516
517   complete_async (task);
518 }
519
520 static void
521 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
522                                        GCancellable             *cancellable,
523                                        GAsyncReadyCallback       callback,
524                                        gpointer                  user_data)
525 {
526   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
527   GTask *task;
528
529   task = g_task_new (enumerator, cancellable, callback, user_data);
530   g_task_set_task_data (task, priv, NULL);
531
532   if (priv->proxies == NULL)
533     {
534       g_proxy_resolver_lookup_async (priv->proxy_resolver,
535                                      priv->dest_uri,
536                                      cancellable,
537                                      proxy_lookup_cb,
538                                      task);
539       return;
540     }
541
542   if (priv->addr_enum)
543     {
544       if (priv->proxy_address)
545         {
546           return_result (task);
547           return;
548         }
549       else
550         {
551           g_socket_address_enumerator_next_async (priv->addr_enum,
552                                                   cancellable,
553                                                   address_enumerate_cb,
554                                                   task);
555           return;
556         }
557     }
558
559   complete_async (task);
560 }
561
562 static GSocketAddress *
563 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
564                                         GAsyncResult              *result,
565                                         GError                   **error)
566 {
567   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
568
569   return g_task_propagate_pointer (G_TASK (result), error);
570 }
571
572 static void
573 g_proxy_address_enumerator_constructed (GObject *object)
574 {
575   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
576   GSocketConnectable *conn;
577   guint port;
578
579   if (priv->dest_uri)
580     {
581       conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
582       if (conn)
583         {
584           g_object_get (conn,
585                         "hostname", &priv->dest_hostname,
586                         "port", &port,
587                         NULL);
588           priv->dest_port = port;
589
590           g_object_unref (conn);
591         }
592       else
593         g_warning ("Invalid URI '%s'", priv->dest_uri);
594     }
595
596   G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
597 }
598
599 static void
600 g_proxy_address_enumerator_get_property (GObject        *object,
601                                          guint           property_id,
602                                          GValue         *value,
603                                          GParamSpec     *pspec)
604 {
605   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
606   switch (property_id)
607     {
608     case PROP_URI:
609       g_value_set_string (value, priv->dest_uri);
610       break;
611
612     case PROP_DEFAULT_PORT:
613       g_value_set_uint (value, priv->default_port);
614       break;
615
616     case PROP_CONNECTABLE:
617       g_value_set_object (value, priv->connectable);
618       break;
619
620     case PROP_PROXY_RESOLVER:
621       g_value_set_object (value, priv->proxy_resolver);
622       break;
623
624     default:
625       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
626     }
627 }
628
629 static void
630 g_proxy_address_enumerator_set_property (GObject        *object,
631                                          guint           property_id,
632                                          const GValue   *value,
633                                          GParamSpec     *pspec)
634 {
635   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
636   switch (property_id)
637     {
638     case PROP_URI:
639       priv->dest_uri = g_value_dup_string (value);
640       break;
641
642     case PROP_DEFAULT_PORT:
643       priv->default_port = g_value_get_uint (value);
644       break;
645
646     case PROP_CONNECTABLE:
647       priv->connectable = g_value_dup_object (value);
648       break;
649
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;
658
659     default:
660       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
661     }
662 }
663
664 static void
665 g_proxy_address_enumerator_finalize (GObject *object)
666 {
667   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
668
669   if (priv->connectable)
670     g_object_unref (priv->connectable);
671
672   if (priv->proxy_resolver)
673     g_object_unref (priv->proxy_resolver);
674
675   g_free (priv->dest_uri);
676   g_free (priv->dest_hostname);
677
678   if (priv->dest_ips)
679     g_resolver_free_addresses (priv->dest_ips);
680
681   g_strfreev (priv->proxies);
682
683   if (priv->addr_enum)
684     g_object_unref (priv->addr_enum);
685
686   g_free (priv->proxy_type);
687   g_free (priv->proxy_username);
688   g_free (priv->proxy_password);
689
690   g_clear_error (&priv->last_error);
691
692   G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
693 }
694
695 static void
696 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
697 {
698   self->priv = g_proxy_address_enumerator_get_instance_private (self);
699 }
700
701 static void
702 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
703 {
704   GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
705   GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
706
707   object_class->constructed = g_proxy_address_enumerator_constructed;
708   object_class->set_property = g_proxy_address_enumerator_set_property;
709   object_class->get_property = g_proxy_address_enumerator_get_property;
710   object_class->finalize = g_proxy_address_enumerator_finalize;
711
712   enumerator_class->next = g_proxy_address_enumerator_next;
713   enumerator_class->next_async = g_proxy_address_enumerator_next_async;
714   enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
715
716   g_object_class_install_property (object_class,
717                                    PROP_URI,
718                                    g_param_spec_string ("uri",
719                                                         P_("URI"),
720                                                         P_("The destination URI, use none:// for generic socket"),
721                                                         NULL,
722                                                         G_PARAM_READWRITE |
723                                                         G_PARAM_CONSTRUCT_ONLY |
724                                                         G_PARAM_STATIC_STRINGS));
725
726   /**
727    * GProxyAddressEnumerator:default-port:
728    *
729    * The default port to use if #GProxyAddressEnumerator:uri does not
730    * specify one.
731    *
732    * Since: 2.38
733    */
734   g_object_class_install_property (object_class,
735                                    PROP_DEFAULT_PORT,
736                                    g_param_spec_uint ("default-port",
737                                                       P_("Default port"),
738                                                       P_("The default port to use if uri does not specify one"),
739                                                       0, 65535, 0,
740                                                       G_PARAM_READWRITE |
741                                                       G_PARAM_CONSTRUCT_ONLY |
742                                                       G_PARAM_STATIC_STRINGS));
743
744   g_object_class_install_property (object_class,
745                                    PROP_CONNECTABLE,
746                                    g_param_spec_object ("connectable",
747                                                         P_("Connectable"),
748                                                         P_("The connectable being enumerated."),
749                                                         G_TYPE_SOCKET_CONNECTABLE,
750                                                         G_PARAM_READWRITE |
751                                                         G_PARAM_CONSTRUCT_ONLY |
752                                                         G_PARAM_STATIC_STRINGS));
753
754   /**
755    * GProxyAddressEnumerator:proxy-resolver:
756    *
757    * The proxy resolver to use.
758    *
759    * Since: 2.36
760    */
761   g_object_class_install_property (object_class,
762                                    PROP_PROXY_RESOLVER,
763                                    g_param_spec_object ("proxy-resolver",
764                                                         P_("Proxy resolver"),
765                                                         P_("The proxy resolver to use."),
766                                                         G_TYPE_PROXY_RESOLVER,
767                                                         G_PARAM_READWRITE |
768                                                         G_PARAM_CONSTRUCT |
769                                                         G_PARAM_STATIC_STRINGS));
770 }