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);
206 do_lookup_records (GTask *task,
207 gpointer source_object,
209 GCancellable *cancellable)
211 LookupRecordsData *lrd = task_data;
213 GError *error = NULL;
214 #if defined(G_OS_UNIX)
220 rrtype = _g_resolver_record_type_to_rrtype (lrd->record_type);
221 answer = g_byte_array_new ();
224 g_byte_array_set_size (answer, len * 2);
225 len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
227 /* If answer fit in the buffer then we're done */
228 if (len < 0 || len < (gint)answer->len)
232 * On overflow some res_query's return the length needed, others
233 * return the full length entered. This code works in either case.
238 records = _g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
239 g_byte_array_free (answer, TRUE);
241 #elif defined(G_OS_WIN32)
243 DNS_RECORD *results = NULL;
246 dnstype = _g_resolver_record_type_to_dnstype (lrd->record_type);
247 status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
248 records = _g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
250 DnsRecordListFree (results, DnsFreeRecordList);
255 g_task_return_pointer (task, records, (GDestroyNotify) free_records);
258 g_task_return_error (task, error);
262 lookup_records (GResolver *resolver,
264 GResolverRecordType record_type,
265 GCancellable *cancellable,
270 LookupRecordsData *lrd;
272 task = g_task_new (resolver, cancellable, NULL, NULL);
274 lrd = g_slice_new (LookupRecordsData);
275 lrd->rrname = g_strdup (rrname);
276 lrd->record_type = record_type;
277 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
279 g_task_set_return_on_cancel (task, TRUE);
280 g_task_run_in_thread_sync (task, do_lookup_records);
281 records = g_task_propagate_pointer (task, error);
282 g_object_unref (task);
288 lookup_records_async (GResolver *resolver,
290 GResolverRecordType record_type,
291 GCancellable *cancellable,
292 GAsyncReadyCallback callback,
296 LookupRecordsData *lrd;
298 task = g_task_new (resolver, cancellable, callback, user_data);
300 lrd = g_slice_new (LookupRecordsData);
301 lrd->rrname = g_strdup (rrname);
302 lrd->record_type = record_type;
303 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
305 g_task_set_return_on_cancel (task, TRUE);
306 g_task_run_in_thread (task, do_lookup_records);
307 g_object_unref (task);
311 lookup_records_finish (GResolver *resolver,
312 GAsyncResult *result,
315 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
317 return g_task_propagate_pointer (G_TASK (result), error);
322 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
324 GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
326 resolver_class->lookup_by_name = lookup_by_name;
327 resolver_class->lookup_by_name_async = lookup_by_name_async;
328 resolver_class->lookup_by_name_finish = lookup_by_name_finish;
329 resolver_class->lookup_by_address = lookup_by_address;
330 resolver_class->lookup_by_address_async = lookup_by_address_async;
331 resolver_class->lookup_by_address_finish = lookup_by_address_finish;
332 resolver_class->lookup_records = lookup_records;
333 resolver_class->lookup_records_async = lookup_records_async;
334 resolver_class->lookup_records_finish = lookup_records_finish;