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);
178 g_set_error_from_last_error (GError **error)
183 int err = WSAGetLastError ();
191 code = G_IO_ERROR_RESOLVER_NOT_FOUND;
194 code = G_IO_ERROR_RESOLVER_NO_DATA;
197 g_warning ("unknown h_errno code encountered");
201 g_set_error (error, G_IO_ERROR, code, winsock_error_message (err));
203 g_set_error (error, G_IO_ERROR, code, hstrerror (err));
207 #if !defined(HAVE_GETADDRINFO)
209 hostent2list (const struct hostent *he)
214 g_return_val_if_fail (he != NULL, NULL);
216 for (i = 0; he->h_addr_list[i]; i++)
218 GInetAddress *address = NULL;
220 if (he->h_addrtype == AF_INET)
221 address = G_INET_ADDRESS (g_inet4_address_from_bytes ((guint8 *) he->h_addr_list[i]));
222 else if (he->h_addrtype == AF_INET6)
223 address = G_INET_ADDRESS (g_inet6_address_from_bytes ((guint8 *) he->h_addr_list[i]));
225 list = g_list_prepend (list, address);
232 #if defined(HAVE_GETADDRINFO)
234 g_io_error_from_addrinfo (GError** error, int err)
236 GIOErrorEnum code = G_IO_ERROR_FAILED;
237 const gchar *message = NULL;
245 code = G_IO_ERROR_RESOLVER_NOT_FOUND;
248 code = G_IO_ERROR_RESOLVER_NO_DATA;
251 g_warning ("unknown getaddrinfo() error code encountered");
257 /* FIXME: is gai_strerror() thread-safe? */
258 message = gai_strerror (err);
260 message = winsock_error_message (WSAGetLastError ());
264 *error = g_error_new_literal (G_IO_ERROR, code, message);
269 g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError **error)
273 #if defined(HAVE_GETADDRINFO)
275 struct addrinfo hints;
276 struct addrinfo *res = NULL, *i;
279 memset (&hints, 0, sizeof (hints));
280 hints.ai_socktype = SOCK_STREAM;
282 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
286 if ((rv = getaddrinfo (hostname, NULL, &hints, &res)))
287 g_io_error_from_addrinfo (error, rv);
289 for (i = res; i != NULL; i = i->ai_next)
291 if (i->ai_family == PF_INET)
292 list = g_list_prepend (list, g_inet4_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
293 else if (i->ai_family == PF_INET6)
294 list = g_list_prepend (list, g_inet6_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr)));
300 #ifdef HAVE_GETADDRINFO_GLIB_MUTEX
304 #elif defined(HAVE_GETHOSTBYNAME_THREADSAFE)
306 struct hostent *he = gethostbyname (hostname);
309 g_set_error_from_last_error (error);
311 list = hostent2list (he);
313 #elif defined(HAVE_GETHOSTBYNAME_R_GLIBC)
315 struct hostent result, *he;
317 gchar *buf = g_new (gchar, len);
320 while ((rv = gethostbyname_r (hostname, &result, buf, len, &he, &herr)) == ERANGE)
323 buf = g_renew (gchar, buf, len);
327 list = hostent2list (he);
329 g_set_error_from_last_error (error);
333 #elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
335 struct hostent result, *he;
341 buf = g_renew (gchar, buf, len);
343 he = gethostbyname_r (hostname, &result, buf, len, &h_errno);
346 while (errno == ERANGE);
349 list = hostent2list (&result);
351 g_set_error_from_last_error (error);
355 #elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
358 struct hostent_data buf;
361 rv = gethostbyname_r (hostname, &he, &buf);
364 list = hostent2list (&he);
366 g_set_error_from_last_error (error);
372 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
376 he = gethostbyname (hostname);
378 list = hostent2list (he);
380 g_set_error_from_last_error (error);
382 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
389 list = g_list_reverse (list);
395 g_resolver_class_init (GResolverClass *klass)
397 GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
401 g_resolver_init (GResolver *address)
412 resolve_list_thread (GSimpleAsyncResult *res,
414 GCancellable *cancellable)
417 GError *error = NULL;
419 op = g_simple_async_result_get_op_res_gpointer (res);
421 op->list = g_resolver_resolve_list (G_RESOLVER (object), op->host, cancellable, &error);
423 if (op->list == NULL)
425 g_simple_async_result_set_from_error (res, error);
426 g_error_free (error);
431 g_resolver_resolve (GResolver *resolver,
433 GCancellable *cancellable,
437 GInetAddress *address;
439 list = g_resolver_get_host_by_name (resolver, host, error);
444 address = G_INET_ADDRESS (g_object_ref (g_list_first (list)->data));
446 g_list_foreach (list, (GFunc) g_object_unref, NULL);
454 g_resolver_resolve_async (GResolver *resolver,
456 GCancellable *cancellable,
457 GAsyncReadyCallback callback,
460 GSimpleAsyncResult *res;
463 op = g_new (ResolveListData, 1);
465 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
467 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
471 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
473 g_object_unref (res);
477 g_resolver_resolve_finish (GResolver *resolver,
478 GAsyncResult *result,
481 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
483 GInetAddress *address;
485 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
487 op = g_simple_async_result_get_op_res_gpointer (res);
489 g_simple_async_result_propagate_error (res, error);
491 if (op->list == NULL)
494 address = G_INET_ADDRESS (g_object_ref (g_list_first (op->list)->data));
496 g_list_foreach (op->list, (GFunc) g_object_unref, NULL);
498 g_list_free (op->list);
504 g_resolver_resolve_list (GResolver *resolver,
506 GCancellable *cancellable,
509 return g_resolver_get_host_by_name (resolver, host, error);
513 g_resolver_resolve_list_async (GResolver *resolver,
515 GCancellable *cancellable,
516 GAsyncReadyCallback callback,
519 GSimpleAsyncResult *res;
522 op = g_new (ResolveListData, 1);
524 res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async);
526 g_simple_async_result_set_op_res_gpointer (res, op, g_free);
530 g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable);
532 g_object_unref (res);
536 g_resolver_resolve_list_finish (GResolver *resolver,
537 GAsyncResult *result,
540 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
543 g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async);
545 op = g_simple_async_result_get_op_res_gpointer (res);
547 g_simple_async_result_propagate_error (res, error);