e92715752f5c282d42af16adf587eb002efb953c
[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 "gtask.h"
34 #include "gsrvtarget.h"
35 #include "gthreadedresolver.h"
36
37 #ifdef G_OS_UNIX
38 #include <sys/stat.h>
39 #endif
40
41 #include <stdlib.h>
42
43
44 /**
45  * SECTION:gresolver
46  * @short_description: Asynchronous and cancellable DNS resolver
47  * @include: gio/gio.h
48  *
49  * #GResolver provides cancellable synchronous and asynchronous DNS
50  * resolution, for hostnames (g_resolver_lookup_by_address(),
51  * g_resolver_lookup_by_name() and their async variants) and SRV
52  * (service) records (g_resolver_lookup_service()).
53  *
54  * #GNetworkAddress and #GNetworkService provide wrappers around
55  * #GResolver functionality that also implement #GSocketConnectable,
56  * making it easy to connect to a remote host/service.
57  */
58
59 enum {
60   RELOAD,
61   LAST_SIGNAL
62 };
63
64 static guint signals[LAST_SIGNAL] = { 0 };
65
66 struct _GResolverPrivate {
67 #ifdef G_OS_UNIX
68   time_t resolv_conf_timestamp;
69 #else
70   int dummy;
71 #endif
72 };
73
74 /**
75  * GResolver:
76  *
77  * The object that handles DNS resolution. Use g_resolver_get_default()
78  * to get the default resolver.
79  */
80 G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT)
81
82 static GList *
83 srv_records_to_targets (GList *records)
84 {
85   const gchar *hostname;
86   guint16 port, priority, weight;
87   GSrvTarget *target;
88   GList *l;
89
90   for (l = records; l != NULL; l = g_list_next (l))
91     {
92       g_variant_get (l->data, "(qqq&s)", &priority, &weight, &port, &hostname);
93       target = g_srv_target_new (hostname, port, priority, weight);
94       g_variant_unref (l->data);
95       l->data = target;
96     }
97
98   return g_srv_target_list_sort (records);
99 }
100
101 static GList *
102 g_resolver_real_lookup_service (GResolver            *resolver,
103                                 const gchar          *rrname,
104                                 GCancellable         *cancellable,
105                                 GError              **error)
106 {
107   GList *records;
108
109   records = G_RESOLVER_GET_CLASS (resolver)->lookup_records (resolver,
110                                                              rrname,
111                                                              G_RESOLVER_RECORD_SRV,
112                                                              cancellable,
113                                                              error);
114
115   return srv_records_to_targets (records);
116 }
117
118 static void
119 g_resolver_real_lookup_service_async (GResolver            *resolver,
120                                       const gchar          *rrname,
121                                       GCancellable         *cancellable,
122                                       GAsyncReadyCallback   callback,
123                                       gpointer              user_data)
124 {
125   G_RESOLVER_GET_CLASS (resolver)->lookup_records_async (resolver,
126                                                          rrname,
127                                                          G_RESOLVER_RECORD_SRV,
128                                                          cancellable,
129                                                          callback,
130                                                          user_data);
131 }
132
133 static GList *
134 g_resolver_real_lookup_service_finish (GResolver            *resolver,
135                                        GAsyncResult         *result,
136                                        GError              **error)
137 {
138   GList *records;
139
140   records = G_RESOLVER_GET_CLASS (resolver)->lookup_records_finish (resolver,
141                                                                     result,
142                                                                     error);
143
144   return srv_records_to_targets (records);
145 }
146
147 static void
148 g_resolver_class_init (GResolverClass *resolver_class)
149 {
150   /* Automatically pass these over to the lookup_records methods */
151   resolver_class->lookup_service = g_resolver_real_lookup_service;
152   resolver_class->lookup_service_async = g_resolver_real_lookup_service_async;
153   resolver_class->lookup_service_finish = g_resolver_real_lookup_service_finish;
154
155   g_type_class_add_private (resolver_class, sizeof (GResolverPrivate));
156
157   /* Make sure _g_networking_init() has been called */
158   g_type_ensure (G_TYPE_INET_ADDRESS);
159
160   /* Initialize _g_resolver_addrinfo_hints */
161 #ifdef AI_ADDRCONFIG
162   _g_resolver_addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
163 #endif
164   /* These two don't actually matter, they just get copied into the
165    * returned addrinfo structures (and then we ignore them). But if
166    * we leave them unset, we'll get back duplicate answers.
167    */
168   _g_resolver_addrinfo_hints.ai_socktype = SOCK_STREAM;
169   _g_resolver_addrinfo_hints.ai_protocol = IPPROTO_TCP;
170
171   /**
172    * GResolver::reload:
173    * @resolver: a #GResolver
174    *
175    * Emitted when the resolver notices that the system resolver
176    * configuration has changed.
177    **/
178   signals[RELOAD] =
179     g_signal_new (I_("reload"),
180                   G_TYPE_RESOLVER,
181                   G_SIGNAL_RUN_LAST,
182                   G_STRUCT_OFFSET (GResolverClass, reload),
183                   NULL, NULL,
184                   g_cclosure_marshal_VOID__VOID,
185                   G_TYPE_NONE, 0);
186 }
187
188 static void
189 g_resolver_init (GResolver *resolver)
190 {
191 #ifdef G_OS_UNIX
192   struct stat st;
193 #endif
194
195   resolver->priv = G_TYPE_INSTANCE_GET_PRIVATE (resolver, G_TYPE_RESOLVER, GResolverPrivate);
196
197 #ifdef G_OS_UNIX
198   if (stat (_PATH_RESCONF, &st) == 0)
199     resolver->priv->resolv_conf_timestamp = st.st_mtime;
200 #endif
201 }
202
203 static GResolver *default_resolver;
204
205 /**
206  * g_resolver_get_default:
207  *
208  * Gets the default #GResolver. You should unref it when you are done
209  * with it. #GResolver may use its reference count as a hint about how
210  * many threads it should allocate for concurrent DNS resolutions.
211  *
212  * Return value: (transfer full): the default #GResolver.
213  *
214  * Since: 2.22
215  */
216 GResolver *
217 g_resolver_get_default (void)
218 {
219   if (!default_resolver)
220     default_resolver = g_object_new (G_TYPE_THREADED_RESOLVER, NULL);
221
222   return g_object_ref (default_resolver);
223 }
224
225 /**
226  * g_resolver_set_default:
227  * @resolver: the new default #GResolver
228  *
229  * Sets @resolver to be the application's default resolver (reffing
230  * @resolver, and unreffing the previous default resolver, if any).
231  * Future calls to g_resolver_get_default() will return this resolver.
232  *
233  * This can be used if an application wants to perform any sort of DNS
234  * caching or "pinning"; it can implement its own #GResolver that
235  * calls the original default resolver for DNS operations, and
236  * implements its own cache policies on top of that, and then set
237  * itself as the default resolver for all later code to use.
238  *
239  * Since: 2.22
240  */
241 void
242 g_resolver_set_default (GResolver *resolver)
243 {
244   if (default_resolver)
245     g_object_unref (default_resolver);
246   default_resolver = g_object_ref (resolver);
247 }
248
249
250 static void
251 g_resolver_maybe_reload (GResolver *resolver)
252 {
253 #ifdef G_OS_UNIX
254   struct stat st;
255
256   if (stat (_PATH_RESCONF, &st) == 0)
257     {
258       if (st.st_mtime != resolver->priv->resolv_conf_timestamp)
259         {
260           resolver->priv->resolv_conf_timestamp = st.st_mtime;
261 #ifndef __BIONIC__
262           res_init ();
263 #endif
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       GTask *task;
402
403       task = g_task_new (resolver, cancellable, callback, user_data);
404       g_task_set_source_tag (task, g_resolver_lookup_by_name_async);
405       g_task_return_pointer (task, g_list_append (NULL, addr),
406                              (GDestroyNotify) g_resolver_free_addresses);
407       g_object_unref (task);
408       return;
409     }
410
411   if (g_hostname_is_non_ascii (hostname))
412     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
413
414   g_resolver_maybe_reload (resolver);
415   G_RESOLVER_GET_CLASS (resolver)->
416     lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
417
418   g_free (ascii_hostname);
419 }
420
421 /**
422  * g_resolver_lookup_by_name_finish:
423  * @resolver: a #GResolver
424  * @result: the result passed to your #GAsyncReadyCallback
425  * @error: return location for a #GError, or %NULL
426  *
427  * Retrieves the result of a call to
428  * g_resolver_lookup_by_name_async().
429  *
430  * If the DNS resolution failed, @error (if non-%NULL) will be set to
431  * a value from #GResolverError. If the operation was cancelled,
432  * @error will be set to %G_IO_ERROR_CANCELLED.
433  *
434  * Return value: (element-type GInetAddress) (transfer full): a #GList
435  * of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
436  * for more details.
437  *
438  * Since: 2.22
439  */
440 GList *
441 g_resolver_lookup_by_name_finish (GResolver     *resolver,
442                                   GAsyncResult  *result,
443                                   GError       **error)
444 {
445   GList *addrs;
446
447   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
448
449   if (g_async_result_legacy_propagate_error (result, error))
450     return NULL;
451   else if (g_async_result_is_tagged (result, g_resolver_lookup_by_name_async))
452     {
453       /* Handle the stringified-IP-addr case */
454       return g_task_propagate_pointer (G_TASK (result), error);
455     }
456
457   addrs = G_RESOLVER_GET_CLASS (resolver)->
458     lookup_by_name_finish (resolver, result, error);
459
460   remove_duplicates (addrs);
461
462   return addrs;
463 }
464
465 /**
466  * g_resolver_free_addresses: (skip)
467  * @addresses: a #GList of #GInetAddress
468  *
469  * Frees @addresses (which should be the return value from
470  * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_finish()).
471  * (This is a convenience method; you can also simply free the results
472  * by hand.)
473  *
474  * Since: 2.22
475  */
476 void
477 g_resolver_free_addresses (GList *addresses)
478 {
479   GList *a;
480
481   for (a = addresses; a; a = a->next)
482     g_object_unref (a->data);
483   g_list_free (addresses);
484 }
485
486 /**
487  * g_resolver_lookup_by_address:
488  * @resolver: a #GResolver
489  * @address: the address to reverse-resolve
490  * @cancellable: (allow-none): a #GCancellable, or %NULL
491  * @error: return location for a #GError, or %NULL
492  *
493  * Synchronously reverse-resolves @address to determine its
494  * associated hostname.
495  *
496  * If the DNS resolution fails, @error (if non-%NULL) will be set to
497  * a value from #GResolverError.
498  *
499  * If @cancellable is non-%NULL, it can be used to cancel the
500  * operation, in which case @error (if non-%NULL) will be set to
501  * %G_IO_ERROR_CANCELLED.
502  *
503  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
504  *     form), or %NULL on error.
505  *
506  * Since: 2.22
507  */
508 gchar *
509 g_resolver_lookup_by_address (GResolver     *resolver,
510                               GInetAddress  *address,
511                               GCancellable  *cancellable,
512                               GError       **error)
513 {
514   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
515   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
516
517   g_resolver_maybe_reload (resolver);
518   return G_RESOLVER_GET_CLASS (resolver)->
519     lookup_by_address (resolver, address, cancellable, error);
520 }
521
522 /**
523  * g_resolver_lookup_by_address_async:
524  * @resolver: a #GResolver
525  * @address: the address to reverse-resolve
526  * @cancellable: (allow-none): a #GCancellable, or %NULL
527  * @callback: (scope async): callback to call after resolution completes
528  * @user_data: (closure): data for @callback
529  *
530  * Begins asynchronously reverse-resolving @address to determine its
531  * associated hostname, and eventually calls @callback, which must
532  * call g_resolver_lookup_by_address_finish() to get the final result.
533  *
534  * Since: 2.22
535  */
536 void
537 g_resolver_lookup_by_address_async (GResolver           *resolver,
538                                     GInetAddress        *address,
539                                     GCancellable        *cancellable,
540                                     GAsyncReadyCallback  callback,
541                                     gpointer             user_data)
542 {
543   g_return_if_fail (G_IS_RESOLVER (resolver));
544   g_return_if_fail (G_IS_INET_ADDRESS (address));
545
546   g_resolver_maybe_reload (resolver);
547   G_RESOLVER_GET_CLASS (resolver)->
548     lookup_by_address_async (resolver, address, cancellable, callback, user_data);
549 }
550
551 /**
552  * g_resolver_lookup_by_address_finish:
553  * @resolver: a #GResolver
554  * @result: the result passed to your #GAsyncReadyCallback
555  * @error: return location for a #GError, or %NULL
556  *
557  * Retrieves the result of a previous call to
558  * g_resolver_lookup_by_address_async().
559  *
560  * If the DNS resolution failed, @error (if non-%NULL) will be set to
561  * a value from #GResolverError. If the operation was cancelled,
562  * @error will be set to %G_IO_ERROR_CANCELLED.
563  *
564  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
565  * form), or %NULL on error.
566  *
567  * Since: 2.22
568  */
569 gchar *
570 g_resolver_lookup_by_address_finish (GResolver     *resolver,
571                                      GAsyncResult  *result,
572                                      GError       **error)
573 {
574   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
575
576   if (g_async_result_legacy_propagate_error (result, error))
577     return NULL;
578
579   return G_RESOLVER_GET_CLASS (resolver)->
580     lookup_by_address_finish (resolver, result, error);
581 }
582
583 static gchar *
584 g_resolver_get_service_rrname (const char *service,
585                                const char *protocol,
586                                const char *domain)
587 {
588   gchar *rrname, *ascii_domain = NULL;
589
590   if (g_hostname_is_non_ascii (domain))
591     domain = ascii_domain = g_hostname_to_ascii (domain);
592
593   rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
594
595   g_free (ascii_domain);
596   return rrname;
597 }
598
599 /**
600  * g_resolver_lookup_service:
601  * @resolver: a #GResolver
602  * @service: the service type to look up (eg, "ldap")
603  * @protocol: the networking protocol to use for @service (eg, "tcp")
604  * @domain: the DNS domain to look up the service in
605  * @cancellable: (allow-none): a #GCancellable, or %NULL
606  * @error: return location for a #GError, or %NULL
607  *
608  * Synchronously performs a DNS SRV lookup for the given @service and
609  * @protocol in the given @domain and returns an array of #GSrvTarget.
610  * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
611  * @service and @protocol arguments <emphasis>do not</emphasis>
612  * include the leading underscore that appears in the actual DNS
613  * entry.
614  *
615  * On success, g_resolver_lookup_service() will return a #GList of
616  * #GSrvTarget, sorted in order of preference. (That is, you should
617  * attempt to connect to the first target first, then the second if
618  * the first fails, etc.)
619  *
620  * If the DNS resolution fails, @error (if non-%NULL) will be set to
621  * a value from #GResolverError.
622  *
623  * If @cancellable is non-%NULL, it can be used to cancel the
624  * operation, in which case @error (if non-%NULL) will be set to
625  * %G_IO_ERROR_CANCELLED.
626  *
627  * If you are planning to connect to the service, it is usually easier
628  * to create a #GNetworkService and use its #GSocketConnectable
629  * interface.
630  *
631  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
632  * or %NULL on error. You must free each of the targets and the list when you are
633  * done with it. (You can use g_resolver_free_targets() to do this.)
634  *
635  * Since: 2.22
636  */
637 GList *
638 g_resolver_lookup_service (GResolver     *resolver,
639                            const gchar   *service,
640                            const gchar   *protocol,
641                            const gchar   *domain,
642                            GCancellable  *cancellable,
643                            GError       **error)
644 {
645   GList *targets;
646   gchar *rrname;
647
648   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
649   g_return_val_if_fail (service != NULL, NULL);
650   g_return_val_if_fail (protocol != NULL, NULL);
651   g_return_val_if_fail (domain != NULL, NULL);
652
653   rrname = g_resolver_get_service_rrname (service, protocol, domain);
654
655   g_resolver_maybe_reload (resolver);
656   targets = G_RESOLVER_GET_CLASS (resolver)->
657     lookup_service (resolver, rrname, cancellable, error);
658
659   g_free (rrname);
660   return targets;
661 }
662
663 /**
664  * g_resolver_lookup_service_async:
665  * @resolver: a #GResolver
666  * @service: the service type to look up (eg, "ldap")
667  * @protocol: the networking protocol to use for @service (eg, "tcp")
668  * @domain: the DNS domain to look up the service in
669  * @cancellable: (allow-none): a #GCancellable, or %NULL
670  * @callback: (scope async): callback to call after resolution completes
671  * @user_data: (closure): data for @callback
672  *
673  * Begins asynchronously performing a DNS SRV lookup for the given
674  * @service and @protocol in the given @domain, and eventually calls
675  * @callback, which must call g_resolver_lookup_service_finish() to
676  * get the final result. See g_resolver_lookup_service() for more
677  * details.
678  *
679  * Since: 2.22
680  */
681 void
682 g_resolver_lookup_service_async (GResolver           *resolver,
683                                  const gchar         *service,
684                                  const gchar         *protocol,
685                                  const gchar         *domain,
686                                  GCancellable        *cancellable,
687                                  GAsyncReadyCallback  callback,
688                                  gpointer             user_data)
689 {
690   gchar *rrname;
691
692   g_return_if_fail (G_IS_RESOLVER (resolver));
693   g_return_if_fail (service != NULL);
694   g_return_if_fail (protocol != NULL);
695   g_return_if_fail (domain != NULL);
696
697   rrname = g_resolver_get_service_rrname (service, protocol, domain);
698
699   g_resolver_maybe_reload (resolver);
700   G_RESOLVER_GET_CLASS (resolver)->
701     lookup_service_async (resolver, rrname, cancellable, callback, user_data);
702
703   g_free (rrname);
704 }
705
706 /**
707  * g_resolver_lookup_service_finish:
708  * @resolver: a #GResolver
709  * @result: the result passed to your #GAsyncReadyCallback
710  * @error: return location for a #GError, or %NULL
711  *
712  * Retrieves the result of a previous call to
713  * g_resolver_lookup_service_async().
714  *
715  * If the DNS resolution failed, @error (if non-%NULL) will be set to
716  * a value from #GResolverError. If the operation was cancelled,
717  * @error will be set to %G_IO_ERROR_CANCELLED.
718  *
719  * Return value: (element-type GSrvTarget) (transfer full): a #GList of #GSrvTarget,
720  * or %NULL on error. See g_resolver_lookup_service() for more details.
721  *
722  * Since: 2.22
723  */
724 GList *
725 g_resolver_lookup_service_finish (GResolver     *resolver,
726                                   GAsyncResult  *result,
727                                   GError       **error)
728 {
729   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
730
731   if (g_async_result_legacy_propagate_error (result, error))
732     return NULL;
733
734   return G_RESOLVER_GET_CLASS (resolver)->
735     lookup_service_finish (resolver, result, error);
736 }
737
738 /**
739  * g_resolver_free_targets: (skip)
740  * @targets: a #GList of #GSrvTarget
741  *
742  * Frees @targets (which should be the return value from
743  * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
744  * (This is a convenience method; you can also simply free the
745  * results by hand.)
746  *
747  * Since: 2.22
748  */
749 void
750 g_resolver_free_targets (GList *targets)
751 {
752   GList *t;
753
754   for (t = targets; t; t = t->next)
755     g_srv_target_free (t->data);
756   g_list_free (targets);
757 }
758
759 /**
760  * g_resolver_lookup_records:
761  * @resolver: a #GResolver
762  * @rrname: the DNS name to lookup the record for
763  * @record_type: the type of DNS record to lookup
764  * @cancellable: (allow-none): a #GCancellable, or %NULL
765  * @error: return location for a #GError, or %NULL
766  *
767  * Synchronously performs a DNS record lookup for the given @rrname and returns
768  * a list of records as #GVariant tuples. See #GResolverRecordType for
769  * information on what the records contain for each @record_type.
770  *
771  * If the DNS resolution fails, @error (if non-%NULL) will be set to
772  * a value from #GResolverError.
773  *
774  * If @cancellable is non-%NULL, it can be used to cancel the
775  * operation, in which case @error (if non-%NULL) will be set to
776  * %G_IO_ERROR_CANCELLED.
777  *
778  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
779  * or %NULL on error. You must free each of the records and the list when you are
780  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
781  *
782  * Since: 2.34
783  */
784 GList *
785 g_resolver_lookup_records (GResolver            *resolver,
786                            const gchar          *rrname,
787                            GResolverRecordType   record_type,
788                            GCancellable         *cancellable,
789                            GError              **error)
790 {
791   GList *records;
792
793   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
794   g_return_val_if_fail (rrname != NULL, NULL);
795
796   g_resolver_maybe_reload (resolver);
797   records = G_RESOLVER_GET_CLASS (resolver)->
798     lookup_records (resolver, rrname, record_type, cancellable, error);
799
800   return records;
801 }
802
803 /**
804  * g_resolver_lookup_records_async:
805  * @resolver: a #GResolver
806  * @rrname: the DNS name to lookup the record for
807  * @record_type: the type of DNS record to lookup
808  * @cancellable: (allow-none): a #GCancellable, or %NULL
809  * @callback: (scope async): callback to call after resolution completes
810  * @user_data: (closure): data for @callback
811  *
812  * Begins asynchronously performing a DNS lookup for the given
813  * @rrname, and eventually calls @callback, which must call
814  * g_resolver_lookup_records_finish() to get the final result. See
815  * g_resolver_lookup_records() for more details.
816  *
817  * Since: 2.34
818  */
819 void
820 g_resolver_lookup_records_async (GResolver           *resolver,
821                                  const gchar         *rrname,
822                                  GResolverRecordType  record_type,
823                                  GCancellable        *cancellable,
824                                  GAsyncReadyCallback  callback,
825                                  gpointer             user_data)
826 {
827   g_return_if_fail (G_IS_RESOLVER (resolver));
828   g_return_if_fail (rrname != NULL);
829
830   g_resolver_maybe_reload (resolver);
831   G_RESOLVER_GET_CLASS (resolver)->
832     lookup_records_async (resolver, rrname, record_type, cancellable, callback, user_data);
833 }
834
835 /**
836  * g_resolver_lookup_records_finish:
837  * @resolver: a #GResolver
838  * @result: the result passed to your #GAsyncReadyCallback
839  * @error: return location for a #GError, or %NULL
840  *
841  * Retrieves the result of a previous call to
842  * g_resolver_lookup_records_async(). Returns a list of records as #GVariant
843  * tuples. See #GResolverRecordType for information on what the records contain.
844  *
845  * If the DNS resolution failed, @error (if non-%NULL) will be set to
846  * a value from #GResolverError. If the operation was cancelled,
847  * @error will be set to %G_IO_ERROR_CANCELLED.
848  *
849  * Return value: (element-type GVariant) (transfer full): a #GList of #GVariant,
850  * or %NULL on error. You must free each of the records and the list when you are
851  * done with it. (You can use g_list_free_full() with g_variant_unref() to do this.)
852  *
853  * Since: 2.34
854  */
855 GList *
856 g_resolver_lookup_records_finish (GResolver     *resolver,
857                                   GAsyncResult  *result,
858                                   GError       **error)
859 {
860   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
861   return G_RESOLVER_GET_CLASS (resolver)->
862     lookup_records_finish (resolver, result, error);
863 }
864
865 /**
866  * g_resolver_error_quark:
867  *
868  * Gets the #GResolver Error Quark.
869  *
870  * Return value: a #GQuark.
871  *
872  * Since: 2.22
873  */
874 G_DEFINE_QUARK (g-resolver-error-quark, g_resolver_error)
875
876 static GResolverError
877 g_resolver_error_from_addrinfo_error (gint err)
878 {
879   switch (err)
880     {
881     case EAI_FAIL:
882 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
883     case EAI_NODATA:
884 #endif
885     case EAI_NONAME:
886       return G_RESOLVER_ERROR_NOT_FOUND;
887
888     case EAI_AGAIN:
889       return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
890
891     default:
892       return G_RESOLVER_ERROR_INTERNAL;
893     }
894 }
895
896 struct addrinfo _g_resolver_addrinfo_hints;
897
898 /* Private method to process a getaddrinfo() response. */
899 GList *
900 _g_resolver_addresses_from_addrinfo (const char       *hostname,
901                                      struct addrinfo  *res,
902                                      gint              gai_retval,
903                                      GError          **error)
904 {
905   struct addrinfo *ai;
906   GSocketAddress *sockaddr;
907   GInetAddress *addr;
908   GList *addrs;
909
910   if (gai_retval != 0)
911     {
912       g_set_error (error, G_RESOLVER_ERROR,
913                    g_resolver_error_from_addrinfo_error (gai_retval),
914                    _("Error resolving '%s': %s"),
915                    hostname, gai_strerror (gai_retval));
916       return NULL;
917     }
918
919   g_return_val_if_fail (res != NULL, NULL);
920
921   addrs = NULL;
922   for (ai = res; ai; ai = ai->ai_next)
923     {
924       sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
925       if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
926         continue;
927
928       addr = g_object_ref (g_inet_socket_address_get_address ((GInetSocketAddress *)sockaddr));
929       addrs = g_list_prepend (addrs, addr);
930       g_object_unref (sockaddr);
931     }
932
933   return g_list_reverse (addrs);
934 }
935
936 /* Private method to set up a getnameinfo() request */
937 void
938 _g_resolver_address_to_sockaddr (GInetAddress            *address,
939                                  struct sockaddr_storage *sa,
940                                  gsize                   *len)
941 {
942   GSocketAddress *sockaddr;
943
944   sockaddr = g_inet_socket_address_new (address, 0);
945   g_socket_address_to_native (sockaddr, (struct sockaddr *)sa, sizeof (*sa), NULL);
946   *len = g_socket_address_get_native_size (sockaddr);
947   g_object_unref (sockaddr);
948 }
949
950 /* Private method to process a getnameinfo() response. */
951 char *
952 _g_resolver_name_from_nameinfo (GInetAddress  *address,
953                                 const gchar   *name,
954                                 gint           gni_retval,
955                                 GError       **error)
956 {
957   if (gni_retval != 0)
958     {
959       gchar *phys;
960
961       phys = g_inet_address_to_string (address);
962       g_set_error (error, G_RESOLVER_ERROR,
963                    g_resolver_error_from_addrinfo_error (gni_retval),
964                    _("Error reverse-resolving '%s': %s"),
965                    phys ? phys : "(unknown)", gai_strerror (gni_retval));
966       g_free (phys);
967       return NULL;
968     }
969
970   return g_strdup (name);
971 }
972
973 #if defined(G_OS_UNIX)
974
975 #ifdef __BIONIC__
976 /* Copy from bionic/libc/private/arpa_nameser_compat.h
977  * and bionic/libc/private/arpa_nameser.h */
978 typedef struct {
979         unsigned        id :16;         /* query identification number */
980 #if BYTE_ORDER == BIG_ENDIAN
981                         /* fields in third byte */
982         unsigned        qr: 1;          /* response flag */
983         unsigned        opcode: 4;      /* purpose of message */
984         unsigned        aa: 1;          /* authoritive answer */
985         unsigned        tc: 1;          /* truncated message */
986         unsigned        rd: 1;          /* recursion desired */
987                         /* fields in fourth byte */
988         unsigned        ra: 1;          /* recursion available */
989         unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
990         unsigned        ad: 1;          /* authentic data from named */
991         unsigned        cd: 1;          /* checking disabled by resolver */
992         unsigned        rcode :4;       /* response code */
993 #endif
994 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
995                         /* fields in third byte */
996         unsigned        rd :1;          /* recursion desired */
997         unsigned        tc :1;          /* truncated message */
998         unsigned        aa :1;          /* authoritive answer */
999         unsigned        opcode :4;      /* purpose of message */
1000         unsigned        qr :1;          /* response flag */
1001                         /* fields in fourth byte */
1002         unsigned        rcode :4;       /* response code */
1003         unsigned        cd: 1;          /* checking disabled by resolver */
1004         unsigned        ad: 1;          /* authentic data from named */
1005         unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
1006         unsigned        ra :1;          /* recursion available */
1007 #endif
1008                         /* remaining bytes */
1009         unsigned        qdcount :16;    /* number of question entries */
1010         unsigned        ancount :16;    /* number of answer entries */
1011         unsigned        nscount :16;    /* number of authority entries */
1012         unsigned        arcount :16;    /* number of resource entries */
1013 } HEADER;
1014
1015 #define NS_INT32SZ      4       /* #/bytes of data in a uint32_t */
1016 #define NS_INT16SZ      2       /* #/bytes of data in a uint16_t */
1017
1018 #define NS_GET16(s, cp) do { \
1019         const u_char *t_cp = (const u_char *)(cp); \
1020         (s) = ((uint16_t)t_cp[0] << 8) \
1021             | ((uint16_t)t_cp[1]) \
1022             ; \
1023         (cp) += NS_INT16SZ; \
1024 } while (/*CONSTCOND*/0)
1025
1026 #define NS_GET32(l, cp) do { \
1027         const u_char *t_cp = (const u_char *)(cp); \
1028         (l) = ((uint32_t)t_cp[0] << 24) \
1029             | ((uint32_t)t_cp[1] << 16) \
1030             | ((uint32_t)t_cp[2] << 8) \
1031             | ((uint32_t)t_cp[3]) \
1032             ; \
1033         (cp) += NS_INT32SZ; \
1034 } while (/*CONSTCOND*/0)
1035
1036 #define GETSHORT                NS_GET16
1037 #define GETLONG                 NS_GET32
1038
1039 #define C_IN 1
1040
1041 /* From bionic/libc/private/resolv_private.h */
1042 int dn_expand(const u_char *, const u_char *, const u_char *, char *, int);
1043 #define dn_skipname __dn_skipname
1044 int dn_skipname(const u_char *, const u_char *);
1045
1046 /* From bionic/libc/private/arpa_nameser_compat.h */
1047 #define T_MX            ns_t_mx
1048 #define T_TXT           ns_t_txt
1049 #define T_SOA           ns_t_soa
1050 #define T_NS            ns_t_ns
1051
1052 /* From bionic/libc/private/arpa_nameser.h */
1053 typedef enum __ns_type {
1054         ns_t_invalid = 0,       /* Cookie. */
1055         ns_t_a = 1,             /* Host address. */
1056         ns_t_ns = 2,            /* Authoritative server. */
1057         ns_t_md = 3,            /* Mail destination. */
1058         ns_t_mf = 4,            /* Mail forwarder. */
1059         ns_t_cname = 5,         /* Canonical name. */
1060         ns_t_soa = 6,           /* Start of authority zone. */
1061         ns_t_mb = 7,            /* Mailbox domain name. */
1062         ns_t_mg = 8,            /* Mail group member. */
1063         ns_t_mr = 9,            /* Mail rename name. */
1064         ns_t_null = 10,         /* Null resource record. */
1065         ns_t_wks = 11,          /* Well known service. */
1066         ns_t_ptr = 12,          /* Domain name pointer. */
1067         ns_t_hinfo = 13,        /* Host information. */
1068         ns_t_minfo = 14,        /* Mailbox information. */
1069         ns_t_mx = 15,           /* Mail routing information. */
1070         ns_t_txt = 16,          /* Text strings. */
1071         ns_t_rp = 17,           /* Responsible person. */
1072         ns_t_afsdb = 18,        /* AFS cell database. */
1073         ns_t_x25 = 19,          /* X_25 calling address. */
1074         ns_t_isdn = 20,         /* ISDN calling address. */
1075         ns_t_rt = 21,           /* Router. */
1076         ns_t_nsap = 22,         /* NSAP address. */
1077         ns_t_nsap_ptr = 23,     /* Reverse NSAP lookup (deprecated). */
1078         ns_t_sig = 24,          /* Security signature. */
1079         ns_t_key = 25,          /* Security key. */
1080         ns_t_px = 26,           /* X.400 mail mapping. */
1081         ns_t_gpos = 27,         /* Geographical position (withdrawn). */
1082         ns_t_aaaa = 28,         /* Ip6 Address. */
1083         ns_t_loc = 29,          /* Location Information. */
1084         ns_t_nxt = 30,          /* Next domain (security). */
1085         ns_t_eid = 31,          /* Endpoint identifier. */
1086         ns_t_nimloc = 32,       /* Nimrod Locator. */
1087         ns_t_srv = 33,          /* Server Selection. */
1088         ns_t_atma = 34,         /* ATM Address */
1089         ns_t_naptr = 35,        /* Naming Authority PoinTeR */
1090         ns_t_kx = 36,           /* Key Exchange */
1091         ns_t_cert = 37,         /* Certification record */
1092         ns_t_a6 = 38,           /* IPv6 address (deprecates AAAA) */
1093         ns_t_dname = 39,        /* Non-terminal DNAME (for IPv6) */
1094         ns_t_sink = 40,         /* Kitchen sink (experimentatl) */
1095         ns_t_opt = 41,          /* EDNS0 option (meta-RR) */
1096         ns_t_apl = 42,          /* Address prefix list (RFC 3123) */
1097         ns_t_tkey = 249,        /* Transaction key */
1098         ns_t_tsig = 250,        /* Transaction signature. */
1099         ns_t_ixfr = 251,        /* Incremental zone transfer. */
1100         ns_t_axfr = 252,        /* Transfer zone of authority. */
1101         ns_t_mailb = 253,       /* Transfer mailbox records. */
1102         ns_t_maila = 254,       /* Transfer mail agent records. */
1103         ns_t_any = 255,         /* Wildcard match. */
1104         ns_t_zxfr = 256,        /* BIND-specific, nonstandard. */
1105         ns_t_max = 65536
1106 } ns_type;
1107
1108 #endif
1109
1110 static gboolean
1111 parse_short (guchar  **p,
1112              guchar   *end,
1113              guint16  *value)
1114 {
1115   if (*p + 2 > end)
1116     return FALSE;
1117   GETSHORT (*value, *p);
1118   return TRUE;
1119 }
1120
1121 static gboolean
1122 parse_long (guchar  **p,
1123             guchar   *end,
1124             guint32  *value)
1125 {
1126   if (*p + 4 > end)
1127     return FALSE;
1128   GETLONG (*value, *p);
1129   return TRUE;
1130 }
1131
1132 static GVariant *
1133 parse_res_srv (guchar  *answer,
1134                guchar  *end,
1135                guchar  *p)
1136 {
1137   gchar namebuf[1024];
1138   guint16 priority, weight, port;
1139   gint n;
1140
1141   if (!parse_short (&p, end, &priority) ||
1142       !parse_short (&p, end, &weight) ||
1143       !parse_short (&p, end, &port))
1144     return NULL;
1145
1146   n = dn_expand (answer, end, p, namebuf, sizeof (namebuf));
1147   if (n < 0)
1148     return NULL;
1149   *p += n;
1150
1151   return g_variant_new ("(qqqs)",
1152                         priority,
1153                         weight,
1154                         port,
1155                         namebuf);
1156 }
1157
1158 static GVariant *
1159 parse_res_soa (guchar  *answer,
1160                guchar  *end,
1161                guchar  *p)
1162 {
1163   gchar mnamebuf[1024];
1164   gchar rnamebuf[1024];
1165   guint32 serial, refresh, retry, expire, ttl;
1166   gint n;
1167
1168   n = dn_expand (answer, end, p, mnamebuf, sizeof (mnamebuf));
1169   if (n < 0)
1170     return NULL;
1171   p += n;
1172
1173   n = dn_expand (answer, end, p, rnamebuf, sizeof (rnamebuf));
1174   if (n < 0)
1175     return NULL;
1176   p += n;
1177
1178   if (!parse_long (&p, end, &serial) ||
1179       !parse_long (&p, end, &refresh) ||
1180       !parse_long (&p, end, &retry) ||
1181       !parse_long (&p, end, &expire) ||
1182       !parse_long (&p, end, &ttl))
1183     return NULL;
1184
1185   return g_variant_new ("(ssuuuuu)",
1186                         mnamebuf,
1187                         rnamebuf,
1188                         serial,
1189                         refresh,
1190                         retry,
1191                         expire,
1192                         ttl);
1193 }
1194
1195 static GVariant *
1196 parse_res_ns (guchar  *answer,
1197               guchar  *end,
1198               guchar  *p)
1199 {
1200   gchar namebuf[1024];
1201   gint n;
1202
1203   n = dn_expand (answer, end, p, namebuf, sizeof (namebuf));
1204   if (n < 0)
1205     return NULL;
1206
1207   return g_variant_new ("(s)", namebuf);
1208 }
1209
1210 static GVariant *
1211 parse_res_mx (guchar  *answer,
1212               guchar  *end,
1213               guchar  *p)
1214 {
1215   gchar namebuf[1024];
1216   guint16 preference;
1217   gint n;
1218
1219   if (!parse_short (&p, end, &preference))
1220     return NULL;
1221
1222   n = dn_expand (answer, end, p, namebuf, sizeof (namebuf));
1223   if (n < 0)
1224     return NULL;
1225   p += n;
1226
1227   return g_variant_new ("(qs)",
1228                         preference,
1229                         namebuf);
1230 }
1231
1232 static GVariant *
1233 parse_res_txt (guchar  *answer,
1234                guchar  *end,
1235                guchar  *p)
1236 {
1237   GVariant *record;
1238   GPtrArray *array;
1239   gsize len;
1240
1241   array = g_ptr_array_new_with_free_func (g_free);
1242   while (p < end)
1243     {
1244       len = *(p++);
1245       if (len > p - end)
1246         break;
1247       g_ptr_array_add (array, g_strndup ((gchar *)p, len));
1248       p += len;
1249     }
1250
1251   record = g_variant_new ("(@as)",
1252                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
1253   g_ptr_array_free (array, TRUE);
1254   return record;
1255 }
1256
1257 gint
1258 _g_resolver_record_type_to_rrtype (GResolverRecordType type)
1259 {
1260   switch (type)
1261   {
1262     case G_RESOLVER_RECORD_SRV:
1263       return T_SRV;
1264     case G_RESOLVER_RECORD_TXT:
1265       return T_TXT;
1266     case G_RESOLVER_RECORD_SOA:
1267       return T_SOA;
1268     case G_RESOLVER_RECORD_NS:
1269       return T_NS;
1270     case G_RESOLVER_RECORD_MX:
1271       return T_MX;
1272   }
1273   g_return_val_if_reached (-1);
1274 }
1275
1276 /* Private method to process a res_query response into GSrvTargets */
1277 GList *
1278 _g_resolver_records_from_res_query (const gchar      *rrname,
1279                                     gint              rrtype,
1280                                     guchar           *answer,
1281                                     gint              len,
1282                                     gint              herr,
1283                                     GError          **error)
1284 {
1285   gint count;
1286   guchar *end, *p;
1287   guint16 type, qclass, rdlength;
1288   guint32 ttl;
1289   HEADER *header;
1290   GList *records;
1291   GVariant *record;
1292   gint n, i;
1293
1294   if (len <= 0)
1295     {
1296       GResolverError errnum;
1297       const gchar *format;
1298
1299       if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
1300         {
1301           errnum = G_RESOLVER_ERROR_NOT_FOUND;
1302           format = _("No DNS record of the requested type for '%s'");
1303         }
1304       else if (herr == TRY_AGAIN)
1305         {
1306           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
1307           format = _("Temporarily unable to resolve '%s'");
1308         }
1309       else
1310         {
1311           errnum = G_RESOLVER_ERROR_INTERNAL;
1312           format = _("Error resolving '%s'");
1313         }
1314
1315       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
1316       return NULL;
1317     }
1318
1319   records = NULL;
1320
1321   header = (HEADER *)answer;
1322   p = answer + sizeof (HEADER);
1323   end = answer + len;
1324
1325   /* Skip query */
1326   count = ntohs (header->qdcount);
1327   for (i = 0; i < count && p < end; i++)
1328     {
1329       n = dn_skipname (p, end);
1330       if (n < 0)
1331         break;
1332       p += n;
1333       p += 4;
1334     }
1335
1336   /* Incomplete response */
1337   if (i < count)
1338     {
1339       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE,
1340                    _("Incomplete data received for '%s'"), rrname);
1341       return NULL;
1342     }
1343
1344   /* Read answers */
1345   count = ntohs (header->ancount);
1346   for (i = 0; i < count && p < end; i++)
1347     {
1348       n = dn_skipname (p, end);
1349       if (n < 0)
1350         break;
1351       p += n;
1352
1353       if (!parse_short (&p, end, &type) ||
1354           !parse_short (&p, end, &qclass) ||
1355           !parse_long (&p, end, &ttl) ||
1356           !parse_short (&p, end, &rdlength))
1357         break;
1358
1359       ttl = ttl; /* To avoid -Wunused-but-set-variable */
1360
1361       if (p + rdlength > end)
1362         break;
1363
1364       if (type == rrtype && qclass == C_IN)
1365         {
1366           switch (rrtype)
1367             {
1368             case T_SRV:
1369               record = parse_res_srv (answer, end, p);
1370               break;
1371             case T_MX:
1372               record = parse_res_mx (answer, end, p);
1373               break;
1374             case T_SOA:
1375               record = parse_res_soa (answer, end, p);
1376               break;
1377             case T_NS:
1378               record = parse_res_ns (answer, end, p);
1379               break;
1380             case T_TXT:
1381               record = parse_res_txt (answer, p + rdlength, p);
1382               break;
1383             default:
1384               g_warn_if_reached ();
1385               record = NULL;
1386               break;
1387             }
1388
1389           if (record != NULL)
1390             records = g_list_prepend (records, record);
1391         }
1392
1393       p += rdlength;
1394     }
1395
1396   /* Somehow got a truncated response */
1397   if (i < count)
1398     {
1399       g_list_free_full (records, (GDestroyNotify)g_variant_unref);
1400       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE,
1401                    _("Incomplete data received for '%s'"), rrname);
1402       return NULL;
1403     }
1404
1405   return records;
1406 }
1407
1408 #elif defined(G_OS_WIN32)
1409 static GVariant *
1410 parse_dns_srv (DNS_RECORD *rec)
1411 {
1412   return g_variant_new ("(qqqs)",
1413                         (guint16)rec->Data.SRV.wPriority,
1414                         (guint16)rec->Data.SRV.wWeight,
1415                         (guint16)rec->Data.SRV.wPort,
1416                         rec->Data.SRV.pNameTarget);
1417 }
1418
1419 static GVariant *
1420 parse_dns_soa (DNS_RECORD *rec)
1421 {
1422   return g_variant_new ("(ssuuuuu)",
1423                         rec->Data.SOA.pNamePrimaryServer,
1424                         rec->Data.SOA.pNameAdministrator,
1425                         (guint32)rec->Data.SOA.dwSerialNo,
1426                         (guint32)rec->Data.SOA.dwRefresh,
1427                         (guint32)rec->Data.SOA.dwRetry,
1428                         (guint32)rec->Data.SOA.dwExpire,
1429                         (guint32)rec->Data.SOA.dwDefaultTtl);
1430 }
1431
1432 static GVariant *
1433 parse_dns_ns (DNS_RECORD *rec)
1434 {
1435   return g_variant_new ("(s)", rec->Data.NS.pNameHost);
1436 }
1437
1438 static GVariant *
1439 parse_dns_mx (DNS_RECORD *rec)
1440 {
1441   return g_variant_new ("(qs)",
1442                         (guint16)rec->Data.MX.wPreference,
1443                         rec->Data.MX.pNameExchange);
1444 }
1445
1446 static GVariant *
1447 parse_dns_txt (DNS_RECORD *rec)
1448 {
1449   GVariant *record;
1450   GPtrArray *array;
1451   DWORD i;
1452
1453   array = g_ptr_array_new ();
1454   for (i = 0; i < rec->Data.TXT.dwStringCount; i++)
1455     g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]);
1456   record = g_variant_new ("(@as)",
1457                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
1458   g_ptr_array_free (array, TRUE);
1459   return record;
1460 }
1461
1462 WORD
1463 _g_resolver_record_type_to_dnstype (GResolverRecordType type)
1464 {
1465   switch (type)
1466   {
1467     case G_RESOLVER_RECORD_SRV:
1468       return DNS_TYPE_SRV;
1469     case G_RESOLVER_RECORD_TXT:
1470       return DNS_TYPE_TEXT;
1471     case G_RESOLVER_RECORD_SOA:
1472       return DNS_TYPE_SOA;
1473     case G_RESOLVER_RECORD_NS:
1474       return DNS_TYPE_NS;
1475     case G_RESOLVER_RECORD_MX:
1476       return DNS_TYPE_MX;
1477   }
1478   g_return_val_if_reached (-1);
1479 }
1480
1481 /* Private method to process a DnsQuery response into GVariants */
1482 GList *
1483 _g_resolver_records_from_DnsQuery (const gchar  *rrname,
1484                                    WORD          dnstype,
1485                                    DNS_STATUS    status,
1486                                    DNS_RECORD   *results,
1487                                    GError      **error)
1488 {
1489   DNS_RECORD *rec;
1490   gpointer record;
1491   GList *records;
1492
1493   if (status != ERROR_SUCCESS)
1494     {
1495       GResolverError errnum;
1496       const gchar *format;
1497
1498       if (status == DNS_ERROR_RCODE_NAME_ERROR)
1499         {
1500           errnum = G_RESOLVER_ERROR_NOT_FOUND;
1501           format = _("No DNS record of the requested type for '%s'");
1502         }
1503       else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
1504         {
1505           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
1506           format = _("Temporarily unable to resolve '%s'");
1507         }
1508       else
1509         {
1510           errnum = G_RESOLVER_ERROR_INTERNAL;
1511           format = _("Error resolving '%s'");
1512         }
1513
1514       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
1515       return NULL;
1516     }
1517
1518   records = NULL;
1519   for (rec = results; rec; rec = rec->pNext)
1520     {
1521       if (rec->wType != dnstype)
1522         continue;
1523       switch (dnstype)
1524         {
1525         case DNS_TYPE_SRV:
1526           record = parse_dns_srv (rec);
1527           break;
1528         case DNS_TYPE_SOA:
1529           record = parse_dns_soa (rec);
1530           break;
1531         case DNS_TYPE_NS:
1532           record = parse_dns_ns (rec);
1533           break;
1534         case DNS_TYPE_MX:
1535           record = parse_dns_mx (rec);
1536           break;
1537         case DNS_TYPE_TEXT:
1538           record = parse_dns_txt (rec);
1539           break;
1540         default:
1541           g_warn_if_reached ();
1542           record = NULL;
1543           break;
1544         }
1545       if (record != NULL)
1546         records = g_list_prepend (records, g_variant_ref_sink (record));
1547     }
1548
1549   return records;
1550 }
1551
1552 #endif