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 do_lookup_records (GTask *task,
201 gpointer source_object,
203 GCancellable *cancellable)
205 LookupRecordsData *lrd = task_data;
207 GError *error = NULL;
208 #if defined(G_OS_UNIX)
214 rrtype = _g_resolver_record_type_to_rrtype (lrd->record_type);
215 answer = g_byte_array_new ();
218 g_byte_array_set_size (answer, len * 2);
219 len = res_query (lrd->rrname, C_IN, rrtype, answer->data, answer->len);
221 /* If answer fit in the buffer then we're done */
222 if (len < 0 || len < (gint)answer->len)
226 * On overflow some res_query's return the length needed, others
227 * return the full length entered. This code works in either case.
232 targets = _g_resolver_records_from_res_query (lrd->rrname, rrtype, answer->data, len, herr, &error);
233 g_byte_array_free (answer, TRUE);
235 #elif defined(G_OS_WIN32)
237 DNS_RECORD *results = NULL;
240 dnstype = _g_resolver_record_type_to_dnstype (lrd->record_type);
241 status = DnsQuery_A (lrd->rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
242 targets = _g_resolver_records_from_DnsQuery (lrd->rrname, dnstype, status, results, &error);
244 DnsRecordListFree (results, DnsFreeRecordList);
249 g_task_return_pointer (task, targets,
250 (GDestroyNotify)g_resolver_free_targets);
253 g_task_return_error (task, error);
257 lookup_records (GResolver *resolver,
259 GResolverRecordType record_type,
260 GCancellable *cancellable,
265 LookupRecordsData *lrd;
267 task = g_task_new (resolver, cancellable, NULL, NULL);
269 lrd = g_slice_new (LookupRecordsData);
270 lrd->rrname = g_strdup (rrname);
271 lrd->record_type = record_type;
272 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
274 g_task_set_return_on_cancel (task, TRUE);
275 g_task_run_in_thread_sync (task, do_lookup_records);
276 targets = g_task_propagate_pointer (task, error);
277 g_object_unref (task);
283 lookup_records_async (GResolver *resolver,
285 GResolverRecordType record_type,
286 GCancellable *cancellable,
287 GAsyncReadyCallback callback,
291 LookupRecordsData *lrd;
293 task = g_task_new (resolver, cancellable, callback, user_data);
295 lrd = g_slice_new (LookupRecordsData);
296 lrd->rrname = g_strdup (rrname);
297 lrd->record_type = record_type;
298 g_task_set_task_data (task, lrd, (GDestroyNotify) free_lookup_records_data);
300 g_task_set_return_on_cancel (task, TRUE);
301 g_task_run_in_thread (task, do_lookup_records);
302 g_object_unref (task);
306 lookup_records_finish (GResolver *resolver,
307 GAsyncResult *result,
310 g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
312 return g_task_propagate_pointer (G_TASK (result), error);
317 g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
319 GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
321 resolver_class->lookup_by_name = lookup_by_name;
322 resolver_class->lookup_by_name_async = lookup_by_name_async;
323 resolver_class->lookup_by_name_finish = lookup_by_name_finish;
324 resolver_class->lookup_by_address = lookup_by_address;
325 resolver_class->lookup_by_address_async = lookup_by_address_async;
326 resolver_class->lookup_by_address_finish = lookup_by_address_finish;
327 resolver_class->lookup_records = lookup_records;
328 resolver_class->lookup_records_async = lookup_records_async;
329 resolver_class->lookup_records_finish = lookup_records_finish;