Starting on TcpClient, some formatting fixes
[cascardo/gnio.git] / gnio / gresolver.c
index af46ae9..5a74b7c 100644 (file)
@@ -1,6 +1,6 @@
 /* GNIO - GLib Network Layer of GIO
- * 
- * Copyright (C) 2008 Christian Kellner 
+ *
+ * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,8 @@
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Author: Christian Kellner <gicmo@gnome.org>
+ * Authors: Christian Kellner <gicmo@gnome.org>
+ *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
  */
 
 #include <config.h>
 #include <gio/gio.h>
 
 #include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
+#ifndef G_OS_WIN32
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#else
+# include <winsock2.h>
+# include <winerror.h>
+# include <ws2tcpip.h>
+# undef HAVE_GETADDRINFO
+# define HAVE_GETHOSTBYNAME_THREADSAFE 1
+#endif
 #include <errno.h>
 
 #include "ginetaddress.h"
@@ -45,6 +54,158 @@ G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT);
 G_LOCK_DEFINE (dnslock);
 #endif
 
+#ifdef G_OS_WIN32
+/* This is copied straight from giowin32.c, but its static there... */
+/* TODO: is there another way to get this functionality? or maybe make this public? */
+static char *
+winsock_error_message (int number)
+{
+  static char unk[100];
+
+  switch (number) {
+  case WSAEINTR:
+    return "Interrupted function call";
+  case WSAEACCES:
+    return "Permission denied";
+  case WSAEFAULT:
+    return "Bad address";
+  case WSAEINVAL:
+    return "Invalid argument";
+  case WSAEMFILE:
+    return "Too many open sockets";
+  case WSAEWOULDBLOCK:
+    return "Resource temporarily unavailable";
+  case WSAEINPROGRESS:
+    return "Operation now in progress";
+  case WSAEALREADY:
+    return "Operation already in progress";
+  case WSAENOTSOCK:
+    return "Socket operation on nonsocket";
+  case WSAEDESTADDRREQ:
+    return "Destination address required";
+  case WSAEMSGSIZE:
+    return "Message too long";
+  case WSAEPROTOTYPE:
+    return "Protocol wrong type for socket";
+  case WSAENOPROTOOPT:
+    return "Bad protocol option";
+  case WSAEPROTONOSUPPORT:
+    return "Protocol not supported";
+  case WSAESOCKTNOSUPPORT:
+    return "Socket type not supported";
+  case WSAEOPNOTSUPP:
+    return "Operation not supported on transport endpoint";
+  case WSAEPFNOSUPPORT:
+    return "Protocol family not supported";
+  case WSAEAFNOSUPPORT:
+    return "Address family not supported by protocol family";
+  case WSAEADDRINUSE:
+    return "Address already in use";
+  case WSAEADDRNOTAVAIL:
+    return "Address not available";
+  case WSAENETDOWN:
+    return "Network interface is not configured";
+  case WSAENETUNREACH:
+    return "Network is unreachable";
+  case WSAENETRESET:
+    return "Network dropped connection on reset";
+  case WSAECONNABORTED:
+    return "Software caused connection abort";
+  case WSAECONNRESET:
+    return "Connection reset by peer";
+  case WSAENOBUFS:
+    return "No buffer space available";
+  case WSAEISCONN:
+    return "Socket is already connected";
+  case WSAENOTCONN:
+    return "Socket is not connected";
+  case WSAESHUTDOWN:
+    return "Can't send after socket shutdown";
+  case WSAETIMEDOUT:
+    return "Connection timed out";
+  case WSAECONNREFUSED:
+    return "Connection refused";
+  case WSAEHOSTDOWN:
+    return "Host is down";
+  case WSAEHOSTUNREACH:
+    return "Host is unreachable";
+  case WSAEPROCLIM:
+    return "Too many processes";
+  case WSASYSNOTREADY:
+    return "Network subsystem is unavailable";
+  case WSAVERNOTSUPPORTED:
+    return "Winsock.dll version out of range";
+  case WSANOTINITIALISED:
+    return "Successful WSAStartup not yet performed";
+  case WSAEDISCON:
+    return "Graceful shutdown in progress";
+  case WSATYPE_NOT_FOUND:
+    return "Class type not found";
+  case WSAHOST_NOT_FOUND:
+    return "Host not found";
+  case WSATRY_AGAIN:
+    return "Nonauthoritative host not found";
+  case WSANO_RECOVERY:
+    return "This is a nonrecoverable error";
+  case WSANO_DATA:
+    return "Valid name, no data record of requested type";
+  case WSA_INVALID_HANDLE:
+    return "Specified event object handle is invalid";
+  case WSA_INVALID_PARAMETER:
+    return "One or more parameters are invalid";
+  case WSA_IO_INCOMPLETE:
+    return "Overlapped I/O event object not in signaled state";
+  case WSA_NOT_ENOUGH_MEMORY:
+    return "Insufficient memory available";
+  case WSA_OPERATION_ABORTED:
+    return "Overlapped operation aborted";
+  case WSAEINVALIDPROCTABLE:
+    return "Invalid procedure table from service provider";
+  case WSAEINVALIDPROVIDER:
+    return "Invalid service provider version number";
+  case WSAEPROVIDERFAILEDINIT:
+    return "Unable to initialize a service provider";
+  case WSASYSCALLFAILURE:
+    return "System call failure";
+  default:
+    sprintf (unk, "Unknown WinSock error %d", number);
+    return unk;
+  }
+}
+#endif
+
+#if !defined(HAVE_GETADDRINFO)
+static void
+g_set_error_from_last_error (GError **error)
+{
+  int code;
+
+#ifdef G_OS_WIN32
+  int err = WSAGetLastError ();
+#else
+  int err = h_errno;
+#endif
+
+  switch (err)
+    {
+      case HOST_NOT_FOUND:
+        code = G_IO_ERROR_RESOLVER_NOT_FOUND;
+        break;
+      case NO_DATA:
+        code = G_IO_ERROR_RESOLVER_NO_DATA;
+        break;
+      default:
+        g_warning ("unknown h_errno code encountered");
+    }
+
+#ifdef G_OS_WIN32
+  g_set_error (error, G_IO_ERROR, code, winsock_error_message (err));
+#else
+  g_set_error (error, G_IO_ERROR, code, hstrerror (err));
+#endif
+}
+#endif
+
 #if !defined(HAVE_GETADDRINFO)
 static GList *
 hostent2list (const struct hostent *he)
