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