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