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 "ginetaddress.h"
43 #include "ginet4address.h"
44 #include "ginet6address.h"
45 #include "gresolver.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 /* Is there another way to get this functionality? */
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 hostent2list (const struct hostent *he)
184 g_return_val_if_fail (he != NULL, NULL);
186 for (i = 0; he->h_addr_list[i]; i++)
188 GInetAddress *address = NULL;
190 if (he->h_addrtype == AF_INET)
191 address = G_INET_ADDRESS (g_inet4_address_from_bytes ((guint8 *) he->h_addr_list[i]));
192 else if (he->h_addrtype == AF_INET6)
193 address = G_INET_ADDRESS (g_inet6_address_from_bytes ((guint8 *) he->h_addr_list[i]));
195 list = g_list_prepend (list, address);
202 #if defined(HAVE_GETADDRINFO)
204 g_io_error_from_addrinfo (GError** error, int err)
206 GIOErrorEnum code = G_IO_ERROR_FAILED;
207 const gchar *message = NULL;
215 code = G_IO_ERROR_RESOLVER_NOT_FOUND;
218 code = G_IO_ERROR_RESOLVER_NO_DATA;
221 g_warning ("unknown getaddrinfo() error code encountered");
227 /* FIXME: is gai_strerror() thread-safe? */
228 message = gai_strerror (err);
230 message = winsock_error_message (WSAGetLastError ());
234 *error = g_error_new_literal (G_IO_ERROR, code, message);
239 g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError **error)
243 #if defined(HAVE_GETADDRINFO)
245 struct addrinfo hints;
246 struct addrinfo *res = NULL, *i;
249 memset (&hints, 0, sizeof (hints));
250 hints.ai_socktype = SOCK_STREAM;
252 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
256 if ((rv = getaddrinfo (hostname, NULL, &hints, &res)))
257 g_io_error_from_addrinfo (error, rv);
259 for (i = res; i != NULL; i = i->ai_next)
261 if (i->ai_family == PF_INET)
262 list = g_list_prepend (list, g_inet4_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
263 else if (i->ai_family == PF_INET6)
264 list = g_list_prepend (list, g_inet6_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
270 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
274 #elif defined(HAVE_GETHOSTBYNAME_THREADSAFE)
276 struct hostent *he = gethostbyname (hostname);
281 *error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, winsock_error_message (WSAGetLastError ()));
284 list = hostent2list (he);
286 #elif defined(HAVE_GETHOSTBYNAME_R_GLIBC)
288 struct hostent result, *he;
290 gchar *buf = g_new (gchar, len);
293 while ((rv = gethostbyname_r (hostname, &result, buf, len, &he, &herr)) == ERANGE)
296 buf = g_renew (gchar, buf, len);
300 list = hostent2list (he);
304 #elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
306 struct hostent result, *he;
312 buf = g_renew (gchar, buf, len);
314 he = gethostbyname_r (hostname, &result, buf, len, &h_errno);
317 while (errno == ERANGE);
320 list = hostent2list (&result);
324 #elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
327 struct hostent_data buf;
330 rv = gethostbyname_r (hostname, &he, &buf);
333 list = hostent2list (&he);
339 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
343 he = gethostbyname (hostname);
344 list = hostent2list (he);
346 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
353 list = g_list_reverse (list);
356 *error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, winsock_error_message (WSAGetLastError ()));
362 g_resolver_class_init (GResolverClass *klass)
364 GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
368 g_resolver_init (GResolver *address)
379 resolve_list_thread (GSimpleAsyncResult *res,
381 GCancellable *cancellable)
384 GError *error = NULL;
386 op = g_simple_async_result_get_op_res_gpointer (res);
388 op->list = g_resolver_resolve_list (G_RESOLVER (object), op->host, cancellable, &error);
390 if (op->list == NULL)
392 g_simple_async_result_set_from_error (res, error);
393 g_error_free (error);
398 g_resolver_resolve (GResolver *resolver,
400 GCancellable *cancellable,
404 GInetAddress *address;
406 list = g_resolver_get_host_by_name (resolver, host, error);
411 address = G_INET_ADDRESS (g_object_ref (g_list_first (list)->data));
413 g_list_foreach (list, (GFunc) g_object_unref, NULL);
421 g_resolver_resolve_async (GResolver *resolver,
423 GCancellable *cancellable,
424 GAsyncReadyCallback callback,
427 GSimpleAsyncResult *res;
430 op = g_new (ResolveListData, 1);
432 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
434 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
438 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
440 g_object_unref (res);
444 g_resolver_resolve_finish (GResolver *resolver,
445 GAsyncResult *result,
448 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
450 GInetAddress *address;
452 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
454 op = g_simple_async_result_get_op_res_gpointer (res);
456 g_simple_async_result_propagate_error (res, error);
458 if (op->list == NULL)
461 address = G_INET_ADDRESS (g_object_ref (g_list_first (op->list)->data));
463 g_list_foreach (op->list, (GFunc) g_object_unref, NULL);
465 g_list_free (op->list);
471 g_resolver_resolve_list (GResolver *resolver,
473 GCancellable *cancellable,
476 return g_resolver_get_host_by_name (resolver, host, error);
480 g_resolver_resolve_list_async (GResolver *resolver,
482 GCancellable *cancellable,
483 GAsyncReadyCallback callback,
486 GSimpleAsyncResult *res;
489 op = g_new (ResolveListData, 1);
491 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
493 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
497 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
499 g_object_unref (res);
503 g_resolver_resolve_list_finish (GResolver *resolver,
504 GAsyncResult *result,
507 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
510 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
512 op = g_simple_async_result_get_op_res_gpointer (res);
514 g_simple_async_result_propagate_error (res, error);