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