5549e4fd2e31c1b870a2d450001fe6753e643c3b
[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
236 static void
237 g_resolver_maybe_reload (GResolver *resolver)
238 {
239 #ifdef G_OS_UNIX
240   struct stat st;
241
242   if (stat (_PATH_RESCONF, &st) == 0)
243     {
244       if (st.st_mtime != resolver->priv->resolv_conf_timestamp)
245         {
246           resolver->priv->resolv_conf_timestamp = st.st_mtime;
247           res_init ();
248           g_signal_emit (resolver, signals[RELOAD], 0);
249         }
250     }
251 #endif
252 }
253
254 /* filter out duplicates, cf. https://bugzilla.gnome.org/show_bug.cgi?id=631379 */
255 static void
256 remove_duplicates (GList *addrs)
257 {
258   GList *l;
259   GList *ll;
260   GList *lll;
261
262   /* TODO: if this is too slow (it's O(n^2) but n is typically really
263    * small), we can do something more clever but note that we must not
264    * change the order of elements...
265    */
266   for (l = addrs; l != NULL; l = l->next)
267     {
268       GInetAddress *address = G_INET_ADDRESS (l->data);
269       for (ll = l->next; ll != NULL; ll = lll)
270         {
271           GInetAddress *other_address = G_INET_ADDRESS (ll->data);
272           lll = ll->next;
273           if (g_inet_address_equal (address, other_address))
274             {
275               g_object_unref (other_address);
276               /* we never return the first element */
277               g_warn_if_fail (g_list_delete_link (addrs, ll) == addrs);
278             }
279         }
280     }
281 }
282
283
284 /**
285  * g_resolver_lookup_by_name:
286  * @resolver: a #GResolver
287  * @hostname: the hostname to look up
288  * @cancellable: (allow-none): a #GCancellable, or %NULL
289  * @error: return location for a #GError, or %NULL
290  *
291  * Synchronously resolves @hostname to determine its associated IP
292  * address(es). @hostname may be an ASCII-only or UTF-8 hostname, or
293  * the textual form of an IP address (in which case this just becomes
294  * a wrapper around g_inet_address_new_from_string()).
295  *
296  * On success, g_resolver_lookup_by_name() will return a #GList of
297  * #GInetAddress, sorted in order of preference and guaranteed to not
298  * contain duplicates. That is, if using the result to connect to
299  * @hostname, you should attempt to connect to the first address
300  * first, then the second if the first fails, etc. If you are using
301  * the result to listen on a socket, it is appropriate to add each
302  * result using e.g. g_socket_listener_add_address().
303  *
304  * If the DNS resolution fails, @error (if non-%NULL) will be set to a
305  * value from #GResolverError.
306  *
307  * If @cancellable is non-%NULL, it can be used to cancel the
308  * operation, in which case @error (if non-%NULL) will be set to
309  * %G_IO_ERROR_CANCELLED.
310  *
311  * If you are planning to connect to a socket on the resolved IP
312  * address, it may be easier to create a #GNetworkAddress and use its
313  * #GSocketConnectable interface.
314  *
315  * Return value: (element-type GInetAddress) (transfer full): a #GList
316  * of #GInetAddress, or %NULL on error. You
317  * must unref each of the addresses and free the list when you are
318  * done with it. (You can use g_resolver_free_addresses() to do this.)
319  *
320  * Since: 2.22
321  */
322 GList *
323 g_resolver_lookup_by_name (GResolver     *resolver,
324                            const gchar   *hostname,
325                            GCancellable  *cancellable,
326                            GError       **error)
327 {
328   GInetAddress *addr;
329   GList *addrs;
330   gchar *ascii_hostname = NULL;
331
332   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
333   g_return_val_if_fail (hostname != NULL, NULL);
334
335   /* Check if @hostname is just an IP address */
336   addr = g_inet_address_new_from_string (hostname);
337   if (addr)
338     return g_list_append (NULL, addr);
339
340   if (g_hostname_is_non_ascii (hostname))
341     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
342
343   g_resolver_maybe_reload (resolver);
344   addrs = G_RESOLVER_GET_CLASS (resolver)->
345     lookup_by_name (resolver, hostname, cancellable, error);
346
347   remove_duplicates (addrs);
348
349   g_free (ascii_hostname);
350   return addrs;
351 }
352
353 /**
354  * g_resolver_lookup_by_name_async:
355  * @resolver: a #GResolver
356  * @hostname: the hostname to look up the address of
357  * @cancellable: (allow-none): a #GCancellable, or %NULL
358  * @callback: (scope async): callback to call after resolution completes
359  * @user_data: (closure): data for @callback
360  *
361  * Begins asynchronously resolving @hostname to determine its
362  * associated IP address(es), and eventually calls @callback, which
363  * must call g_resolver_lookup_by_name_finish() to get the result.
364  * See g_resolver_lookup_by_name() for more details.
365  *
366  * Since: 2.22
367  */
368 void
369 g_resolver_lookup_by_name_async (GResolver           *resolver,
370                                  const gchar         *hostname,
371                                  GCancellable        *cancellable,
372                                  GAsyncReadyCallback  callback,
373                                  gpointer             user_data)
374 {
375   GInetAddress *addr;
376   gchar *ascii_hostname = NULL;
377
378   g_return_if_fail (G_IS_RESOLVER (resolver));
379   g_return_if_fail (hostname != NULL);
380
381   /* Check if @hostname is just an IP address */
382   addr = g_inet_address_new_from_string (hostname);
383   if (addr)
384     {
385       GTask *task;
386
387       task = g_task_new (resolver, cancellable, callback, user_data);
388       g_task_set_source_tag (task, g_resolver_lookup_by_name_async);
389       g_task_return_pointer (task, g_list_append (NULL, addr),
390                              (GDestroyNotify) g_resolver_free_addresses);
391       g_object_unref (task);
392       return;
393     }
394
395   if (g_hostname_is_non_ascii (hostname))
396     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
397
398   g_resolver_maybe_reload (resolver);
399   G_RESOLVER_GET_CLASS (resolver)->
400     lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
401
402   g_free (ascii_hostname);
403 }
404
405 /**
406  * g_resolver_lookup_by_name_finish:
407  * @resolver: a #GResolver
408  * @result: the result passed to your #GAsyncReadyCallback
409  * @error: return location for a #GError, or %NULL
410  *
411  * Retrieves the result of a call to
412  * g_resolver_lookup_by_name_async().
413  *
414  * If the DNS resolution failed, @error (if non-%NULL) will be set to
415  * a value from #GResolverError. If the operation was cancelled,
416  * @error will be set to %G_IO_ERROR_CANCELLED.
417  *
418  * Return value: (element-type GInetAddress) (transfer full): a #GList
419  * of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
420  * for more details.
421  *
422  * Since: 2.22
423  */
424 GList *
425 g_resolver_lookup_by_name_finish (GResolver     *resolver,
426                                   GAsyncResult  *result,
427                                   GError       **error)
428 {
429   GList *addrs;
430
431   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
432
433   if (g_async_result_legacy_propagate_error (result, error))
434     return NULL;
435   else if (g_async_result_is_tagged (result, g_resolver_lookup_by_name_async))
436     {
437       /* Handle the stringified-IP-addr case */
438       return g_task_propagate_pointer (G_TASK (result), error);
439     }
440
441   addrs = G_RESOLVER_GET_CLASS (resolver)->
442     lookup_by_name_finish (resolver, result, error);
443
444   remove_duplicates (addrs);
445
446   return addrs;
447 }
448
449 /**
450  * g_resolver_free_addresses: (skip)
451  * @addresses: a #GList of #GInetAddress
452  *
453  * Frees @addresses (which should be the return value from
454  * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_finish()).
455  * (This is a convenience method; you can also simply free the results
456  * by hand.)
457  *
458  * Since: 2.22
459  */
460 void
461 g_resolver_free_addresses (GList *addresses)
462 {
463   GList *a;
464
465   for (a = addresses; a; a = a->next)
466     g_object_unref (a->data);
467   g_list_free (addresses);
468 }
469
470 /**
471  * g_resolver_lookup_by_address:
472  * @resolver: a #GResolver
473  * @address: the address to reverse-resolve
474  * @cancellable: (allow-none): a #GCancellable, or %NULL
475  * @error: return location for a #GError, or %NULL
476  *
477  * Synchronously reverse-resolves @address to determine its
478  * associated hostname.
479  *
480  * If the DNS resolution fails, @error (if non-%NULL) will be set to
481  * a value from #GResolverError.
482  *
483  * If @cancellable is non-%NULL, it can be used to cancel the
484  * operation, in which case @error (if non-%NULL) will be set to
485  * %G_IO_ERROR_CANCELLED.
486  *
487  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
488  *     form), or %NULL on error.
489  *
490  * Since: 2.22
491  */
492 gchar *
493 g_resolver_lookup_by_address (GResolver     *resolver,
494                               GInetAddress  *address,
495                               GCancellable  *cancellable,
496                               GError       **error)
497 {
498   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
499   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
500
501   g_resolver_maybe_reload (resolver);
502   return G_RESOLVER_GET_CLASS (resolver)->
503     lookup_by_address (resolver, address, cancellable, error);
504 }
505
506 /**
507  * g_resolver_lookup_by_address_async:
508  * @resolver: a #GResolver
509  * @address: the address to reverse-resolve
510  * @cancellable: (allow-none): a #GCancellable, or %NULL
511  * @callback: (scope async): callback to call after resolution completes
512  * @user_data: (closure): data for @callback
513  *
514  * Begins asynchronously reverse-resolving @address to determine its
515  * associated hostname, and eventually calls @callback, which must
516  * call g_resolver_lookup_by_address_finish() to get the final result.
517  *
518  * Since: 2.22
519  */
520 void
521 g_resolver_lookup_by_address_async (GResolver           *resolver,
522                                     GInetAddress        *address,
523                                     GCancellable        *cancellable,
524                                     GAsyncReadyCallback  callback,
525                                     gpointer             user_data)
526 {
527   g_return_if_fail (G_IS_RESOLVER (resolver));
528   g_return_if_fail (G_IS_INET_ADDRESS (address));
529
530   g_resolver_maybe_reload (resolver);
531   G_RESOLVER_GET_CLASS (resolver)->
532     lookup_by_address_async (resolver, address, cancellable, callback, user_data);
533 }
534
535 /**
536  * g_resolver_lookup_by_address_finish:
537  * @resolver: a #GResolver
538  * @result: the result passed to your #GAsyncReadyCallback
539  * @error: return location for a #GError, or %NULL
540  *
541  * Retrieves the result of a previous call to
542  * g_resolver_lookup_by_address_async().
543  *
544  * If the DNS resolution failed, @error (if non-%NULL) will be set to
545  * a value from #GResolverError. If the operation was cancelled,
546  * @error will be set to %G_IO_ERROR_CANCELLED.
547  *
548  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
549  * form), or %NULL on error.
550  *
551  * Since: 2.22
552  */
553 gchar *
554 g_resolver_lookup_by_address_finish (GResolver     *resolver,
555                                      GAsyncResult  *result,
556                                      GError       **error)
557 {
558   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
559
560   if (g_async_result_legacy_propagate_error (result, error))
561     return NULL;
562
563   return G_RESOLVER_GET_CLASS (resolver)->
564     lookup_by_address_finish (resolver, result, error);
565 }
566
567 static gchar *
568 g_resolver_get_service_rrname (const char *service,
569                                const char *protocol,
570                                const char *domain)
571 {
572   gchar *rrname, *ascii_domain = NULL;
573
574   if (g_hostname_is_non_ascii (domain))
575     domain = ascii_domain = g_hostname_to_ascii (domain);
576
577   rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
578
579   g_free (ascii_domain);
580   return rrname;
581 }
582
583 /**
584  * g_resolver_lookup_service:
585  * @resolver: a #GResolver
586  * @service: the service type to look up (eg, "ldap")
587  * @protocol: the networking protocol to use for @service (eg, "tcp")
588  * @domain: the DNS domain to look up the service in
589  * @cancellable: (allow-none): a #GCancellable, or %NULL
590  * @error: return location for a #GError, or %NULL
591  *
592  * Synchronously performs a DNS SRV lookup for the given @service and
593  * @protocol in the given @domain and returns an array of #GSrvTarget.
594  * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
595  * @service and @protocol arguments <emphasis>do not</emphasis>
596  * include the leading underscore that appears in the actual DNS
597  * entry.
598  *
599  * On success, g_resolver_lookup_service() will return a #GList of
600  * #GSrvTarget, sorted in order of preference. (That is, you should
601  * attempt to connect to the first target first, then the second if
602  * the first fails, etc.)
603  *
604  * If the DNS resolution fails, @error (if non-%NULL) will be set to
605  * a value from #GResolverError.
606  *
607  * If @cancellable is non-%NULL, it can be used to cancel the
608  * operation, in which case @error (if non-%NULL) will be set to
609  * %G_IO_ERROR_CANCELLED.
610  *
611  * If you are planning to connect to the service, it is usually easier
612  * to create a #GNetworkService and use its #GSocketConnectable
613  * interface.
614  *
615  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
616  * or %NULL on error. You must free each of the targets and the list when you are
617  * done with it. (You can use g_resolver_free_targets() to do this.)
618  *
619  * Since: 2.22
620  */
621 GList *
622 g_resolver_lookup_service (GResolver     *resolver,
623                            const gchar   *service,
624                            const gchar   *protocol,
625                            const gchar   *domain,
626                            GCancellable  *cancellable,
627                            GError       **error)
628 {
629   GList *targets;
630   gchar *rrname;
631
632   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
633   g_return_val_if_fail (service != NULL, NULL);
634   g_return_val_if_fail (protocol != NULL, NULL);
635   g_return_val_if_fail (domain != NULL, NULL);
636
637   rrname = g_resolver_get_service_rrname (service, protocol, domain);
638
639   g_resolver_maybe_reload (resolver);
640   targets = G_RESOLVER_GET_CLASS (resolver)->
641     lookup_service (resolver, rrname, cancellable, error);
642
643   g_free (rrname);
644   return targets;
645 }
646
647 /**
648  * g_resolver_lookup_service_async:
649  * @resolver: a #GResolver
650  * @service: the service type to look up (eg, "ldap")
651  * @protocol: the networking protocol to use for @service (eg, "tcp")
652  * @domain: the DNS domain to look up the service in
653  * @cancellable: (allow-none): a #GCancellable, or %NULL
654  * @callback: (scope async): callback to call after resolution completes
655  * @user_data: (closure): data for @callback
656  *
657  * Begins asynchronously performing a DNS SRV lookup for the given
658  * @service and @protocol in the given @domain, and eventually calls
659  * @callback, which must call g_resolver_lookup_service_finish() to
660  * get the final result. See g_resolver_lookup_service() for more
661  * details.
662  *
663  * Since: 2.22
664  */
665 void
666 g_resolver_lookup_service_async (GResolver           *resolver,
667                                  const gchar         *service,
668                                  const gchar         *protocol,
669                                  const gchar         *domain,
670                                  GCancellable        *cancellable,
671                                  GAsyncReadyCallback  callback,
672                                  gpointer             user_data)
673 {
674   gchar *rrname;
675
676   g_return_if_fail (G_IS_RESOLVER (resolver));
677   g_return_if_fail (service != NULL);
678   g_return_if_fail (protocol != NULL);
679   g_return_if_fail (domain != NULL);
680
681   rrname = g_resolver_get_service_rrname (service, protocol, domain);
682
683   g_resolver_maybe_reload (resolver);
684   G_RESOLVER_GET_CLASS (resolver)->
685     lookup_service_async (resolver, rrname, cancellable, callback, user_data);
686
687   g_free (rrname);
688 }
689
690 /**
691  * g_resolver_lookup_service_finish:
692  * @resolver: a #GResolver
693  * @result: the result passed to your #GAsyncReadyCallback
694  * @error: return location for a #GError, or %NULL
695  *
696  * Retrieves the result of a previous call to
697  * g_resolver_lookup_service_async().
698  *
699  * If the DNS resolution failed, @error (if non-%NULL) will be set to
700  * a value from #GResolverError. If the operation was cancelled,
701  * @error will be set to %G_IO_ERROR_CANCELLED.
702  *
703  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
704  * or %NULL on error. See g_resolver_lookup_service() for more details.
705  *
706  * Since: 2.22
707  */
708 GList *
709 g_resolver_lookup_service_finish (GResolver     *resolver,
710                                   GAsyncResult  *result,
711                                   GError       **error)
712 {
713   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
714
715   if (g_async_result_legacy_propagate_error (result, error))
716     return NULL;
717
718   return G_RESOLVER_GET_CLASS (resolver)->
719     lookup_service_finish (resolver, result, error);
720 }
721
722 /**
723  * g_resolver_free_targets: (skip)
724  * @targets: a #GList of #GSrvTarget
725  *
726  * Frees @targets (which should be the return value from
727  * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
728  * (This is a convenience method; you can also simply free the
729  * results by hand.)
730  *
731  * Since: 2.22
732  */
733 void
734 g_resolver_free_targets (GList *targets)
735 {
736   GList *t;
737
738   for (t = targets; t; t = t->next)
739     g_srv_target_free (t->data);
740   g_list_free (targets);
741 }
742
743 /**
744  * g_resolver_lookup_records:
745  * @resolver: a #GResolver
746  * @rrname: the DNS name to lookup the record for
747  * @record_type: the type of DNS record to lookup
748  * @cancellable: (allow-none): a #GCancellable, or %NULL
749  * @error: return location for a #GError, or %NULL
750  *
751  * Synchronously performs a DNS record lookup for the given @rrname and returns
752  * a list of records as #GVariant tuples. See #GResolverRecordType for
753  * information on what the records contain for each @record_type.
754  *
755  * If the DNS resolution fails, @error (if non-%NULL) will be set to
756  * a value from #GResolverError.
757  *
758  * If @cancellable is non-%NULL, it can be used to cancel the
759  * operation, in which case @error (if non-%NULL) will be set to
760  * %G_IO_ERROR_CANCELLED.
761  *
762  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
763  * or %NULL on error. You must free each of the records and the list when you are
764  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
765  *
766  * Since: 2.34
767  */
768 GList *
769 g_resolver_lookup_records (GResolver            *resolver,
770                            const gchar          *rrname,
771                            GResolverRecordType   record_type,
772                            GCancellable         *cancellable,
773                            GError              **error)
774 {
775   GList *records;
776
777   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
778   g_return_val_if_fail (rrname != NULL, NULL);
779
780   g_resolver_maybe_reload (resolver);
781   records = G_RESOLVER_GET_CLASS (resolver)->
782     lookup_records (resolver, rrname, record_type, cancellable, error);
783
784   return records;
785 }
786
787 /**
788  * g_resolver_lookup_records_async:
789  * @resolver: a #GResolver
790  * @rrname: the DNS name to lookup the record for
791  * @record_type: the type of DNS record to lookup
792  * @cancellable: (allow-none): a #GCancellable, or %NULL
793  * @callback: (scope async): callback to call after resolution completes
794  * @user_data: (closure): data for @callback
795  *
796  * Begins asynchronously performing a DNS lookup for the given
797  * @rrname, and eventually calls @callback, which must call
798  * g_resolver_lookup_records_finish() to get the final result. See
799  * g_resolver_lookup_records() for more details.
800  *
801  * Since: 2.34
802  */
803 void
804 g_resolver_lookup_records_async (GResolver           *resolver,
805                                  const gchar         *rrname,
806                                  GResolverRecordType  record_type,
807                                  GCancellable        *cancellable,
808                                  GAsyncReadyCallback  callback,
809                                  gpointer             user_data)
810 {
811   g_return_if_fail (G_IS_RESOLVER (resolver));
812   g_return_if_fail (rrname != NULL);
813
814   g_resolver_maybe_reload (resolver);
815   G_RESOLVER_GET_CLASS (resolver)->
816     lookup_records_async (resolver, rrname, record_type, cancellable, callback, user_data);
817 }
818
819 /**
820  * g_resolver_lookup_records_finish:
821  * @resolver: a #GResolver
822  * @result: the result passed to your #GAsyncReadyCallback
823  * @error: return location for a #GError, or %NULL
824  *
825  * Retrieves the result of a previous call to
826  * g_resolver_lookup_records_async(). Returns a list of records as #GVariant
827  * tuples. See #GResolverRecordType for information on what the records contain.
828  *
829  * If the DNS resolution failed, @error (if non-%NULL) will be set to
830  * a value from #GResolverError. If the operation was cancelled,
831  * @error will be set to %G_IO_ERROR_CANCELLED.
832  *
833  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
834  * or %NULL on error. You must free each of the records and the list when you are
835  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
836  *
837  * Since: 2.34
838  */
839 GList *
840 g_resolver_lookup_records_finish (GResolver     *resolver,
841                                   GAsyncResult  *result,
842                                   GError       **error)
843 {
844   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
845   return G_RESOLVER_GET_CLASS (resolver)->
846     lookup_records_finish (resolver, result, error);
847 }
848
849 guint64
850 g_resolver_get_serial (GResolver *resolver)
851 {
852   g_return_val_if_fail (G_IS_RESOLVER (resolver), 0);
853
854   g_resolver_maybe_reload (resolver);
855
856 #ifdef G_OS_UNIX
857   return (guint64) resolver->priv->resolv_conf_timestamp;
858 #else
859   return 1;
860 #endif
861 }
862
863 /**
864  * g_resolver_error_quark:
865  *
866  * Gets the #GResolver Error Quark.
867  *
868  * Return value: a #GQuark.
869  *
870  * Since: 2.22
871  */
872 G_DEFINE_QUARK (g-resolver-error-quark, g_resolver_error)