1 /* GNIO - GLib Network Layer of GIO
3 * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
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 * Authors: Christian Kellner <gicmo@gnome.org>
21 * Samuel Cormier-Iijima <sciyoshi@gmail.com>
30 # include <netinet/in.h>
31 # include <arpa/inet.h>
34 # include <winsock2.h>
35 # include <winerror.h>
36 # include <ws2tcpip.h>
37 # undef HAVE_GETADDRINFO
38 # define HAVE_GETHOSTBYNAME_THREADSAFE 1
42 #include "gresolver.h"
43 #include "ginetaddress.h"
44 #include "ginet4address.h"
45 #include "ginet6address.h"
46 #include "gnioerror.h"
48 G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT);
50 #if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX) || defined(HAVE_GETADDRINFO_GLIB_MUTEX)
51 # ifndef G_THREADS_ENABLED
52 # error Using GLib Mutex but thread are not enabled.
54 G_LOCK_DEFINE (dnslock);
58 /* This is copied straight from giowin32.c, but its static there... */
59 /* TODO: is there another way to get this functionality? or maybe make this public? */
61 winsock_error_message (int number)
67 return "Interrupted function call";
69 return "Permission denied";
73 return "Invalid argument";
75 return "Too many open sockets";
77 return "Resource temporarily unavailable";
79 return "Operation now in progress";
81 return "Operation already in progress";
83 return "Socket operation on nonsocket";
85 return "Destination address required";
87 return "Message too long";
89 return "Protocol wrong type for socket";
91 return "Bad protocol option";
92 case WSAEPROTONOSUPPORT:
93 return "Protocol not supported";
94 case WSAESOCKTNOSUPPORT:
95 return "Socket type not supported";
97 return "Operation not supported on transport endpoint";
99 return "Protocol family not supported";
100 case WSAEAFNOSUPPORT:
101 return "Address family not supported by protocol family";
103 return "Address already in use";
104 case WSAEADDRNOTAVAIL:
105 return "Address not available";
107 return "Network interface is not configured";
109 return "Network is unreachable";
111 return "Network dropped connection on reset";
112 case WSAECONNABORTED:
113 return "Software caused connection abort";
115 return "Connection reset by peer";
117 return "No buffer space available";
119 return "Socket is already connected";
121 return "Socket is not connected";
123 return "Can't send after socket shutdown";
125 return "Connection timed out";
126 case WSAECONNREFUSED:
127 return "Connection refused";
129 return "Host is down";
130 case WSAEHOSTUNREACH:
131 return "Host is unreachable";
133 return "Too many processes";
135 return "Network subsystem is unavailable";
136 case WSAVERNOTSUPPORTED:
137 return "Winsock.dll version out of range";
138 case WSANOTINITIALISED:
139 return "Successful WSAStartup not yet performed";
141 return "Graceful shutdown in progress";
142 case WSATYPE_NOT_FOUND:
143 return "Class type not found";
144 case WSAHOST_NOT_FOUND:
145 return "Host not found";
147 return "Nonauthoritative host not found";
149 return "This is a nonrecoverable error";
151 return "Valid name, no data record of requested type";
152 case WSA_INVALID_HANDLE:
153 return "Specified event object handle is invalid";
154 case WSA_INVALID_PARAMETER:
155 return "One or more parameters are invalid";
156 case WSA_IO_INCOMPLETE:
157 return "Overlapped I/O event object not in signaled state";
158 case WSA_NOT_ENOUGH_MEMORY:
159 return "Insufficient memory available";
160 case WSA_OPERATION_ABORTED:
161 return "Overlapped operation aborted";
162 case WSAEINVALIDPROCTABLE:
163 return "Invalid procedure table from service provider";
164 case WSAEINVALIDPROVIDER:
165 return "Invalid service provider version number";
166 case WSAEPROVIDERFAILEDINIT:
167 return "Unable to initialize a service provider";
168 case WSASYSCALLFAILURE:
169 return "System call failure";
171 sprintf (unk, "Unknown WinSock error %d", number);
177 #if !defined(HAVE_GETADDRINFO)
179 g_set_error_from_last_error (GError **error)
184 int err = WSAGetLastError ();
192 code = G_IO_ERROR_RESOLVER_NOT_FOUND;
195 code = G_IO_ERROR_RESOLVER_NO_DATA;
198 g_warning ("unknown h_errno code encountered");
202 g_set_error (error, G_IO_ERROR, code, winsock_error_message (err));
204 g_set_error (error, G_IO_ERROR, code, hstrerror (err));
209 #if !defined(HAVE_GETADDRINFO)
211 hostent2list (const struct hostent *he)
216 g_return_val_if_fail (he != NULL, NULL);
218 for (i = 0; he->h_addr_list[i]; i++)
220 GInetAddress *address = NULL;
222 if (he->h_addrtype == AF_INET)
223 address = G_INET_ADDRESS (g_inet4_address_from_bytes ((guint8 *) he->h_addr_list[i]));
224 else if (he->h_addrtype == AF_INET6)
225 address = G_INET_ADDRESS (g_inet6_address_from_bytes ((guint8 *) he->h_addr_list[i]));
227 list = g_list_prepend (list, address);
234 #if defined(HAVE_GETADDRINFO)
236 g_io_error_from_addrinfo (GError** error, int err)
238 GIOErrorEnum code = G_IO_ERROR_FAILED;
239 const gchar *message = NULL;
247 code = G_IO_ERROR_RESOLVER_NOT_FOUND;
250 code = G_IO_ERROR_RESOLVER_NO_DATA;
253 g_warning ("unknown getaddrinfo() error code encountered");
259 /* FIXME: is gai_strerror() thread-safe? */
260 message = gai_strerror (err);
262 message = winsock_error_message (WSAGetLastError ());
266 *error = g_error_new_literal (G_IO_ERROR, code, message);
271 g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError **error)
275 #if defined(HAVE_GETADDRINFO)
277 struct addrinfo hints;
278 struct addrinfo *res = NULL, *i;
281 memset (&hints, 0, sizeof (hints));
282 hints.ai_socktype = SOCK_STREAM;
284 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
288 if ((rv = getaddrinfo (hostname, NULL, &hints, &res)))
289 g_io_error_from_addrinfo (error, rv);
291 for (i = res; i != NULL; i = i->ai_next)
293 if (i->ai_family == PF_INET)
294 list = g_list_prepend (list, g_inet4_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
295 else if (i->ai_family == PF_INET6)
296 list = g_list_prepend (list, g_inet6_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
302 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
306 #elif defined(HAVE_GETHOSTBYNAME_THREADSAFE)
308 struct hostent *he = gethostbyname (hostname);
311 g_set_error_from_last_error (error);
313 list = hostent2list (he);
315 #elif defined(HAVE_GETHOSTBYNAME_R_GLIBC)
317 struct hostent result, *he;
319 gchar *buf = g_new (gchar, len);
322 while ((rv = gethostbyname_r (hostname, &result, buf, len, &he, &herr)) == ERANGE)
325 buf = g_renew (gchar, buf, len);
329 list = hostent2list (he);
331 g_set_error_from_last_error (error);
335 #elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
337 struct hostent result, *he;
343 buf = g_renew (gchar, buf, len);
345 he = gethostbyname_r (hostname, &result, buf, len, &h_errno);
348 while (errno == ERANGE);
351 list = hostent2list (&result);
353 g_set_error_from_last_error (error);
357 #elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
360 struct hostent_data buf;
363 rv = gethostbyname_r (hostname, &he, &buf);
366 list = hostent2list (&he);
368 g_set_error_from_last_error (error);
374 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
378 he = gethostbyname (hostname);
380 list = hostent2list (he);
382 g_set_error_from_last_error (error);
384 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
391 list = g_list_reverse (list);
397 g_resolver_class_init (GResolverClass *klass)
399 GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
403 g_resolver_init (GResolver *address)
411 return G_RESOLVER (g_object_new (G_TYPE_RESOLVER, NULL));
420 resolve_list_thread (GSimpleAsyncResult *res,
422 GCancellable *cancellable)
425 GError *error = NULL;
427 op = g_simple_async_result_get_op_res_gpointer (res);
429 op->list = g_resolver_resolve_list (G_RESOLVER (object), op->host, cancellable, &error);
431 if (op->list == NULL)
433 g_simple_async_result_set_from_error (res, error);
434 g_error_free (error);
439 g_resolver_resolve (GResolver *resolver,
441 GCancellable *cancellable,
445 GInetAddress *address;
447 list = g_resolver_get_host_by_name (resolver, host, error);
452 address = G_INET_ADDRESS (g_object_ref (g_list_first (list)->data));
454 g_list_foreach (list, (GFunc) g_object_unref, NULL);
462 g_resolver_resolve_async (GResolver *resolver,
464 GCancellable *cancellable,
465 GAsyncReadyCallback callback,
468 GSimpleAsyncResult *res;
471 op = g_new (ResolveListData, 1);
473 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
475 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
479 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
481 g_object_unref (res);
485 g_resolver_resolve_finish (GResolver *resolver,
486 GAsyncResult *result,
489 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
491 GInetAddress *address;
493 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
495 op = g_simple_async_result_get_op_res_gpointer (res);
497 g_simple_async_result_propagate_error (res, error);
499 if (op->list == NULL)
502 address = G_INET_ADDRESS (g_object_ref (g_list_first (op->list)->data));
504 g_list_foreach (op->list, (GFunc) g_object_unref, NULL);
506 g_list_free (op->list);
512 g_resolver_resolve_list (GResolver *resolver,
514 GCancellable *cancellable,
517 return g_resolver_get_host_by_name (resolver, host, error);
521 g_resolver_resolve_list_async (GResolver *resolver,
523 GCancellable *cancellable,
524 GAsyncReadyCallback callback,
527 GSimpleAsyncResult *res;
530 op = g_new (ResolveListData, 1);
532 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
534 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
538 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
540 g_object_unref (res);
544 g_resolver_resolve_list_finish (GResolver *resolver,
545 GAsyncResult *result,
548 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
551 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
553 op = g_simple_async_result_get_op_res_gpointer (res);
555 g_simple_async_result_propagate_error (res, error);