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 "gunixresolver.h"
31 #include "gnetworkingprivate.h"
33 #include "gcancellable.h"
34 #include "gsimpleasyncresult.h"
35 #include "gsocketaddress.h"
38 G_DEFINE_TYPE (GUnixResolver, g_unix_resolver, G_TYPE_THREADED_RESOLVER)
40 static gboolean g_unix_resolver_watch (GIOChannel *iochannel,
41 GIOCondition condition,
43 static void g_unix_resolver_reload (GResolver *resolver);
46 g_unix_resolver_init (GUnixResolver *gur)
48 g_unix_resolver_reload (G_RESOLVER (gur));
52 g_unix_resolver_finalize (GObject *object)
54 GUnixResolver *gur = G_UNIX_RESOLVER (object);
57 g_source_remove (gur->watch);
58 _g_asyncns_free (gur->asyncns);
60 G_OBJECT_CLASS (g_unix_resolver_parent_class)->finalize (object);
64 g_unix_resolver_reload (GResolver *resolver)
66 GUnixResolver *gur = G_UNIX_RESOLVER (resolver);
72 if (_g_asyncns_getnqueries (gur->asyncns) == 0)
74 g_source_remove (gur->watch);
75 _g_asyncns_free (gur->asyncns);
77 /* else, we will free it later from g_unix_resolver_watch */
80 /* FIXME: how many workers? */
81 gur->asyncns = _g_asyncns_new (2);
83 fd = _g_asyncns_fd (gur->asyncns);
84 io = g_io_channel_unix_new (fd);
85 gur->watch = g_io_add_watch (io, G_IO_IN | G_IO_HUP | G_IO_ERR,
86 g_unix_resolver_watch, gur->asyncns);
87 g_io_channel_unref (io);
90 /* The various request possibilities:
92 * 1. Synchronous: handed off to the base class (GThreadedResolver);
93 * since it's never possible to cancel a synchronous request in a
94 * single-threaded program, the request is done in the calling
97 * 2. Asynchronous: An appropriate _g_asyncns_query_t is created, and
98 * then a GUnixResolverRequest is created with that query and a
99 * GSimpleAsyncResult. Two sub-possibilities:
101 * a. The resolution completes: g_unix_resolver_watch() sees that
102 * the request has completed, and calls
103 * g_unix_resolver_request_complete(), which detaches the
104 * "cancelled" signal handler (if it was present), queues the
105 * async_result to be completed, and then unrefs it.
107 * b. The resolution is cancelled: request_cancelled() calls
108 * _g_asyncns_cancel() to cancel the resolution. Then it calls
109 * g_unix_resolver_request_complete(), which detaches the
110 * signal handler, and queues async_result to complete in an
111 * idle handler. Because the asyncns resolution was cancelled,
112 * g_unix_resolver_watch() will never be triggered for this
115 * Since there's only a single thread, it's not possible for the
116 * request to both complete and be cancelled "at the same time",
117 * and each of the two possibilities takes steps to block the other
118 * from being able to happen later, so it's always safe to free req
119 * after the async_result completes.
122 typedef struct _GUnixResolverRequest GUnixResolverRequest;
123 typedef void (*GUnixResolverFunc) (GUnixResolverRequest *);
125 struct _GUnixResolverRequest {
127 _g_asyncns_t *asyncns;
129 _g_asyncns_query_t *qy;
137 GInetAddress *address;
146 GUnixResolverFunc process_func, free_func;
148 GCancellable *cancellable;
149 GSimpleAsyncResult *async_result;
153 static void g_unix_resolver_request_free (GUnixResolverRequest *req);
154 static void request_cancelled (GCancellable *cancellable,
157 static GUnixResolverRequest *
158 g_unix_resolver_request_new (GUnixResolver *gur,
159 _g_asyncns_query_t *qy,
160 GUnixResolverFunc process_func,
161 GUnixResolverFunc free_func,
162 GCancellable *cancellable,
163 GSimpleAsyncResult *async_result)
165 GUnixResolverRequest *req;
167 req = g_slice_new0 (GUnixResolverRequest);
168 req->gur = g_object_ref (gur);
169 req->asyncns = gur->asyncns;
171 req->process_func = process_func;
172 req->free_func = free_func;
176 req->cancellable = g_object_ref (cancellable);
177 g_signal_connect (cancellable, "cancelled",
178 G_CALLBACK (request_cancelled), req);
181 req->async_result = g_object_ref (async_result);
183 g_simple_async_result_set_op_res_gpointer (req->async_result, req, (GDestroyNotify)g_unix_resolver_request_free);
189 g_unix_resolver_request_free (GUnixResolverRequest *req)
191 req->free_func (req);
193 /* We don't have to free req->cancellable and req->async_result,
194 * since they must already have been freed if we're here.
197 /* Check if this was the last request remaining on an old asyncns. */
198 if (req->asyncns != req->gur->asyncns &&
199 _g_asyncns_getnqueries (req->asyncns) == 0)
200 _g_asyncns_free (req->asyncns);
202 g_object_unref (req->gur);
203 g_slice_free (GUnixResolverRequest, req);
207 g_unix_resolver_request_complete (GUnixResolverRequest *req)
209 if (req->cancellable)
211 g_signal_handlers_disconnect_by_func (req->cancellable, request_cancelled, req);
212 g_object_unref (req->cancellable);
213 req->cancellable = NULL;
216 /* We always complete_in_idle, even if we were called from
217 * g_unix_resolver_watch(), since we might have been started under a
218 * non-default g_main_context_get_thread_default().
220 g_simple_async_result_complete_in_idle (req->async_result);
221 g_object_unref (req->async_result);
225 request_cancelled (GCancellable *cancellable,
228 GUnixResolverRequest *req = user_data;
229 GError *error = NULL;
231 _g_asyncns_cancel (req->asyncns, req->qy);
234 g_cancellable_set_error_if_cancelled (cancellable, &error);
235 g_simple_async_result_take_error (req->async_result, error);
237 g_unix_resolver_request_complete (req);
241 g_unix_resolver_watch (GIOChannel *iochannel,
242 GIOCondition condition,
245 _g_asyncns_t *asyncns = user_data;
246 _g_asyncns_query_t *qy;
247 GUnixResolverRequest *req;
249 if (condition & (G_IO_HUP | G_IO_ERR))
251 /* Will happen if we reload, and then eventually kill the old
252 * _g_asyncns_t when it's done processing requests.
257 while (_g_asyncns_wait (asyncns, FALSE) == 0 &&
258 (qy = _g_asyncns_getnext (asyncns)) != NULL)
260 req = _g_asyncns_getuserdata (asyncns, qy);
261 req->process_func (req);
262 g_unix_resolver_request_complete (req);
268 static GUnixResolverRequest *
269 resolve_async (GUnixResolver *gur,
270 _g_asyncns_query_t *qy,
271 GUnixResolverFunc process_func,
272 GUnixResolverFunc free_func,
273 GCancellable *cancellable,
274 GAsyncReadyCallback callback,
278 GSimpleAsyncResult *result;
279 GUnixResolverRequest *req;
281 result = g_simple_async_result_new (G_OBJECT (gur), callback, user_data, tag);
282 req = g_unix_resolver_request_new (gur, qy, process_func, free_func,
283 cancellable, result);
284 g_object_unref (result);
285 _g_asyncns_setuserdata (gur->asyncns, qy, req);
291 lookup_by_name_process (GUnixResolverRequest *req)
293 struct addrinfo *res;
295 GError *error = NULL;
297 retval = _g_asyncns_getaddrinfo_done (req->asyncns, req->qy, &res);
298 req->u.name.addresses =
299 _g_resolver_addresses_from_addrinfo (req->u.name.hostname,
300 res, retval, &error);
305 g_simple_async_result_take_error (req->async_result, error);
309 lookup_by_name_free (GUnixResolverRequest *req)
311 g_free (req->u.name.hostname);
312 if (req->u.name.addresses)
313 g_resolver_free_addresses (req->u.name.addresses);
317 lookup_by_name_async (GResolver *resolver,
318 const gchar *hostname,
319 GCancellable *cancellable,
320 GAsyncReadyCallback callback,
323 GUnixResolver *gur = G_UNIX_RESOLVER (resolver);
324 GUnixResolverRequest *req;
325 _g_asyncns_query_t *qy;
327 qy = _g_asyncns_getaddrinfo (gur->asyncns, hostname, NULL,
328 &_g_resolver_addrinfo_hints);
329 req = resolve_async (gur, qy, lookup_by_name_process, lookup_by_name_free,
330 cancellable, callback, user_data, lookup_by_name_async);
331 req->u.name.hostname = g_strdup (hostname);
335 lookup_by_name_finish (GResolver *resolver,
336 GAsyncResult *result,
339 GSimpleAsyncResult *simple;
340 GUnixResolverRequest *req;
343 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (resolver), lookup_by_name_async), NULL);
345 simple = G_SIMPLE_ASYNC_RESULT (result);
347 if (g_simple_async_result_propagate_error (simple, error))
350 req = g_simple_async_result_get_op_res_gpointer (simple);
351 addresses = req->u.name.addresses;
352 req->u.name.addresses = NULL;
359 lookup_by_address_process (GUnixResolverRequest *req)
361 gchar host[NI_MAXHOST];
363 GError *error = NULL;
365 retval = _g_asyncns_getnameinfo_done (req->asyncns, req->qy,
366 host, sizeof (host), NULL, 0);
367 req->u.address.hostname =
368 _g_resolver_name_from_nameinfo (req->u.address.address,
369 host, retval, &error);
372 g_simple_async_result_take_error (req->async_result, error);
376 lookup_by_address_free (GUnixResolverRequest *req)
378 g_object_unref (req->u.address.address);
379 if (req->u.address.hostname)
380 g_free (req->u.address.hostname);
384 lookup_by_address_async (GResolver *resolver,
385 GInetAddress *address,
386 GCancellable *cancellable,
387 GAsyncReadyCallback callback,
390 GUnixResolver *gur = G_UNIX_RESOLVER (resolver);
391 GUnixResolverRequest *req;
392 _g_asyncns_query_t *qy;
393 struct sockaddr_storage sockaddr;
396 _g_resolver_address_to_sockaddr (address, &sockaddr, &sockaddr_size);
397 qy = _g_asyncns_getnameinfo (gur->asyncns,
398 (struct sockaddr *)&sockaddr, sockaddr_size,
399 NI_NAMEREQD, TRUE, FALSE);
400 req = resolve_async (gur, qy, lookup_by_address_process,
401 lookup_by_address_free, cancellable,
402 callback, user_data, lookup_by_address_async);
403 req->u.address.address = g_object_ref (address);
407 lookup_by_address_finish (GResolver *resolver,
408 GAsyncResult *result,
411 GSimpleAsyncResult *simple;
412 GUnixResolverRequest *req;
415 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (resolver), lookup_by_address_async), NULL);
417 simple = G_SIMPLE_ASYNC_RESULT (result);
419 if (g_simple_async_result_propagate_error (simple, error))
422 req = g_simple_async_result_get_op_res_gpointer (simple);
423 name = req->u.address.hostname;
424 req->u.address.hostname = NULL;
431 lookup_service_process (GUnixResolverRequest *req)
435 GError *error = NULL;
437 len = _g_asyncns_res_done (req->asyncns, req->qy, &answer);
443 req->u.service.targets =
444 _g_resolver_targets_from_res_query (req->u.service.service,
445 answer, len, herr, &error);
446 _g_asyncns_freeanswer (answer);
449 g_simple_async_result_take_error (req->async_result, error);
453 lookup_service_free (GUnixResolverRequest *req)
455 g_free (req->u.service.service);
456 if (req->u.service.targets)
457 g_resolver_free_targets (req->u.service.targets);
461 lookup_service_async (GResolver *resolver,
463 GCancellable *cancellable,
464 GAsyncReadyCallback callback,
467 GUnixResolver *gur = G_UNIX_RESOLVER (resolver);
468 GUnixResolverRequest *req;
469 _g_asyncns_query_t *qy;
471 qy = _g_asyncns_res_query (gur->asyncns, rrname, C_IN, T_SRV);
472 req = resolve_async (gur, qy, lookup_service_process, lookup_service_free,
473 cancellable, callback, user_data, lookup_service_async);
474 req->u.service.service = g_strdup (rrname);
478 lookup_service_finish (GResolver *resolver,
479 GAsyncResult *result,
482 GSimpleAsyncResult *simple;
483 GUnixResolverRequest *req;
486 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (resolver), lookup_service_async), NULL);
488 simple = G_SIMPLE_ASYNC_RESULT (result);
490 if (g_simple_async_result_propagate_error (simple, error))
493 req = g_simple_async_result_get_op_res_gpointer (simple);
494 targets = req->u.service.targets;
495 req->u.service.targets = NULL;
502 g_unix_resolver_class_init (GUnixResolverClass *unix_class)
504 GResolverClass *resolver_class = G_RESOLVER_CLASS (unix_class);
505 GObjectClass *object_class = G_OBJECT_CLASS (unix_class);
507 resolver_class->reload = g_unix_resolver_reload;
508 resolver_class->lookup_by_name_async = lookup_by_name_async;
509 resolver_class->lookup_by_name_finish = lookup_by_name_finish;
510 resolver_class->lookup_by_address_async = lookup_by_address_async;
511 resolver_class->lookup_by_address_finish = lookup_by_address_finish;
512 resolver_class->lookup_service_async = lookup_service_async;
513 resolver_class->lookup_service_finish = lookup_service_finish;
515 object_class->finalize = g_unix_resolver_finalize;