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