gio: Add names to idles and timeouts
[platform/upstream/glib.git] / gio / gthreadedresolver.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright (C) 2008 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "config.h"
22 #include <glib.h>
23 #include "glibintl.h"
24
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "gthreadedresolver.h"
29 #include "gnetworkingprivate.h"
30
31 #include "gcancellable.h"
32 #include "ginetaddress.h"
33 #include "ginetsocketaddress.h"
34 #include "gtask.h"
35 #include "gsocketaddress.h"
36 #include "gsrvtarget.h"
37
38
39 G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
40
41 static void
42 g_threaded_resolver_init (GThreadedResolver *gtr)
43 {
44 }
45
46 static GResolverError
47 g_resolver_error_from_addrinfo_error (gint err)
48 {
49   switch (err)
50     {
51     case EAI_FAIL:
52 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
53     case EAI_NODATA:
54 #endif
55     case EAI_NONAME:
56       return G_RESOLVER_ERROR_NOT_FOUND;
57
58     case EAI_AGAIN:
59       return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
60
61     default:
62       return G_RESOLVER_ERROR_INTERNAL;
63     }
64 }
65
66 static struct addrinfo addrinfo_hints;
67
68 static void
69 do_lookup_by_name (GTask         *task,
70                    gpointer       source_object,
71                    gpointer       task_data,
72                    GCancellable  *cancellable)
73 {
74   const char *hostname = task_data;
75   struct addrinfo *res = NULL;
76   GList *addresses;
77   gint retval;
78
79   retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
80
81   if (retval == 0)
82     {
83       struct addrinfo *ai;
84       GSocketAddress *sockaddr;
85       GInetAddress *addr;
86
87       addresses = NULL;
88       for (ai = res; ai; ai = ai->ai_next)
89         {
90           sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
91           if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
92             continue;
93
94           addr = g_object_ref (g_inet_socket_address_get_address ((GInetSocketAddress *)sockaddr));
95           addresses = g_list_prepend (addresses, addr);
96           g_object_unref (sockaddr);
97         }
98
99       addresses = g_list_reverse (addresses);
100       g_task_return_pointer (task, addresses,
101                              (GDestroyNotify)g_resolver_free_addresses);
102     }
103   else
104     {
105       g_task_return_new_error (task,
106                                G_RESOLVER_ERROR,
107                                g_resolver_error_from_addrinfo_error (retval),
108                                _("Error resolving '%s': %s"),
109                                hostname, gai_strerror (retval));
110     }
111
112   if (res)
113     freeaddrinfo (res);
114 }
115
116 static GList *
117 lookup_by_name (GResolver     *resolver,
118                 const gchar   *hostname,
119                 GCancellable  *cancellable,
120                 GError       **error)
121 {
122   GTask *task;
123   GList *addresses;
124
125   task = g_task_new (resolver, cancellable, NULL, NULL);
126   g_task_set_task_data (task, g_strdup (hostname), g_free);
127   g_task_set_return_on_cancel (task, TRUE);
128   g_task_run_in_thread_sync (task, do_lookup_by_name);
129   addresses = g_task_propagate_pointer (task, error);
130   g_object_unref (task);
131
132   return addresses;
133 }
134
135 static void
136 lookup_by_name_async (GResolver           *resolver,
137                       const gchar         *hostname,
138                       GCancellable        *cancellable,
139                       GAsyncReadyCallback  callback,
140                       gpointer             user_data)
141 {
142   GTask *task;
143
144   task = g_task_new (resolver, cancellable, callback, user_data);
145   g_task_set_task_data (task, g_strdup (hostname), g_free);
146   g_task_set_return_on_cancel (task, TRUE);
147   g_task_run_in_thread (task, do_lookup_by_name);
148   g_object_unref (task);
149 }
150
151 static GList *
152 lookup_by_name_finish (GResolver     *resolver,
153                        GAsyncResult  *result,
154                        GError       **error)
155 {
156   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
157
158   return g_task_propagate_pointer (G_TASK (result), error);
159 }
160
161
162 static void
163 do_lookup_by_address (GTask         *task,
164                       gpointer       source_object,
165                       gpointer       task_data,
166                       GCancellable  *cancellable)
167 {
168   GInetAddress *address = task_data;
169   struct sockaddr_storage sockaddr;
170   gsize sockaddr_size;
171   GSocketAddress *gsockaddr;
172   gchar name[NI_MAXHOST];
173   gint retval;
174
175   gsockaddr = g_inet_socket_address_new (address, 0);
176   g_socket_address_to_native (gsockaddr, (struct sockaddr *)&sockaddr,
177                               sizeof (sockaddr), NULL);
178   sockaddr_size = g_socket_address_get_native_size (gsockaddr);
179   g_object_unref (gsockaddr);
180
181   retval = getnameinfo ((struct sockaddr *)&sockaddr, sockaddr_size,
182                         name, sizeof (name), NULL, 0, NI_NAMEREQD);
183   if (retval == 0)
184     g_task_return_pointer (task, g_strdup (name), g_free);
185   else
186     {
187       gchar *phys;
188
189       phys = g_inet_address_to_string (address);
190       g_task_return_new_error (task,
191                                G_RESOLVER_ERROR,
192                                g_resolver_error_from_addrinfo_error (retval),
193                                _("Error reverse-resolving '%s': %s"),
194                                phys ? phys : "(unknown)",
195                                gai_strerror (retval));
196       g_free (phys);
197     }
198 }
199
200 static gchar *
201 lookup_by_address (GResolver        *resolver,
202                    GInetAddress     *address,
203                    GCancellable     *cancellable,
204                    GError          **error)
205 {
206   GTask *task;
207   gchar *name;
208
209   task = g_task_new (resolver, cancellable, NULL, NULL);
210   g_task_set_task_data (task, g_object_ref (address), g_object_unref);
211   g_task_set_return_on_cancel (task, TRUE);
212   g_task_run_in_thread_sync (task, do_lookup_by_address);
213   name = g_task_propagate_pointer (task, error);
214   g_object_unref (task);
215
216   return name;
217 }
218
219 static void
220 lookup_by_address_async (GResolver           *resolver,
221                          GInetAddress        *address,
222                          GCancellable        *cancellable,
223                          GAsyncReadyCallback  callback,
224                          gpointer             user_data)
225 {
226   GTask *task;
227
228   task = g_task_new (resolver, cancellable, callback, user_data);
229   g_task_set_task_data (task, g_object_ref (address), g_object_unref);
230   g_task_set_return_on_cancel (task, TRUE);
231   g_task_run_in_thread (task, do_lookup_by_address);
232   g_object_unref (task);
233 }
234
235 static gchar *
236 lookup_by_address_finish (GResolver     *resolver,
237                           GAsyncResult  *result,
238                           GError       **error)
239 {
240   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
241
242   return g_task_propagate_pointer (G_TASK (result), error);
243 }
244
245
246 #if defined(G_OS_UNIX)
247
248 #ifdef __BIONIC__
249 /* Copy from bionic/libc/private/arpa_nameser_compat.h
250  * and bionic/libc/private/arpa_nameser.h */
251 typedef struct {
252         unsigned        id :16;         /* query identification number */
253 #if BYTE_ORDER == BIG_ENDIAN
254                         /* fields in third byte */
255         unsigned        qr: 1;          /* response flag */
256         unsigned        opcode: 4;      /* purpose of message */
257         unsigned        aa: 1;          /* authoritive answer */
258         unsigned        tc: 1;          /* truncated message */
259         unsigned        rd: 1;          /* recursion desired */
260                         /* fields in fourth byte */
261         unsigned        ra: 1;          /* recursion available */
262         unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
263         unsigned        ad: 1;          /* authentic data from named */
264         unsigned        cd: 1;          /* checking disabled by resolver */
265         unsigned        rcode :4;       /* response code */
266 #endif
267 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
268                         /* fields in third byte */
269         unsigned        rd :1;          /* recursion desired */
270         unsigned        tc :1;          /* truncated message */
271         unsigned        aa :1;          /* authoritive answer */
272         unsigned        opcode :4;      /* purpose of message */
273         unsigned        qr :1;          /* response flag */
274                         /* fields in fourth byte */
275         unsigned        rcode :4;       /* response code */
276         unsigned        cd: 1;          /* checking disabled by resolver */
277         unsigned        ad: 1;          /* authentic data from named */
278         unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
279         unsigned        ra :1;          /* recursion available */
280 #endif
281                         /* remaining bytes */
282         unsigned        qdcount :16;    /* number of question entries */
283         unsigned        ancount :16;    /* number of answer entries */
284         unsigned        nscount :16;    /* number of authority entries */
285         unsigned        arcount :16;    /* number of resource entries */
286 } HEADER;
287
288 #define NS_INT32SZ      4       /* #/bytes of data in a uint32_t */
289 #define NS_INT16SZ      2       /* #/bytes of data in a uint16_t */
290
291 #define NS_GET16(s, cp) do { \
292         const u_char *t_cp = (const u_char *)(cp); \
293         (s) = ((uint16_t)t_cp[0] << 8) \
294             | ((uint16_t)t_cp[1]) \
295             ; \
296         (cp) += NS_INT16SZ; \
297 } while (/*CONSTCOND*/0)
298
299 #define NS_GET32(l, cp) do { \
300         const u_char *t_cp = (const u_char *)(cp); \
301         (l) = ((uint32_t)t_cp[0] << 24) \
302             | ((uint32_t)t_cp[1] << 16) \
303             | ((uint32_t)t_cp[2] << 8) \
304             | ((uint32_t)t_cp[3]) \
305             ; \
306         (cp) += NS_INT32SZ; \
307 } while (/*CONSTCOND*/0)
308
309 #define GETSHORT                NS_GET16
310 #define GETLONG                 NS_GET32
311
312 #define C_IN 1
313
314 /* From bionic/libc/private/resolv_private.h */
315 int dn_expand(const u_char *, const u_char *, const u_char *, char *, int);
316 #define dn_skipname __dn_skipname
317 int dn_skipname(const u_char *, const u_char *);
318
319 /* From bionic/libc/private/arpa_nameser_compat.h */
320 #define T_MX            ns_t_mx
321 #define T_TXT           ns_t_txt
322 #define T_SOA           ns_t_soa
323 #define T_NS            ns_t_ns
324
325 /* From bionic/libc/private/arpa_nameser.h */
326 typedef enum __ns_type {
327         ns_t_invalid = 0,       /* Cookie. */
328         ns_t_a = 1,             /* Host address. */
329         ns_t_ns = 2,            /* Authoritative server. */
330         ns_t_md = 3,            /* Mail destination. */
331         ns_t_mf = 4,            /* Mail forwarder. */
332         ns_t_cname = 5,         /* Canonical name. */
333         ns_t_soa = 6,           /* Start of authority zone. */
334         ns_t_mb = 7,            /* Mailbox domain name. */
335         ns_t_mg = 8,            /* Mail group member. */
336         ns_t_mr = 9,            /* Mail rename name. */
337         ns_t_null = 10,         /* Null resource record. */
338         ns_t_wks = 11,          /* Well known service. */
339         ns_t_ptr = 12,          /* Domain name pointer. */
340         ns_t_hinfo = 13,        /* Host information. */
341         ns_t_minfo = 14,        /* Mailbox information. */
342         ns_t_mx = 15,           /* Mail routing information. */
343         ns_t_txt = 16,          /* Text strings. */
344         ns_t_rp = 17,           /* Responsible person. */
345         ns_t_afsdb = 18,        /* AFS cell database. */
346         ns_t_x25 = 19,          /* X_25 calling address. */
347         ns_t_isdn = 20,         /* ISDN calling address. */
348         ns_t_rt = 21,           /* Router. */
349         ns_t_nsap = 22,         /* NSAP address. */
350         ns_t_nsap_ptr = 23,     /* Reverse NSAP lookup (deprecated). */
351         ns_t_sig = 24,          /* Security signature. */
352         ns_t_key = 25,          /* Security key. */
353         ns_t_px = 26,           /* X.400 mail mapping. */
354         ns_t_gpos = 27,         /* Geographical position (withdrawn). */
355         ns_t_aaaa = 28,         /* Ip6 Address. */
356         ns_t_loc = 29,          /* Location Information. */
357         ns_t_nxt = 30,          /* Next domain (security). */
358         ns_t_eid = 31,          /* Endpoint identifier. */
359         ns_t_nimloc = 32,       /* Nimrod Locator. */
360         ns_t_srv = 33,          /* Server Selection. */
361         ns_t_atma = 34,         /* ATM Address */
362         ns_t_naptr = 35,        /* Naming Authority PoinTeR */
363         ns_t_kx = 36,           /* Key Exchange */
364         ns_t_cert = 37,         /* Certification record */
365         ns_t_a6 = 38,           /* IPv6 address (deprecates AAAA) */
366         ns_t_dname = 39,        /* Non-terminal DNAME (for IPv6) */
367         ns_t_sink = 40,         /* Kitchen sink (experimentatl) */
368         ns_t_opt = 41,          /* EDNS0 option (meta-RR) */
369         ns_t_apl = 42,          /* Address prefix list (RFC 3123) */
370         ns_t_tkey = 249,        /* Transaction key */
371         ns_t_tsig = 250,        /* Transaction signature. */
372         ns_t_ixfr = 251,        /* Incremental zone transfer. */
373         ns_t_axfr = 252,        /* Transfer zone of authority. */
374         ns_t_mailb = 253,       /* Transfer mailbox records. */
375         ns_t_maila = 254,       /* Transfer mail agent records. */
376         ns_t_any = 255,         /* Wildcard match. */
377         ns_t_zxfr = 256,        /* BIND-specific, nonstandard. */
378         ns_t_max = 65536
379 } ns_type;
380
381 #endif /* __BIONIC__ */
382
383 static GVariant *
384 parse_res_srv (guchar  *answer,
385                guchar  *end,
386                guchar **p)
387 {
388   gchar namebuf[1024];
389   guint16 priority, weight, port;
390
391   GETSHORT (priority, *p);
392   GETSHORT (weight, *p);
393   GETSHORT (port, *p);
394   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
395
396   return g_variant_new ("(qqqs)",
397                         priority,
398                         weight,
399                         port,
400                         namebuf);
401 }
402
403 static GVariant *
404 parse_res_soa (guchar  *answer,
405                guchar  *end,
406                guchar **p)
407 {
408   gchar mnamebuf[1024];
409   gchar rnamebuf[1024];
410   guint32 serial, refresh, retry, expire, ttl;
411
412   *p += dn_expand (answer, end, *p, mnamebuf, sizeof (mnamebuf));
413   *p += dn_expand (answer, end, *p, rnamebuf, sizeof (rnamebuf));
414
415   GETLONG (serial, *p);
416   GETLONG (refresh, *p);
417   GETLONG (retry, *p);
418   GETLONG (expire, *p);
419   GETLONG (ttl, *p);
420
421   return g_variant_new ("(ssuuuuu)",
422                         mnamebuf,
423                         rnamebuf,
424                         serial,
425                         refresh,
426                         retry,
427                         expire,
428                         ttl);
429 }
430
431 static GVariant *
432 parse_res_ns (guchar  *answer,
433               guchar  *end,
434               guchar **p)
435 {
436   gchar namebuf[1024];
437
438   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
439
440   return g_variant_new ("(s)", namebuf);
441 }
442
443 static GVariant *
444 parse_res_mx (guchar  *answer,
445               guchar  *end,
446               guchar **p)
447 {
448   gchar namebuf[1024];
449   guint16 preference;
450
451   GETSHORT (preference, *p);
452
453   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
454
455   return g_variant_new ("(qs)",
456                         preference,
457                         namebuf);
458 }
459
460 static GVariant *
461 parse_res_txt (guchar  *answer,
462                guchar  *end,
463                guchar **p)
464 {
465   GVariant *record;
466   GPtrArray *array;
467   guchar *at = *p;
468   gsize len;
469
470   array = g_ptr_array_new_with_free_func (g_free);
471   while (at < end)
472     {
473       len = *(at++);
474       if (len > at - end)
475         break;
476       g_ptr_array_add (array, g_strndup ((gchar *)at, len));
477       at += len;
478     }
479
480   *p = at;
481   record = g_variant_new ("(@as)",
482                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
483   g_ptr_array_free (array, TRUE);
484   return record;
485 }
486
487 static gint
488 g_resolver_record_type_to_rrtype (GResolverRecordType type)
489 {
490   switch (type)
491   {
492     case G_RESOLVER_RECORD_SRV:
493       return T_SRV;
494     case G_RESOLVER_RECORD_TXT:
495       return T_TXT;
496     case G_RESOLVER_RECORD_SOA:
497       return T_SOA;
498     case G_RESOLVER_RECORD_NS:
499       return T_NS;
500     case G_RESOLVER_RECORD_MX:
501       return T_MX;
502   }
503   g_return_val_if_reached (-1);
504 }
505
506 #pragma GCC diagnostic push
507 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
508
509 static GList *
510 g_resolver_records_from_res_query (const gchar      *rrname,
511                                    gint              rrtype,
512                                    guchar           *answer,
513                                    gint              len,
514                                    gint              herr,
515                                    GError          **error)
516 {
517   gint count;
518   gchar namebuf[1024];
519   guchar *end, *p;
520   guint16 type, qclass, rdlength;
521   guint32 ttl;
522   HEADER *header;
523   GList *records;
524   GVariant *record;
525
526   if (len <= 0)
527     {
528       if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
529         {
530           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
531                        _("No DNS record of the requested type for '%s'"), rrname);
532         }
533       else if (herr == TRY_AGAIN)
534         {
535           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE,
536                        _("Temporarily unable to resolve '%s'"), rrname);
537         }
538       else
539         {
540           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL,
541                        _("Error resolving '%s'"), rrname);
542         }
543
544       return NULL;
545     }
546
547   records = NULL;
548
549   header = (HEADER *)answer;
550   p = answer + sizeof (HEADER);
551   end = answer + len;
552
553   /* Skip query */
554   count = ntohs (header->qdcount);
555   while (count-- && p < end)
556     {
557       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
558       p += 4;
559
560       /* To silence gcc warnings */
561       namebuf[0] = namebuf[1];
562     }
563
564   /* Read answers */
565   count = ntohs (header->ancount);
566   while (count-- && p < end)
567     {
568       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
569       GETSHORT (type, p);
570       GETSHORT (qclass, p);
571       GETLONG  (ttl, p);
572       ttl = ttl; /* To avoid -Wunused-but-set-variable */
573       GETSHORT (rdlength, p);
574
575       if (type != rrtype || qclass != C_IN)
576         {
577           p += rdlength;
578           continue;
579         }
580
581       switch (rrtype)
582         {
583         case T_SRV:
584           record = parse_res_srv (answer, end, &p);
585           break;
586         case T_MX:
587           record = parse_res_mx (answer, end, &p);
588           break;
589         case T_SOA:
590           record = parse_res_soa (answer, end, &p);
591           break;
592         case T_NS:
593           record = parse_res_ns (answer, end, &p);
594           break;
595         case T_TXT:
596           record = parse_res_txt (answer, p + rdlength, &p);
597           break;
598         default:
599           g_warn_if_reached ();
600           record = NULL;
601           break;
602         }
603
604       if (record != NULL)
605         records = g_list_prepend (records, record);
606     }
607
608   if (records == NULL)
609     {
610       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
611                    _("No DNS record of the requested type for '%s'"), rrname);
612
613       return NULL;
614     }
615   else
616     return records;
617 }
618
619 #pragma GCC diagnostic pop
620
621 #elif defined(G_OS_WIN32)
622
623 static GVariant *
624 parse_dns_srv (DNS_RECORD *rec)
625 {
626   return g_variant_new ("(qqqs)",
627                         (guint16)rec->Data.SRV.wPriority,
628                         (guint16)rec->Data.SRV.wWeight,
629                         (guint16)rec->Data.SRV.wPort,
630                         rec->Data.SRV.pNameTarget);
631 }
632
633 static GVariant *
634 parse_dns_soa (DNS_RECORD *rec)
635 {
636   return g_variant_new ("(ssuuuuu)",
637                         rec->Data.SOA.pNamePrimaryServer,
638                         rec->Data.SOA.pNameAdministrator,
639                         (guint32)rec->Data.SOA.dwSerialNo,
640                         (guint32)rec->Data.SOA.dwRefresh,
641                         (guint32)rec->Data.SOA.dwRetry,
642                         (guint32)rec->Data.SOA.dwExpire,
643                         (guint32)rec->Data.SOA.dwDefaultTtl);
644 }
645
646 static GVariant *
647 parse_dns_ns (DNS_RECORD *rec)
648 {
649   return g_variant_new ("(s)", rec->Data.NS.pNameHost);
650 }
651
652 static GVariant *
653 parse_dns_mx (DNS_RECORD *rec)
654 {
655   return g_variant_new ("(qs)",
656                         (guint16)rec->Data.MX.wPreference,
657                         rec->Data.MX.pNameExchange);
658 }
659
660 static GVariant *
661 parse_dns_txt (DNS_RECORD *rec)
662 {
663   GVariant *record;
664   GPtrArray *array;
665   DWORD i;
666
667   array = g_ptr_array_new ();
668   for (i = 0; i < rec->Data.TXT.dwStringCount; i++)
669     g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]);
670   record = g_variant_new ("(@as)",
671                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
672   g_ptr_array_free (array, TRUE);
673   return record;
674 }
675
676 static WORD
677 g_resolver_record_type_to_dnstype (GResolverRecordType type)
678 {
679   switch (type)
680   {
681     case G_RESOLVER_RECORD_SRV:
682       return DNS_TYPE_SRV;
683     case G_RESOLVER_RECORD_TXT:
684       return DNS_TYPE_TEXT;
685     case G_RESOLVER_RECORD_SOA:
686       return DNS_TYPE_SOA;
687     case G_RESOLVER_RECORD_NS:
688       return DNS_TYPE_NS;
689     case G_RESOLVER_RECORD_MX:
690       return DNS_TYPE_MX;
691   }
692   g_return_val_if_reached (-1);
693 }
694
695 static GList *
696 g_resolver_records_from_DnsQuery (const gchar  *rrname,
697                                   WORD          dnstype,
698                                   DNS_STATUS    status,
699                                   DNS_RECORD   *results,
700                                   GError      **error)
701 {
702   DNS_RECORD *rec;
703   gpointer record;
704   GList *records;
705
706   if (status != ERROR_SUCCESS)
707     {
708       if (status == DNS_ERROR_RCODE_NAME_ERROR)
709         {
710           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
711                        _("No DNS record of the requested type for '%s'"), rrname);
712         }
713       else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
714         {
715           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE,
716                        _("Temporarily unable to resolve '%s'"), rrname);
717         }
718       else
719         {
720           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL,
721                        _("Error resolving '%s'"), rrname);
722         }
723
724       return NULL;
725     }
726
727   records = NULL;
728   for (rec = results; rec; rec = rec->pNext)
729     {
730       if (rec->wType != dnstype)
731         continue;
732       switch (dnstype)
733         {
734         case DNS_TYPE_SRV:
735           record = parse_dns_srv (rec);
736           break;
737         case DNS_TYPE_SOA:
738           record = parse_dns_soa (rec);
739           break;
740         case DNS_TYPE_NS:
741           record = parse_dns_ns (rec);
742           break;
743         case DNS_TYPE_MX:
744           record = parse_dns_mx (rec);
745           break;
746         case DNS_TYPE_TEXT:
747           record = parse_dns_txt (rec);
748           break;
749         default:
750           g_warn_if_reached ();
751           record = NULL;
752           break;
753         }
754       if (record != NULL)
755         records = g_list_prepend (records, g_variant_ref_sink (record));
756     }
757
758   if (records == NULL)
759     {
760       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
761                    _("No DNS record of the requested type for '%s'"), rrname);
762
763       return NULL;
764     }
765   else
766     return records;
767 }
768
769 #endif
770
771 typedef struct {
772   char *rrname;
773   GResolverRecordType record_type;
774 } LookupRecordsData;
775
776 static void
777 free_lookup_records_data (LookupRecordsData *lrd)
778 {
779   g_free (lrd->rrname);
780   g_slice_free (LookupRecordsData, lrd);
781 }
782
783 static void
784 free_records (GList *records)
785 {
786   g_list_free_full (records, (GDestroyNotify) g_variant_unref);
787 }
788
789 #if defined(G_OS_UNIX)
790 #ifdef __BIONIC__
791 #define C_IN 1
792 int res_query(const char *, int, int, u_char *, int);
793 #endif
794 #endif
795
796 static void
797 do_lookup_records (GTask         *task,
798                    gpointer       source_object,
799                    gpointer       task_data,
800                    GCancellable  *cancellable)
801 {
802   LookupRecordsData *lrd = task_data;
803   GList *records;
804   GError *error = NULL;
805
806 #if defined(G_OS_UNIX)
807   gint len = 512;
808   gint herr;
809   GByteArray *answer;
810   gint rrtype;
811
812   rrtype = g_resolver_record_type_to_rrtype (lrd->record_type);
813   answer = g_byte_array_new ();
814   for (;;)
815     {
816       g_byte_array_set_size (answer, len * 2);
817       len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
818
819       /* If answer fit in the buffer then we're done */
820       if (len < 0 || len < (gint)answer->len)
821         break;
822
823       /*
824        * On overflow some res_query's return the length needed, others
825        * return the full length entered. This code works in either case.
826        */
827     }
828
829   herr = h_errno;
830   records = g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
831   g_byte_array_free (answer, TRUE);
832
833 #else
834
835   DNS_STATUS status;
836   DNS_RECORD *results = NULL;
837   WORD dnstype;
838
839   dnstype = g_resolver_record_type_to_dnstype (lrd->record_type);
840   status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
841   records = g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
842   if (results != NULL)
843     DnsRecordListFree (results, DnsFreeRecordList);
844
845 #endif
846
847   if (records)
848     g_task_return_pointer (task, records, (GDestroyNotify) free_records);
849   else
850     g_task_return_error (task, error);
851 }
852
853 static GList *
854 lookup_records (GResolver              *resolver,
855                 const gchar            *rrname,
856                 GResolverRecordType     record_type,
857                 GCancellable           *cancellable,
858                 GError                **error)
859 {
860   GTask *task;
861   GList *records;
862   LookupRecordsData *lrd;
863
864   task = g_task_new (resolver, cancellable, NULL, NULL);
865
866   lrd = g_slice_new (LookupRecordsData);
867   lrd->rrname = g_strdup (rrname);
868   lrd->record_type = record_type;
869   g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
870
871   g_task_set_return_on_cancel (task, TRUE);
872   g_task_run_in_thread_sync (task, do_lookup_records);
873   records = g_task_propagate_pointer (task, error);
874   g_object_unref (task);
875
876   return records;
877 }
878
879 static void
880 lookup_records_async (GResolver           *resolver,
881                       const char          *rrname,
882                       GResolverRecordType  record_type,
883                       GCancellable        *cancellable,
884                       GAsyncReadyCallback  callback,
885                       gpointer             user_data)
886 {
887   GTask *task;
888   LookupRecordsData *lrd;
889
890   task = g_task_new (resolver, cancellable, callback, user_data);
891
892   lrd = g_slice_new (LookupRecordsData);
893   lrd->rrname = g_strdup (rrname);
894   lrd->record_type = record_type;
895   g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
896
897   g_task_set_return_on_cancel (task, TRUE);
898   g_task_run_in_thread (task, do_lookup_records);
899   g_object_unref (task);
900 }
901
902 static GList *
903 lookup_records_finish (GResolver     *resolver,
904                        GAsyncResult  *result,
905                        GError       **error)
906 {
907   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
908
909   return g_task_propagate_pointer (G_TASK (result), error);
910 }
911
912
913 static void
914 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
915 {
916   GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
917
918   resolver_class->lookup_by_name           = lookup_by_name;
919   resolver_class->lookup_by_name_async     = lookup_by_name_async;
920   resolver_class->lookup_by_name_finish    = lookup_by_name_finish;
921   resolver_class->lookup_by_address        = lookup_by_address;
922   resolver_class->lookup_by_address_async  = lookup_by_address_async;
923   resolver_class->lookup_by_address_finish = lookup_by_address_finish;
924   resolver_class->lookup_records           = lookup_records;
925   resolver_class->lookup_records_async     = lookup_records_async;
926   resolver_class->lookup_records_finish    = lookup_records_finish;
927
928   /* Initialize addrinfo_hints */
929 #ifdef AI_ADDRCONFIG
930   addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
931 #endif
932   /* These two don't actually matter, they just get copied into the
933    * returned addrinfo structures (and then we ignore them). But if
934    * we leave them unset, we'll get back duplicate answers.
935    */
936   addrinfo_hints.ai_socktype = SOCK_STREAM;
937   addrinfo_hints.ai_protocol = IPPROTO_TCP;
938 }