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"
35 #include "gsocketaddress.h"
38 G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
41 g_threaded_resolver_init (GThreadedResolver *gtr)
46 do_lookup_by_name (GTask *task,
47 gpointer source_object,
49 GCancellable *cancellable)
51 const char *hostname = task_data;
52 struct addrinfo *res = NULL;
57 retval = getaddrinfo (hostname, NULL, &_g_resolver_addrinfo_hints, &res);
58 addresses = _g_resolver_addresses_from_addrinfo (hostname, res, retval, &error);
64 g_task_return_pointer (task, addresses,
65 (GDestroyNotify)g_resolver_free_addresses);
68 g_task_return_error (task, error);
72 lookup_by_name (GResolver *resolver,
73 const gchar *hostname,
74 GCancellable *cancellable,
80 task = g_task_new (resolver, cancellable, NULL, NULL);
81 g_task_set_task_data (task, g_strdup (hostname), g_free);
82 g_task_set_return_on_cancel (task, TRUE);
83 g_task_run_in_thread_sync (task, do_lookup_by_name);
84 addresses = g_task_propagate_pointer (task, error);
85 g_object_unref (task);
91 lookup_by_name_async (GResolver *resolver,
92 const gchar *hostname,
93 GCancellable *cancellable,
94 GAsyncReadyCallback callback,
99 task = g_task_new (resolver, cancellable, callback, user_data);
100 g_task_set_task_data (task, g_strdup (hostname), g_free);
101 g_task_set_return_on_cancel (task, TRUE);
102 g_task_run_in_thread (task, do_lookup_by_name);
103 g_object_unref (task);
107 lookup_by_name_finish (GResolver *resolver,
108 GAsyncResult *result,
111 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
113 return g_task_propagate_pointer (G_TASK (result), error);
118 do_lookup_by_address (GTask *task,
119 gpointer source_object,
121 GCancellable *cancellable)
123 GInetAddress *address = task_data;
124 struct sockaddr_storage sockaddr;
126 gchar namebuf[NI_MAXHOST], *name;
128 GError *error = NULL;
130 _g_resolver_address_to_sockaddr (address, &sockaddr, &sockaddr_size);
131 retval = getnameinfo ((struct sockaddr *)&sockaddr, sockaddr_size,
132 namebuf, sizeof (namebuf), NULL, 0, NI_NAMEREQD);
133 name = _g_resolver_name_from_nameinfo (address, namebuf, retval, &error);
136 g_task_return_pointer (task, name, g_free);
138 g_task_return_error (task, error);
142 lookup_by_address (GResolver *resolver,
143 GInetAddress *address,
144 GCancellable *cancellable,
150 task = g_task_new (resolver, cancellable, NULL, NULL);
151 g_task_set_task_data (task, g_object_ref (address), g_object_unref);
152 g_task_set_return_on_cancel (task, TRUE);
153 g_task_run_in_thread_sync (task, do_lookup_by_address);
154 name = g_task_propagate_pointer (task, error);
155 g_object_unref (task);
161 lookup_by_address_async (GResolver *resolver,
162 GInetAddress *address,
163 GCancellable *cancellable,
164 GAsyncReadyCallback callback,
169 task = g_task_new (resolver, cancellable, callback, user_data);
170 g_task_set_task_data (task, g_object_ref (address), g_object_unref);
171 g_task_set_return_on_cancel (task, TRUE);
172 g_task_run_in_thread (task, do_lookup_by_address);
173 g_object_unref (task);
177 lookup_by_address_finish (GResolver *resolver,
178 GAsyncResult *result,
181 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
183 return g_task_propagate_pointer (G_TASK (result), error);
189 GResolverRecordType record_type;
193 free_lookup_records_data (LookupRecordsData *lrd)
195 g_free (lrd->rrname);
196 g_slice_free (LookupRecordsData, lrd);
200 free_records (GList *records)
202 g_list_free_full (records, (GDestroyNotify) g_variant_unref);
205 #if defined(G_OS_UNIX)
208 int res_query(const char *, int, int, u_char *, int);
213 do_lookup_records (GTask *task,
214 gpointer source_object,
216 GCancellable *cancellable)
218 LookupRecordsData *lrd = task_data;
220 GError *error = NULL;
221 #if defined(G_OS_UNIX)
227 rrtype = _g_resolver_record_type_to_rrtype (lrd->record_type);
228 answer = g_byte_array_new ();
231 g_byte_array_set_size (answer, len * 2);
232 len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
234 /* If answer fit in the buffer then we're done */
235 if (len < 0 || len < (gint)answer->len)
239 * On overflow some res_query's return the length needed, others
240 * return the full length entered. This code works in either case.
245 records = _g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
246 g_byte_array_free (answer, TRUE);
248 #elif defined(G_OS_WIN32)
250 DNS_RECORD *results = NULL;
253 dnstype = _g_resolver_record_type_to_dnstype (lrd->record_type);
254 status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
255 records = _g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
257 DnsRecordListFree (results, DnsFreeRecordList);
262 g_task_return_pointer (task, records, (GDestroyNotify) free_records);
265 g_task_return_error (task, error);
269 lookup_records (GResolver *resolver,
271 GResolverRecordType record_type,
272 GCancellable *cancellable,
277 LookupRecordsData *lrd;
279 task = g_task_new (resolver, cancellable, NULL, NULL);
281 lrd = g_slice_new (LookupRecordsData);
282 lrd->rrname = g_strdup (rrname);
283 lrd->record_type = record_type;
284 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
286 g_task_set_return_on_cancel (task, TRUE);
287 g_task_run_in_thread_sync (task, do_lookup_records);
288 records = g_task_propagate_pointer (task, error);
289 g_object_unref (task);
295 lookup_records_async (GResolver *resolver,
297 GResolverRecordType record_type,
298 GCancellable *cancellable,
299 GAsyncReadyCallback callback,
303 LookupRecordsData *lrd;
305 task = g_task_new (resolver, cancellable, callback, user_data);
307 lrd = g_slice_new (LookupRecordsData);
308 lrd->rrname = g_strdup (rrname);
309 lrd->record_type = record_type;
310 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
312 g_task_set_return_on_cancel (task, TRUE);
313 g_task_run_in_thread (task, do_lookup_records);
314 g_object_unref (task);
318 lookup_records_finish (GResolver *resolver,
319 GAsyncResult *result,
322 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
324 return g_task_propagate_pointer (G_TASK (result), error);
329 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
331 GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
333 resolver_class->lookup_by_name = lookup_by_name;
334 resolver_class->lookup_by_name_async = lookup_by_name_async;
335 resolver_class->lookup_by_name_finish = lookup_by_name_finish;
336 resolver_class->lookup_by_address = lookup_by_address;
337 resolver_class->lookup_by_address_async = lookup_by_address_async;
338 resolver_class->lookup_by_address_finish = lookup_by_address_finish;
339 resolver_class->lookup_records = lookup_records;
340 resolver_class->lookup_records_async = lookup_records_async;
341 resolver_class->lookup_records_finish = lookup_records_finish;