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