1 /* GNIO - GLib Network Layer of GIO
3 * Copyright (C) 2008 Christian Kellner
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Christian Kellner <gicmo@gnome.org>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
33 #include "ginetaddress.h"
34 #include "ginet4address.h"
35 #include "ginet6address.h"
36 #include "gresolver.h"
37 #include "gnioerror.h"
39 G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT);
41 #if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX) || defined(HAVE_GETADDRINFO_GLIB_MUTEX)
42 # ifndef G_THREADS_ENABLED
43 # error Using GLib Mutex but thread are not enabled.
45 G_LOCK_DEFINE (dnslock);
48 #if !defined(HAVE_GETADDRINFO)
50 hostent2list (const struct hostent *he)
55 g_return_val_if_fail (he != NULL, NULL);
57 for (i = 0; he->h_addr_list[i]; i++)
59 GInetAddress *address = NULL;
61 if (he->h_addrtype == AF_INET)
62 address = G_INET_ADDRESS (g_inet4_address_from_bytes ((guint8 *) he->h_addr_list[i]));
63 else if (he->h_addrtype == AF_INET6)
64 address = G_INET_ADDRESS (g_inet6_address_from_bytes ((guint8 *) he->h_addr_list[i]));
66 list = g_list_prepend (list, address);
73 #if defined(HAVE_GETADDRINFO)
75 g_io_error_from_addrinfo (GError** error, int err)
77 GIOErrorEnum code = G_IO_ERROR_FAILED;
78 const gchar *message = NULL;
86 code = G_IO_ERROR_RESOLVER_NOT_FOUND;
89 code = G_IO_ERROR_RESOLVER_NO_DATA;
92 g_warning ("unknown getaddrinfo() error code encountered");
97 /* FIXME: is gai_strerror() thread-safe? */
98 message = gai_strerror (err);
101 *error = g_error_new_literal (G_IO_ERROR, code, message);
106 g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError **error)
110 #if defined(HAVE_GETADDRINFO)
112 struct addrinfo hints;
113 struct addrinfo *res = NULL, *i;
116 memset (&hints, 0, sizeof (hints));
117 hints.ai_socktype = SOCK_STREAM;
119 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
123 if ((rv = getaddrinfo (hostname, NULL, &hints, &res)))
124 g_io_error_from_addrinfo (error, rv);
126 for (i = res; i != NULL; i = i->ai_next)
128 if (i->ai_family == PF_INET)
129 list = g_list_prepend (list, g_inet4_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
130 else if (i->ai_family == PF_INET6)
131 list = g_list_prepend (list, g_inet6_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
137 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
141 #elif defined(HAVE_GETHOSTBYNAME_THREADSAFE)
143 struct hostent *he = gethostbyname (hostname);
146 g_io_error_from_errno (error);
148 list = hostent2list (he);
150 #elif defined(HAVE_GETHOSTBYNAME_R_GLIBC)
152 struct hostent result, *he;
154 gchar *buf = g_new (gchar, len);
157 while ((rv = gethostbyname_r (hostname, &result, buf, len, &he, &herr)) == ERANGE)
160 buf = g_renew (gchar, buf, len);
164 list = hostent2list (he);
168 #elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
170 struct hostent result, *he;
176 buf = g_renew (gchar, buf, len);
178 he = gethostbyname_r (hostname, &result, buf, len, &h_errno);
181 while (errno == ERANGE);
184 list = hostent2list (&result);
188 #elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
191 struct hostent_data buf;
194 rv = gethostbyname_r (hostname, &he, &buf);
197 list = hostent2list (&he);
203 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
207 he = gethostbyname (hostname);
208 list = hostent2list (he);
210 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
217 list = g_list_reverse (list);
223 g_resolver_class_init (GResolverClass *klass)
225 GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
229 g_resolver_init (GResolver *address)
240 resolve_list_thread (GSimpleAsyncResult *res,
242 GCancellable *cancellable)
245 GError *error = NULL;
247 op = g_simple_async_result_get_op_res_gpointer (res);
249 op->list = g_resolver_resolve_list (G_RESOLVER (object), op->host, cancellable, &error);
251 if (op->list == NULL)
253 g_simple_async_result_set_from_error (res, error);
254 g_error_free (error);
259 g_resolver_resolve (GResolver *resolver,
261 GCancellable *cancellable,
265 GInetAddress *address;
267 list = g_resolver_get_host_by_name (resolver, host, error);
272 address = G_INET_ADDRESS (g_object_ref (g_list_first (list)->data));
274 g_list_foreach (list, (GFunc) g_object_unref, NULL);
282 g_resolver_resolve_async (GResolver *resolver,
284 GCancellable *cancellable,
285 GAsyncReadyCallback callback,
288 GSimpleAsyncResult *res;
291 op = g_new (ResolveListData, 1);
293 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
295 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
299 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
301 g_object_unref (res);
305 g_resolver_resolve_finish (GResolver *resolver,
306 GAsyncResult *result,
309 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
311 GInetAddress *address;
313 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
315 op = g_simple_async_result_get_op_res_gpointer (res);
317 g_simple_async_result_propagate_error (res, error);
319 if (op->list == NULL)
322 address = G_INET_ADDRESS (g_object_ref (g_list_first (op->list)->data));
324 g_list_foreach (op->list, (GFunc) g_object_unref, NULL);
326 g_list_free (op->list);
332 g_resolver_resolve_list (GResolver *resolver,
334 GCancellable *cancellable,
337 return g_resolver_get_host_by_name (resolver, host, error);
341 g_resolver_resolve_list_async (GResolver *resolver,
343 GCancellable *cancellable,
344 GAsyncReadyCallback callback,
347 GSimpleAsyncResult *res;
350 op = g_new (ResolveListData, 1);
352 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
354 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
358 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
360 g_object_unref (res);
364 g_resolver_resolve_list_finish (GResolver *resolver,
365 GAsyncResult *result,
368 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
371 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
373 op = g_simple_async_result_get_op_res_gpointer (res);
375 g_simple_async_result_propagate_error (res, error);