2332adf4ae606be23891d5e1cf1a76802b857ff8
[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, 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 <stdio.h>
28 #include <string.h>
29
30 #include "gthreadedresolver.h"
31 #include "gnetworkingprivate.h"
32
33 #include "gcancellable.h"
34 #include "ginetaddress.h"
35 #include "ginetsocketaddress.h"
36 #include "gtask.h"
37 #include "gsocketaddress.h"
38 #include "gsrvtarget.h"
39
40
41 G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
42
43 static void
44 g_threaded_resolver_init (GThreadedResolver *gtr)
45 {
46 }
47
48 static GResolverError
49 g_resolver_error_from_addrinfo_error (gint err)
50 {
51   switch (err)
52     {
53     case EAI_FAIL:
54 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
55     case EAI_NODATA:
56 #endif
57     case EAI_NONAME:
58       return G_RESOLVER_ERROR_NOT_FOUND;
59
60     case EAI_AGAIN:
61       return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
62
63     default:
64       return G_RESOLVER_ERROR_INTERNAL;
65     }
66 }
67
68 static struct addrinfo addrinfo_hints;
69
70 static void
71 do_lookup_by_name (GTask         *task,
72                    gpointer       source_object,
73                    gpointer       task_data,
74                    GCancellable  *cancellable)
75 {
76   const char *hostname = task_data;
77   struct addrinfo *res = NULL;
78   GList *addresses;
79   gint retval;
80
81   retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
82
83   if (retval == 0)
84     {
85       struct addrinfo *ai;
86       GSocketAddress *sockaddr;
87       GInetAddress *addr;
88
89       addresses = NULL;
90       for (ai = res; ai; ai = ai->ai_next)
91         {
92           sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
93           if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
94             continue;
95
96           addr = g_object_ref (g_inet_socket_address_get_address ((GInetSocketAddress *)sockaddr));
97           addresses = g_list_prepend (addresses, addr);
98           g_object_unref (sockaddr);
99         }
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       g_task_return_new_error (task,
108                                G_RESOLVER_ERROR,
109                                g_resolver_error_from_addrinfo_error (retval),
110                                _("Error resolving '%s': %s"),
111                                hostname, gai_strerror (retval));
112     }
113
114   if (res)
115     freeaddrinfo (res);
116 }
117
118 static GList *
119 lookup_by_name (GResolver     *resolver,
120                 const gchar   *hostname,
121                 GCancellable  *cancellable,
122                 GError       **error)
123 {
124   GTask *task;
125   GList *addresses;
126
127   task = g_task_new (resolver, cancellable, NULL, NULL);
128   g_task_set_task_data (task, g_strdup (hostname), g_free);
129   g_task_set_return_on_cancel (task, TRUE);
130   g_task_run_in_thread_sync (task, do_lookup_by_name);
131   addresses = g_task_propagate_pointer (task, error);
132   g_object_unref (task);
133
134   return addresses;
135 }
136
137 static void
138 lookup_by_name_async (GResolver           *resolver,
139                       const gchar         *hostname,
140                       GCancellable        *cancellable,
141                       GAsyncReadyCallback  callback,
142                       gpointer             user_data)
143 {
144   GTask *task;
145
146   task = g_task_new (resolver, cancellable, callback, user_data);
147   g_task_set_task_data (task, g_strdup (hostname), g_free);
148   g_task_set_return_on_cancel (task, TRUE);
149   g_task_run_in_thread (task, do_lookup_by_name);
150   g_object_unref (task);
151 }
152
153 static GList *
154 lookup_by_name_finish (GResolver     *resolver,
155                        GAsyncResult  *result,
156                        GError       **error)
157 {
158   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
159
160   return g_task_propagate_pointer (G_TASK (result), error);
161 }
162
163
164 static void
165 do_lookup_by_address (GTask         *task,
166                       gpointer       source_object,
167                       gpointer       task_data,
168                       GCancellable  *cancellable)
169 {
170   GInetAddress *address = task_data;
171   struct sockaddr_storage sockaddr;
172   gsize sockaddr_size;
173   GSocketAddress *gsockaddr;
174   gchar name[NI_MAXHOST];
175   gint retval;
176
177   gsockaddr = g_inet_socket_address_new (address, 0);
178   g_socket_address_to_native (gsockaddr, (struct sockaddr *)&sockaddr,
179                               sizeof (sockaddr), NULL);
180   sockaddr_size = g_socket_address_get_native_size (gsockaddr);
181   g_object_unref (gsockaddr);
182
183   retval = getnameinfo ((struct sockaddr *)&sockaddr, sockaddr_size,
184                         name, sizeof (name), NULL, 0, NI_NAMEREQD);
185   if (retval == 0)
186     g_task_return_pointer (task, g_strdup (name), g_free);
187   else
188     {
189       gchar *phys;
190
191       phys = g_inet_address_to_string (address);
192       g_task_return_new_error (task,
193                                G_RESOLVER_ERROR,
194                                g_resolver_error_from_addrinfo_error (retval),
195                                _("Error reverse-resolving '%s': %s"),
196                                phys ? phys : "(unknown)",
197                                gai_strerror (retval));
198       g_free (phys);
199     }
200 }
201
202 static gchar *
203 lookup_by_address (GResolver        *resolver,
204                    GInetAddress     *address,
205                    GCancellable     *cancellable,
206                    GError          **error)
207 {
208   GTask *task;
209   gchar *name;
210
211   task = g_task_new (resolver, cancellable, NULL, NULL);
212   g_task_set_task_data (task, g_object_ref (address), g_object_unref);
213   g_task_set_return_on_cancel (task, TRUE);
214   g_task_run_in_thread_sync (task, do_lookup_by_address);
215   name = g_task_propagate_pointer (task, error);
216   g_object_unref (task);
217
218   return name;
219 }
220
221 static void
222 lookup_by_address_async (GResolver           *resolver,
223                          GInetAddress        *address,
224                          GCancellable        *cancellable,
225                          GAsyncReadyCallback  callback,
226                          gpointer             user_data)
227 {
228   GTask *task;
229
230   task = g_task_new (resolver, cancellable, callback, user_data);
231   g_task_set_task_data (task, g_object_ref (address), g_object_unref);
232   g_task_set_return_on_cancel (task, TRUE);
233   g_task_run_in_thread (task, do_lookup_by_address);
234   g_object_unref (task);
235 }
236
237 static gchar *
238 lookup_by_address_finish (GResolver     *resolver,
239                           GAsyncResult  *result,
240                           GError       **error)
241 {
242   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
243
244   return g_task_propagate_pointer (G_TASK (result), error);
245 }
246
247
248 #if defined(G_OS_UNIX)
249 static GVariant *
250 parse_res_srv (guchar  *answer,
251                guchar  *end,
252                guchar **p)
253 {
254   gchar namebuf[1024];
255   guint16 priority, weight, port;
256
257   GETSHORT (priority, *p);
258   GETSHORT (weight, *p);
259   GETSHORT (port, *p);
260   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
261
262   return g_variant_new ("(qqqs)",
263                         priority,
264                         weight,
265                         port,
266                         namebuf);
267 }
268
269 static GVariant *
270 parse_res_soa (guchar  *answer,
271                guchar  *end,
272                guchar **p)
273 {
274   gchar mnamebuf[1024];
275   gchar rnamebuf[1024];
276   guint32 serial, refresh, retry, expire, ttl;
277
278   *p += dn_expand (answer, end, *p, mnamebuf, sizeof (mnamebuf));
279   *p += dn_expand (answer, end, *p, rnamebuf, sizeof (rnamebuf));
280
281   GETLONG (serial, *p);
282   GETLONG (refresh, *p);
283   GETLONG (retry, *p);
284   GETLONG (expire, *p);
285   GETLONG (ttl, *p);
286
287   return g_variant_new ("(ssuuuuu)",
288                         mnamebuf,
289                         rnamebuf,
290                         serial,
291                         refresh,
292                         retry,
293                         expire,
294                         ttl);
295 }
296
297 static GVariant *
298 parse_res_ns (guchar  *answer,
299               guchar  *end,
300               guchar **p)
301 {
302   gchar namebuf[1024];
303
304   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
305
306   return g_variant_new ("(s)", namebuf);
307 }
308
309 static GVariant *
310 parse_res_mx (guchar  *answer,
311               guchar  *end,
312               guchar **p)
313 {
314   gchar namebuf[1024];
315   guint16 preference;
316
317   GETSHORT (preference, *p);
318
319   *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
320
321   return g_variant_new ("(qs)",
322                         preference,
323                         namebuf);
324 }
325
326 static GVariant *
327 parse_res_txt (guchar  *answer,
328                guchar  *end,
329                guchar **p)
330 {
331   GVariant *record;
332   GPtrArray *array;
333   guchar *at = *p;
334   gsize len;
335
336   array = g_ptr_array_new_with_free_func (g_free);
337   while (at < end)
338     {
339       len = *(at++);
340       if (len > at - end)
341         break;
342       g_ptr_array_add (array, g_strndup ((gchar *)at, len));
343       at += len;
344     }
345
346   *p = at;
347   record = g_variant_new ("(@as)",
348                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
349   g_ptr_array_free (array, TRUE);
350   return record;
351 }
352
353 static gint
354 g_resolver_record_type_to_rrtype (GResolverRecordType type)
355 {
356   switch (type)
357   {
358     case G_RESOLVER_RECORD_SRV:
359       return T_SRV;
360     case G_RESOLVER_RECORD_TXT:
361       return T_TXT;
362     case G_RESOLVER_RECORD_SOA:
363       return T_SOA;
364     case G_RESOLVER_RECORD_NS:
365       return T_NS;
366     case G_RESOLVER_RECORD_MX:
367       return T_MX;
368   }
369   g_return_val_if_reached (-1);
370 }
371
372 static GList *
373 g_resolver_records_from_res_query (const gchar      *rrname,
374                                    gint              rrtype,
375                                    guchar           *answer,
376                                    gint              len,
377                                    gint              herr,
378                                    GError          **error)
379 {
380   gint count;
381   gchar namebuf[1024];
382   guchar *end, *p;
383   guint16 type, qclass, rdlength;
384   guint32 ttl;
385   HEADER *header;
386   GList *records;
387   GVariant *record;
388
389   if (len <= 0)
390     {
391       GResolverError errnum;
392       const gchar *format;
393
394       if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
395         {
396           errnum = G_RESOLVER_ERROR_NOT_FOUND;
397           format = _("No DNS record of the requested type for '%s'");
398         }
399       else if (herr == TRY_AGAIN)
400         {
401           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
402           format = _("Temporarily unable to resolve '%s'");
403         }
404       else
405         {
406           errnum = G_RESOLVER_ERROR_INTERNAL;
407           format = _("Error resolving '%s'");
408         }
409
410       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
411       return NULL;
412     }
413
414   records = NULL;
415
416   header = (HEADER *)answer;
417   p = answer + sizeof (HEADER);
418   end = answer + len;
419
420   /* Skip query */
421   count = ntohs (header->qdcount);
422   while (count-- && p < end)
423     {
424       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
425       p += 4;
426
427       /* To silence gcc warnings */
428       namebuf[0] = namebuf[1];
429     }
430
431   /* Read answers */
432   count = ntohs (header->ancount);
433   while (count-- && p < end)
434     {
435       p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
436       GETSHORT (type, p);
437       GETSHORT (qclass, p);
438       GETLONG  (ttl, p);
439       ttl = ttl; /* To avoid -Wunused-but-set-variable */
440       GETSHORT (rdlength, p);
441
442       if (type != rrtype || qclass != C_IN)
443         {
444           p += rdlength;
445           continue;
446         }
447
448       switch (rrtype)
449         {
450         case T_SRV:
451           record = parse_res_srv (answer, end, &p);
452           break;
453         case T_MX:
454           record = parse_res_mx (answer, end, &p);
455           break;
456         case T_SOA:
457           record = parse_res_soa (answer, end, &p);
458           break;
459         case T_NS:
460           record = parse_res_ns (answer, end, &p);
461           break;
462         case T_TXT:
463           record = parse_res_txt (answer, p + rdlength, &p);
464           break;
465         default:
466           g_warn_if_reached ();
467           record = NULL;
468           break;
469         }
470
471       if (record != NULL)
472         records = g_list_prepend (records, record);
473     }
474
475   if (records == NULL)
476     {
477       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
478                    _("No DNS record of the requested type for '%s'"), rrname);
479
480       return NULL;
481     }
482   else
483     return records;
484 }
485
486 #elif defined(G_OS_WIN32)
487
488 static GVariant *
489 parse_dns_srv (DNS_RECORD *rec)
490 {
491   return g_variant_new ("(qqqs)",
492                         (guint16)rec->Data.SRV.wPriority,
493                         (guint16)rec->Data.SRV.wWeight,
494                         (guint16)rec->Data.SRV.wPort,
495                         rec->Data.SRV.pNameTarget);
496 }
497
498 static GVariant *
499 parse_dns_soa (DNS_RECORD *rec)
500 {
501   return g_variant_new ("(ssuuuuu)",
502                         rec->Data.SOA.pNamePrimaryServer,
503                         rec->Data.SOA.pNameAdministrator,
504                         (guint32)rec->Data.SOA.dwSerialNo,
505                         (guint32)rec->Data.SOA.dwRefresh,
506                         (guint32)rec->Data.SOA.dwRetry,
507                         (guint32)rec->Data.SOA.dwExpire,
508                         (guint32)rec->Data.SOA.dwDefaultTtl);
509 }
510
511 static GVariant *
512 parse_dns_ns (DNS_RECORD *rec)
513 {
514   return g_variant_new ("(s)", rec->Data.NS.pNameHost);
515 }
516
517 static GVariant *
518 parse_dns_mx (DNS_RECORD *rec)
519 {
520   return g_variant_new ("(qs)",
521                         (guint16)rec->Data.MX.wPreference,
522                         rec->Data.MX.pNameExchange);
523 }
524
525 static GVariant *
526 parse_dns_txt (DNS_RECORD *rec)
527 {
528   GVariant *record;
529   GPtrArray *array;
530   DWORD i;
531
532   array = g_ptr_array_new ();
533   for (i = 0; i < rec->Data.TXT.dwStringCount; i++)
534     g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]);
535   record = g_variant_new ("(@as)",
536                           g_variant_new_strv ((const gchar **)array->pdata, array->len));
537   g_ptr_array_free (array, TRUE);
538   return record;
539 }
540
541 static WORD
542 g_resolver_record_type_to_dnstype (GResolverRecordType type)
543 {
544   switch (type)
545   {
546     case G_RESOLVER_RECORD_SRV:
547       return DNS_TYPE_SRV;
548     case G_RESOLVER_RECORD_TXT:
549       return DNS_TYPE_TEXT;
550     case G_RESOLVER_RECORD_SOA:
551       return DNS_TYPE_SOA;
552     case G_RESOLVER_RECORD_NS:
553       return DNS_TYPE_NS;
554     case G_RESOLVER_RECORD_MX:
555       return DNS_TYPE_MX;
556   }
557   g_return_val_if_reached (-1);
558 }
559
560 static GList *
561 g_resolver_records_from_DnsQuery (const gchar  *rrname,
562                                   WORD          dnstype,
563                                   DNS_STATUS    status,
564                                   DNS_RECORD   *results,
565                                   GError      **error)
566 {
567   DNS_RECORD *rec;
568   gpointer record;
569   GList *records;
570
571   if (status != ERROR_SUCCESS)
572     {
573       GResolverError errnum;
574       const gchar *format;
575
576       if (status == DNS_ERROR_RCODE_NAME_ERROR)
577         {
578           errnum = G_RESOLVER_ERROR_NOT_FOUND;
579           format = _("No DNS record of the requested type for '%s'");
580         }
581       else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
582         {
583           errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
584           format = _("Temporarily unable to resolve '%s'");
585         }
586       else
587         {
588           errnum = G_RESOLVER_ERROR_INTERNAL;
589           format = _("Error resolving '%s'");
590         }
591
592       g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
593       return NULL;
594     }
595
596   records = NULL;
597   for (rec = results; rec; rec = rec->pNext)
598     {
599       if (rec->wType != dnstype)
600         continue;
601       switch (dnstype)
602         {
603         case DNS_TYPE_SRV:
604           record = parse_dns_srv (rec);
605           break;
606         case DNS_TYPE_SOA:
607           record = parse_dns_soa (rec);
608           break;
609         case DNS_TYPE_NS:
610           record = parse_dns_ns (rec);
611           break;
612         case DNS_TYPE_MX:
613           record = parse_dns_mx (rec);
614           break;
615         case DNS_TYPE_TEXT:
616           record = parse_dns_txt (rec);
617           break;
618         default:
619           g_warn_if_reached ();
620           record = NULL;
621           break;
622         }
623       if (record != NULL)
624         records = g_list_prepend (records, g_variant_ref_sink (record));
625     }
626
627   if (records == NULL)
628     {
629       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
630                    _("No DNS record of the requested type for '%s'"), rrname);
631
632       return NULL;
633     }
634   else
635     return records;
636 }
637
638 #endif
639
640 typedef struct {
641   char *rrname;
642   GResolverRecordType record_type;
643 } LookupRecordsData;
644
645 static void
646 free_lookup_records_data (LookupRecordsData *lrd)
647 {
648   g_free (lrd->rrname);
649   g_slice_free (LookupRecordsData, lrd);
650 }
651
652 static void
653 free_records (GList *records)
654 {
655   g_list_free_full (records, (GDestroyNotify) g_variant_unref);
656 }
657
658 static void
659 do_lookup_records (GTask         *task,
660                    gpointer       source_object,
661                    gpointer       task_data,
662                    GCancellable  *cancellable)
663 {
664   LookupRecordsData *lrd = task_data;
665   GList *records;
666   GError *error = NULL;
667
668 #if defined(G_OS_UNIX)
669   gint len = 512;
670   gint herr;
671   GByteArray *answer;
672   gint rrtype;
673
674   rrtype = g_resolver_record_type_to_rrtype (lrd->record_type);
675   answer = g_byte_array_new ();
676   for (;;)
677     {
678       g_byte_array_set_size (answer, len * 2);
679       len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
680
681       /* If answer fit in the buffer then we're done */
682       if (len < 0 || len < (gint)answer->len)
683         break;
684
685       /*
686        * On overflow some res_query's return the length needed, others
687        * return the full length entered. This code works in either case.
688        */
689     }
690
691   herr = h_errno;
692   records = g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
693   g_byte_array_free (answer, TRUE);
694
695 #else
696
697   DNS_STATUS status;
698   DNS_RECORD *results = NULL;
699   WORD dnstype;
700
701   dnstype = g_resolver_record_type_to_dnstype (lrd->record_type);
702   status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
703   records = g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
704   if (results != NULL)
705     DnsRecordListFree (results, DnsFreeRecordList);
706
707 #endif
708
709   if (records)
710     g_task_return_pointer (task, records, (GDestroyNotify) free_records);
711   else
712     g_task_return_error (task, error);
713 }
714
715 static GList *
716 lookup_records (GResolver              *resolver,
717                 const gchar            *rrname,
718                 GResolverRecordType     record_type,
719                 GCancellable           *cancellable,
720                 GError                **error)
721 {
722   GTask *task;
723   GList *records;
724   LookupRecordsData *lrd;
725
726   task = g_task_new (resolver, cancellable, NULL, NULL);
727
728   lrd = g_slice_new (LookupRecordsData);
729   lrd->rrname = g_strdup (rrname);
730   lrd->record_type = record_type;
731   g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
732
733   g_task_set_return_on_cancel (task, TRUE);
734   g_task_run_in_thread_sync (task, do_lookup_records);
735   records = g_task_propagate_pointer (task, error);
736   g_object_unref (task);
737
738   return records;
739 }
740
741 static void
742 lookup_records_async (GResolver           *resolver,
743                       const char          *rrname,
744                       GResolverRecordType  record_type,
745                       GCancellable        *cancellable,
746                       GAsyncReadyCallback  callback,
747                       gpointer             user_data)
748 {
749   GTask *task;
750   LookupRecordsData *lrd;
751
752   task = g_task_new (resolver, cancellable, callback, user_data);
753
754   lrd = g_slice_new (LookupRecordsData);
755   lrd->rrname = g_strdup (rrname);
756   lrd->record_type = record_type;
757   g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
758
759   g_task_set_return_on_cancel (task, TRUE);
760   g_task_run_in_thread (task, do_lookup_records);
761   g_object_unref (task);
762 }
763
764 static GList *
765 lookup_records_finish (GResolver     *resolver,
766                        GAsyncResult  *result,
767                        GError       **error)
768 {
769   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
770
771   return g_task_propagate_pointer (G_TASK (result), error);
772 }
773
774
775 static void
776 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
777 {
778   GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
779
780   resolver_class->lookup_by_name           = lookup_by_name;
781   resolver_class->lookup_by_name_async     = lookup_by_name_async;
782   resolver_class->lookup_by_name_finish    = lookup_by_name_finish;
783   resolver_class->lookup_by_address        = lookup_by_address;
784   resolver_class->lookup_by_address_async  = lookup_by_address_async;
785   resolver_class->lookup_by_address_finish = lookup_by_address_finish;
786   resolver_class->lookup_records           = lookup_records;
787   resolver_class->lookup_records_async     = lookup_records_async;
788   resolver_class->lookup_records_finish    = lookup_records_finish;
789
790   /* Initialize _g_resolver_addrinfo_hints */
791 #ifdef AI_ADDRCONFIG
792   addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
793 #endif
794   /* These two don't actually matter, they just get copied into the
795    * returned addrinfo structures (and then we ignore them). But if
796    * we leave them unset, we'll get back duplicate answers.
797    */
798   addrinfo_hints.ai_socktype = SOCK_STREAM;
799   addrinfo_hints.ai_protocol = IPPROTO_TCP;
800 }