Declare res_init() for builds against Android's Bionic
[platform/upstream/glib.git] / gio / gresolver.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 "gresolver.h"
28 #include "gnetworkingprivate.h"
29 #include "gasyncresult.h"
30 #include "ginetaddress.h"
31 #include "gsimpleasyncresult.h"
32 #include "gtask.h"
33 #include "gsrvtarget.h"
34 #include "gthreadedresolver.h"
35
36 #ifdef G_OS_UNIX
37 #include <sys/stat.h>
38 #endif
39
40 #include <stdlib.h>
41
42
43 /**
44  * SECTION:gresolver
45  * @short_description: Asynchronous and cancellable DNS resolver
46  * @include: gio/gio.h
47  *
48  * #GResolver provides cancellable synchronous and asynchronous DNS
49  * resolution, for hostnames (g_resolver_lookup_by_address(),
50  * g_resolver_lookup_by_name() and their async variants) and SRV
51  * (service) records (g_resolver_lookup_service()).
52  *
53  * #GNetworkAddress and #GNetworkService provide wrappers around
54  * #GResolver functionality that also implement #GSocketConnectable,
55  * making it easy to connect to a remote host/service.
56  */
57
58 enum {
59   RELOAD,
60   LAST_SIGNAL
61 };
62
63 static guint signals[LAST_SIGNAL] = { 0 };
64
65 struct _GResolverPrivate {
66 #ifdef G_OS_UNIX
67   time_t resolv_conf_timestamp;
68 #else
69   int dummy;
70 #endif
71 };
72
73 /**
74  * GResolver:
75  *
76  * The object that handles DNS resolution. Use g_resolver_get_default()
77  * to get the default resolver.
78  */
79 G_DEFINE_TYPE_WITH_CODE (GResolver, g_resolver, G_TYPE_OBJECT,
80                          g_networking_init ();)
81
82 static GList *
83 srv_records_to_targets (GList *records)
84 {
85   const gchar *hostname;
86   guint16 port, priority, weight;
87   GSrvTarget *target;
88   GList *l;
89
90   for (l = records; l != NULL; l = g_list_next (l))
91     {
92       g_variant_get (l->data, "(qqq&s)", &priority, &weight, &port, &hostname);
93       target = g_srv_target_new (hostname, port, priority, weight);
94       g_variant_unref (l->data);
95       l->data = target;
96     }
97
98   return g_srv_target_list_sort (records);
99 }
100
101 static GList *
102 g_resolver_real_lookup_service (GResolver            *resolver,
103                                 const gchar          *rrname,
104                                 GCancellable         *cancellable,
105                                 GError              **error)
106 {
107   GList *records;
108
109   records = G_RESOLVER_GET_CLASS (resolver)->lookup_records (resolver,
110                                                              rrname,
111                                                              G_RESOLVER_RECORD_SRV,
112                                                              cancellable,
113                                                              error);
114
115   return srv_records_to_targets (records);
116 }
117
118 static void
119 g_resolver_real_lookup_service_async (GResolver            *resolver,
120                                       const gchar          *rrname,
121                                       GCancellable         *cancellable,
122                                       GAsyncReadyCallback   callback,
123                                       gpointer              user_data)
124 {
125   G_RESOLVER_GET_CLASS (resolver)->lookup_records_async (resolver,
126                                                          rrname,
127                                                          G_RESOLVER_RECORD_SRV,
128                                                          cancellable,
129                                                          callback,
130                                                          user_data);
131 }
132
133 static GList *
134 g_resolver_real_lookup_service_finish (GResolver            *resolver,
135                                        GAsyncResult         *result,
136                                        GError              **error)
137 {
138   GList *records;
139
140   records = G_RESOLVER_GET_CLASS (resolver)->lookup_records_finish (resolver,
141                                                                     result,
142                                                                     error);
143
144   return srv_records_to_targets (records);
145 }
146
147 static void
148 g_resolver_class_init (GResolverClass *resolver_class)
149 {
150   /* Automatically pass these over to the lookup_records methods */
151   resolver_class->lookup_service = g_resolver_real_lookup_service;
152   resolver_class->lookup_service_async = g_resolver_real_lookup_service_async;
153   resolver_class->lookup_service_finish = g_resolver_real_lookup_service_finish;
154
155   g_type_class_add_private (resolver_class, sizeof (GResolverPrivate));
156
157   /**
158    * GResolver::reload:
159    * @resolver: a #GResolver
160    *
161    * Emitted when the resolver notices that the system resolver
162    * configuration has changed.
163    **/
164   signals[RELOAD] =
165     g_signal_new (I_("reload"),
166                   G_TYPE_RESOLVER,
167                   G_SIGNAL_RUN_LAST,
168                   G_STRUCT_OFFSET (GResolverClass, reload),
169                   NULL, NULL,
170                   g_cclosure_marshal_VOID__VOID,
171                   G_TYPE_NONE, 0);
172 }
173
174 static void
175 g_resolver_init (GResolver *resolver)
176 {
177 #ifdef G_OS_UNIX
178   struct stat st;
179 #endif
180
181   resolver->priv = G_TYPE_INSTANCE_GET_PRIVATE (resolver, G_TYPE_RESOLVER, GResolverPrivate);
182
183 #ifdef G_OS_UNIX
184   if (stat (_PATH_RESCONF, &st) == 0)
185     resolver->priv->resolv_conf_timestamp = st.st_mtime;
186 #endif
187 }
188
189 static GResolver *default_resolver;
190
191 /**
192  * g_resolver_get_default:
193  *
194  * Gets the default #GResolver. You should unref it when you are done
195  * with it. #GResolver may use its reference count as a hint about how
196  * many threads it should allocate for concurrent DNS resolutions.
197  *
198  * Return value: (transfer full): the default #GResolver.
199  *
200  * Since: 2.22
201  */
202 GResolver *
203 g_resolver_get_default (void)
204 {
205   if (!default_resolver)
206     default_resolver = g_object_new (G_TYPE_THREADED_RESOLVER, NULL);
207
208   return g_object_ref (default_resolver);
209 }
210
211 /**
212  * g_resolver_set_default:
213  * @resolver: the new default #GResolver
214  *
215  * Sets @resolver to be the application's default resolver (reffing
216  * @resolver, and unreffing the previous default resolver, if any).
217  * Future calls to g_resolver_get_default() will return this resolver.
218  *
219  * This can be used if an application wants to perform any sort of DNS
220  * caching or "pinning"; it can implement its own #GResolver that
221  * calls the original default resolver for DNS operations, and
222  * implements its own cache policies on top of that, and then set
223  * itself as the default resolver for all later code to use.
224  *
225  * Since: 2.22
226  */
227 void
228 g_resolver_set_default (GResolver *resolver)
229 {
230   if (default_resolver)
231     g_object_unref (default_resolver);
232   default_resolver = g_object_ref (resolver);
233 }
234
235 /* Bionic has res_init() but it's not in any header */
236 #ifdef __BIONIC__
237 int res_init (void);
238 #endif
239
240 static void
241 g_resolver_maybe_reload (GResolver *resolver)
242 {
243 #ifdef G_OS_UNIX
244   struct stat st;
245
246   if (stat (_PATH_RESCONF, &st) == 0)
247     {
248       if (st.st_mtime != resolver->priv->resolv_conf_timestamp)
249         {
250           resolver->priv->resolv_conf_timestamp = st.st_mtime;
251 #ifdef HAVE_RES_INIT
252           res_init ();
253 #endif
254           g_signal_emit (resolver, signals[RELOAD], 0);
255         }
256     }
257 #endif
258 }
259
260 /* filter out duplicates, cf. https://bugzilla.gnome.org/show_bug.cgi?id=631379 */
261 static void
262 remove_duplicates (GList *addrs)
263 {
264   GList *l;
265   GList *ll;
266   GList *lll;
267
268   /* TODO: if this is too slow (it's O(n^2) but n is typically really
269    * small), we can do something more clever but note that we must not
270    * change the order of elements...
271    */
272   for (l = addrs; l != NULL; l = l->next)
273     {
274       GInetAddress *address = G_INET_ADDRESS (l->data);
275       for (ll = l->next; ll != NULL; ll = lll)
276         {
277           GInetAddress *other_address = G_INET_ADDRESS (ll->data);
278           lll = ll->next;
279           if (g_inet_address_equal (address, other_address))
280             {
281               g_object_unref (other_address);
282               /* we never return the first element */
283               g_warn_if_fail (g_list_delete_link (addrs, ll) == addrs);
284             }
285         }
286     }
287 }
288
289
290 /**
291  * g_resolver_lookup_by_name:
292  * @resolver: a #GResolver
293  * @hostname: the hostname to look up
294  * @cancellable: (allow-none): a #GCancellable, or %NULL
295  * @error: return location for a #GError, or %NULL
296  *
297  * Synchronously resolves @hostname to determine its associated IP
298  * address(es). @hostname may be an ASCII-only or UTF-8 hostname, or
299  * the textual form of an IP address (in which case this just becomes
300  * a wrapper around g_inet_address_new_from_string()).
301  *
302  * On success, g_resolver_lookup_by_name() will return a #GList of
303  * #GInetAddress, sorted in order of preference and guaranteed to not
304  * contain duplicates. That is, if using the result to connect to
305  * @hostname, you should attempt to connect to the first address
306  * first, then the second if the first fails, etc. If you are using
307  * the result to listen on a socket, it is appropriate to add each
308  * result using e.g. g_socket_listener_add_address().
309  *
310  * If the DNS resolution fails, @error (if non-%NULL) will be set to a
311  * value from #GResolverError.
312  *
313  * If @cancellable is non-%NULL, it can be used to cancel the
314  * operation, in which case @error (if non-%NULL) will be set to
315  * %G_IO_ERROR_CANCELLED.
316  *
317  * If you are planning to connect to a socket on the resolved IP
318  * address, it may be easier to create a #GNetworkAddress and use its
319  * #GSocketConnectable interface.
320  *
321  * Return value: (element-type GInetAddress) (transfer full): a #GList
322  * of #GInetAddress, or %NULL on error. You
323  * must unref each of the addresses and free the list when you are
324  * done with it. (You can use g_resolver_free_addresses() to do this.)
325  *
326  * Since: 2.22
327  */
328 GList *
329 g_resolver_lookup_by_name (GResolver     *resolver,
330                            const gchar   *hostname,
331                            GCancellable  *cancellable,
332                            GError       **error)
333 {
334   GInetAddress *addr;
335   GList *addrs;
336   gchar *ascii_hostname = NULL;
337
338   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
339   g_return_val_if_fail (hostname != NULL, NULL);
340
341   /* Check if @hostname is just an IP address */
342   addr = g_inet_address_new_from_string (hostname);
343   if (addr)
344     return g_list_append (NULL, addr);
345
346   if (g_hostname_is_non_ascii (hostname))
347     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
348
349   g_resolver_maybe_reload (resolver);
350   addrs = G_RESOLVER_GET_CLASS (resolver)->
351     lookup_by_name (resolver, hostname, cancellable, error);
352
353   remove_duplicates (addrs);
354
355   g_free (ascii_hostname);
356   return addrs;
357 }
358
359 /**
360  * g_resolver_lookup_by_name_async:
361  * @resolver: a #GResolver
362  * @hostname: the hostname to look up the address of
363  * @cancellable: (allow-none): a #GCancellable, or %NULL
364  * @callback: (scope async): callback to call after resolution completes
365  * @user_data: (closure): data for @callback
366  *
367  * Begins asynchronously resolving @hostname to determine its
368  * associated IP address(es), and eventually calls @callback, which
369  * must call g_resolver_lookup_by_name_finish() to get the result.
370  * See g_resolver_lookup_by_name() for more details.
371  *
372  * Since: 2.22
373  */
374 void
375 g_resolver_lookup_by_name_async (GResolver           *resolver,
376                                  const gchar         *hostname,
377                                  GCancellable        *cancellable,
378                                  GAsyncReadyCallback  callback,
379                                  gpointer             user_data)
380 {
381   GInetAddress *addr;
382   gchar *ascii_hostname = NULL;
383
384   g_return_if_fail (G_IS_RESOLVER (resolver));
385   g_return_if_fail (hostname != NULL);
386
387   /* Check if @hostname is just an IP address */
388   addr = g_inet_address_new_from_string (hostname);
389   if (addr)
390     {
391       GTask *task;
392
393       task = g_task_new (resolver, cancellable, callback, user_data);
394       g_task_set_source_tag (task, g_resolver_lookup_by_name_async);
395       g_task_return_pointer (task, g_list_append (NULL, addr),
396                              (GDestroyNotify) g_resolver_free_addresses);
397       g_object_unref (task);
398       return;
399     }
400
401   if (g_hostname_is_non_ascii (hostname))
402     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
403
404   g_resolver_maybe_reload (resolver);
405   G_RESOLVER_GET_CLASS (resolver)->
406     lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
407
408   g_free (ascii_hostname);
409 }
410
411 /**
412  * g_resolver_lookup_by_name_finish:
413  * @resolver: a #GResolver
414  * @result: the result passed to your #GAsyncReadyCallback
415  * @error: return location for a #GError, or %NULL
416  *
417  * Retrieves the result of a call to
418  * g_resolver_lookup_by_name_async().
419  *
420  * If the DNS resolution failed, @error (if non-%NULL) will be set to
421  * a value from #GResolverError. If the operation was cancelled,
422  * @error will be set to %G_IO_ERROR_CANCELLED.
423  *
424  * Return value: (element-type GInetAddress) (transfer full): a #GList
425  * of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
426  * for more details.
427  *
428  * Since: 2.22
429  */
430 GList *
431 g_resolver_lookup_by_name_finish (GResolver     *resolver,
432                                   GAsyncResult  *result,
433                                   GError       **error)
434 {
435   GList *addrs;
436
437   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
438
439   if (g_async_result_legacy_propagate_error (result, error))
440     return NULL;
441   else if (g_async_result_is_tagged (result, g_resolver_lookup_by_name_async))
442     {
443       /* Handle the stringified-IP-addr case */
444       return g_task_propagate_pointer (G_TASK (result), error);
445     }
446
447   addrs = G_RESOLVER_GET_CLASS (resolver)->
448     lookup_by_name_finish (resolver, result, error);
449
450   remove_duplicates (addrs);
451
452   return addrs;
453 }
454
455 /**
456  * g_resolver_free_addresses: (skip)
457  * @addresses: a #GList of #GInetAddress
458  *
459  * Frees @addresses (which should be the return value from
460  * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_finish()).
461  * (This is a convenience method; you can also simply free the results
462  * by hand.)
463  *
464  * Since: 2.22
465  */
466 void
467 g_resolver_free_addresses (GList *addresses)
468 {
469   GList *a;
470
471   for (a = addresses; a; a = a->next)
472     g_object_unref (a->data);
473   g_list_free (addresses);
474 }
475
476 /**
477  * g_resolver_lookup_by_address:
478  * @resolver: a #GResolver
479  * @address: the address to reverse-resolve
480  * @cancellable: (allow-none): a #GCancellable, or %NULL
481  * @error: return location for a #GError, or %NULL
482  *
483  * Synchronously reverse-resolves @address to determine its
484  * associated hostname.
485  *
486  * If the DNS resolution fails, @error (if non-%NULL) will be set to
487  * a value from #GResolverError.
488  *
489  * If @cancellable is non-%NULL, it can be used to cancel the
490  * operation, in which case @error (if non-%NULL) will be set to
491  * %G_IO_ERROR_CANCELLED.
492  *
493  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
494  *     form), or %NULL on error.
495  *
496  * Since: 2.22
497  */
498 gchar *
499 g_resolver_lookup_by_address (GResolver     *resolver,
500                               GInetAddress  *address,
501                               GCancellable  *cancellable,
502                               GError       **error)
503 {
504   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
505   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
506
507   g_resolver_maybe_reload (resolver);
508   return G_RESOLVER_GET_CLASS (resolver)->
509     lookup_by_address (resolver, address, cancellable, error);
510 }
511
512 /**
513  * g_resolver_lookup_by_address_async:
514  * @resolver: a #GResolver
515  * @address: the address to reverse-resolve
516  * @cancellable: (allow-none): a #GCancellable, or %NULL
517  * @callback: (scope async): callback to call after resolution completes
518  * @user_data: (closure): data for @callback
519  *
520  * Begins asynchronously reverse-resolving @address to determine its
521  * associated hostname, and eventually calls @callback, which must
522  * call g_resolver_lookup_by_address_finish() to get the final result.
523  *
524  * Since: 2.22
525  */
526 void
527 g_resolver_lookup_by_address_async (GResolver           *resolver,
528                                     GInetAddress        *address,
529                                     GCancellable        *cancellable,
530                                     GAsyncReadyCallback  callback,
531                                     gpointer             user_data)
532 {
533   g_return_if_fail (G_IS_RESOLVER (resolver));
534   g_return_if_fail (G_IS_INET_ADDRESS (address));
535
536   g_resolver_maybe_reload (resolver);
537   G_RESOLVER_GET_CLASS (resolver)->
538     lookup_by_address_async (resolver, address, cancellable, callback, user_data);
539 }
540
541 /**
542  * g_resolver_lookup_by_address_finish:
543  * @resolver: a #GResolver
544  * @result: the result passed to your #GAsyncReadyCallback
545  * @error: return location for a #GError, or %NULL
546  *
547  * Retrieves the result of a previous call to
548  * g_resolver_lookup_by_address_async().
549  *
550  * If the DNS resolution failed, @error (if non-%NULL) will be set to
551  * a value from #GResolverError. If the operation was cancelled,
552  * @error will be set to %G_IO_ERROR_CANCELLED.
553  *
554  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
555  * form), or %NULL on error.
556  *
557  * Since: 2.22
558  */
559 gchar *
560 g_resolver_lookup_by_address_finish (GResolver     *resolver,
561                                      GAsyncResult  *result,
562                                      GError       **error)
563 {
564   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
565
566   if (g_async_result_legacy_propagate_error (result, error))
567     return NULL;
568
569   return G_RESOLVER_GET_CLASS (resolver)->
570     lookup_by_address_finish (resolver, result, error);
571 }
572
573 static gchar *
574 g_resolver_get_service_rrname (const char *service,
575                                const char *protocol,
576                                const char *domain)
577 {
578   gchar *rrname, *ascii_domain = NULL;
579
580   if (g_hostname_is_non_ascii (domain))
581     domain = ascii_domain = g_hostname_to_ascii (domain);
582
583   rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
584
585   g_free (ascii_domain);
586   return rrname;
587 }
588
589 /**
590  * g_resolver_lookup_service:
591  * @resolver: a #GResolver
592  * @service: the service type to look up (eg, "ldap")
593  * @protocol: the networking protocol to use for @service (eg, "tcp")
594  * @domain: the DNS domain to look up the service in
595  * @cancellable: (allow-none): a #GCancellable, or %NULL
596  * @error: return location for a #GError, or %NULL
597  *
598  * Synchronously performs a DNS SRV lookup for the given @service and
599  * @protocol in the given @domain and returns an array of #GSrvTarget.
600  * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
601  * @service and @protocol arguments <emphasis>do not</emphasis>
602  * include the leading underscore that appears in the actual DNS
603  * entry.
604  *
605  * On success, g_resolver_lookup_service() will return a #GList of
606  * #GSrvTarget, sorted in order of preference. (That is, you should
607  * attempt to connect to the first target first, then the second if
608  * the first fails, etc.)
609  *
610  * If the DNS resolution fails, @error (if non-%NULL) will be set to
611  * a value from #GResolverError.
612  *
613  * If @cancellable is non-%NULL, it can be used to cancel the
614  * operation, in which case @error (if non-%NULL) will be set to
615  * %G_IO_ERROR_CANCELLED.
616  *
617  * If you are planning to connect to the service, it is usually easier
618  * to create a #GNetworkService and use its #GSocketConnectable
619  * interface.
620  *
621  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
622  * or %NULL on error. You must free each of the targets and the list when you are
623  * done with it. (You can use g_resolver_free_targets() to do this.)
624  *
625  * Since: 2.22
626  */
627 GList *
628 g_resolver_lookup_service (GResolver     *resolver,
629                            const gchar   *service,
630                            const gchar   *protocol,
631                            const gchar   *domain,
632                            GCancellable  *cancellable,
633                            GError       **error)
634 {
635   GList *targets;
636   gchar *rrname;
637
638   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
639   g_return_val_if_fail (service != NULL, NULL);
640   g_return_val_if_fail (protocol != NULL, NULL);
641   g_return_val_if_fail (domain != NULL, NULL);
642
643   rrname = g_resolver_get_service_rrname (service, protocol, domain);
644
645   g_resolver_maybe_reload (resolver);
646   targets = G_RESOLVER_GET_CLASS (resolver)->
647     lookup_service (resolver, rrname, cancellable, error);
648
649   g_free (rrname);
650   return targets;
651 }
652
653 /**
654  * g_resolver_lookup_service_async:
655  * @resolver: a #GResolver
656  * @service: the service type to look up (eg, "ldap")
657  * @protocol: the networking protocol to use for @service (eg, "tcp")
658  * @domain: the DNS domain to look up the service in
659  * @cancellable: (allow-none): a #GCancellable, or %NULL
660  * @callback: (scope async): callback to call after resolution completes
661  * @user_data: (closure): data for @callback
662  *
663  * Begins asynchronously performing a DNS SRV lookup for the given
664  * @service and @protocol in the given @domain, and eventually calls
665  * @callback, which must call g_resolver_lookup_service_finish() to
666  * get the final result. See g_resolver_lookup_service() for more
667  * details.
668  *
669  * Since: 2.22
670  */
671 void
672 g_resolver_lookup_service_async (GResolver           *resolver,
673                                  const gchar         *service,
674                                  const gchar         *protocol,
675                                  const gchar         *domain,
676                                  GCancellable        *cancellable,
677                                  GAsyncReadyCallback  callback,
678                                  gpointer             user_data)
679 {
680   gchar *rrname;
681
682   g_return_if_fail (G_IS_RESOLVER (resolver));
683   g_return_if_fail (service != NULL);
684   g_return_if_fail (protocol != NULL);
685   g_return_if_fail (domain != NULL);
686
687   rrname = g_resolver_get_service_rrname (service, protocol, domain);
688
689   g_resolver_maybe_reload (resolver);
690   G_RESOLVER_GET_CLASS (resolver)->
691     lookup_service_async (resolver, rrname, cancellable, callback, user_data);
692
693   g_free (rrname);
694 }
695
696 /**
697  * g_resolver_lookup_service_finish:
698  * @resolver: a #GResolver
699  * @result: the result passed to your #GAsyncReadyCallback
700  * @error: return location for a #GError, or %NULL
701  *
702  * Retrieves the result of a previous call to
703  * g_resolver_lookup_service_async().
704  *
705  * If the DNS resolution failed, @error (if non-%NULL) will be set to
706  * a value from #GResolverError. If the operation was cancelled,
707  * @error will be set to %G_IO_ERROR_CANCELLED.
708  *
709  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
710  * or %NULL on error. See g_resolver_lookup_service() for more details.
711  *
712  * Since: 2.22
713  */
714 GList *
715 g_resolver_lookup_service_finish (GResolver     *resolver,
716                                   GAsyncResult  *result,
717                                   GError       **error)
718 {
719   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
720
721   if (g_async_result_legacy_propagate_error (result, error))
722     return NULL;
723
724   return G_RESOLVER_GET_CLASS (resolver)->
725     lookup_service_finish (resolver, result, error);
726 }
727
728 /**
729  * g_resolver_free_targets: (skip)
730  * @targets: a #GList of #GSrvTarget
731  *
732  * Frees @targets (which should be the return value from
733  * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
734  * (This is a convenience method; you can also simply free the
735  * results by hand.)
736  *
737  * Since: 2.22
738  */
739 void
740 g_resolver_free_targets (GList *targets)
741 {
742   GList *t;
743
744   for (t = targets; t; t = t->next)
745     g_srv_target_free (t->data);
746   g_list_free (targets);
747 }
748
749 /**
750  * g_resolver_lookup_records:
751  * @resolver: a #GResolver
752  * @rrname: the DNS name to lookup the record for
753  * @record_type: the type of DNS record to lookup
754  * @cancellable: (allow-none): a #GCancellable, or %NULL
755  * @error: return location for a #GError, or %NULL
756  *
757  * Synchronously performs a DNS record lookup for the given @rrname and returns
758  * a list of records as #GVariant tuples. See #GResolverRecordType for
759  * information on what the records contain for each @record_type.
760  *
761  * If the DNS resolution fails, @error (if non-%NULL) will be set to
762  * a value from #GResolverError.
763  *
764  * If @cancellable is non-%NULL, it can be used to cancel the
765  * operation, in which case @error (if non-%NULL) will be set to
766  * %G_IO_ERROR_CANCELLED.
767  *
768  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
769  * or %NULL on error. You must free each of the records and the list when you are
770  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
771  *
772  * Since: 2.34
773  */
774 GList *
775 g_resolver_lookup_records (GResolver            *resolver,
776                            const gchar          *rrname,
777                            GResolverRecordType   record_type,
778                            GCancellable         *cancellable,
779                            GError              **error)
780 {
781   GList *records;
782
783   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
784   g_return_val_if_fail (rrname != NULL, NULL);
785
786   g_resolver_maybe_reload (resolver);
787   records = G_RESOLVER_GET_CLASS (resolver)->
788     lookup_records (resolver, rrname, record_type, cancellable, error);
789
790   return records;
791 }
792
793 /**
794  * g_resolver_lookup_records_async:
795  * @resolver: a #GResolver
796  * @rrname: the DNS name to lookup the record for
797  * @record_type: the type of DNS record to lookup
798  * @cancellable: (allow-none): a #GCancellable, or %NULL
799  * @callback: (scope async): callback to call after resolution completes
800  * @user_data: (closure): data for @callback
801  *
802  * Begins asynchronously performing a DNS lookup for the given
803  * @rrname, and eventually calls @callback, which must call
804  * g_resolver_lookup_records_finish() to get the final result. See
805  * g_resolver_lookup_records() for more details.
806  *
807  * Since: 2.34
808  */
809 void
810 g_resolver_lookup_records_async (GResolver           *resolver,
811                                  const gchar         *rrname,
812                                  GResolverRecordType  record_type,
813                                  GCancellable        *cancellable,
814                                  GAsyncReadyCallback  callback,
815                                  gpointer             user_data)
816 {
817   g_return_if_fail (G_IS_RESOLVER (resolver));
818   g_return_if_fail (rrname != NULL);
819
820   g_resolver_maybe_reload (resolver);
821   G_RESOLVER_GET_CLASS (resolver)->
822     lookup_records_async (resolver, rrname, record_type, cancellable, callback, user_data);
823 }
824
825 /**
826  * g_resolver_lookup_records_finish:
827  * @resolver: a #GResolver
828  * @result: the result passed to your #GAsyncReadyCallback
829  * @error: return location for a #GError, or %NULL
830  *
831  * Retrieves the result of a previous call to
832  * g_resolver_lookup_records_async(). Returns a list of records as #GVariant
833  * tuples. See #GResolverRecordType for information on what the records contain.
834  *
835  * If the DNS resolution failed, @error (if non-%NULL) will be set to
836  * a value from #GResolverError. If the operation was cancelled,
837  * @error will be set to %G_IO_ERROR_CANCELLED.
838  *
839  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
840  * or %NULL on error. You must free each of the records and the list when you are
841  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
842  *
843  * Since: 2.34
844  */
845 GList *
846 g_resolver_lookup_records_finish (GResolver     *resolver,
847                                   GAsyncResult  *result,
848                                   GError       **error)
849 {
850   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
851   return G_RESOLVER_GET_CLASS (resolver)->
852     lookup_records_finish (resolver, result, error);
853 }
854
855 guint64
856 g_resolver_get_serial (GResolver *resolver)
857 {
858   g_return_val_if_fail (G_IS_RESOLVER (resolver), 0);
859
860   g_resolver_maybe_reload (resolver);
861
862 #ifdef G_OS_UNIX
863   return (guint64) resolver->priv->resolv_conf_timestamp;
864 #else
865   return 1;
866 #endif
867 }
868
869 /**
870  * g_resolver_error_quark:
871  *
872  * Gets the #GResolver Error Quark.
873  *
874  * Return value: a #GQuark.
875  *
876  * Since: 2.22
877  */
878 G_DEFINE_QUARK (g-resolver-error-quark, g_resolver_error)