Add support for MX, TXT, NS and SOA records to GResolver
[platform/upstream/glib.git] / gio / gresolver.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright (C) 2008 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include "glibintl.h"
26
27 #include "gresolver.h"
28 #include "gnetworkingprivate.h"
29 #include "gasyncresult.h"
30 #include "ginetaddress.h"
31 #include "ginetsocketaddress.h"
32 #include "gsimpleasyncresult.h"
33 #include "gsrvtarget.h"
34 #include "gthreadedresolver.h"
35
36 #ifdef G_OS_UNIX
37 #include <sys/stat.h>
38 #endif
39
40 #include <stdlib.h>
41
42
43 /**
44  * SECTION:gresolver
45  * @short_description: Asynchronous and cancellable DNS resolver
46  * @include: gio/gio.h
47  *
48  * #GResolver provides cancellable synchronous and asynchronous DNS
49  * resolution, for hostnames (g_resolver_lookup_by_address(),
50  * g_resolver_lookup_by_name() and their async variants) and SRV
51  * (service) records (g_resolver_lookup_service()).
52  *
53  * #GNetworkAddress and #GNetworkService provide wrappers around
54  * #GResolver functionality that also implement #GSocketConnectable,
55  * making it easy to connect to a remote host/service.
56  */
57
58 enum {
59   RELOAD,
60   LAST_SIGNAL
61 };
62
63 static guint signals[LAST_SIGNAL] = { 0 };
64
65 struct _GResolverPrivate {
66 #ifdef G_OS_UNIX
67   time_t resolv_conf_timestamp;
68 #else
69   int dummy;
70 #endif
71 };
72
73 /**
74  * GResolver:
75  *
76  * The object that handles DNS resolution. Use g_resolver_get_default()
77  * to get the default resolver.
78  */
79 G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT)
80
81 static GList *
82 srv_records_to_targets (GList *records)
83 {
84   const gchar *hostname;
85   guint16 port, priority, weight;
86   GSrvTarget *target;
87   GList *l;
88
89   for (l = records; l != NULL; l = g_list_next (l))
90     {
91       g_variant_get (l->data, "(qqq&s)", &priority, &weight, &port, &hostname);
92       target = g_srv_target_new (hostname, port, priority, weight);
93       g_variant_unref (l->data);
94       l->data = target;
95     }
96
97   return g_srv_target_list_sort (records);
98 }
99
100 static GList *
101 g_resolver_real_lookup_service (GResolver            *resolver,
102                                 const gchar          *rrname,
103                                 GCancellable         *cancellable,
104                                 GError              **error)
105 {
106   GList *records;
107
108   records = G_RESOLVER_GET_CLASS (resolver)->lookup_records (resolver,
109                                                              rrname,
110                                                              G_RESOLVER_RECORD_SRV,
111                                                              cancellable,
112                                                              error);
113
114   return srv_records_to_targets (records);
115 }
116
117 static void
118 g_resolver_real_lookup_service_async (GResolver            *resolver,
119                                       const gchar          *rrname,
120                                       GCancellable         *cancellable,
121                                       GAsyncReadyCallback   callback,
122                                       gpointer              user_data)
123 {
124   G_RESOLVER_GET_CLASS (resolver)->lookup_records_async (resolver,
125                                                          rrname,
126                                                          G_RESOLVER_RECORD_SRV,
127                                                          cancellable,
128                                                          callback,
129                                                          user_data);
130 }
131
132 static GList *
133 g_resolver_real_lookup_service_finish (GResolver            *resolver,
134                                        GAsyncResult         *result,
135                                        GError              **error)
136 {
137   GList *records;
138
139   records = G_RESOLVER_GET_CLASS (resolver)->lookup_records_finish (resolver,
140                                                                     result,
141                                                                     error);
142
143   return srv_records_to_targets (records);
144 }
145
146 static void
147 g_resolver_class_init (GResolverClass *resolver_class)
148 {
149   volatile GType type;
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   g_type_class_add_private (resolver_class, sizeof (GResolverPrivate));
157
158   /* Make sure _g_networking_init() has been called */
159   type = g_inet_address_get_type ();
160   (type); /* To avoid -Wunused-but-set-variable */
161
162   /* Initialize _g_resolver_addrinfo_hints */
163 #ifdef AI_ADDRCONFIG
164   _g_resolver_addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
165 #endif
166   /* These two don't actually matter, they just get copied into the
167    * returned addrinfo structures (and then we ignore them). But if
168    * we leave them unset, we'll get back duplicate answers.
169    */
170   _g_resolver_addrinfo_hints.ai_socktype = SOCK_STREAM;
171   _g_resolver_addrinfo_hints.ai_protocol = IPPROTO_TCP;
172
173   /**
174    * GResolver::reload:
175    * @resolver: a #GResolver
176    *
177    * Emitted when the resolver notices that the system resolver
178    * configuration has changed.
179    **/
180   signals[RELOAD] =
181     g_signal_new (I_("reload"),
182                   G_TYPE_RESOLVER,
183                   G_SIGNAL_RUN_LAST,
184                   G_STRUCT_OFFSET (GResolverClass, reload),
185                   NULL, NULL,
186                   g_cclosure_marshal_VOID__VOID,
187                   G_TYPE_NONE, 0);
188 }
189
190 static void
191 g_resolver_init (GResolver *resolver)
192 {
193 #ifdef G_OS_UNIX
194   struct stat st;
195 #endif
196
197   resolver->priv = G_TYPE_INSTANCE_GET_PRIVATE (resolver, G_TYPE_RESOLVER, GResolverPrivate);
198
199 #ifdef G_OS_UNIX
200   if (stat (_PATH_RESCONF, &st) == 0)
201     resolver->priv->resolv_conf_timestamp = st.st_mtime;
202 #endif
203 }
204
205 static GResolver *default_resolver;
206
207 /**
208  * g_resolver_get_default:
209  *
210  * Gets the default #GResolver. You should unref it when you are done
211  * with it. #GResolver may use its reference count as a hint about how
212  * many threads it should allocate for concurrent DNS resolutions.
213  *
214  * Return value: (transfer full): the default #GResolver.
215  *
216  * Since: 2.22
217  */
218 GResolver *
219 g_resolver_get_default (void)
220 {
221   if (!default_resolver)
222     default_resolver = g_object_new (G_TYPE_THREADED_RESOLVER, NULL);
223
224   return g_object_ref (default_resolver);
225 }
226
227 /**
228  * g_resolver_set_default:
229  * @resolver: the new default #GResolver
230  *
231  * Sets @resolver to be the application's default resolver (reffing
232  * @resolver, and unreffing the previous default resolver, if any).
233  * Future calls to g_resolver_get_default() will return this resolver.
234  *
235  * This can be used if an application wants to perform any sort of DNS
236  * caching or "pinning"; it can implement its own #GResolver that
237  * calls the original default resolver for DNS operations, and
238  * implements its own cache policies on top of that, and then set
239  * itself as the default resolver for all later code to use.
240  *
241  * Since: 2.22
242  */
243 void
244 g_resolver_set_default (GResolver *resolver)
245 {
246   if (default_resolver)
247     g_object_unref (default_resolver);
248   default_resolver = g_object_ref (resolver);
249 }
250
251
252 static void
253 g_resolver_maybe_reload (GResolver *resolver)
254 {
255 #ifdef G_OS_UNIX
256   struct stat st;
257
258   if (stat (_PATH_RESCONF, &st) == 0)
259     {
260       if (st.st_mtime != resolver->priv->resolv_conf_timestamp)
261         {
262           resolver->priv->resolv_conf_timestamp = st.st_mtime;
263           res_init ();
264           g_signal_emit (resolver, signals[RELOAD], 0);
265         }
266     }
267 #endif
268 }
269
270 /* filter out duplicates, cf. https://bugzilla.gnome.org/show_bug.cgi?id=631379 */
271 static void
272 remove_duplicates (GList *addrs)
273 {
274   GList *l;
275   GList *ll;
276   GList *lll;
277
278   /* TODO: if this is too slow (it's O(n^2) but n is typically really
279    * small), we can do something more clever but note that we must not
280    * change the order of elements...
281    */
282   for (l = addrs; l != NULL; l = l->next)
283     {
284       GInetAddress *address = G_INET_ADDRESS (l->data);
285       for (ll = l->next; ll != NULL; ll = lll)
286         {
287           GInetAddress *other_address = G_INET_ADDRESS (ll->data);
288           lll = ll->next;
289           if (g_inet_address_equal (address, other_address))
290             {
291               g_object_unref (other_address);
292               /* we never return the first element */
293               g_warn_if_fail (g_list_delete_link (addrs, ll) == addrs);
294             }
295         }
296     }
297 }
298
299
300 /**
301  * g_resolver_lookup_by_name:
302  * @resolver: a #GResolver
303  * @hostname: the hostname to look up
304  * @cancellable: (allow-none): a #GCancellable, or %NULL
305  * @error: return location for a #GError, or %NULL
306  *
307  * Synchronously resolves @hostname to determine its associated IP
308  * address(es). @hostname may be an ASCII-only or UTF-8 hostname, or
309  * the textual form of an IP address (in which case this just becomes
310  * a wrapper around g_inet_address_new_from_string()).
311  *
312  * On success, g_resolver_lookup_by_name() will return a #GList of
313  * #GInetAddress, sorted in order of preference and guaranteed to not
314  * contain duplicates. That is, if using the result to connect to
315  * @hostname, you should attempt to connect to the first address
316  * first, then the second if the first fails, etc. If you are using
317  * the result to listen on a socket, it is appropriate to add each
318  * result using e.g. g_socket_listener_add_address().
319  *
320  * If the DNS resolution fails, @error (if non-%NULL) will be set to a
321  * value from #GResolverError.
322  *
323  * If @cancellable is non-%NULL, it can be used to cancel the
324  * operation, in which case @error (if non-%NULL) will be set to
325  * %G_IO_ERROR_CANCELLED.
326  *
327  * If you are planning to connect to a socket on the resolved IP
328  * address, it may be easier to create a #GNetworkAddress and use its
329  * #GSocketConnectable interface.
330  *
331  * Return value: (element-type GInetAddress) (transfer full): a #GList
332  * of #GInetAddress, or %NULL on error. You
333  * must unref each of the addresses and free the list when you are
334  * done with it. (You can use g_resolver_free_addresses() to do this.)
335  *
336  * Since: 2.22
337  */
338 GList *
339 g_resolver_lookup_by_name (GResolver     *resolver,
340                            const gchar   *hostname,
341                            GCancellable  *cancellable,
342                            GError       **error)
343 {
344   GInetAddress *addr;
345   GList *addrs;
346   gchar *ascii_hostname = NULL;
347
348   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
349   g_return_val_if_fail (hostname != NULL, NULL);
350
351   /* Check if @hostname is just an IP address */
352   addr = g_inet_address_new_from_string (hostname);
353   if (addr)
354     return g_list_append (NULL, addr);
355
356   if (g_hostname_is_non_ascii (hostname))
357     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
358
359   g_resolver_maybe_reload (resolver);
360   addrs = G_RESOLVER_GET_CLASS (resolver)->
361     lookup_by_name (resolver, hostname, cancellable, error);
362
363   remove_duplicates (addrs);
364
365   g_free (ascii_hostname);
366   return addrs;
367 }
368
369 /**
370  * g_resolver_lookup_by_name_async:
371  * @resolver: a #GResolver
372  * @hostname: the hostname to look up the address of
373  * @cancellable: (allow-none): a #GCancellable, or %NULL
374  * @callback: (scope async): callback to call after resolution completes
375  * @user_data: (closure): data for @callback
376  *
377  * Begins asynchronously resolving @hostname to determine its
378  * associated IP address(es), and eventually calls @callback, which
379  * must call g_resolver_lookup_by_name_finish() to get the result.
380  * See g_resolver_lookup_by_name() for more details.
381  *
382  * Since: 2.22
383  */
384 void
385 g_resolver_lookup_by_name_async (GResolver           *resolver,
386                                  const gchar         *hostname,
387                                  GCancellable        *cancellable,
388                                  GAsyncReadyCallback  callback,
389                                  gpointer             user_data)
390 {
391   GInetAddress *addr;
392   gchar *ascii_hostname = NULL;
393
394   g_return_if_fail (G_IS_RESOLVER (resolver));
395   g_return_if_fail (hostname != NULL);
396
397   /* Check if @hostname is just an IP address */
398   addr = g_inet_address_new_from_string (hostname);
399   if (addr)
400     {
401       GSimpleAsyncResult *simple;
402
403       simple = g_simple_async_result_new (G_OBJECT (resolver),
404                                           callback, user_data,
405                                           g_resolver_lookup_by_name_async);
406
407       g_simple_async_result_set_op_res_gpointer (simple, addr, g_object_unref);
408       g_simple_async_result_complete_in_idle (simple);
409       g_object_unref (simple);
410       return;
411     }
412
413   if (g_hostname_is_non_ascii (hostname))
414     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
415
416   g_resolver_maybe_reload (resolver);
417   G_RESOLVER_GET_CLASS (resolver)->
418     lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
419
420   g_free (ascii_hostname);
421 }
422
423 /**
424  * g_resolver_lookup_by_name_finish:
425  * @resolver: a #GResolver
426  * @result: the result passed to your #GAsyncReadyCallback
427  * @error: return location for a #GError, or %NULL
428  *
429  * Retrieves the result of a call to
430  * g_resolver_lookup_by_name_async().
431  *
432  * If the DNS resolution failed, @error (if non-%NULL) will be set to
433  * a value from #GResolverError. If the operation was cancelled,
434  * @error will be set to %G_IO_ERROR_CANCELLED.
435  *
436  * Return value: (element-type GInetAddress) (transfer full): a #GList
437  * of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
438  * for more details.
439  *
440  * Since: 2.22
441  */
442 GList *
443 g_resolver_lookup_by_name_finish (GResolver     *resolver,
444                                   GAsyncResult  *result,
445                                   GError       **error)
446 {
447   GList *addrs;
448
449   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
450
451   if (G_IS_SIMPLE_ASYNC_RESULT (result))
452     {
453       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
454
455       if (g_simple_async_result_propagate_error (simple, error))
456         return NULL;
457
458       /* Handle the stringified-IP-addr case */
459       if (g_simple_async_result_get_source_tag (simple) == g_resolver_lookup_by_name_async)
460         {
461           GInetAddress *addr;
462
463           addr = g_simple_async_result_get_op_res_gpointer (simple);
464           return g_list_append (NULL, g_object_ref (addr));
465         }
466     }
467
468   addrs = G_RESOLVER_GET_CLASS (resolver)->
469     lookup_by_name_finish (resolver, result, error);
470
471   remove_duplicates (addrs);
472
473   return addrs;
474 }
475
476 /**
477  * g_resolver_free_addresses: (skip)
478  * @addresses: a #GList of #GInetAddress
479  *
480  * Frees @addresses (which should be the return value from
481  * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_finish()).
482  * (This is a convenience method; you can also simply free the results
483  * by hand.)
484  *
485  * Since: 2.22
486  */
487 void
488 g_resolver_free_addresses (GList *addresses)
489 {
490   GList *a;
491
492   for (a = addresses; a; a = a->next)
493     g_object_unref (a->data);
494   g_list_free (addresses);
495 }
496
497 /**
498  * g_resolver_lookup_by_address:
499  * @resolver: a #GResolver
500  * @address: the address to reverse-resolve
501  * @cancellable: (allow-none): a #GCancellable, or %NULL
502  * @error: return location for a #GError, or %NULL
503  *
504  * Synchronously reverse-resolves @address to determine its
505  * associated hostname.
506  *
507  * If the DNS resolution fails, @error (if non-%NULL) will be set to
508  * a value from #GResolverError.
509  *
510  * If @cancellable is non-%NULL, it can be used to cancel the
511  * operation, in which case @error (if non-%NULL) will be set to
512  * %G_IO_ERROR_CANCELLED.
513  *
514  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
515  *     form), or %NULL on error.
516  *
517  * Since: 2.22
518  */
519 gchar *
520 g_resolver_lookup_by_address (GResolver     *resolver,
521                               GInetAddress  *address,
522                               GCancellable  *cancellable,
523                               GError       **error)
524 {
525   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
526   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
527
528   g_resolver_maybe_reload (resolver);
529   return G_RESOLVER_GET_CLASS (resolver)->
530     lookup_by_address (resolver, address, cancellable, error);
531 }
532
533 /**
534  * g_resolver_lookup_by_address_async:
535  * @resolver: a #GResolver
536  * @address: the address to reverse-resolve
537  * @cancellable: (allow-none): a #GCancellable, or %NULL
538  * @callback: (scope async): callback to call after resolution completes
539  * @user_data: (closure): data for @callback
540  *
541  * Begins asynchronously reverse-resolving @address to determine its
542  * associated hostname, and eventually calls @callback, which must
543  * call g_resolver_lookup_by_address_finish() to get the final result.
544  *
545  * Since: 2.22
546  */
547 void
548 g_resolver_lookup_by_address_async (GResolver           *resolver,
549                                     GInetAddress        *address,
550                                     GCancellable        *cancellable,
551                                     GAsyncReadyCallback  callback,
552                                     gpointer             user_data)
553 {
554   g_return_if_fail (G_IS_RESOLVER (resolver));
555   g_return_if_fail (G_IS_INET_ADDRESS (address));
556
557   g_resolver_maybe_reload (resolver);
558   G_RESOLVER_GET_CLASS (resolver)->
559     lookup_by_address_async (resolver, address, cancellable, callback, user_data);
560 }
561
562 /**
563  * g_resolver_lookup_by_address_finish:
564  * @resolver: a #GResolver
565  * @result: the result passed to your #GAsyncReadyCallback
566  * @error: return location for a #GError, or %NULL
567  *
568  * Retrieves the result of a previous call to
569  * g_resolver_lookup_by_address_async().
570  *
571  * If the DNS resolution failed, @error (if non-%NULL) will be set to
572  * a value from #GResolverError. If the operation was cancelled,
573  * @error will be set to %G_IO_ERROR_CANCELLED.
574  *
575  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
576  * form), or %NULL on error.
577  *
578  * Since: 2.22
579  */
580 gchar *
581 g_resolver_lookup_by_address_finish (GResolver     *resolver,
582                                      GAsyncResult  *result,
583                                      GError       **error)
584 {
585   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
586
587   if (G_IS_SIMPLE_ASYNC_RESULT (result))
588     {
589       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
590
591       if (g_simple_async_result_propagate_error (simple, error))
592         return NULL;
593     }
594
595   return G_RESOLVER_GET_CLASS (resolver)->
596     lookup_by_address_finish (resolver, result, error);
597 }
598
599 static gchar *
600 g_resolver_get_service_rrname (const char *service,
601                                const char *protocol,
602                                const char *domain)
603 {
604   gchar *rrname, *ascii_domain = NULL;
605
606   if (g_hostname_is_non_ascii (domain))
607     domain = ascii_domain = g_hostname_to_ascii (domain);
608
609   rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
610
611   g_free (ascii_domain);
612   return rrname;
613 }
614
615 /**
616  * g_resolver_lookup_service:
617  * @resolver: a #GResolver
618  * @service: the service type to look up (eg, "ldap")
619  * @protocol: the networking protocol to use for @service (eg, "tcp")
620  * @domain: the DNS domain to look up the service in
621  * @cancellable: (allow-none): a #GCancellable, or %NULL
622  * @error: return location for a #GError, or %NULL
623  *
624  * Synchronously performs a DNS SRV lookup for the given @service and
625  * @protocol in the given @domain and returns an array of #GSrvTarget.
626  * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
627  * @service and @protocol arguments <emphasis>do not</emphasis>
628  * include the leading underscore that appears in the actual DNS
629  * entry.
630  *
631  * On success, g_resolver_lookup_service() will return a #GList of
632  * #GSrvTarget, sorted in order of preference. (That is, you should
633  * attempt to connect to the first target first, then the second if
634  * the first fails, etc.)
635  *
636  * If the DNS resolution fails, @error (if non-%NULL) will be set to
637  * a value from #GResolverError.
638  *
639  * If @cancellable is non-%NULL, it can be used to cancel the
640  * operation, in which case @error (if non-%NULL) will be set to
641  * %G_IO_ERROR_CANCELLED.
642  *
643  * If you are planning to connect to the service, it is usually easier
644  * to create a #GNetworkService and use its #GSocketConnectable
645  * interface.
646  *
647  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
648  * or %NULL on error. You must free each of the targets and the list when you are
649  * done with it. (You can use g_resolver_free_targets() to do this.)
650  *
651  * Since: 2.22
652  */
653 GList *
654 g_resolver_lookup_service (GResolver     *resolver,
655                            const gchar   *service,
656                            const gchar   *protocol,
657                            const gchar   *domain,
658                            GCancellable  *cancellable,
659                            GError       **error)
660 {
661   GList *targets;
662   gchar *rrname;
663
664   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
665   g_return_val_if_fail (service != NULL, NULL);
666   g_return_val_if_fail (protocol != NULL, NULL);
667   g_return_val_if_fail (domain != NULL, NULL);
668
669   rrname = g_resolver_get_service_rrname (service, protocol, domain);
670
671   g_resolver_maybe_reload (resolver);
672   targets = G_RESOLVER_GET_CLASS (resolver)->
673     lookup_service (resolver, rrname, cancellable, error);
674
675   g_free (rrname);
676   return targets;
677 }
678
679 /**
680  * g_resolver_lookup_service_async:
681  * @resolver: a #GResolver
682  * @service: the service type to look up (eg, "ldap")
683  * @protocol: the networking protocol to use for @service (eg, "tcp")
684  * @domain: the DNS domain to look up the service in
685  * @cancellable: (allow-none): a #GCancellable, or %NULL
686  * @callback: (scope async): callback to call after resolution completes
687  * @user_data: (closure): data for @callback
688  *
689  * Begins asynchronously performing a DNS SRV lookup for the given
690  * @service and @protocol in the given @domain, and eventually calls
691  * @callback, which must call g_resolver_lookup_service_finish() to
692  * get the final result. See g_resolver_lookup_service() for more
693  * details.
694  *
695  * Since: 2.22
696  */
697 void
698 g_resolver_lookup_service_async (GResolver           *resolver,
699                                  const gchar         *service,
700                                  const gchar         *protocol,
701                                  const gchar         *domain,
702                                  GCancellable        *cancellable,
703                                  GAsyncReadyCallback  callback,
704                                  gpointer             user_data)
705 {
706   gchar *rrname;
707
708   g_return_if_fail (G_IS_RESOLVER (resolver));
709   g_return_if_fail (service != NULL);
710   g_return_if_fail (protocol != NULL);
711   g_return_if_fail (domain != NULL);
712
713   rrname = g_resolver_get_service_rrname (service, protocol, domain);
714
715   g_resolver_maybe_reload (resolver);
716   G_RESOLVER_GET_CLASS (resolver)->
717     lookup_service_async (resolver, rrname, cancellable, callback, user_data);
718
719   g_free (rrname);
720 }
721
722 /**
723  * g_resolver_lookup_service_finish:
724  * @resolver: a #GResolver
725  * @result: the result passed to your #GAsyncReadyCallback
726  * @error: return location for a #GError, or %NULL
727  *
728  * Retrieves the result of a previous call to
729  * g_resolver_lookup_service_async().
730  *
731  * If the DNS resolution failed, @error (if non-%NULL) will be set to
732  * a value from #GResolverError. If the operation was cancelled,
733  * @error will be set to %G_IO_ERROR_CANCELLED.
734  *
735  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
736  * or %NULL on error. See g_resolver_lookup_service() for more details.
737  *
738  * Since: 2.22
739  */
740 GList *
741 g_resolver_lookup_service_finish (GResolver     *resolver,
742                                   GAsyncResult  *result,
743                                   GError       **error)
744 {
745   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
746
747   if (G_IS_SIMPLE_ASYNC_RESULT (result))
748     {
749       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
750
751       if (g_simple_async_result_propagate_error (simple, error))
752         return NULL;
753     }
754
755   return G_RESOLVER_GET_CLASS (resolver)->
756     lookup_service_finish (resolver, result, error);
757 }
758
759 /**
760  * g_resolver_free_targets: (skip)
761  * @targets: a #GList of #GSrvTarget
762  *
763  * Frees @targets (which should be the return value from
764  * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
765  * (This is a convenience method; you can also simply free the
766  * results by hand.)
767  *
768  * Since: 2.22
769  */
770 void
771 g_resolver_free_targets (GList *targets)
772 {
773   GList *t;
774
775   for (t = targets; t; t = t->next)
776     g_srv_target_free (t->data);
777   g_list_free (targets);
778 }
779
780 /**
781  * g_resolver_lookup_records:
782  * @resolver: a #GResolver
783  * @rrname: the DNS name to lookup the record for
784  * @record_type: the type of DNS record to lookup
785  * @cancellable: (allow-none): a #GCancellable, or %NULL
786  * @error: return location for a #GError, or %NULL
787  *
788  * Synchronously performs a DNS record lookup for the given @rrname and returns
789  * a list of records as #GVariant tuples. See #GResolverRecordType for
790  * information on what the records contain for each @record_type.
791  *
792  * If the DNS resolution fails, @error (if non-%NULL) will be set to
793  * a value from #GResolverError.
794  *
795  * If @cancellable is non-%NULL, it can be used to cancel the
796  * operation, in which case @error (if non-%NULL) will be set to
797  * %G_IO_ERROR_CANCELLED.
798  *
799  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
800  * or %NULL on error. You must free each of the records and the list when you are
801  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
802  *
803  * Since: 2.34
804  */
805 GList *
806 g_resolver_lookup_records (GResolver            *resolver,
807                            const gchar          *rrname,
808                            GResolverRecordType   record_type,
809                            GCancellable         *cancellable,
810                            GError              **error)
811 {
812   GList *records;
813
814   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
815   g_return_val_if_fail (rrname != NULL, NULL);
816
817   g_resolver_maybe_reload (resolver);
818   records = G_RESOLVER_GET_CLASS (resolver)->
819     lookup_records (resolver, rrname, record_type, cancellable, error);
820
821   return records;
822 }
823
824 /**
825  * g_resolver_lookup_records_async:
826  * @resolver: a #GResolver
827  * @rrname: the DNS name to lookup the record for
828  * @record_type: the type of DNS record to lookup
829  * @cancellable: (allow-none): a #GCancellable, or %NULL
830  * @callback: (scope async): callback to call after resolution completes
831  * @user_data: (closure): data for @callback
832  *
833  * Begins asynchronously performing a DNS lookup for the given
834  * @rrname, and eventually calls @callback, which must call
835  * g_resolver_lookup_records_finish() to get the final result. See
836  * g_resolver_lookup_records() for more details.
837  *
838  * Since: 2.34
839  */
840 void
841 g_resolver_lookup_records_async (GResolver           *resolver,
842                                  const gchar         *rrname,
843                                  GResolverRecordType  record_type,
844                                  GCancellable        *cancellable,
845                                  GAsyncReadyCallback  callback,
846                                  gpointer             user_data)
847 {
848   g_return_if_fail (G_IS_RESOLVER (resolver));
849   g_return_if_fail (rrname != NULL);
850
851   g_resolver_maybe_reload (resolver);
852   G_RESOLVER_GET_CLASS (resolver)->
853     lookup_records_async (resolver, rrname, record_type, cancellable, callback, user_data);
854 }
855
856 /**
857  * g_resolver_lookup_records_finish:
858  * @resolver: a #GResolver
859  * @result: the result passed to your #GAsyncReadyCallback
860  * @error: return location for a #GError, or %NULL
861  *
862  * Retrieves the result of a previous call to
863  * g_resolver_lookup_records_async(). Returns a list of records as #GVariant
864  * tuples. See #GResolverRecordType for information on what the records contain.
865  *
866  * If the DNS resolution failed, @error (if non-%NULL) will be set to
867  * a value from #GResolverError. If the operation was cancelled,
868  * @error will be set to %G_IO_ERROR_CANCELLED.
869  *
870  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
871  * or %NULL on error. You must free each of the records and the list when you are
872  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
873  *
874  * Since: 2.34
875  */
876 GList *
877 g_resolver_lookup_records_finish (GResolver     *resolver,
878                                   GAsyncResult  *result,
879                                   GError       **error)
880 {
881   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
882   return G_RESOLVER_GET_CLASS (resolver)->
883     lookup_records_finish (resolver, result, error);
884 }
885
886 /**
887  * g_resolver_error_quark:
888  *
889  * Gets the #GResolver Error Quark.
890  *
891  * Return value: a #GQuark.
892  *
893  * Since: 2.22
894  */
895 GQuark
896 g_resolver_error_quark (void)
897 {
898   return g_quark_from_static_string ("g-resolver-error-quark");
899 }
900
901
902 static GResolverError
903 g_resolver_error_from_addrinfo_error (gint err)
904 {
905   switch (err)
906     {
907     case EAI_FAIL:
908 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
909     case EAI_NODATA:
910 #endif
911     case EAI_NONAME:
912       return G_RESOLVER_ERROR_NOT_FOUND;
913
914     case EAI_AGAIN:
915       return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
916
917     default:
918       return G_RESOLVER_ERROR_INTERNAL;
919     }
920 }
921
922 struct addrinfo _g_resolver_addrinfo_hints;
923
924 /* Private method to process a getaddrinfo() response. */
925 GList *
926 _g_resolver_addresses_from_addrinfo (const char       *hostname,
927                                      struct addrinfo  *res,
928                                      gint              gai_retval,
929                                      GError          **error)
930 {
931   struct addrinfo *ai;
932   GSocketAddress *sockaddr;
933   GInetAddress *addr;
934   GList *addrs;
935
936   if (gai_retval != 0)
937     {
938       g_set_error (error, G_RESOLVER_ERROR,
939                    g_resolver_error_from_addrinfo_error (gai_retval),
940                    _("Error resolving '%s': %s"),
941                    hostname, gai_strerror (gai_retval));
942       return NULL;
943     }
944
945   g_return_val_if_fail (res != NULL, NULL);
946
947   addrs = NULL;
948   for (ai = res; ai; ai = ai->ai_next)
949     {
950       sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
951       if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
952         continue;
953
954       addr = g_object_ref (g_inet_socket_address_get_address ((GInetSocketAddress *)sockaddr));
955       addrs = g_list_prepend (addrs, addr);
956       g_object_unref (sockaddr);
957     }
958
959   return g_list_reverse (addrs);
960 }
961
962 /* Private method to set up a getnameinfo() request */
963 void
964 _g_resolver_address_to_sockaddr (GInetAddress            *address,
965                                  struct sockaddr_storage *sa,
966                                  gsize                   *len)
967 {
968   GSocketAddress *sockaddr;
969
970   sockaddr = g_inet_socket_address_new (address, 0);
971   g_socket_address_to_native (sockaddr, (struct sockaddr *)sa, sizeof (*sa), NULL);
972   *len = g_socket_address_get_native_size (sockaddr);
973   g_object_unref (sockaddr);
974 }
975
976 /* Private method to process a getnameinfo() response. */
977 char *
978 _g_resolver_name_from_nameinfo (GInetAddress  *address,
979                                 const gchar   *name,
980                                 gint           gni_retval,
981                                 GError       **error)
982 {
983   if (gni_retval != 0)
984     {
985       gchar *phys;
986
987       phys = g_inet_address_to_string (address);
988       g_set_error (error, G_RESOLVER_ERROR,
989                    g_resolver_error_from_addrinfo_error (gni_retval),
990                    _("Error reverse-resolving '%s': %s"),
991                    phys ? phys : "(unknown)", gai_strerror (gni_retval));
992       g_free (phys);
993       return NULL;
994     }
995
996   return g_strdup (name);
997 }
998
999 #if defined(G_OS_UNIX)
1000 static GVariant *
1001 parse_res_srv (guchar  *answer,
1002                guchar  *end,
1003                guchar **p)
1004 {
1005   gchar namebuf[1024];
1006   guint16 priority, weight, port;
1007
1008   GETSHORT (priority, *p);
1009   GETSHORT (weight, *p);
1010   GETSHORT (port, *p);
1011   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
1012
1013   return g_variant_new ("(qqqs)",
1014                         priority,
1015                         weight,
1016                         port,
1017                         namebuf);
1018 }
1019
1020 static GVariant *
1021 parse_res_soa (guchar  *answer,
1022                guchar  *end,
1023                guchar **p)
1024 {
1025   gchar mnamebuf[1024];
1026   gchar rnamebuf[1024];
1027   guint32 serial, refresh, retry, expire, ttl;
1028
1029   *p += dn_expand (answer, end, *p, mnamebuf, sizeof (mnamebuf));
1030   *p += dn_expand (answer, end, *p, rnamebuf, sizeof (rnamebuf));
1031
1032   GETLONG (serial, *p);
1033   GETLONG (refresh, *p);
1034   GETLONG (retry, *p);
1035   GETLONG (expire, *p);
1036   GETLONG (ttl, *p);
1037
1038   return g_variant_new ("(ssuuuuu)",
1039                         mnamebuf,
1040                         rnamebuf,
1041                         serial,
1042                         refresh,
1043                         retry,
1044                         expire,
1045                         ttl);
1046 }
1047
1048 static GVariant *
1049 parse_res_ns (guchar  *answer,
1050               guchar  *end,
1051               guchar **p)
1052 {
1053   gchar namebuf[1024];
1054
1055   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
1056
1057   return g_variant_new ("(s)", namebuf);
1058 }
1059
1060 static GVariant *
1061 parse_res_mx (guchar  *answer,
1062               guchar  *end,
1063               guchar **p)
1064 {
1065   gchar namebuf[1024];
1066   guint16 preference;
1067
1068   GETSHORT (preference, *p);
1069
1070   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
1071
1072   return g_variant_new ("(qs)",
1073                         preference,
1074                         namebuf);
1075 }
1076
1077 static GVariant *
1078 parse_res_txt (guchar  *answer,
1079                guchar  *end,
1080                guchar **p)
1081 {
1082   GVariant *record;
1083   GPtrArray *array;
1084   guchar *at = *p;
1085   gsize len;
1086
1087   array = g_ptr_array_new_with_free_func (g_free);
1088   while (at < end)
1089     {
1090       len = *(at++);
1091       if (len > at - end)
1092         break;
1093       g_ptr_array_add (array, g_strndup ((gchar *)at, len));
1094       at += len;
1095     }
1096
1097   *p = at;
1098   record = g_variant_new ("(@as)",
1099                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
1100   g_ptr_array_free (array, TRUE);
1101   return record;
1102 }
1103
1104 gint
1105 _g_resolver_record_type_to_rrtype (GResolverRecordType type)
1106 {
1107   switch (type)
1108   {
1109     case G_RESOLVER_RECORD_SRV:
1110       return T_SRV;
1111     case G_RESOLVER_RECORD_TXT:
1112       return T_TXT;
1113     case G_RESOLVER_RECORD_SOA:
1114       return T_SOA;
1115     case G_RESOLVER_RECORD_NS:
1116       return T_NS;
1117     case G_RESOLVER_RECORD_MX:
1118       return T_MX;
1119   }
1120   g_return_val_if_reached (-1);
1121 }
1122
1123 /* Private method to process a res_query response into GSrvTargets */
1124 GList *
1125 _g_resolver_records_from_res_query (const gchar      *rrname,
1126                                     gint              rrtype,
1127                                     guchar           *answer,
1128                                     gint              len,
1129                                     gint              herr,
1130                                     GError          **error)
1131 {
1132   gint count;
1133   gchar namebuf[1024];
1134   guchar *end, *p;
1135   guint16 type, qclass, rdlength;
1136   guint32 ttl;
1137   HEADER *header;
1138   GList *records;
1139   GVariant *record;
1140
1141   if (len <= 0)
1142     {
1143       GResolverError errnum;
1144       const gchar *format;
1145
1146       if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
1147         {
1148           errnum = G_RESOLVER_ERROR_NOT_FOUND;
1149           format = _("No DNS record of the requested type for '%s'");
1150         }
1151       else if (herr == TRY_AGAIN)
1152         {
1153           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
1154           format = _("Temporarily unable to resolve '%s'");
1155         }
1156       else
1157         {
1158           errnum = G_RESOLVER_ERROR_INTERNAL;
1159           format = _("Error resolving '%s'");
1160         }
1161
1162       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
1163       return NULL;
1164     }
1165
1166   records = NULL;
1167
1168   header = (HEADER *)answer;
1169   p = answer + sizeof (HEADER);
1170   end = answer + len;
1171
1172   /* Skip query */
1173   count = ntohs (header->qdcount);
1174   while (count-- && p < end)
1175     {
1176       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
1177       p += 4;
1178
1179       /* To silence gcc warnings */
1180       namebuf[0] = namebuf[1];
1181     }
1182
1183   /* Read answers */
1184   count = ntohs (header->ancount);
1185   while (count-- && p < end)
1186     {
1187       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
1188       GETSHORT (type, p);
1189       GETSHORT (qclass, p);
1190       GETLONG  (ttl, p);
1191       ttl = ttl; /* To avoid -Wunused-but-set-variable */
1192       GETSHORT (rdlength, p);
1193
1194       if (type != rrtype || qclass != C_IN)
1195         {
1196           p += rdlength;
1197           continue;
1198         }
1199
1200       switch (rrtype)
1201         {
1202         case T_SRV:
1203           record = parse_res_srv (answer, end, &p);
1204           break;
1205         case T_MX:
1206           record = parse_res_mx (answer, end, &p);
1207           break;
1208         case T_SOA:
1209           record = parse_res_soa (answer, end, &p);
1210           break;
1211         case T_NS:
1212           record = parse_res_ns (answer, end, &p);
1213           break;
1214         case T_TXT:
1215           record = parse_res_txt (answer, p + rdlength, &p);
1216           break;
1217         default:
1218           g_warn_if_reached ();
1219           record = NULL;
1220           break;
1221         }
1222
1223       if (record != NULL)
1224         records = g_list_prepend (records, record);
1225     }
1226
1227     return records;
1228 }
1229
1230 #elif defined(G_OS_WIN32)
1231 static GVariant *
1232 parse_dns_srv (DNS_RECORD *rec)
1233 {
1234   return g_variant_new ("(qqqs)",
1235                         (guint16)rec->Data.SRV.wPriority,
1236                         (guint16)rec->Data.SRV.wWeight,
1237                         (guint16)rec->Data.SRV.wPort,
1238                         rec->Data.SRV.pNameTarget);
1239 }
1240
1241 static GVariant *
1242 parse_dns_soa (DNS_RECORD *rec)
1243 {
1244   return g_variant_new ("(ssuuuuu)",
1245                         rec->Data.SOA.pNamePrimaryServer,
1246                         rec->Data.SOA.pNameAdministrator,
1247                         (guint32)rec->Data.SOA.dwSerialNo,
1248                         (guint32)rec->Data.SOA.dwRefresh,
1249                         (guint32)rec->Data.SOA.dwRetry,
1250                         (guint32)rec->Data.SOA.dwExpire,
1251                         (guint32)rec->Data.SOA.dwDefaultTtl);
1252 }
1253
1254 static GVariant *
1255 parse_dns_ns (DNS_RECORD *rec)
1256 {
1257   return g_variant_new ("(s)", rec->Data.NS.pNameHost);
1258 }
1259
1260 static GVariant *
1261 parse_dns_mx (DNS_RECORD *rec)
1262 {
1263   return g_variant_new ("(qs)",
1264                         (guint16)rec->Data.MX.wPreference,
1265                         rec->Data.MX.pNameExchange);
1266 }
1267
1268 static GVariant *
1269 parse_dns_txt (DNS_RECORD *rec)
1270 {
1271   GVariant *record;
1272   GPtrArray *array;
1273   DWORD i;
1274
1275   array = g_ptr_array_new ();
1276   for (i = 0; i < rec->Data.TXT.dwStringCount; i++)
1277     g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]);
1278   record = g_variant_new ("(@as)",
1279                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
1280   g_ptr_array_free (array, TRUE);
1281   return record;
1282 }
1283
1284 WORD
1285 _g_resolver_record_type_to_dnstype (GResolverRecordType type)
1286 {
1287   switch (type)
1288   {
1289     case G_RESOLVER_RECORD_SRV:
1290       return DNS_TYPE_SRV;
1291     case G_RESOLVER_RECORD_TXT:
1292       return DNS_TYPE_TEXT;
1293     case G_RESOLVER_RECORD_SOA:
1294       return DNS_TYPE_SOA;
1295     case G_RESOLVER_RECORD_NS:
1296       return DNS_TYPE_NS;
1297     case G_RESOLVER_RECORD_MX:
1298       return DNS_TYPE_MX;
1299   }
1300   g_return_val_if_reached (-1);
1301 }
1302
1303 /* Private method to process a DnsQuery response into GVariants */
1304 GList *
1305 _g_resolver_records_from_DnsQuery (const gchar  *rrname,
1306                                    WORD          dnstype,
1307                                    DNS_STATUS    status,
1308                                    DNS_RECORD   *results,
1309                                    GError      **error)
1310 {
1311   DNS_RECORD *rec;
1312   gpointer record;
1313   GList *records;
1314
1315   if (status != ERROR_SUCCESS)
1316     {
1317       GResolverError errnum;
1318       const gchar *format;
1319
1320       if (status == DNS_ERROR_RCODE_NAME_ERROR)
1321         {
1322           errnum = G_RESOLVER_ERROR_NOT_FOUND;
1323           format = _("No DNS record of the requested type for '%s'");
1324         }
1325       else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
1326         {
1327           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
1328           format = _("Temporarily unable to resolve '%s'");
1329         }
1330       else
1331         {
1332           errnum = G_RESOLVER_ERROR_INTERNAL;
1333           format = _("Error resolving '%s'");
1334         }
1335
1336       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
1337       return NULL;
1338     }
1339
1340   records = NULL;
1341   for (rec = results; rec; rec = rec->pNext)
1342     {
1343       if (rec->wType != dnstype)
1344         continue;
1345       switch (dnstype)
1346         {
1347         case DNS_TYPE_SRV:
1348           record = parse_dns_srv (rec);
1349           break;
1350         case DNS_TYPE_SOA:
1351           record = parse_dns_soa (rec);
1352           break;
1353         case DNS_TYPE_NS:
1354           record = parse_dns_ns (rec);
1355           break;
1356         case DNS_TYPE_MX:
1357           record = parse_dns_mx (rec);
1358           break;
1359         case DNS_TYPE_TEXT:
1360           record = parse_dns_txt (rec);
1361           break;
1362         default:
1363           g_warn_if_reached ();
1364           record = NULL;
1365           break;
1366         }
1367       if (record != NULL)
1368         records = g_list_prepend (records, g_variant_ref_sink (record));
1369     }
1370
1371   return records;
1372 }
1373
1374 #endif