1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
30 #include "gthreadedresolver.h"
31 #include "gnetworkingprivate.h"
33 #include "gcancellable.h"
34 #include "ginetaddress.h"
35 #include "ginetsocketaddress.h"
37 #include "gsocketaddress.h"
38 #include "gsrvtarget.h"
41 G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
44 g_threaded_resolver_init (GThreadedResolver *gtr)
49 g_resolver_error_from_addrinfo_error (gint err)
54 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
58 return G_RESOLVER_ERROR_NOT_FOUND;
61 return G_RESOLVER_ERROR_TEMPORARY_FAILURE;
64 return G_RESOLVER_ERROR_INTERNAL;
68 static struct addrinfo addrinfo_hints;
71 do_lookup_by_name (GTask *task,
72 gpointer source_object,
74 GCancellable *cancellable)
76 const char *hostname = task_data;
77 struct addrinfo *res = NULL;
81 retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
86 GSocketAddress *sockaddr;
90 for (ai = res; ai; ai = ai->ai_next)
92 sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen);
93 if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
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);
101 addresses = g_list_reverse (addresses);
102 g_task_return_pointer (task, addresses,
103 (GDestroyNotify)g_resolver_free_addresses);
107 g_task_return_new_error (task,
109 g_resolver_error_from_addrinfo_error (retval),
110 _("Error resolving '%s': %s"),
111 hostname, gai_strerror (retval));
119 lookup_by_name (GResolver *resolver,
120 const gchar *hostname,
121 GCancellable *cancellable,
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);
138 lookup_by_name_async (GResolver *resolver,
139 const gchar *hostname,
140 GCancellable *cancellable,
141 GAsyncReadyCallback callback,
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);
154 lookup_by_name_finish (GResolver *resolver,
155 GAsyncResult *result,
158 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
160 return g_task_propagate_pointer (G_TASK (result), error);
165 do_lookup_by_address (GTask *task,
166 gpointer source_object,
168 GCancellable *cancellable)
170 GInetAddress *address = task_data;
171 struct sockaddr_storage sockaddr;
173 GSocketAddress *gsockaddr;
174 gchar name[NI_MAXHOST];
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);
183 retval = getnameinfo ((struct sockaddr *)&sockaddr, sockaddr_size,
184 name, sizeof (name), NULL, 0, NI_NAMEREQD);
186 g_task_return_pointer (task, g_strdup (name), g_free);
191 phys = g_inet_address_to_string (address);
192 g_task_return_new_error (task,
194 g_resolver_error_from_addrinfo_error (retval),
195 _("Error reverse-resolving '%s': %s"),
196 phys ? phys : "(unknown)",
197 gai_strerror (retval));
203 lookup_by_address (GResolver *resolver,
204 GInetAddress *address,
205 GCancellable *cancellable,
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);
222 lookup_by_address_async (GResolver *resolver,
223 GInetAddress *address,
224 GCancellable *cancellable,
225 GAsyncReadyCallback callback,
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);
238 lookup_by_address_finish (GResolver *resolver,
239 GAsyncResult *result,
242 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
244 return g_task_propagate_pointer (G_TASK (result), error);
248 #if defined(G_OS_UNIX)
250 parse_res_srv (guchar *answer,
255 guint16 priority, weight, port;
257 GETSHORT (priority, *p);
258 GETSHORT (weight, *p);
260 *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
262 return g_variant_new ("(qqqs)",
270 parse_res_soa (guchar *answer,
274 gchar mnamebuf[1024];
275 gchar rnamebuf[1024];
276 guint32 serial, refresh, retry, expire, ttl;
278 *p += dn_expand (answer, end, *p, mnamebuf, sizeof (mnamebuf));
279 *p += dn_expand (answer, end, *p, rnamebuf, sizeof (rnamebuf));
281 GETLONG (serial, *p);
282 GETLONG (refresh, *p);
284 GETLONG (expire, *p);
287 return g_variant_new ("(ssuuuuu)",
298 parse_res_ns (guchar *answer,
304 *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
306 return g_variant_new ("(s)", namebuf);
310 parse_res_mx (guchar *answer,
317 GETSHORT (preference, *p);
319 *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf));
321 return g_variant_new ("(qs)",
327 parse_res_txt (guchar *answer,
336 array = g_ptr_array_new_with_free_func (g_free);
342 g_ptr_array_add (array, g_strndup ((gchar *)at, len));
347 record = g_variant_new ("(@as)",
348 g_variant_new_strv ((const gchar **)array->pdata, array->len));
349 g_ptr_array_free (array, TRUE);
354 g_resolver_record_type_to_rrtype (GResolverRecordType type)
358 case G_RESOLVER_RECORD_SRV:
360 case G_RESOLVER_RECORD_TXT:
362 case G_RESOLVER_RECORD_SOA:
364 case G_RESOLVER_RECORD_NS:
366 case G_RESOLVER_RECORD_MX:
369 g_return_val_if_reached (-1);
373 g_resolver_records_from_res_query (const gchar *rrname,
383 guint16 type, qclass, rdlength;
391 GResolverError errnum;
394 if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
396 errnum = G_RESOLVER_ERROR_NOT_FOUND;
397 format = _("No DNS record of the requested type for '%s'");
399 else if (herr == TRY_AGAIN)
401 errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
402 format = _("Temporarily unable to resolve '%s'");
406 errnum = G_RESOLVER_ERROR_INTERNAL;
407 format = _("Error resolving '%s'");
410 g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
416 header = (HEADER *)answer;
417 p = answer + sizeof (HEADER);
421 count = ntohs (header->qdcount);
422 while (count-- && p < end)
424 p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
427 /* To silence gcc warnings */
428 namebuf[0] = namebuf[1];
432 count = ntohs (header->ancount);
433 while (count-- && p < end)
435 p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
437 GETSHORT (qclass, p);
439 ttl = ttl; /* To avoid -Wunused-but-set-variable */
440 GETSHORT (rdlength, p);
442 if (type != rrtype || qclass != C_IN)
451 record = parse_res_srv (answer, end, &p);
454 record = parse_res_mx (answer, end, &p);
457 record = parse_res_soa (answer, end, &p);
460 record = parse_res_ns (answer, end, &p);
463 record = parse_res_txt (answer, p + rdlength, &p);
466 g_warn_if_reached ();
472 records = g_list_prepend (records, record);
478 #elif defined(G_OS_WIN32)
481 parse_dns_srv (DNS_RECORD *rec)
483 return g_variant_new ("(qqqs)",
484 (guint16)rec->Data.SRV.wPriority,
485 (guint16)rec->Data.SRV.wWeight,
486 (guint16)rec->Data.SRV.wPort,
487 rec->Data.SRV.pNameTarget);
491 parse_dns_soa (DNS_RECORD *rec)
493 return g_variant_new ("(ssuuuuu)",
494 rec->Data.SOA.pNamePrimaryServer,
495 rec->Data.SOA.pNameAdministrator,
496 (guint32)rec->Data.SOA.dwSerialNo,
497 (guint32)rec->Data.SOA.dwRefresh,
498 (guint32)rec->Data.SOA.dwRetry,
499 (guint32)rec->Data.SOA.dwExpire,
500 (guint32)rec->Data.SOA.dwDefaultTtl);
504 parse_dns_ns (DNS_RECORD *rec)
506 return g_variant_new ("(s)", rec->Data.NS.pNameHost);
510 parse_dns_mx (DNS_RECORD *rec)
512 return g_variant_new ("(qs)",
513 (guint16)rec->Data.MX.wPreference,
514 rec->Data.MX.pNameExchange);
518 parse_dns_txt (DNS_RECORD *rec)
524 array = g_ptr_array_new ();
525 for (i = 0; i < rec->Data.TXT.dwStringCount; i++)
526 g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]);
527 record = g_variant_new ("(@as)",
528 g_variant_new_strv ((const gchar **)array->pdata, array->len));
529 g_ptr_array_free (array, TRUE);
534 g_resolver_record_type_to_dnstype (GResolverRecordType type)
538 case G_RESOLVER_RECORD_SRV:
540 case G_RESOLVER_RECORD_TXT:
541 return DNS_TYPE_TEXT;
542 case G_RESOLVER_RECORD_SOA:
544 case G_RESOLVER_RECORD_NS:
546 case G_RESOLVER_RECORD_MX:
549 g_return_val_if_reached (-1);
553 g_resolver_records_from_DnsQuery (const gchar *rrname,
563 if (status != ERROR_SUCCESS)
565 GResolverError errnum;
568 if (status == DNS_ERROR_RCODE_NAME_ERROR)
570 errnum = G_RESOLVER_ERROR_NOT_FOUND;
571 format = _("No DNS record of the requested type for '%s'");
573 else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
575 errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
576 format = _("Temporarily unable to resolve '%s'");
580 errnum = G_RESOLVER_ERROR_INTERNAL;
581 format = _("Error resolving '%s'");
584 g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
589 for (rec = results; rec; rec = rec->pNext)
591 if (rec->wType != dnstype)
596 record = parse_dns_srv (rec);
599 record = parse_dns_soa (rec);
602 record = parse_dns_ns (rec);
605 record = parse_dns_mx (rec);
608 record = parse_dns_txt (rec);
611 g_warn_if_reached ();
616 records = g_list_prepend (records, g_variant_ref_sink (record));
626 GResolverRecordType record_type;
630 free_lookup_records_data (LookupRecordsData *lrd)
632 g_free (lrd->rrname);
633 g_slice_free (LookupRecordsData, lrd);
637 free_records (GList *records)
639 g_list_free_full (records, (GDestroyNotify) g_variant_unref);
643 do_lookup_records (GTask *task,
644 gpointer source_object,
646 GCancellable *cancellable)
648 LookupRecordsData *lrd = task_data;
650 GError *error = NULL;
652 #if defined(G_OS_UNIX)
658 rrtype = g_resolver_record_type_to_rrtype (lrd->record_type);
659 answer = g_byte_array_new ();
662 g_byte_array_set_size (answer, len * 2);
663 len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
665 /* If answer fit in the buffer then we're done */
666 if (len < 0 || len < (gint)answer->len)
670 * On overflow some res_query's return the length needed, others
671 * return the full length entered. This code works in either case.
676 records = g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
677 g_byte_array_free (answer, TRUE);
682 DNS_RECORD *results = NULL;
685 dnstype = g_resolver_record_type_to_dnstype (lrd->record_type);
686 status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
687 records = g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
689 DnsRecordListFree (results, DnsFreeRecordList);
694 g_task_return_pointer (task, records, (GDestroyNotify) free_records);
696 g_task_return_error (task, error);
700 lookup_records (GResolver *resolver,
702 GResolverRecordType record_type,
703 GCancellable *cancellable,
708 LookupRecordsData *lrd;
710 task = g_task_new (resolver, cancellable, NULL, NULL);
712 lrd = g_slice_new (LookupRecordsData);
713 lrd->rrname = g_strdup (rrname);
714 lrd->record_type = record_type;
715 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
717 g_task_set_return_on_cancel (task, TRUE);
718 g_task_run_in_thread_sync (task, do_lookup_records);
719 records = g_task_propagate_pointer (task, error);
720 g_object_unref (task);
726 lookup_records_async (GResolver *resolver,
728 GResolverRecordType record_type,
729 GCancellable *cancellable,
730 GAsyncReadyCallback callback,
734 LookupRecordsData *lrd;
736 task = g_task_new (resolver, cancellable, callback, user_data);
738 lrd = g_slice_new (LookupRecordsData);
739 lrd->rrname = g_strdup (rrname);
740 lrd->record_type = record_type;
741 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
743 g_task_set_return_on_cancel (task, TRUE);
744 g_task_run_in_thread (task, do_lookup_records);
745 g_object_unref (task);
749 lookup_records_finish (GResolver *resolver,
750 GAsyncResult *result,
753 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
755 return g_task_propagate_pointer (G_TASK (result), error);
760 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
762 GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
764 resolver_class->lookup_by_name = lookup_by_name;
765 resolver_class->lookup_by_name_async = lookup_by_name_async;
766 resolver_class->lookup_by_name_finish = lookup_by_name_finish;
767 resolver_class->lookup_by_address = lookup_by_address;
768 resolver_class->lookup_by_address_async = lookup_by_address_async;
769 resolver_class->lookup_by_address_finish = lookup_by_address_finish;
770 resolver_class->lookup_records = lookup_records;
771 resolver_class->lookup_records_async = lookup_records_async;
772 resolver_class->lookup_records_finish = lookup_records_finish;
774 /* Initialize _g_resolver_addrinfo_hints */
776 addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
778 /* These two don't actually matter, they just get copied into the
779 * returned addrinfo structures (and then we ignore them). But if
780 * we leave them unset, we'll get back duplicate answers.
782 addrinfo_hints.ai_socktype = SOCK_STREAM;
783 addrinfo_hints.ai_protocol = IPPROTO_TCP;