gio/: fully remove gioalias hacks
[platform/upstream/glib.git] / gio / gnetworkservice.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright (C) 2008 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include "glibintl.h"
26
27 #include "gnetworkservice.h"
28 #include "gcancellable.h"
29 #include "ginetaddress.h"
30 #include "ginetsocketaddress.h"
31 #include "gresolver.h"
32 #include "gsimpleasyncresult.h"
33 #include "gsocketaddressenumerator.h"
34 #include "gsocketconnectable.h"
35 #include "gsrvtarget.h"
36
37 #include <stdlib.h>
38 #include <string.h>
39
40
41 /**
42  * SECTION:gnetworkservice
43  * @short_description: A GSocketConnectable for resolving SRV records
44  * @include: gio/gio.h
45  *
46  * Like #GNetworkAddress does with hostnames, #GNetworkService
47  * provides an easy way to resolve a SRV record, and then attempt to
48  * connect to one of the hosts that implements that service, handling
49  * service priority/weighting, multiple IP addresses, and multiple
50  * address families.
51  *
52  * See #GSrvTarget for more information about SRV records, and see
53  * #GSocketConnectable for and example of using the connectable
54  * interface.
55  */
56
57 /**
58  * GNetworkService:
59  *
60  * A #GSocketConnectable for resolving a SRV record and connecting to
61  * that service.
62  */
63
64 struct _GNetworkServicePrivate
65 {
66   gchar *service, *protocol, *domain;
67   GList *targets;
68 };
69
70 enum {
71   PROP_0,
72   PROP_SERVICE,
73   PROP_PROTOCOL,
74   PROP_DOMAIN,
75 };
76
77 static void g_network_service_set_property (GObject      *object,
78                                             guint         prop_id,
79                                             const GValue *value,
80                                             GParamSpec   *pspec);
81 static void g_network_service_get_property (GObject      *object,
82                                             guint         prop_id,
83                                             GValue       *value,
84                                             GParamSpec   *pspec);
85
86 static void                      g_network_service_connectable_iface_init (GSocketConnectableIface *iface);
87 static GSocketAddressEnumerator *g_network_service_connectable_enumerate  (GSocketConnectable      *connectable);
88
89 G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
90                          G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
91                                                 g_network_service_connectable_iface_init))
92
93 static void
94 g_network_service_finalize (GObject *object)
95 {
96   GNetworkService *srv = G_NETWORK_SERVICE (object);
97
98   g_free (srv->priv->service);
99   g_free (srv->priv->protocol);
100   g_free (srv->priv->domain);
101
102   if (srv->priv->targets)
103     g_resolver_free_targets (srv->priv->targets);
104
105   G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object);
106 }
107
108 static void
109 g_network_service_class_init (GNetworkServiceClass *klass)
110 {
111   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
112
113   g_type_class_add_private (klass, sizeof (GNetworkServicePrivate));
114
115   gobject_class->set_property = g_network_service_set_property;
116   gobject_class->get_property = g_network_service_get_property;
117   gobject_class->finalize = g_network_service_finalize;
118
119   g_object_class_install_property (gobject_class, PROP_SERVICE,
120                                    g_param_spec_string ("service",
121                                                         P_("Service"),
122                                                         P_("Service name, eg \"ldap\""),
123                                                         NULL,
124                                                         G_PARAM_READWRITE |
125                                                         G_PARAM_CONSTRUCT_ONLY |
126                                                         G_PARAM_STATIC_STRINGS));
127   g_object_class_install_property (gobject_class, PROP_PROTOCOL,
128                                    g_param_spec_string ("protocol",
129                                                         P_("Protocol"),
130                                                         P_("Network protocol, eg \"tcp\""),
131                                                         NULL,
132                                                         G_PARAM_READWRITE |
133                                                         G_PARAM_CONSTRUCT_ONLY |
134                                                         G_PARAM_STATIC_STRINGS));
135   g_object_class_install_property (gobject_class, PROP_DOMAIN,
136                                    g_param_spec_string ("domain",
137                                                         P_("Domain"),
138                                                         P_("Network domain, eg, \"example.com\""),
139                                                         NULL,
140                                                         G_PARAM_READWRITE |
141                                                         G_PARAM_CONSTRUCT_ONLY |
142                                                         G_PARAM_STATIC_STRINGS));
143 }
144
145 static void
146 g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
147 {
148   connectable_iface->enumerate = g_network_service_connectable_enumerate;
149 }
150
151 static void
152 g_network_service_init (GNetworkService *srv)
153 {
154   srv->priv = G_TYPE_INSTANCE_GET_PRIVATE (srv, G_TYPE_NETWORK_SERVICE,
155                                            GNetworkServicePrivate);
156 }
157
158 static void
159 g_network_service_set_property (GObject      *object,
160                                 guint         prop_id,
161                                 const GValue *value,
162                                 GParamSpec   *pspec)
163 {
164   GNetworkService *srv = G_NETWORK_SERVICE (object);
165
166   switch (prop_id)
167     {
168     case PROP_SERVICE:
169       srv->priv->service = g_value_dup_string (value);
170       break;
171
172     case PROP_PROTOCOL:
173       srv->priv->protocol = g_value_dup_string (value);
174       break;
175
176     case PROP_DOMAIN:
177       srv->priv->domain = g_value_dup_string (value);
178       break;
179
180     default:
181       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
182       break;
183     }
184 }
185
186 static void
187 g_network_service_get_property (GObject    *object,
188                                 guint       prop_id,
189                                 GValue     *value,
190                                 GParamSpec *pspec)
191 {
192   GNetworkService *srv = G_NETWORK_SERVICE (object);
193
194   switch (prop_id)
195     {
196     case PROP_SERVICE:
197       g_value_set_string (value, g_network_service_get_service (srv));
198       break;
199
200     case PROP_PROTOCOL:
201       g_value_set_string (value, g_network_service_get_protocol (srv));
202       break;
203
204     case PROP_DOMAIN:
205       g_value_set_string (value, g_network_service_get_domain (srv));
206       break;
207
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211     }
212 }
213
214 /**
215  * g_network_service_new:
216  * @service: the service type to look up (eg, "ldap")
217  * @protocol: the networking protocol to use for @service (eg, "tcp")
218  * @domain: the DNS domain to look up the service in
219  *
220  * Creates a new #GNetworkService representing the given @service,
221  * @protocol, and @domain. This will initially be unresolved; use the
222  * #GSocketConnectable interface to resolve it.
223  *
224  * Return value: a new #GNetworkService
225  *
226  * Since: 2.22
227  */
228 GSocketConnectable *
229 g_network_service_new (const gchar *service,
230                        const gchar *protocol,
231                        const gchar *domain)
232 {
233   return g_object_new (G_TYPE_NETWORK_SERVICE,
234                        "service", service,
235                        "protocol", protocol,
236                        "domain", domain,
237                        NULL);
238 }
239
240 /**
241  * g_network_service_get_service:
242  * @srv: a #GNetworkService
243  *
244  * Gets @srv's service name (eg, "ldap").
245  *
246  * Return value: @srv's service name
247  *
248  * Since: 2.22
249  */
250 const gchar *
251 g_network_service_get_service (GNetworkService *srv)
252 {
253   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
254
255   return srv->priv->service;
256 }
257
258 /**
259  * g_network_service_get_protocol:
260  * @srv: a #GNetworkService
261  *
262  * Gets @srv's protocol name (eg, "tcp").
263  *
264  * Return value: @srv's protocol name
265  *
266  * Since: 2.22
267  */
268 const gchar *
269 g_network_service_get_protocol (GNetworkService *srv)
270 {
271   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
272
273   return srv->priv->protocol;
274 }
275
276 /**
277  * g_network_service_get_domain:
278  * @srv: a #GNetworkService
279  *
280  * Gets the domain that @srv serves. This might be either UTF-8 or
281  * ASCII-encoded, depending on what @srv was created with.
282  *
283  * Return value: @srv's domain name
284  *
285  * Since: 2.22
286  */
287 const gchar *
288 g_network_service_get_domain (GNetworkService *srv)
289 {
290   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
291
292   return srv->priv->domain;
293 }
294
295 #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
296 #define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
297
298 typedef struct {
299   GSocketAddressEnumerator parent_instance;
300
301   GResolver *resolver;
302   GNetworkService *srv;
303   GList *addrs, *a, *t;
304
305   GError *error;
306
307   /* For async operation */
308   GCancellable *cancellable;
309   GSimpleAsyncResult *result;
310 } GNetworkServiceAddressEnumerator;
311
312 typedef struct {
313   GSocketAddressEnumeratorClass parent_class;
314
315 } GNetworkServiceAddressEnumeratorClass;
316
317 G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
318
319 static void
320 g_network_service_address_enumerator_finalize (GObject *object)
321 {
322   GNetworkServiceAddressEnumerator *srv_enum =
323     G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
324
325   g_object_unref (srv_enum->srv);
326   if (srv_enum->addrs)
327     {
328       while (srv_enum->a)
329         {
330           g_object_unref (srv_enum->a->data);
331           srv_enum->a = srv_enum->a->next;
332         }
333       g_list_free (srv_enum->addrs);
334     }
335   g_object_unref (srv_enum->resolver);
336   if (srv_enum->error)
337     g_error_free (srv_enum->error);
338
339   G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
340 }
341
342 static GSocketAddress *
343 g_network_service_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
344                                            GCancellable              *cancellable,
345                                            GError                   **error)
346 {
347   GNetworkServiceAddressEnumerator *srv_enum =
348     G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
349   GSrvTarget *target;
350   GSocketAddress *sockaddr;
351
352   /* If we haven't yet resolved srv, do that */
353   if (!srv_enum->srv->priv->targets)
354     {
355       GList *targets;
356
357       targets = g_resolver_lookup_service (srv_enum->resolver,
358                                            srv_enum->srv->priv->service,
359                                            srv_enum->srv->priv->protocol,
360                                            srv_enum->srv->priv->domain,
361                                            cancellable, error);
362       if (!targets)
363         return NULL;
364
365       if (!srv_enum->srv->priv->targets)
366         srv_enum->srv->priv->targets = targets;
367       srv_enum->t = srv_enum->srv->priv->targets;
368     }
369
370   /* Make sure we have a set of resolved addresses for the current
371    * target. When resolving the first target, we save the GError, if
372    * any. If any later target succeeds, we'll free the earlier error,
373    * but if we get to the last target without any of them resolving,
374    * we return that initial error.
375    */
376   do
377     {
378       /* Return if we're out of targets. */
379       if (!srv_enum->t)
380         {
381           if (srv_enum->error)
382             {
383               g_propagate_error (error, srv_enum->error);
384               srv_enum->error = NULL;
385             }
386           return NULL;
387         }
388       target = srv_enum->t->data;
389
390       /* If we haven't resolved the addrs for the current target, do that */
391       if (!srv_enum->addrs)
392         {
393           GError **error_p;
394
395           error_p = (srv_enum->t == srv_enum->srv->priv->targets) ? &srv_enum->error : NULL;
396           srv_enum->addrs = g_resolver_lookup_by_name (srv_enum->resolver,
397                                                        g_srv_target_get_hostname (target),
398                                                        cancellable, error_p);
399           if (g_cancellable_set_error_if_cancelled (cancellable, error))
400             return NULL;
401
402           if (srv_enum->addrs)
403             {
404               srv_enum->a = srv_enum->addrs;
405               if (srv_enum->error)
406                 {
407                   g_error_free (srv_enum->error);
408                   srv_enum->error = NULL;
409                 }
410             }
411           else
412             {
413               /* Try the next target */
414               srv_enum->t = srv_enum->t->next;
415             }
416         }
417     }
418   while (!srv_enum->addrs);
419
420   /* Return the next address for this target. If it's the last one,
421    * advance the target counter.
422    */
423   sockaddr = g_inet_socket_address_new (srv_enum->a->data,
424                                         g_srv_target_get_port (target));
425   g_object_unref (srv_enum->a->data);
426   srv_enum->a = srv_enum->a->next;
427
428   if (!srv_enum->a)
429     {
430       g_list_free (srv_enum->addrs);
431       srv_enum->addrs = NULL;
432       srv_enum->t = srv_enum->t->next;
433     }
434
435   return sockaddr;
436 }
437
438 static void next_async_resolved_targets   (GObject                          *source_object,
439                                            GAsyncResult                     *result,
440                                            gpointer                          user_data);
441 static void next_async_have_targets       (GNetworkServiceAddressEnumerator *srv_enum);
442 static void next_async_resolved_addresses (GObject                          *source_object,
443                                            GAsyncResult                     *result,
444                                            gpointer                          user_data);
445 static void next_async_have_addresses     (GNetworkServiceAddressEnumerator *srv_enum);
446
447 /* The async version is basically the same as the sync, except we have
448  * to split it into multiple functions.
449  */
450 static void
451 g_network_service_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
452                                                  GCancellable              *cancellable,
453                                                  GAsyncReadyCallback        callback,
454                                                  gpointer                   user_data)
455 {
456   GNetworkServiceAddressEnumerator *srv_enum =
457     G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
458
459   g_return_if_fail (srv_enum->result == NULL);
460
461   srv_enum->result = g_simple_async_result_new (G_OBJECT (enumerator),
462                                                 callback, user_data,
463                                                 g_network_service_address_enumerator_next_async);
464   srv_enum->cancellable = cancellable;
465
466   /* If we haven't yet resolved srv, do that */
467   if (!srv_enum->srv->priv->targets)
468     {
469       g_resolver_lookup_service_async (srv_enum->resolver,
470                                        srv_enum->srv->priv->service,
471                                        srv_enum->srv->priv->protocol,
472                                        srv_enum->srv->priv->domain,
473                                        cancellable,
474                                        next_async_resolved_targets,
475                                        srv_enum);
476     }
477   else
478     next_async_have_targets (srv_enum);
479 }
480
481 static void
482 next_async_resolved_targets (GObject      *source_object,
483                              GAsyncResult *result,
484                              gpointer      user_data)
485 {
486   GNetworkServiceAddressEnumerator *srv_enum = user_data;
487   GList *targets;
488   GError *error = NULL;
489
490   targets = g_resolver_lookup_service_finish (srv_enum->resolver, result, &error);
491   if (!srv_enum->srv->priv->targets)
492     {
493       if (error)
494         {
495           GSimpleAsyncResult *simple = srv_enum->result;
496
497           srv_enum->result = NULL;
498           g_simple_async_result_set_from_error (simple, error);
499           g_error_free (error);
500           g_simple_async_result_complete (simple);
501           g_object_unref (simple);
502           return;
503         }
504
505       srv_enum->srv->priv->targets = targets;
506       srv_enum->t = srv_enum->srv->priv->targets;
507     }
508
509   next_async_have_targets (srv_enum);
510 }
511
512 static void
513 next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum)
514 {
515   GSrvTarget *target;
516
517   /* Get the current target, check if we're already done. */
518   if (!srv_enum->t)
519     {
520       if (srv_enum->error)
521         {
522           g_simple_async_result_set_from_error (srv_enum->result, srv_enum->error);
523           g_error_free (srv_enum->error);
524           srv_enum->error = NULL;
525         }
526       g_simple_async_result_complete_in_idle (srv_enum->result);
527       g_object_unref (srv_enum->result);
528       srv_enum->result = NULL;
529       return;
530     }
531   target = srv_enum->t->data;
532
533   /* If we haven't resolved the addrs for the current target, do that */
534   if (!srv_enum->addrs)
535     {
536       g_resolver_lookup_by_name_async (srv_enum->resolver,
537                                        g_srv_target_get_hostname (target),
538                                        srv_enum->cancellable,
539                                        next_async_resolved_addresses,
540                                        srv_enum);
541     }
542   else
543     next_async_have_addresses (srv_enum);
544 }
545
546 static void
547 next_async_resolved_addresses (GObject      *source_object,
548                                GAsyncResult *result,
549                                gpointer      user_data)
550 {
551   GNetworkServiceAddressEnumerator *srv_enum = user_data;
552   GError *error = NULL;
553
554   srv_enum->addrs = g_resolver_lookup_by_name_finish (srv_enum->resolver, result, &error);
555   if (srv_enum->addrs)
556     {
557       srv_enum->a = srv_enum->addrs;
558       if (srv_enum->error)
559         {
560           g_error_free (srv_enum->error);
561           srv_enum->error = NULL;
562         }
563       next_async_have_addresses (srv_enum);
564     }
565   else
566     {
567       if (g_cancellable_is_cancelled (srv_enum->cancellable))
568         {
569           GSimpleAsyncResult *simple = srv_enum->result;
570
571           srv_enum->result = NULL;
572           g_simple_async_result_set_from_error (srv_enum->result, error);
573           g_error_free (error);
574           g_simple_async_result_complete (simple);
575           g_object_unref (simple);
576         }
577       else
578         {
579           if (srv_enum->t == srv_enum->srv->priv->targets)
580             srv_enum->error = error;
581           else
582             g_error_free (error);
583
584           /* Try the next target */
585           srv_enum->t = srv_enum->t->next;
586           next_async_have_targets (srv_enum);
587         }
588     }
589 }
590
591 static void
592 next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum)
593 {
594   GSocketAddress *sockaddr;
595   GSimpleAsyncResult *simple = srv_enum->result;
596
597   /* Return the next address for this target. If it's the last one,
598    * advance the target counter.
599    */
600   sockaddr = g_inet_socket_address_new (srv_enum->a->data,
601                                         g_srv_target_get_port (srv_enum->t->data));
602   g_object_unref (srv_enum->a->data);
603
604   srv_enum->a = srv_enum->a->next;
605   if (!srv_enum->a)
606     {
607       g_list_free (srv_enum->addrs);
608       srv_enum->addrs = NULL;
609       srv_enum->t = srv_enum->t->next;
610     }
611
612   srv_enum->result = NULL;
613   g_simple_async_result_set_op_res_gpointer (simple, sockaddr, NULL);
614   g_simple_async_result_complete_in_idle (simple);
615   g_object_unref (simple);
616 }
617
618 static GSocketAddress *
619 g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
620                                                   GAsyncResult              *result,
621                                                   GError                   **error)
622 {
623   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
624   GSocketAddress *sockaddr;
625
626   if (g_simple_async_result_propagate_error (simple, error))
627     return NULL;
628
629   sockaddr = g_simple_async_result_get_op_res_gpointer (simple);
630   return sockaddr ? g_object_ref (sockaddr) : NULL;
631 }
632
633 static void
634 _g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
635 {
636 }
637
638 static void
639 _g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *addrenum_class)
640 {
641   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
642   GSocketAddressEnumeratorClass *enumerator_class =
643     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
644
645   enumerator_class->next = g_network_service_address_enumerator_next;
646   enumerator_class->next_async = g_network_service_address_enumerator_next_async;
647   enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
648   object_class->finalize = g_network_service_address_enumerator_finalize;
649 }
650
651 static GSocketAddressEnumerator *
652 g_network_service_connectable_enumerate (GSocketConnectable *connectable)
653 {
654   GNetworkServiceAddressEnumerator *srv_enum;
655
656   srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
657   srv_enum->srv = g_object_ref (connectable);
658   srv_enum->resolver = g_resolver_get_default ();
659
660   return (GSocketAddressEnumerator *)srv_enum;
661 }