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);
477 g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
478 _("No DNS record of the requested type for '%s'"), rrname);
486 #elif defined(G_OS_WIN32)
489 parse_dns_srv (DNS_RECORD *rec)
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);
499 parse_dns_soa (DNS_RECORD *rec)
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);
512 parse_dns_ns (DNS_RECORD *rec)
514 return g_variant_new ("(s)", rec->Data.NS.pNameHost);
518 parse_dns_mx (DNS_RECORD *rec)
520 return g_variant_new ("(qs)",
521 (guint16)rec->Data.MX.wPreference,
522 rec->Data.MX.pNameExchange);
526 parse_dns_txt (DNS_RECORD *rec)
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);
542 g_resolver_record_type_to_dnstype (GResolverRecordType type)
546 case G_RESOLVER_RECORD_SRV:
548 case G_RESOLVER_RECORD_TXT:
549 return DNS_TYPE_TEXT;
550 case G_RESOLVER_RECORD_SOA:
552 case G_RESOLVER_RECORD_NS:
554 case G_RESOLVER_RECORD_MX:
557 g_return_val_if_reached (-1);
561 g_resolver_records_from_DnsQuery (const gchar *rrname,
571 if (status != ERROR_SUCCESS)
573 GResolverError errnum;
576 if (status == DNS_ERROR_RCODE_NAME_ERROR)
578 errnum = G_RESOLVER_ERROR_NOT_FOUND;
579 format = _("No DNS record of the requested type for '%s'");
581 else if (status == DNS_ERROR_RCODE_SERVER_FAILURE)
583 errnum = G_RESOLVER_ERROR_TEMPORARY_FAILURE;
584 format = _("Temporarily unable to resolve '%s'");
588 errnum = G_RESOLVER_ERROR_INTERNAL;
589 format = _("Error resolving '%s'");
592 g_set_error (error, G_RESOLVER_ERROR, errnum, format, rrname);
597 for (rec = results; rec; rec = rec->pNext)
599 if (rec->wType != dnstype)
604 record = parse_dns_srv (rec);
607 record = parse_dns_soa (rec);
610 record = parse_dns_ns (rec);
613 record = parse_dns_mx (rec);
616 record = parse_dns_txt (rec);
619 g_warn_if_reached ();
624 records = g_list_prepend (records, g_variant_ref_sink (record));
629 g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
630 _("No DNS record of the requested type for '%s'"), rrname);
642 GResolverRecordType record_type;
646 free_lookup_records_data (LookupRecordsData *lrd)
648 g_free (lrd->rrname);
649 g_slice_free (LookupRecordsData, lrd);
653 free_records (GList *records)
655 g_list_free_full (records, (GDestroyNotify) g_variant_unref);
659 do_lookup_records (GTask *task,
660 gpointer source_object,
662 GCancellable *cancellable)
664 LookupRecordsData *lrd = task_data;
666 GError *error = NULL;
668 #if defined(G_OS_UNIX)
674 rrtype = g_resolver_record_type_to_rrtype (lrd->record_type);
675 answer = g_byte_array_new ();
678 g_byte_array_set_size (answer, len * 2);
679 len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
681 /* If answer fit in the buffer then we're done */
682 if (len < 0 || len < (gint)answer->len)
686 * On overflow some res_query's return the length needed, others
687 * return the full length entered. This code works in either case.
692 records = g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
693 g_byte_array_free (answer, TRUE);
698 DNS_RECORD *results = NULL;
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);
705 DnsRecordListFree (results, DnsFreeRecordList);
710 g_task_return_pointer (task, records, (GDestroyNotify) free_records);
712 g_task_return_error (task, error);
716 lookup_records (GResolver *resolver,
718 GResolverRecordType record_type,
719 GCancellable *cancellable,
724 LookupRecordsData *lrd;
726 task = g_task_new (resolver, cancellable, NULL, NULL);
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);
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);
742 lookup_records_async (GResolver *resolver,
744 GResolverRecordType record_type,
745 GCancellable *cancellable,
746 GAsyncReadyCallback callback,
750 LookupRecordsData *lrd;
752 task = g_task_new (resolver, cancellable, callback, user_data);
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);
759 g_task_set_return_on_cancel (task, TRUE);
760 g_task_run_in_thread (task, do_lookup_records);
761 g_object_unref (task);
765 lookup_records_finish (GResolver *resolver,
766 GAsyncResult *result,
769 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
771 return g_task_propagate_pointer (G_TASK (result), error);
776 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
778 GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
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;
790 /* Initialize _g_resolver_addrinfo_hints */
792 addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
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.
798 addrinfo_hints.ai_socktype = SOCK_STREAM;
799 addrinfo_hints.ai_protocol = IPPROTO_TCP;