Imported Upstream version 2.55.2
[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.1 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   if (!domain)
663     return NULL;
664
665   rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
666
667   g_free (ascii_domain);
668   return rrname;
669 }
670
671 /**
672  * g_resolver_lookup_service:
673  * @resolver: a #GResolver
674  * @service: the service type to look up (eg, "ldap")
675  * @protocol: the networking protocol to use for @service (eg, "tcp")
676  * @domain: the DNS domain to look up the service in
677  * @cancellable: (nullable): a #GCancellable, or %NULL
678  * @error: return location for a #GError, or %NULL
679  *
680  * Synchronously performs a DNS SRV lookup for the given @service and
681  * @protocol in the given @domain and returns an array of #GSrvTarget.
682  * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
683  * @service and @protocol arguments do not include the leading underscore
684  * that appears in the actual DNS entry.
685  *
686  * On success, g_resolver_lookup_service() will return a non-empty #GList of
687  * #GSrvTarget, sorted in order of preference. (That is, you should
688  * attempt to connect to the first target first, then the second if
689  * the first fails, etc.)
690  *
691  * If the DNS resolution fails, @error (if non-%NULL) will be set to
692  * a value from #GResolverError and %NULL will be returned.
693  *
694  * If @cancellable is non-%NULL, it can be used to cancel the
695  * operation, in which case @error (if non-%NULL) will be set to
696  * %G_IO_ERROR_CANCELLED.
697  *
698  * If you are planning to connect to the service, it is usually easier
699  * to create a #GNetworkService and use its #GSocketConnectable
700  * interface.
701  *
702  * Returns: (element-type GSrvTarget) (transfer full): a non-empty #GList of
703  * #GSrvTarget, or %NULL on error. You must free each of the targets and the
704  * list when you are done with it. (You can use g_resolver_free_targets() to do
705  * this.)
706  *
707  * Since: 2.22
708  */
709 GList *
710 g_resolver_lookup_service (GResolver     *resolver,
711                            const gchar   *service,
712                            const gchar   *protocol,
713                            const gchar   *domain,
714                            GCancellable  *cancellable,
715                            GError       **error)
716 {
717   GList *targets;
718   gchar *rrname;
719
720   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
721   g_return_val_if_fail (service != NULL, NULL);
722   g_return_val_if_fail (protocol != NULL, NULL);
723   g_return_val_if_fail (domain != NULL, NULL);
724
725   rrname = g_resolver_get_service_rrname (service, protocol, domain);
726   if (!rrname)
727     {
728       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
729                            _("Invalid domain"));
730       return NULL;
731     }
732
733   g_resolver_maybe_reload (resolver);
734   targets = G_RESOLVER_GET_CLASS (resolver)->
735     lookup_service (resolver, rrname, cancellable, error);
736
737   g_free (rrname);
738   return targets;
739 }
740
741 /**
742  * g_resolver_lookup_service_async:
743  * @resolver: a #GResolver
744  * @service: the service type to look up (eg, "ldap")
745  * @protocol: the networking protocol to use for @service (eg, "tcp")
746  * @domain: the DNS domain to look up the service in
747  * @cancellable: (nullable): a #GCancellable, or %NULL
748  * @callback: (scope async): callback to call after resolution completes
749  * @user_data: (closure): data for @callback
750  *
751  * Begins asynchronously performing a DNS SRV lookup for the given
752  * @service and @protocol in the given @domain, and eventually calls
753  * @callback, which must call g_resolver_lookup_service_finish() to
754  * get the final result. See g_resolver_lookup_service() for more
755  * details.
756  *
757  * Since: 2.22
758  */
759 void
760 g_resolver_lookup_service_async (GResolver           *resolver,
761                                  const gchar         *service,
762                                  const gchar         *protocol,
763                                  const gchar         *domain,
764                                  GCancellable        *cancellable,
765                                  GAsyncReadyCallback  callback,
766                                  gpointer             user_data)
767 {
768   gchar *rrname;
769
770   g_return_if_fail (G_IS_RESOLVER (resolver));
771   g_return_if_fail (service != NULL);
772   g_return_if_fail (protocol != NULL);
773   g_return_if_fail (domain != NULL);
774
775   rrname = g_resolver_get_service_rrname (service, protocol, domain);
776   if (!rrname)
777     {
778       g_task_report_new_error (resolver, callback, user_data,
779                                g_resolver_lookup_service_async,
780                                G_IO_ERROR, G_IO_ERROR_FAILED,
781                                _("Invalid domain"));
782       return;
783     }
784
785   g_resolver_maybe_reload (resolver);
786   G_RESOLVER_GET_CLASS (resolver)->
787     lookup_service_async (resolver, rrname, cancellable, callback, user_data);
788
789   g_free (rrname);
790 }
791
792 /**
793  * g_resolver_lookup_service_finish:
794  * @resolver: a #GResolver
795  * @result: the result passed to your #GAsyncReadyCallback
796  * @error: return location for a #GError, or %NULL
797  *
798  * Retrieves the result of a previous call to
799  * g_resolver_lookup_service_async().
800  *
801  * If the DNS resolution failed, @error (if non-%NULL) will be set to
802  * a value from #GResolverError. If the operation was cancelled,
803  * @error will be set to %G_IO_ERROR_CANCELLED.
804  *
805  * Returns: (element-type GSrvTarget) (transfer full): a non-empty #GList of
806  * #GSrvTarget, or %NULL on error. See g_resolver_lookup_service() for more
807  * details.
808  *
809  * Since: 2.22
810  */
811 GList *
812 g_resolver_lookup_service_finish (GResolver     *resolver,
813                                   GAsyncResult  *result,
814                                   GError       **error)
815 {
816   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
817
818   if (g_async_result_legacy_propagate_error (result, error))
819     return NULL;
820
821   return G_RESOLVER_GET_CLASS (resolver)->
822     lookup_service_finish (resolver, result, error);
823 }
824
825 /**
826  * g_resolver_free_targets: (skip)
827  * @targets: a #GList of #GSrvTarget
828  *
829  * Frees @targets (which should be the return value from
830  * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
831  * (This is a convenience method; you can also simply free the
832  * results by hand.)
833  *
834  * Since: 2.22
835  */
836 void
837 g_resolver_free_targets (GList *targets)
838 {
839   GList *t;
840
841   for (t = targets; t; t = t->next)
842     g_srv_target_free (t->data);
843   g_list_free (targets);
844 }
845
846 /**
847  * g_resolver_lookup_records:
848  * @resolver: a #GResolver
849  * @rrname: the DNS name to lookup the record for
850  * @record_type: the type of DNS record to lookup
851  * @cancellable: (nullable): a #GCancellable, or %NULL
852  * @error: return location for a #GError, or %NULL
853  *
854  * Synchronously performs a DNS record lookup for the given @rrname and returns
855  * a list of records as #GVariant tuples. See #GResolverRecordType for
856  * information on what the records contain for each @record_type.
857  *
858  * If the DNS resolution fails, @error (if non-%NULL) will be set to
859  * a value from #GResolverError and %NULL will be returned.
860  *
861  * If @cancellable is non-%NULL, it can be used to cancel the
862  * operation, in which case @error (if non-%NULL) will be set to
863  * %G_IO_ERROR_CANCELLED.
864  *
865  * Returns: (element-type GVariant) (transfer full): a non-empty #GList of
866  * #GVariant, or %NULL on error. You must free each of the records and the list
867  * when you are done with it. (You can use g_list_free_full() with
868  * g_variant_unref() to do this.)
869  *
870  * Since: 2.34
871  */
872 GList *
873 g_resolver_lookup_records (GResolver            *resolver,
874                            const gchar          *rrname,
875                            GResolverRecordType   record_type,
876                            GCancellable         *cancellable,
877                            GError              **error)
878 {
879   GList *records;
880
881   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
882   g_return_val_if_fail (rrname != NULL, NULL);
883
884   g_resolver_maybe_reload (resolver);
885   records = G_RESOLVER_GET_CLASS (resolver)->
886     lookup_records (resolver, rrname, record_type, cancellable, error);
887
888   return records;
889 }
890
891 /**
892  * g_resolver_lookup_records_async:
893  * @resolver: a #GResolver
894  * @rrname: the DNS name to lookup the record for
895  * @record_type: the type of DNS record to lookup
896  * @cancellable: (nullable): a #GCancellable, or %NULL
897  * @callback: (scope async): callback to call after resolution completes
898  * @user_data: (closure): data for @callback
899  *
900  * Begins asynchronously performing a DNS lookup for the given
901  * @rrname, and eventually calls @callback, which must call
902  * g_resolver_lookup_records_finish() to get the final result. See
903  * g_resolver_lookup_records() for more details.
904  *
905  * Since: 2.34
906  */
907 void
908 g_resolver_lookup_records_async (GResolver           *resolver,
909                                  const gchar         *rrname,
910                                  GResolverRecordType  record_type,
911                                  GCancellable        *cancellable,
912                                  GAsyncReadyCallback  callback,
913                                  gpointer             user_data)
914 {
915   g_return_if_fail (G_IS_RESOLVER (resolver));
916   g_return_if_fail (rrname != NULL);
917
918   g_resolver_maybe_reload (resolver);
919   G_RESOLVER_GET_CLASS (resolver)->
920     lookup_records_async (resolver, rrname, record_type, cancellable, callback, user_data);
921 }
922
923 /**
924  * g_resolver_lookup_records_finish:
925  * @resolver: a #GResolver
926  * @result: the result passed to your #GAsyncReadyCallback
927  * @error: return location for a #GError, or %NULL
928  *
929  * Retrieves the result of a previous call to
930  * g_resolver_lookup_records_async(). Returns a non-empty list of records as
931  * #GVariant tuples. See #GResolverRecordType for information on what the
932  * records contain.
933  *
934  * If the DNS resolution failed, @error (if non-%NULL) will be set to
935  * a value from #GResolverError. If the operation was cancelled,
936  * @error will be set to %G_IO_ERROR_CANCELLED.
937  *
938  * Returns: (element-type GVariant) (transfer full): a non-empty #GList of
939  * #GVariant, or %NULL on error. You must free each of the records and the list
940  * when you are done with it. (You can use g_list_free_full() with
941  * g_variant_unref() to do this.)
942  *
943  * Since: 2.34
944  */
945 GList *
946 g_resolver_lookup_records_finish (GResolver     *resolver,
947                                   GAsyncResult  *result,
948                                   GError       **error)
949 {
950   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
951   return G_RESOLVER_GET_CLASS (resolver)->
952     lookup_records_finish (resolver, result, error);
953 }
954
955 guint64
956 g_resolver_get_serial (GResolver *resolver)
957 {
958   g_return_val_if_fail (G_IS_RESOLVER (resolver), 0);
959
960   g_resolver_maybe_reload (resolver);
961
962 #ifdef G_OS_UNIX
963   return (guint64) resolver->priv->resolv_conf_timestamp;
964 #else
965   return 1;
966 #endif
967 }
968
969 /**
970  * g_resolver_error_quark:
971  *
972  * Gets the #GResolver Error Quark.
973  *
974  * Returns: a #GQuark.
975  *
976  * Since: 2.22
977  */
978 G_DEFINE_QUARK (g-resolver-error-quark, g_resolver_error)