@@ -94,8 +255,12 @@ g_io_error_from_addrinfo (GError** error, int err)
 
   if (message == NULL)
     {
+#ifndef G_OS_WIN32
       /* FIXME: is gai_strerror() thread-safe? */
       message = gai_strerror (err);
+#else
+      message = winsock_error_message (WSAGetLastError ());
+#endif
     }
 
   *error = g_error_new_literal (G_IO_ERROR, code, message);
@@ -143,7 +308,7 @@ g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError
     struct hostent *he = gethostbyname (hostname);
 
     if (!he)
-      g_io_error_from_errno (error);
+      g_set_error_from_last_error (error);
     else
       list = hostent2list (he);
   }
@@ -162,6 +327,8 @@ g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError
 
     if (!rv)
       list = hostent2list (he);
+    else
+      g_set_error_from_last_error (error);
 
     g_free (buf);
   }
@@ -182,6 +349,8 @@ g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError
 
     if (he)
       list = hostent2list (&result);
+    else
+      g_set_error_from_last_error (error);
 
     g_free (buf);
   }
@@ -195,6 +364,8 @@ g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError
 
     if (!rv)
       list = hostent2list (&he);
+    else
+      g_set_error_from_last_error (error);
   }
 #else
   {
@@ -205,7 +376,10 @@ g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError
 #endif
 
     he = gethostbyname (hostname);
-    list = hostent2list (he);
+    if (he)
+      list = hostent2list (he);
+    else
+      g_set_error_from_last_error (error);
 
 #ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
     G_UNLOCK (dnslock);
@@ -232,7 +406,7 @@ g_resolver_init (GResolver *address)
 }
 
 typedef struct {
-  GList *list;
+  GList       *list;
   const gchar *host;
 } ResolveListData;