Ensure g_inet_address_get_type() call is not optimized away
[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
35 #ifdef G_OS_UNIX
36 #include "gunixresolver.h"
37 #endif
38 #ifdef G_OS_WIN32
39 #include "gwin32resolver.h"
40 #endif
41
42 #include <stdlib.h>
43
44 #include "gioalias.h"
45
46 /**
47  * SECTION:gresolver
48  * @short_description: Asynchronous and cancellable DNS resolver
49  * @include: gio/gio.h
50  *
51  * #GResolver provides cancellable synchronous and asynchronous DNS
52  * resolution, for hostnames (g_resolver_lookup_by_address(),
53  * g_resolver_lookup_by_name() and their async variants) and SRV
54  * (service) records (g_resolver_lookup_service()).
55  *
56  * #GNetworkAddress and #GNetworkService provide wrappers around
57  * #GResolver functionality that also implement #GSocketConnectable,
58  * making it easy to connect to a remote host/service.
59  **/
60
61 /**
62  * GResolver:
63  *
64  * The object that handles DNS resolution. Use g_resolver_get_default()
65  * to get the default resolver.
66  */
67 G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT)
68
69 static void
70 g_resolver_class_init (GResolverClass *resolver_class)
71 {
72   volatile GType type;
73
74   /* Make sure _g_networking_init() has been called */
75   type = g_inet_address_get_type ();
76
77   /* Initialize _g_resolver_addrinfo_hints */
78 #ifdef AI_ADDRCONFIG
79   _g_resolver_addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
80 #endif
81   /* These two don't actually matter, they just get copied into the
82    * returned addrinfo structures (and then we ignore them). But if
83    * we leave them unset, we'll get back duplicate answers.
84    */
85   _g_resolver_addrinfo_hints.ai_socktype = SOCK_STREAM;
86   _g_resolver_addrinfo_hints.ai_protocol = IPPROTO_TCP;
87 }
88
89 static void
90 g_resolver_init (GResolver *resolver)
91 {
92   ;
93 }
94
95 static GResolver *default_resolver;
96
97 /**
98  * g_resolver_get_default:
99  *
100  * Gets the default #GResolver. You should unref it when you are done
101  * with it. #GResolver may use its reference count as a hint about how
102  * many threads/processes, etc it should allocate for concurrent DNS
103  * resolutions.
104  *
105  * Return value: the #GResolver.
106  *
107  * Since: 2.22
108  **/
109 GResolver *
110 g_resolver_get_default (void)
111 {
112   if (!default_resolver)
113     {
114       if (g_thread_supported ())
115         default_resolver = g_object_new (G_TYPE_THREADED_RESOLVER, NULL);
116       else
117         {
118 #if defined(G_OS_UNIX)
119           default_resolver = g_object_new (G_TYPE_UNIX_RESOLVER, NULL);
120 #elif defined(G_OS_WIN32)
121           default_resolver = g_object_new (G_TYPE_WIN32_RESOLVER, NULL);
122 #endif
123         }
124     }
125
126   return g_object_ref (default_resolver);
127 }
128
129 /**
130  * g_resolver_set_default:
131  * @resolver: the new default #GResolver
132  *
133  * Sets @resolver to be the application's default resolver (reffing
134  * @resolver, and unreffing the previous default resolver, if any).
135  * Future calls to g_resolver_get_default() will return this resolver.
136  *
137  * This can be used if an application wants to perform any sort of DNS
138  * caching or "pinning"; it can implement its own #GResolver that
139  * calls the original default resolver for DNS operations, and
140  * implements its own cache policies on top of that, and then set
141  * itself as the default resolver for all later code to use.
142  *
143  * Since: 2.22
144  **/
145 void
146 g_resolver_set_default (GResolver *resolver)
147 {
148   if (default_resolver)
149     g_object_unref (default_resolver);
150   default_resolver = g_object_ref (resolver);
151 }
152
153
154 /**
155  * g_resolver_lookup_by_name:
156  * @resolver: a #GResolver
157  * @hostname: the hostname to look up
158  * @cancellable: a #GCancellable, or %NULL
159  * @error: return location for a #GError, or %NULL
160  *
161  * Synchronously resolves @hostname to determine its associated IP
162  * address(es). @hostname may be an ASCII-only or UTF-8 hostname, or
163  * the textual form of an IP address (in which case this just becomes
164  * a wrapper around g_inet_address_new_from_string()).
165  *
166  * On success, g_resolver_lookup_by_name() will return a #GList of
167  * #GInetAddress, sorted in order of preference. (That is, you should
168  * attempt to connect to the first address first, then the second if
169  * the first fails, etc.)
170  *
171  * If the DNS resolution fails, @error (if non-%NULL) will be set to a
172  * value from #GResolverError.
173  *
174  * If @cancellable is non-%NULL, it can be used to cancel the
175  * operation, in which case @error (if non-%NULL) will be set to
176  * %G_IO_ERROR_CANCELLED.
177  *
178  * If you are planning to connect to a socket on the resolved IP
179  * address, it may be easier to create a #GNetworkAddress and use its
180  * #GSocketConnectable interface.
181  *
182  * Return value: a #GList of #GInetAddress, or %NULL on error. You
183  * must unref each of the addresses and free the list when you are
184  * done with it. (You can use g_resolver_free_addresses() to do this.)
185  *
186  * Since: 2.22
187  **/
188 GList *
189 g_resolver_lookup_by_name (GResolver     *resolver,
190                            const gchar   *hostname,
191                            GCancellable  *cancellable,
192                            GError       **error)
193 {
194   GInetAddress *addr;
195   GList *addrs;
196   gchar *ascii_hostname = NULL;
197
198   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
199   g_return_val_if_fail (hostname != NULL, NULL);
200
201   /* Check if @hostname is just an IP address */
202   addr = g_inet_address_new_from_string (hostname);
203   if (addr)
204     return g_list_append (NULL, addr);
205
206   if (g_hostname_is_non_ascii (hostname))
207     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
208
209   addrs = G_RESOLVER_GET_CLASS (resolver)->
210     lookup_by_name (resolver, hostname, cancellable, error);
211
212   g_free (ascii_hostname);
213   return addrs;
214 }
215
216 /**
217  * g_resolver_lookup_by_name_async:
218  * @resolver: a #GResolver
219  * @hostname: the hostname to look up the address of
220  * @cancellable: a #GCancellable, or %NULL
221  * @callback: callback to call after resolution completes
222  * @user_data: data for @callback
223  *
224  * Begins asynchronously resolving @hostname to determine its
225  * associated IP address(es), and eventually calls @callback, which
226  * must call g_resolver_lookup_by_name_finish() to get the result. See
227  * g_resolver_lookup_by_name() for more details.
228  *
229  * Since: 2.22
230  **/
231 void
232 g_resolver_lookup_by_name_async (GResolver           *resolver,
233                                  const gchar         *hostname,
234                                  GCancellable        *cancellable,
235                                  GAsyncReadyCallback  callback,
236                                  gpointer             user_data)
237 {
238   GInetAddress *addr;
239   gchar *ascii_hostname = NULL;
240
241   g_return_if_fail (G_IS_RESOLVER (resolver));
242   g_return_if_fail (hostname != NULL);
243
244   /* Check if @hostname is just an IP address */
245   addr = g_inet_address_new_from_string (hostname);
246   if (addr)
247     {
248       GSimpleAsyncResult *simple;
249       GList *addrs;
250
251       simple = g_simple_async_result_new (G_OBJECT (resolver),
252                                           callback, user_data,
253                                           g_resolver_lookup_by_name_async);
254
255       addrs = g_list_append (NULL, addr);
256       g_simple_async_result_set_op_res_gpointer (simple, addrs, (GDestroyNotify)g_resolver_free_addresses);
257       g_simple_async_result_complete_in_idle (simple);
258       g_object_unref (simple);
259       return;
260     }
261
262   if (g_hostname_is_non_ascii (hostname))
263     hostname = ascii_hostname = g_hostname_to_ascii (hostname);
264
265   G_RESOLVER_GET_CLASS (resolver)->
266     lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
267
268   g_free (ascii_hostname);
269 }
270
271 /**
272  * g_resolver_lookup_by_name_finish:
273  * @resolver: a #GResolver
274  * @result: the result passed to your #GAsyncReadyCallback
275  * @error: return location for a #GError, or %NULL
276  *
277  * Retrieves the result of a call to
278  * g_resolver_lookup_by_name_async().
279  *
280  * If the DNS resolution failed, @error (if non-%NULL) will be set to
281  * a value from #GResolverError. If the operation was cancelled,
282  * @error will be set to %G_IO_ERROR_CANCELLED.
283  *
284  * Return value: a #GList of #GInetAddress, or %NULL on error. See
285  * g_resolver_lookup_by_name() for more details.
286  *
287  * Since: 2.22
288  **/
289 GList *
290 g_resolver_lookup_by_name_finish (GResolver     *resolver,
291                                   GAsyncResult  *result,
292                                   GError       **error)
293 {
294   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
295
296   if (G_IS_SIMPLE_ASYNC_RESULT (result))
297     {
298       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
299
300       if (g_simple_async_result_propagate_error (simple, error))
301         return NULL;
302
303       /* Handle the stringified-IP-addr case */
304       if (g_simple_async_result_get_source_tag (simple) == g_resolver_lookup_by_name_async)
305         {
306           GList *addrs;
307
308           addrs = g_simple_async_result_get_op_res_gpointer (simple);
309           g_simple_async_result_set_op_res_gpointer (simple, NULL, NULL);
310           return addrs;
311         }
312     }
313
314   return G_RESOLVER_GET_CLASS (resolver)->
315     lookup_by_name_finish (resolver, result, error);
316 }
317
318 /**
319  * g_resolver_free_addresses:
320  * @addresses: a #GList of #GInetAddress
321  *
322  * Frees @addresses (which should be the return value from
323  * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_finish()).
324  * (This is a convenience method; you can also simply free the results
325  * by hand.)
326  *
327  * Since: 2.22
328  **/
329 void
330 g_resolver_free_addresses (GList *addresses)
331 {
332   GList *a;
333
334   for (a = addresses; a; a = a->next)
335     g_object_unref (a->data);
336   g_list_free (addresses);
337 }
338
339 /**
340  * g_resolver_lookup_by_address:
341  * @resolver: a #GResolver
342  * @address: the address to reverse-resolve
343  * @cancellable: a #GCancellable, or %NULL
344  * @error: return location for a #GError, or %NULL
345  *
346  * Synchronously reverse-resolves @address to determine its
347  * associated hostname.
348  *
349  * If the DNS resolution fails, @error (if non-%NULL) will be set to
350  * a value from #GResolverError.
351  *
352  * If @cancellable is non-%NULL, it can be used to cancel the
353  * operation, in which case @error (if non-%NULL) will be set to
354  * %G_IO_ERROR_CANCELLED.
355  *
356  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
357  * form), or %NULL on error.
358  *
359  * Since: 2.22
360  **/
361 gchar *
362 g_resolver_lookup_by_address (GResolver     *resolver,
363                               GInetAddress  *address,
364                               GCancellable  *cancellable,
365                               GError       **error)
366 {
367   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
368   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
369
370   return G_RESOLVER_GET_CLASS (resolver)->
371     lookup_by_address (resolver, address, cancellable, error);
372 }
373
374 /**
375  * g_resolver_lookup_by_address_async:
376  * @resolver: a #GResolver
377  * @address: the address to reverse-resolve
378  * @cancellable: a #GCancellable, or %NULL
379  * @callback: callback to call after resolution completes
380  * @user_data: data for @callback
381  *
382  * Begins asynchronously reverse-resolving @address to determine its
383  * associated hostname, and eventually calls @callback, which must
384  * call g_resolver_lookup_by_address_finish() to get the final result.
385  *
386  * Since: 2.22
387  **/
388 void
389 g_resolver_lookup_by_address_async (GResolver           *resolver,
390                                     GInetAddress        *address,
391                                     GCancellable        *cancellable,
392                                     GAsyncReadyCallback  callback,
393                                     gpointer             user_data)
394 {
395   g_return_if_fail (G_IS_RESOLVER (resolver));
396   g_return_if_fail (G_IS_INET_ADDRESS (address));
397
398   G_RESOLVER_GET_CLASS (resolver)->
399     lookup_by_address_async (resolver, address, cancellable, callback, user_data);
400 }
401
402 /**
403  * g_resolver_lookup_by_address_finish:
404  * @resolver: a #GResolver
405  * @result: the result passed to your #GAsyncReadyCallback
406  * @error: return location for a #GError, or %NULL
407  *
408  * Retrieves the result of a previous call to
409  * g_resolver_lookup_by_address_async().
410  *
411  * If the DNS resolution failed, @error (if non-%NULL) will be set to
412  * a value from #GResolverError. If the operation was cancelled,
413  * @error will be set to %G_IO_ERROR_CANCELLED.
414  *
415  * Return value: a hostname (either ASCII-only, or in ASCII-encoded
416  * form), or %NULL on error.
417  *
418  * Since: 2.22
419  **/
420 gchar *
421 g_resolver_lookup_by_address_finish (GResolver     *resolver,
422                                      GAsyncResult  *result,
423                                      GError       **error)
424 {
425   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
426
427   if (G_IS_SIMPLE_ASYNC_RESULT (result))
428     {
429       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
430
431       if (g_simple_async_result_propagate_error (simple, error))
432         return NULL;
433     }
434
435   return G_RESOLVER_GET_CLASS (resolver)->
436     lookup_by_address_finish (resolver, result, error);
437 }
438
439 static gchar *
440 g_resolver_get_service_rrname (const char *service,
441                                const char *protocol,
442                                const char *domain)
443 {
444   gchar *rrname, *ascii_domain = NULL;
445
446   if (g_hostname_is_non_ascii (domain))
447     domain = ascii_domain = g_hostname_to_ascii (domain);
448
449   rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
450
451   g_free (ascii_domain);
452   return rrname;
453 }
454
455 /**
456  * g_resolver_lookup_service:
457  * @resolver: a #GResolver
458  * @service: the service type to look up (eg, "ldap")
459  * @protocol: the networking protocol to use for @service (eg, "tcp")
460  * @domain: the DNS domain to look up the service in
461  * @cancellable: a #GCancellable, or %NULL
462  * @error: return location for a #GError, or %NULL
463  *
464  * Synchronously performs a DNS SRV lookup for the given @service and
465  * @protocol in the given @domain and returns an array of #GSrvTarget.
466  * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
467  * @service and @protocol arguments <emphasis>do not</emphasis>
468  * include the leading underscore that appears in the actual DNS
469  * entry.
470  *
471  * On success, g_resolver_lookup_service() will return a #GList of
472  * #GSrvTarget, sorted in order of preference. (That is, you should
473  * attempt to connect to the first target first, then the second if
474  * the first fails, etc.)
475  *
476  * If the DNS resolution fails, @error (if non-%NULL) will be set to
477  * a value from #GResolverError.
478  *
479  * If @cancellable is non-%NULL, it can be used to cancel the
480  * operation, in which case @error (if non-%NULL) will be set to
481  * %G_IO_ERROR_CANCELLED.
482  *
483  * If you are planning to connect to the service, it is usually easier
484  * to create a #GNetworkService and use its #GSocketConnectable
485  * interface.
486  *
487  * Return value: a #GList of #GSrvTarget, or %NULL on error. You must
488  * free each of the targets and the list when you are done with it.
489  * (You can use g_resolver_free_targets() to do this.)
490  *
491  * Since: 2.22
492  **/
493 GList *
494 g_resolver_lookup_service (GResolver     *resolver,
495                            const gchar   *service,
496                            const gchar   *protocol,
497                            const gchar   *domain,
498                            GCancellable  *cancellable,
499                            GError       **error)
500 {
501   GList *targets;
502   gchar *rrname;
503
504   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
505   g_return_val_if_fail (service != NULL, NULL);
506   g_return_val_if_fail (protocol != NULL, NULL);
507   g_return_val_if_fail (domain != NULL, NULL);
508
509   rrname = g_resolver_get_service_rrname (service, protocol, domain);
510
511   targets = G_RESOLVER_GET_CLASS (resolver)->
512     lookup_service (resolver, rrname, cancellable, error);
513
514   g_free (rrname);
515   return targets;
516 }
517
518 /**
519  * g_resolver_lookup_service_async:
520  * @resolver: a #GResolver
521  * @service: the service type to look up (eg, "ldap")
522  * @protocol: the networking protocol to use for @service (eg, "tcp")
523  * @domain: the DNS domain to look up the service in
524  * @cancellable: a #GCancellable, or %NULL
525  * @callback: callback to call after resolution completes
526  * @user_data: data for @callback
527  *
528  * Begins asynchronously performing a DNS SRV lookup for the given
529  * @service and @protocol in the given @domain, and eventually calls
530  * @callback, which must call g_resolver_lookup_service_finish() to
531  * get the final result. See g_resolver_lookup_service() for more
532  * details.
533  *
534  * Since: 2.22
535  **/
536 void
537 g_resolver_lookup_service_async (GResolver           *resolver,
538                                  const gchar         *service,
539                                  const gchar         *protocol,
540                                  const gchar         *domain,
541                                  GCancellable        *cancellable,
542                                  GAsyncReadyCallback  callback,
543                                  gpointer             user_data)
544 {
545   gchar *rrname;
546
547   g_return_if_fail (G_IS_RESOLVER (resolver));
548   g_return_if_fail (service != NULL);
549   g_return_if_fail (protocol != NULL);
550   g_return_if_fail (domain != NULL);
551
552   rrname = g_resolver_get_service_rrname (service, protocol, domain);
553
554   G_RESOLVER_GET_CLASS (resolver)->
555     lookup_service_async (resolver, rrname, cancellable, callback, user_data);
556
557   g_free (rrname);
558 }
559
560 /**
561  * g_resolver_lookup_service_finish:
562  * @resolver: a #GResolver
563  * @result: the result passed to your #GAsyncReadyCallback
564  * @error: return location for a #GError, or %NULL
565  *
566  * Retrieves the result of a previous call to
567  * g_resolver_lookup_service_async().
568  *
569  * If the DNS resolution failed, @error (if non-%NULL) will be set to
570  * a value from #GResolverError. If the operation was cancelled,
571  * @error will be set to %G_IO_ERROR_CANCELLED.
572  *
573  * Return value: a #GList of #GSrvTarget, or %NULL on error. See
574  * g_resolver_lookup_service() for more details.
575  *
576  * Since: 2.22
577  **/
578 GList *
579 g_resolver_lookup_service_finish (GResolver     *resolver,
580                                   GAsyncResult  *result,
581                                   GError       **error)
582 {
583   g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
584
585   if (G_IS_SIMPLE_ASYNC_RESULT (result))
586     {
587       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
588
589       if (g_simple_async_result_propagate_error (simple, error))
590         return NULL;
591     }
592
593   return G_RESOLVER_GET_CLASS (resolver)->
594     lookup_service_finish (resolver, result, error);
595 }
596
597 /**
598  * g_resolver_free_targets:
599  * @targets: a #GList of #GSrvTarget
600  *
601  * Frees @targets (which should be the return value from
602  * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
603  * (This is a convenience method; you can also simply free the
604  * results by hand.)
605  *
606  * Since: 2.22
607  **/
608 void
609 g_resolver_free_targets (GList *targets)
610 {
611   GList *t;
612
613   for (t = targets; t; t = t->next)
614     g_srv_target_free (t->data);
615   g_list_free (targets);
616 }
617
618 /**
619  * g_resolver_error_quark:
620  * 
621  * Gets the #GResolver Error Quark.
622  *
623  * Return value: a #GQuark.
624  *
625  * Since: 2.22
626  **/
627 GQuark
628 g_resolver_error_quark (void)
629 {
630   return g_quark_from_static_string ("g-resolver-error-quark");
631 }
632
633
634 static GResolverError
635 g_resolver_error_from_addrinfo_error (gint err)
636 {
637   switch (err)
638     {
639     case EAI_FAIL:
640     case EAI_NODATA:
641     case EAI_NONAME:
642       return G_RESOLVER_ERROR_NOT_FOUND;
643
644     case EAI_AGAIN:
645       return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
646
647     default:
648       return G_RESOLVER_ERROR_INTERNAL;
649     }
650 }
651
652 struct addrinfo _g_resolver_addrinfo_hints;
653
654 /* Private method to process a getaddrinfo() response. */
655 GList *
656 _g_resolver_addresses_from_addrinfo (const char       *hostname,
657                                      struct addrinfo  *res,
658                                      gint              gai_retval,
659                                      GError          **error)
660 {
661   struct addrinfo *ai;
662   GSocketAddress *sockaddr;
663   GInetAddress *addr;
664   GList *addrs;
665
666   if (gai_retval != 0)
667     {
668       g_set_error (error, G_RESOLVER_ERROR,
669                    g_resolver_error_from_addrinfo_error (gai_retval),
670                    _("Error resolving '%s': %s"),
671                    hostname, gai_strerror (gai_retval));
672       return NULL;
673     }
674
675   g_return_val_if_fail (res != NULL, NULL);
676
677   addrs = NULL;
678   for (ai = res; ai; ai = ai->ai_next)
679     {
680       sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
681       if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
682         continue;
683
684       addr = g_object_ref (g_inet_socket_address_get_address ((GInetSocketAddress *)sockaddr));
685       addrs = g_list_prepend (addrs, addr);
686       g_object_unref (sockaddr);
687     }
688
689   return g_list_reverse (addrs);
690 }
691
692 /* Private method to set up a getnameinfo() request */
693 void
694 _g_resolver_address_to_sockaddr (GInetAddress            *address,
695                                  struct sockaddr_storage *sa,
696                                  gsize                   *sa_len)
697 {
698   GSocketAddress *sockaddr;
699
700   sockaddr = g_inet_socket_address_new (address, 0);
701   g_socket_address_to_native (sockaddr, (struct sockaddr *)sa, sizeof (*sa));
702   *sa_len = g_socket_address_get_native_size (sockaddr);
703   g_object_unref (sockaddr);
704 }
705
706 /* Private method to process a getnameinfo() response. */
707 char *
708 _g_resolver_name_from_nameinfo (GInetAddress  *address,
709                                 const gchar   *name,
710                                 gint           gni_retval,
711                                 GError       **error)
712 {
713   if (gni_retval != 0)
714     {
715       gchar *phys;
716
717       phys = g_inet_address_to_string (address);
718       g_set_error (error, G_RESOLVER_ERROR,
719                    g_resolver_error_from_addrinfo_error (gni_retval),
720                    _("Error reverse-resolving '%s': %s"),
721                    phys ? phys : "(unknown)", gai_strerror (gni_retval));
722       g_free (phys);
723       return NULL;
724     }
725
726   return g_strdup (name);
727 }
728
729 #if defined(G_OS_UNIX)
730 /* Private method to process a res_query response into GSrvTargets */
731 GList *
732 _g_resolver_targets_from_res_query (const gchar      *rrname,
733                                     guchar           *answer,
734                                     gint              len,
735                                     gint              herr,
736                                     GError          **error)
737 {
738   gint count;
739   gchar namebuf[1024];
740   guchar *end, *p;
741   guint16 type, qclass, rdlength, priority, weight, port;
742   guint32 ttl;
743   HEADER *header;
744   GSrvTarget *target;
745   GList *targets;
746
747   if (len <= 0)
748     {
749       GResolverError errnum;
750       const gchar *format;
751
752       if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
753         {
754           errnum = G_RESOLVER_ERROR_NOT_FOUND;
755           format = _("No service record for '%s'");
756         }
757       else if (herr == TRY_AGAIN)
758         {
759           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
760           format = _("Temporarily unable to resolve '%s'");
761         }
762       else
763         {
764           errnum = G_RESOLVER_ERROR_INTERNAL;
765           format = _("Error resolving '%s'");
766         }
767
768       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
769       return NULL;
770     }
771
772   targets = NULL;
773
774   header = (HEADER *)answer;
775   p = answer + sizeof (HEADER);
776   end = answer + len;
777
778   /* Skip query */
779   count = ntohs (header->qdcount);
780   while (count-- && p < end)
781     {
782       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
783       p += 4;
784     }
785
786   /* Read answers */
787   count = ntohs (header->ancount);
788   while (count-- && p < end)
789     {
790       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
791       GETSHORT (type, p);
792       GETSHORT (qclass, p);
793       GETLONG  (ttl, p);
794       GETSHORT (rdlength, p);
795
796       if (type != T_SRV || qclass != C_IN)
797         {
798           p += rdlength;
799           continue;
800         }
801
802       GETSHORT (priority, p);
803       GETSHORT (weight, p);
804       GETSHORT (port, p);
805       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
806
807       target = g_srv_target_new (namebuf, port, priority, weight);
808       targets = g_list_prepend (targets, target);
809     }
810
811   return g_srv_target_list_sort (targets);
812 }
813 #elif defined(G_OS_WIN32)
814 /* Private method to process a DnsQuery response into GSrvTargets */
815 GList *
816 _g_resolver_targets_from_DnsQuery (const gchar  *rrname,
817                                    DNS_STATUS    status,
818                                    DNS_RECORD   *results,
819                                    GError      **error)
820 {
821   DNS_RECORD *rec;
822   GSrvTarget *target;
823   GList *targets;
824
825   if (status != ERROR_SUCCESS)
826     {
827       GResolverError errnum;
828       const gchar *format;
829
830       if (status == DNS_ERROR_RCODE_NAME_ERROR)
831         {
832           errnum = G_RESOLVER_ERROR_NOT_FOUND;
833           format = _("No service record for '%s'");
834         }
835       else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
836         {
837           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
838           format = _("Temporarily unable to resolve '%s'");
839         }
840       else
841         {
842           errnum = G_RESOLVER_ERROR_INTERNAL;
843           format = _("Error resolving '%s'");
844         }
845
846       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
847       return NULL;
848     }
849
850   targets = NULL;
851   for (rec = results; rec; rec = rec->pNext)
852     {
853       if (rec->wType != DNS_TYPE_SRV)
854         continue;
855
856       target = g_srv_target_new (rec->Data.SRV.pNameTarget,
857                                  rec->Data.SRV.wPort,
858                                  rec->Data.SRV.wPriority,
859                                  rec->Data.SRV.wWeight);
860       targets = g_list_prepend (targets, target);
861     }
862
863   return g_srv_target_list_sort (targets);
864 }
865
866 #endif
867
868 #define __G_RESOLVER_C__
869 #include "gioaliasdef.c"