2008-10-24 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / metadata / socket-io.c
index a0caca9c366efce4970b870132c846936c8b7c56..225aa585e6b15df6a1062f67ab86c87aee5a3468 100644 (file)
@@ -1,10 +1,12 @@
 /*
  * socket-io.c: Socket IO internal calls
  *
- * Author:
+ * Authors:
  *     Dick Porter (dick@ximian.com)
+ *     Gonzalo Paniagua Javier (gonzalo@ximian.com)
  *
  * (C) 2001 Ximian, Inc.
+ * Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
  */
 
 #include <config.h>
@@ -12,7 +14,9 @@
 #include <glib.h>
 #include <string.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <errno.h>
 
 #include <mono/metadata/object.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/threads.h>
+#include <mono/metadata/threads-types.h>
+#include <mono/utils/mono-poll.h>
 /* FIXME change this code to not mess so much with the internals */
 #include <mono/metadata/class-internals.h>
+#include <mono/metadata/threadpool-internals.h>
+#include <mono/metadata/domain-internals.h>
 
-#include <sys/time.h> 
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
 
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
@@ -252,6 +268,52 @@ static gint32 convert_proto(MonoProtocolType mono_proto)
        return(proto);
 }
 
+/* Convert MonoSocketFlags */
+static gint32 convert_socketflags (gint32 sflags)
+{
+       gint32 flags = 0;
+
+       if (!sflags)
+               /* SocketFlags.None */
+               return 0;
+
+       if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek | 
+                       SocketFlags_DontRoute | SocketFlags_Partial))
+               /* Contains invalid flag values */
+               return -1;
+
+       if (sflags & SocketFlags_OutOfBand)
+               flags |= MSG_OOB;
+       if (sflags & SocketFlags_Peek)
+               flags |= MSG_PEEK;
+       if (sflags & SocketFlags_DontRoute)
+               flags |= MSG_DONTROUTE;
+#if 0
+       /* Ignore Partial - see bug 349688.  Don't return -1, because
+        * according to the comment in that bug ms runtime doesn't for
+        * UDP sockets (this means we will silently ignore it for TCP
+        * too)
+        */
+       if (sflags & SocketFlags_Partial)
+#ifdef MSG_MORE
+               flags |= MSG_MORE;
+#else
+               return -1;      
+#endif
+#endif
+       if (sflags & SocketFlags_MaxIOVectorLength)
+               /* FIXME: Don't know what to do for MaxIOVectorLength query */
+               return -1;      
+       
+       return (flags ? flags : -1);
+}
+
+/*
+ * Returns:
+ *    0 on success (mapped mono_level and mono_name to system_level and system_name
+ *   -1 on error
+ *   -2 on non-fatal error (ie, must ignore)
+ */
 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
                                             MonoSocketOptionName mono_name,
                                             int *system_level,
@@ -395,7 +457,19 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
                        *system_name = IP_PKTINFO;
                        break;
 #endif /* HAVE_IP_PKTINFO */
+
                case SocketOptionName_DontFragment:
+#ifdef HAVE_IP_DONTFRAGMENT
+                       *system_name = IP_DONTFRAGMENT;
+                       break;
+#elif defined HAVE_IP_MTU_DISCOVER
+                       /* Not quite the same */
+                       *system_name = IP_MTU_DISCOVER;
+                       break;
+#else
+                       /* If the flag is not available on this system, we can ignore this error */
+                       return (-2);
+#endif /* HAVE_IP_DONTFRAGMENT */
                case SocketOptionName_AddSourceMembership:
                case SocketOptionName_DropSourceMembership:
                case SocketOptionName_BlockSource:
@@ -450,7 +524,9 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
                        *system_name = IPV6_LEAVE_GROUP;
                        break;
                case SocketOptionName_PacketInformation:
+#ifdef HAVE_IPV6_PKTINFO
                        *system_name = IPV6_PKTINFO;
+#endif
                        break;
                case SocketOptionName_HeaderIncluded:
                case SocketOptionName_IPOptions:
@@ -532,44 +608,82 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
        return(0);
 }
 
-#define STASH_SYS_ASS(this) \
-       if(system_assembly == NULL) { \
-               system_assembly=mono_image_loaded ("System"); \
-               if (!system_assembly) { \
-                       MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);     \
-                       if (!sa) g_assert_not_reached ();       \
-                       else {system_assembly = mono_assembly_get_image (sa);}  \
-               }       \
+static MonoImage *get_socket_assembly (void)
+{
+       static const char *version = NULL;
+       static gboolean moonlight;
+       static MonoImage *socket_assembly = NULL;
+       
+       if (version == NULL) {
+               version = mono_get_runtime_info ()->framework_version;
+               moonlight = !strcmp (version, "2.1");
        }
-
-static MonoImage *system_assembly=NULL;
-
+       
+       if (socket_assembly == NULL) {
+               if (moonlight) {
+                       socket_assembly = mono_image_loaded ("System.Net");
+                       if (!socket_assembly) {
+                               MonoAssembly *sa = mono_assembly_open ("System.Net.dll", NULL);
+                       
+                               if (!sa) {
+                                       g_assert_not_reached ();
+                               } else {
+                                       socket_assembly = mono_assembly_get_image (sa);
+                               }
+                       }
+               } else {
+                       socket_assembly = mono_image_loaded ("System");
+                       if (!socket_assembly) {
+                               MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);
+                       
+                               if (!sa) {
+                                       g_assert_not_reached ();
+                               } else {
+                                       socket_assembly = mono_assembly_get_image (sa);
+                               }
+                       }
+               }
+       }
+       
+       return(socket_assembly);
+}
 
 #ifdef AF_INET6
 static gint32 get_family_hint(void)
 {
-       MonoClass *socket_class;
-       MonoClassField *ipv6_field, *ipv4_field;
-       gint32 ipv6_enabled = -1, ipv4_enabled = -1;
-       MonoVTable *vtable;
-
-       socket_class = mono_class_from_name (system_assembly,
-                                            "System.Net.Sockets", "Socket");
-       ipv4_field = mono_class_get_field_from_name (socket_class,
-                                                    "ipv4Supported");
-       ipv6_field = mono_class_get_field_from_name (socket_class,
-                                                    "ipv6Supported");
-       vtable = mono_class_vtable (mono_domain_get (), socket_class);
-
-       mono_field_static_get_value(vtable, ipv4_field, &ipv4_enabled);
-       mono_field_static_get_value(vtable, ipv6_field, &ipv6_enabled);
-
-       if(ipv4_enabled == 1 && ipv6_enabled == 1) {
-               return(PF_UNSPEC);
-       } else if(ipv4_enabled == 1) {
-               return(PF_INET);
-       } else {
-               return(PF_INET6);
+       MonoDomain *domain = mono_domain_get ();
+
+       if (!domain->inet_family_hint) {
+               MonoClass *socket_class;
+               MonoClassField *ipv6_field, *ipv4_field;
+               gint32 ipv6_enabled = -1, ipv4_enabled = -1;
+               MonoVTable *vtable;
+
+               socket_class = mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket");
+               ipv4_field = mono_class_get_field_from_name (socket_class, "ipv4Supported");
+               ipv6_field = mono_class_get_field_from_name (socket_class, "ipv6Supported");
+               vtable = mono_class_vtable (mono_domain_get (), socket_class);
+               mono_runtime_class_init (vtable);
+
+               mono_field_static_get_value (vtable, ipv4_field, &ipv4_enabled);
+               mono_field_static_get_value (vtable, ipv6_field, &ipv6_enabled);
+
+               mono_domain_lock (domain);
+               if (ipv4_enabled == 1 && ipv6_enabled == 1) {
+                       domain->inet_family_hint = 1;
+               } else if (ipv4_enabled == 1) {
+                       domain->inet_family_hint = 2;
+               } else {
+                       domain->inet_family_hint = 3;
+               }
+               mono_domain_unlock (domain);
+       }
+       switch (domain->inet_family_hint) {
+       case 1: return PF_UNSPEC;
+       case 2: return PF_INET;
+       case 3: return PF_INET6;
+       default:
+               return PF_UNSPEC;
        }
 }
 #endif
@@ -583,8 +697,6 @@ gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, g
        
        MONO_ARCH_SAVE_REGS;
 
-       STASH_SYS_ASS(this);
-       
        *error = 0;
        
        sock_family=convert_family(family);
@@ -623,33 +735,6 @@ gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, g
        }
 #endif
 
-#ifndef PLATFORM_WIN32
-       /* .net seems to set this by default for SOCK_STREAM,
-        * not for SOCK_DGRAM (see bug #36322)
-        *
-        * It seems winsock has a rather different idea of what
-        * SO_REUSEADDR means.  If it's set, then a new socket can be
-        * bound over an existing listening socket.  There's a new
-        * windows-specific option called SO_EXCLUSIVEADDRUSE but
-        * using that means the socket MUST be closed properly, or a
-        * denial of service can occur.  Luckily for us, winsock
-        * behaves as though any other system would when SO_REUSEADDR
-        * is true, so we don't need to do anything else here.  See
-        * bug 53992.
-        */
-       {
-       int ret, true = 1;
-       
-       ret = _wapi_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (true));
-       if(ret==SOCKET_ERROR) {
-               *error = WSAGetLastError ();
-               
-               closesocket(sock);
-               return(NULL);
-       }
-       }
-#endif
-       
        return(GUINT_TO_POINTER (sock));
 }
 
@@ -666,7 +751,10 @@ void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock,
 #endif
 
        *error = 0;
-       
+
+       /* Clear any pending work item from this socket if the underlying
+        * polling system does not notify when the socket is closed */
+       mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock));
        closesocket(sock);
 }
 
@@ -767,18 +855,29 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
        MonoAddressFamily family;
 
        /* Build a System.Net.SocketAddress object instance */
-       sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
+       sockaddr_class=mono_class_from_name(get_socket_assembly (), "System.Net", "SocketAddress");
        sockaddr_obj=mono_object_new(domain, sockaddr_class);
        
        /* Locate the SocketAddress data buffer in the object */
        field=mono_class_get_field_from_name(sockaddr_class, "data");
 
        /* Make sure there is space for the family and size bytes */
-       data=mono_array_new(domain, mono_get_byte_class (), sa_size+2);
+#ifdef HAVE_SYS_UN_H
+       if (saddr->sa_family == AF_UNIX) {
+               /* sa_len includes the entire sockaddr size, so we don't need the
+                * N bytes (sizeof (unsigned short)) of the family. */
+               data=mono_array_new(domain, mono_get_byte_class (), sa_size);
+       } else
+#endif
+       {
+               /* May be the +2 here is too conservative, as sa_len returns
+                * the length of the entire sockaddr_in/in6, including
+                * sizeof (unsigned short) of the family */
+               data=mono_array_new(domain, mono_get_byte_class (), sa_size+2);
+       }
 
        /* The data buffer is laid out as follows:
-        * byte 0 is the address family
-        * byte 1 is the buffer length
+        * bytes 0 and 1 are the address family
         * bytes 2 and 3 are the port info
         * the rest is the address info
         */
@@ -790,7 +889,7 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
        }
 
        mono_array_set(data, guint8, 0, family & 0x0FF);
-       mono_array_set(data, guint8, 1, ((family << 8) & 0x0FFFF));
+       mono_array_set(data, guint8, 1, (family >> 8) & 0x0FF);
        
        if(saddr->sa_family==AF_INET) {
                struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
@@ -863,7 +962,7 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 *error)
 {
        gchar sa[32];   /* sockaddr in not big enough for sockaddr_in6 */
-       int salen;
+       socklen_t salen;
        int ret;
        
        MONO_ARCH_SAVE_REGS;
@@ -889,7 +988,7 @@ extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SO
 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 *error)
 {
        gchar sa[32];   /* sockaddr in not big enough for sockaddr_in6 */
-       int salen;
+       socklen_t salen;
        int ret;
        
        MONO_ARCH_SAVE_REGS;
@@ -913,7 +1012,7 @@ extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(S
 }
 
 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
-                                                   int *sa_size,
+                                                   socklen_t *sa_size,
                                                    gint32 *error)
 {
        MonoClassField *field;
@@ -940,57 +1039,81 @@ static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
        }
        
        family = convert_family (mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8));
-       if(family==AF_INET) {
-               struct sockaddr_in *sa=g_new0(struct sockaddr_in, 1);
-               guint16 port=(mono_array_get(data, guint8, 2) << 8) +
-                       mono_array_get(data, guint8, 3);
-               guint32 address=(mono_array_get(data, guint8, 4) << 24) +
-                       (mono_array_get(data, guint8, 5) << 16 ) +
-                       (mono_array_get(data, guint8, 6) << 8) +
-                       mono_array_get(data, guint8, 7);
+       if (family == AF_INET) {
+               struct sockaddr_in *sa;
+               guint16 port;
+               guint32 address;
                
-               sa->sin_family=family;
-               sa->sin_addr.s_addr=htonl(address);
-               sa->sin_port=htons(port);
+               if (len < 8) {
+                       mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
+               }
+
+               sa = g_new0 (struct sockaddr_in, 1);
+               port = (mono_array_get (data, guint8, 2) << 8) +
+                       mono_array_get (data, guint8, 3);
+               address = (mono_array_get (data, guint8, 4) << 24) +
+                       (mono_array_get (data, guint8, 5) << 16 ) +
+                       (mono_array_get (data, guint8, 6) << 8) +
+                       mono_array_get (data, guint8, 7);
+
+               sa->sin_family = family;
+               sa->sin_addr.s_addr = htonl (address);
+               sa->sin_port = htons (port);
 
-               *sa_size=sizeof(struct sockaddr_in);
+               *sa_size = sizeof(struct sockaddr_in);
                return((struct sockaddr *)sa);
 
 #ifdef AF_INET6
        } else if (family == AF_INET6) {
-               struct sockaddr_in6 *sa=g_new0(struct sockaddr_in6, 1);
+               struct sockaddr_in6 *sa;
                int i;
+               guint16 port;
+               guint32 scopeid;
+               
+               if (len < 28) {
+                       mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
+               }
 
-               guint16 port = mono_array_get(data, guint8, 3) + (mono_array_get(data, guint8, 2) << 8);
-               guint32 scopeid = mono_array_get(data, guint8, 24) + 
-                       (mono_array_get(data, guint8, 25)<<8) + 
-                       (mono_array_get(data, guint8, 26)<<16) + 
-                       (mono_array_get(data, guint8, 27)<<24);
+               sa = g_new0 (struct sockaddr_in6, 1);
+               port = mono_array_get (data, guint8, 3) +
+                       (mono_array_get (data, guint8, 2) << 8);
+               scopeid = mono_array_get (data, guint8, 24) + 
+                       (mono_array_get (data, guint8, 25) << 8) + 
+                       (mono_array_get (data, guint8, 26) << 16) + 
+                       (mono_array_get (data, guint8, 27) << 24);
 
-               sa->sin6_family=family;
-               sa->sin6_port=htons(port);
+               sa->sin6_family = family;
+               sa->sin6_port = htons (port);
                sa->sin6_scope_id = scopeid;
 
-               for(i=0; i<16; i++)
-                       sa->sin6_addr.s6_addr[i] = mono_array_get(data, guint8, 8+i);
+               for(i=0; i<16; i++) {
+                       sa->sin6_addr.s6_addr[i] = mono_array_get (data, guint8, 8+i);
+               }
 
-               *sa_size=sizeof(struct sockaddr_in6);
+               *sa_size = sizeof(struct sockaddr_in6);
                return((struct sockaddr *)sa);
 #endif
 #ifdef HAVE_SYS_UN_H
        } else if (family == AF_UNIX) {
-               struct sockaddr_un *sock_un = g_new0 (struct sockaddr_un, 1);
+               struct sockaddr_un *sock_un;
                int i;
 
-               if (len - 2 > MONO_SIZEOF_SUNPATH)
+               /* Need a byte for the '\0' terminator/prefix, and the first
+                * two bytes hold the SocketAddress family
+                */
+               if (len - 2 >= MONO_SIZEOF_SUNPATH) {
                        mono_raise_exception (mono_get_exception_index_out_of_range ());
+               }
+               
+               sock_un = g_new0 (struct sockaddr_un, 1);
 
                sock_un->sun_family = family;
-               for (i = 0; i < len - 2; i++)
+               for (i = 0; i < len - 2; i++) {
                        sock_un->sun_path [i] = mono_array_get (data, guint8,
                                                                i + 2);
-               sock_un->sun_path [len - 2] = '\0';
-               *sa_size = sizeof (struct sockaddr_un);
+               }
+               
+               *sa_size = len;
 
                return (struct sockaddr *)sock_un;
 #endif
@@ -1003,7 +1126,7 @@ static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
 {
        struct sockaddr *sa;
-       int sa_size;
+       socklen_t sa_size;
        int ret;
        
        MONO_ARCH_SAVE_REGS;
@@ -1037,47 +1160,81 @@ MonoBoolean
 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
                                                   gint timeout, gint32 *error)
 {
-       fd_set fds;
-       int ret = 0;
-       struct timeval tv;
-       struct timeval *tvptr;
-       div_t divvy;
+       MonoThread *thread = NULL;
+       mono_pollfd *pfds;
+       int ret;
+       time_t start;
+       
 
        MONO_ARCH_SAVE_REGS;
+       
+       pfds = g_new0 (mono_pollfd, 1);
+       pfds[0].fd = GPOINTER_TO_INT (sock);
+       pfds[0].events = (mode == SelectModeRead) ? MONO_POLLIN :
+               (mode == SelectModeWrite) ? MONO_POLLOUT :
+               (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL);
 
+       timeout = (timeout >= 0) ? (timeout / 1000) : -1;
+       start = time (NULL);
        do {
-               /* FIXME: in case of extra iteration (WSAEINTR), substract time
-                * from the initial timeout */
                *error = 0;
-               FD_ZERO (&fds);
-               _wapi_FD_SET (sock, &fds);
-               if (timeout >= 0) {
-                       divvy = div (timeout, 1000000);
-                       tv.tv_sec = divvy.quot;
-                       tv.tv_usec = divvy.rem;
-                       tvptr = &tv;
-               } else {
-                       tvptr = NULL;
+               
+               ret = mono_poll (pfds, 1, timeout);
+               if (timeout > 0 && ret < 0) {
+                       int err = errno;
+                       int sec = time (NULL) - start;
+                       
+                       timeout -= sec * 1000;
+                       if (timeout < 0) {
+                               timeout = 0;
+                       }
+                       
+                       errno = err;
                }
+               
+               if (ret == -1 && errno == EINTR) {
+                       int leave = 0;
 
-               if (mode == SelectModeRead) {
-                       ret = _wapi_select (0, &fds, NULL, NULL, tvptr);
-               } else if (mode == SelectModeWrite) {
-                       ret = _wapi_select (0, NULL, &fds, NULL, tvptr);
-               } else if (mode == SelectModeError) {
-                       ret = _wapi_select (0, NULL, NULL, &fds, tvptr);
-               } else {
-                       g_assert_not_reached ();
+                       if (thread == NULL) {
+                               thread = mono_thread_current ();
+                       }
+                       
+                       leave = mono_thread_test_state (thread, ThreadState_AbortRequested | ThreadState_StopRequested);
+                       
+                       if (leave != 0) {
+                               g_free (pfds);
+                               return(FALSE);
+                       } else {
+                               /* Suspend requested? */
+                               mono_thread_interruption_checkpoint ();
+                       }
+                       errno = EINTR;
                }
-       } while ((ret == SOCKET_ERROR) && (*error == WSAGetLastError ()) == WSAEINTR);
+       } while (ret == -1 && errno == EINTR);
 
-       return (ret != SOCKET_ERROR && _wapi_FD_ISSET (sock, &fds));
+       if (ret == -1) {
+#ifdef PLATFORM_WIN32
+               *error = WSAGetLastError ();
+#else
+               *error = errno_to_WSA (errno, __func__);
+#endif
+               g_free (pfds);
+               return(FALSE);
+       }
+       
+       g_free (pfds);
+
+       if (ret == 0) {
+               return(FALSE);
+       } else {
+               return (TRUE);
+       }
 }
 
 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
 {
        struct sockaddr *sa;
-       int sa_size;
+       socklen_t sa_size;
        int ret;
        
        MONO_ARCH_SAVE_REGS;
@@ -1101,6 +1258,92 @@ extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, Mo
        g_free(sa);
 }
 
+/* These #defines from mswsock.h from wine.  Defining them here allows
+ * us to build this file on a mingw box that doesn't know the magic
+ * numbers, but still run on a newer windows box that does.
+ */
+#ifndef WSAID_DISCONNECTEX
+#define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
+typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
+#endif
+
+#ifndef WSAID_TRANSMITFILE
+#define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
+#endif
+
+extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error)
+{
+       int ret;
+       glong output_bytes = 0;
+       GUID disco_guid = WSAID_DISCONNECTEX;
+       GUID trans_guid = WSAID_TRANSMITFILE;
+       LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
+       LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
+       gboolean bret;
+       
+       MONO_ARCH_SAVE_REGS;
+
+       *error = 0;
+       
+#ifdef DEBUG
+       g_message("%s: disconnecting from socket %p (reuse %d)", __func__,
+                 sock, reuse);
+#endif
+
+       /* I _think_ the extension function pointers need to be looked
+        * up for each socket.  FIXME: check the best way to store
+        * pointers to functions in managed objects that still works
+        * on 64bit platforms.
+        */
+       ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+                       (void *)&disco_guid, sizeof(GUID),
+                       (void *)&_wapi_disconnectex, sizeof(void *),
+                       &output_bytes, NULL, NULL);
+       if (ret != 0) {
+               /* make sure that WSAIoctl didn't put crap in the
+                * output pointer
+                */
+               _wapi_disconnectex = NULL;
+
+               /* Look up the TransmitFile extension function pointer
+                * instead of calling TransmitFile() directly, because
+                * apparently "Several of the extension functions have
+                * been available since WinSock 1.1 and are exported
+                * from MSWsock.dll, however it's not advisable to
+                * link directly to this dll as this ties you to the
+                * Microsoft WinSock provider. A provider neutral way
+                * of accessing these extension functions is to load
+                * them dynamically via WSAIoctl using the
+                * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
+                * should, theoretically, allow you to access these
+                * functions from any provider that supports them..." 
+                * (http://www.codeproject.com/internet/jbsocketserver3.asp)
+                */
+               ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+                               (void *)&trans_guid, sizeof(GUID),
+                               (void *)&_wapi_transmitfile, sizeof(void *),
+                               &output_bytes, NULL, NULL);
+               if (ret != 0) {
+                       _wapi_transmitfile = NULL;
+               }
+       }
+
+       if (_wapi_disconnectex != NULL) {
+               bret = _wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0);
+       } else if (_wapi_transmitfile != NULL) {
+               bret = _wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL,
+                                          TF_DISCONNECT | TF_REUSE_SOCKET);
+       } else {
+               *error = ERROR_NOT_SUPPORTED;
+               return;
+       }
+
+       if (bret == FALSE) {
+               *error = WSAGetLastError ();
+       }
+}
+
 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
 {
        int ret;
@@ -1112,13 +1355,19 @@ gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArr
 
        *error = 0;
        
-       alen=mono_array_length(buffer);
-       if(offset+count>alen) {
+       alen = mono_array_length (buffer);
+       if (offset > alen - count) {
                return(0);
        }
        
        buf=mono_array_addr(buffer, guchar, offset);
        
+       recvflags = convert_socketflags (flags);
+       if (recvflags == -1) {
+               *error = WSAEOPNOTSUPP;
+               return (0);
+       }
+               
        ret = _wapi_recv (sock, buf, count, recvflags);
        if(ret==SOCKET_ERROR) {
                *error = WSAGetLastError ();
@@ -1128,6 +1377,35 @@ gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArr
        return(ret);
 }
 
+gint32 ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
+{
+       int ret, count;
+       DWORD recv;
+       WSABUF *wsabufs;
+       DWORD recvflags = 0;
+       
+       MONO_ARCH_SAVE_REGS;
+
+       *error = 0;
+       
+       wsabufs = mono_array_addr (buffers, WSABUF, 0);
+       count = mono_array_length (buffers);
+       
+       recvflags = convert_socketflags (flags);
+       if (recvflags == -1) {
+               *error = WSAEOPNOTSUPP;
+               return(0);
+       }
+       
+       ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
+       if (ret == SOCKET_ERROR) {
+               *error = WSAGetLastError ();
+               return(0);
+       }
+       
+       return(recv);
+}
+
 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
 {
        int ret;
@@ -1135,14 +1413,14 @@ gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoAr
        gint32 alen;
        int recvflags=0;
        struct sockaddr *sa;
-       int sa_size;
+       socklen_t sa_size;
        
        MONO_ARCH_SAVE_REGS;
 
        *error = 0;
        
-       alen=mono_array_length(buffer);
-       if(offset+count>alen) {
+       alen = mono_array_length (buffer);
+       if (offset > alen - count) {
                return(0);
        }
 
@@ -1153,6 +1431,12 @@ gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoAr
        
        buf=mono_array_addr(buffer, guchar, offset);
        
+       recvflags = convert_socketflags (flags);
+       if (recvflags == -1) {
+               *error = WSAEOPNOTSUPP;
+               return (0);
+       }
+
        ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
        if(ret==SOCKET_ERROR) {
                g_free(sa);
@@ -1185,8 +1469,8 @@ gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray
 
        *error = 0;
        
-       alen=mono_array_length(buffer);
-       if(offset+count>alen) {
+       alen = mono_array_length (buffer);
+       if (offset > alen - count) {
                return(0);
        }
 
@@ -1200,6 +1484,12 @@ gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray
        g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
 #endif
 
+       sendflags = convert_socketflags (flags);
+       if (sendflags == -1) {
+               *error = WSAEOPNOTSUPP;
+               return (0);
+       }
+
        ret = _wapi_send (sock, buf, count, sendflags);
        if(ret==SOCKET_ERROR) {
                *error = WSAGetLastError ();
@@ -1209,6 +1499,35 @@ gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray
        return(ret);
 }
 
+gint32 ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
+{
+       int ret, count;
+       DWORD sent;
+       WSABUF *wsabufs;
+       DWORD sendflags = 0;
+       
+       MONO_ARCH_SAVE_REGS;
+
+       *error = 0;
+       
+       wsabufs = mono_array_addr (buffers, WSABUF, 0);
+       count = mono_array_length (buffers);
+       
+       sendflags = convert_socketflags (flags);
+       if (sendflags == -1) {
+               *error = WSAEOPNOTSUPP;
+               return(0);
+       }
+       
+       ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
+       if (ret == SOCKET_ERROR) {
+               *error = WSAGetLastError ();
+               return(0);
+       }
+       
+       return(sent);
+}
+
 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
 {
        int ret;
@@ -1216,14 +1535,14 @@ gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArra
        gint32 alen;
        int sendflags=0;
        struct sockaddr *sa;
-       int sa_size;
+       socklen_t sa_size;
        
        MONO_ARCH_SAVE_REGS;
 
        *error = 0;
        
-       alen=mono_array_length(buffer);
-       if(offset+count>alen) {
+       alen = mono_array_length (buffer);
+       if (offset > alen - count) {
                return(0);
        }
 
@@ -1242,6 +1561,12 @@ gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArra
        g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
 #endif
 
+       sendflags = convert_socketflags (flags);
+       if (sendflags == -1) {
+               *error = WSAEOPNOTSUPP;
+               return (0);
+       }
+
        ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
        if(ret==SOCKET_ERROR) {
                *error = WSAGetLastError ();
@@ -1263,165 +1588,128 @@ static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
        return(sock);
 }
 
-void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout, gint32 *error)
+#define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
+void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
 {
-       fd_set readfds, writefds, errfds;
-       fd_set *readptr = NULL, *writeptr = NULL, *errptr = NULL;
-       struct timeval tv;
-       div_t divvy;
+       MonoThread *thread = NULL;
+       MonoObject *obj;
+       mono_pollfd *pfds;
+       int nfds, idx;
        int ret;
-       int readarrsize = 0, writearrsize = 0, errarrsize = 0;
-       MonoDomain *domain=mono_domain_get();
+       int i, count;
+       int mode;
        MonoClass *sock_arr_class;
        MonoArray *socks;
-       int count;
-       int i;
-       SOCKET handle;
+       time_t start;
+       mono_array_size_t socks_size;
        
        MONO_ARCH_SAVE_REGS;
 
-       if (*read_socks)
-               readarrsize=mono_array_length(*read_socks);
-
-       *error = 0;
-       
-       if(readarrsize>FD_SETSIZE) {
-               *error = WSAEFAULT;
-               return;
-       }
-       
-       if (readarrsize) {
-               readptr = &readfds;
-               FD_ZERO(&readfds);
-               for(i=0; i<readarrsize; i++) {
-                       handle = Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i));
-                       _wapi_FD_SET(handle, &readfds);
+       /* *sockets -> READ, null, WRITE, null, ERROR, null */
+       count = mono_array_length (*sockets);
+       nfds = count - 3; /* NULL separators */
+       pfds = g_new0 (mono_pollfd, nfds);
+       mode = idx = 0;
+       for (i = 0; i < count; i++) {
+               obj = mono_array_get (*sockets, MonoObject *, i);
+               if (obj == NULL) {
+                       mode++;
+                       continue;
                }
-       }
-       
-       if (*write_socks)
-               writearrsize=mono_array_length(*write_socks);
 
-       if(writearrsize>FD_SETSIZE) {
-               *error = WSAEFAULT;
-               return;
-       }
-       
-       if (writearrsize) {
-               writeptr = &writefds;
-               FD_ZERO(&writefds);
-               for(i=0; i<writearrsize; i++) {
-                       handle = Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i));
-                       _wapi_FD_SET(handle, &writefds);
+               if (idx >= nfds) {
+                       /* The socket array was bogus */
+                       g_free (pfds);
+                       *error = WSAEFAULT;
+                       return;
                }
-       }
-       
-       if (*err_socks)
-               errarrsize=mono_array_length(*err_socks);
 
-       if(errarrsize>FD_SETSIZE) {
-               *error = WSAEFAULT;
-               return;
-       }
-       
-       if (errarrsize) {
-               errptr = &errfds;
-               FD_ZERO(&errfds);
-               for(i=0; i<errarrsize; i++) {
-                       handle = Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i));
-                       _wapi_FD_SET(handle, &errfds);
-               }
+               pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj));
+               pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
+               idx++;
        }
 
-       /* Negative timeout meaning block until ready is only
-        * specified in Poll, not Select
-        */
-
-       divvy = div (timeout, 1000000);
-       
+       timeout = (timeout >= 0) ? (timeout / 1000) : -1;
+       start = time (NULL);
        do {
-               if(timeout>=0) {
-                       tv.tv_sec=divvy.quot;
-                       tv.tv_usec=divvy.rem;
+               *error = 0;
+               ret = mono_poll (pfds, nfds, timeout);
+               if (timeout > 0 && ret < 0) {
+                       int err = errno;
+                       int sec = time (NULL) - start;
+
+                       timeout -= sec * 1000;
+                       if (timeout < 0)
+                               timeout = 0;
+                       errno = err;
+               }
 
-                       ret = _wapi_select (0, readptr, writeptr, errptr, &tv);
-               } else {
-                       ret = _wapi_select (0, readptr, writeptr, errptr, NULL);
+               if (ret == -1 && errno == EINTR) {
+                       int leave = 0;
+                       if (thread == NULL)
+                               thread = mono_thread_current ();
+
+                       leave = mono_thread_test_state (thread, ThreadState_AbortRequested | ThreadState_StopRequested);
+                       
+                       if (leave != 0) {
+                               g_free (pfds);
+                               *sockets = NULL;
+                               return;
+                       } else {
+                               /* Suspend requested? */
+                               mono_thread_interruption_checkpoint ();
+                       }
+                       errno = EINTR;
                }
-       } while ((ret==SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
+       } while (ret == -1 && errno == EINTR);
        
-       if(ret==SOCKET_ERROR) {
+       if (ret == -1) {
+#ifdef PLATFORM_WIN32
                *error = WSAGetLastError ();
+#else
+               *error = errno_to_WSA (errno, __func__);
+#endif
+               g_free (pfds);
                return;
        }
 
-       if (readarrsize) {
-               sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
-               
-               count=0;
-               for(i=0; i<readarrsize; i++) {
-                       if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
-                               count++;
-                       }
-               }
-               socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
-               count=0;
-               for(i=0; i<readarrsize; i++) {
-                       MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
-                       
-                       if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
-                               mono_array_set(socks, MonoObject *, count, sock);
-                               count++;
-                       }
-               }
-               *read_socks=socks;
-       } else {
-               *read_socks = NULL;
+       if (ret == 0) {
+               g_free (pfds);
+               *sockets = NULL;
+               return;
        }
 
-       if (writearrsize) {
-               sock_arr_class=((MonoObject *)*write_socks)->vtable->klass;
-               count=0;
-               for(i=0; i<writearrsize; i++) {
-                       if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
-                               count++;
-                       }
-               }
-               socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
-               count=0;
-               for(i=0; i<writearrsize; i++) {
-                       MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
-                       
-                       if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
-                               mono_array_set(socks, MonoObject *, count, sock);
-                               count++;
-                       }
-               }
-               *write_socks=socks;
-       } else {
-               *write_socks = NULL;
-       }
+       sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
+       socks_size = ((mono_array_size_t)ret) + 3; /* space for the NULL delimiters */
+       socks = mono_array_new_full (mono_domain_get (), sock_arr_class, &socks_size, NULL);
 
-       if (errarrsize) {
-               sock_arr_class=((MonoObject *)*err_socks)->vtable->klass;
-               count=0;
-               for(i=0; i<errarrsize; i++) {
-                       if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
-                               count++;
-                       }
+       mode = idx = 0;
+       for (i = 0; i < count && ret > 0; i++) {
+               mono_pollfd *pfd;
+
+               obj = mono_array_get (*sockets, MonoObject *, i);
+               if (obj == NULL) {
+                       mode++;
+                       idx++;
+                       continue;
                }
-               socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
-               count=0;
-               for(i=0; i<errarrsize; i++) {
-                       MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
-                       
-                       if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
-                               mono_array_set(socks, MonoObject *, count, sock);
-                               count++;
-                       }
+
+               pfd = &pfds [i - mode];
+               if (pfd->revents == 0)
+                       continue;
+
+               ret--;
+               if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
+                       mono_array_setref (socks, idx++, obj);
+               } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
+                       mono_array_setref (socks, idx++, obj);
+               } else if ((pfd->revents & POLL_ERRORS) != 0) {
+                       mono_array_setref (socks, idx++, obj);
                }
-               *err_socks=socks;
        }
+
+       *sockets = socks;
+       g_free (pfds);
 }
 
 static MonoObject* int_to_object (MonoDomain *domain, int val)
@@ -1436,14 +1724,14 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc
        int system_name;
        int ret;
        int val;
-       int valsize=sizeof(val);
+       socklen_t valsize=sizeof(val);
        struct linger linger;
-       int lingersize=sizeof(linger);
-       struct timeval tv;
-       int tvsize=sizeof(tv);
+       socklen_t lingersize=sizeof(linger);
+       int time_ms = 0;
+       socklen_t time_ms_size = sizeof (time_ms);
 #ifdef SO_PEERCRED
        struct ucred cred;
-       int credsize = sizeof(cred);
+       socklen_t credsize = sizeof(cred);
 #endif
        MonoDomain *domain=mono_domain_get();
        MonoObject *obj;
@@ -1460,6 +1748,10 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc
                *error = WSAENOPROTOOPT;
                return;
        }
+       if (ret == -2) {
+               *obj_val = int_to_object (domain, 0);
+               return;
+       }
        
        /* No need to deal with MulticastOption names here, because
         * you cant getsockopt AddMembership or DropMembership (the
@@ -1474,8 +1766,7 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc
                
        case SocketOptionName_SendTimeout:
        case SocketOptionName_ReceiveTimeout:
-               ret = _wapi_getsockopt (sock, system_level, system_name, &tv,
-                          &tvsize);
+               ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
                break;
 
 #ifdef SO_PEERCRED
@@ -1498,7 +1789,7 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc
        switch(name) {
        case SocketOptionName_Linger:
                /* build a System.Net.Sockets.LingerOption */
-               obj_class=mono_class_from_name(system_assembly,
+               obj_class=mono_class_from_name(get_socket_assembly (),
                                               "System.Net.Sockets",
                                               "LingerOption");
                obj=mono_object_new(domain, obj_class);
@@ -1521,7 +1812,7 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc
                
        case SocketOptionName_SendTimeout:
        case SocketOptionName_ReceiveTimeout:
-               obj = int_to_object (domain, (tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+               obj = int_to_object (domain, time_ms);
                break;
 
 #ifdef SO_PEERCRED
@@ -1548,7 +1839,7 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc
                
                obj_class = mono_class_from_name(mono_posix_image,
                                                 "Mono.Posix",
-                                                "PeerCred/PeerCredData");
+                                                "PeerCredData");
                obj = mono_object_new(domain, obj_class);
                cred_data = (MonoPeerCredData *)obj;
                cred_data->pid = cred.pid;
@@ -1571,7 +1862,7 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET soc
        int system_name;
        int ret;
        guchar *buf;
-       int valsize;
+       socklen_t valsize;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -1583,6 +1874,8 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET soc
                *error = WSAENOPROTOOPT;
                return;
        }
+       if(ret==-2)
+               return;
 
        valsize=mono_array_length(*byte_val);
        buf=mono_array_addr(*byte_val, guchar, 0);
@@ -1599,14 +1892,13 @@ static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
        struct in_addr inaddr;
        MonoClassField *field;
        
-       field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
+       field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
 
        /* No idea why .net uses a 64bit type to hold a 32bit value...
         *
-        * Internal value of IPAddess is in Network Order, there is no need
-        * to call htonl here.
+        * Internal value of IPAddess is in little-endian order
         */
-       inaddr.s_addr=(guint32)*(guint64 *)(((char *)ipaddr)+field->offset);
+       inaddr.s_addr=GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr)+field->offset));
        
        return(inaddr);
 }
@@ -1620,7 +1912,7 @@ static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
        MonoArray *data;
        int i;
 
-       field=mono_class_get_field_from_name(ipaddr->vtable->klass, "_numbers");
+       field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
        data=*(MonoArray **)(((char *)ipaddr) + field->offset);
 
 /* Solaris has only the 8 bit version. */
@@ -1678,6 +1970,9 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g
                *error = WSAENOPROTOOPT;
                return;
        }
+       if(ret==-2){
+               return;
+       }
 
        /* Only one of obj_val, byte_val or int_val has data */
        if(obj_val!=NULL) {
@@ -1790,18 +2085,21 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g
                        return;
                }
        } else {
+               /* ReceiveTimeout/SendTimeout get here */
                switch(name) {
-                       case SocketOptionName_SendTimeout:
-                       case SocketOptionName_ReceiveTimeout: {
-                               struct timeval tv;
-                               tv.tv_sec = int_val / 1000;
-                               tv.tv_usec = (int_val % 1000) * 1000;
-                               ret = _wapi_setsockopt (sock, system_level, system_name, &tv, sizeof (tv));
-                               break;
+               case SocketOptionName_DontFragment:
+#ifdef HAVE_IP_MTU_DISCOVER
+                       /* Fiddle with the value slightly if we're
+                        * turning DF on
+                        */
+                       if (int_val == 1) {
+                               int_val = IP_PMTUDISC_DO;
                        }
-                       default:
-                               ret = _wapi_setsockopt (sock, system_level, system_name, &int_val,
-                              sizeof(int_val));
+                       /* Fall through */
+#endif
+                       
+               default:
+                       ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
                }
        }
 
@@ -1834,7 +2132,7 @@ ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
                                              MonoArray *input,
                                              MonoArray *output, gint32 *error)
 {
-       gulong output_bytes = 0;
+       glong output_bytes = 0;
        gchar *i_buffer, *o_buffer;
        gint i_len, o_len;
        gint ret;
@@ -1873,13 +2171,122 @@ ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
        return (gint) output_bytes;
 }
 
+#ifdef HAVE_SIOCGIFCONF
+static gboolean
+is_loopback (int family, void *ad)
+{
+       char *ptr = (char *) ad;
+
+       if (family == AF_INET) {
+               return (ptr [0] == 127);
+       }
+#ifdef AF_INET6
+       else {
+               return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
+       }
+#endif
+       return FALSE;
+}
+
+static void *
+get_local_ips (int family, int *nips)
+{
+       int addr_size, offset, fd, i, count;
+       int max_ifaces = 50; /* 50 interfaces should be enough... */
+       struct ifconf ifc;
+       struct ifreq *ifr;
+       struct ifreq iflags;
+       char *result, *tmp_ptr;
+       gboolean ignore_loopback = FALSE;
+
+       *nips = 0;
+       if (family == AF_INET) {
+               addr_size = sizeof (struct in_addr);
+               offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
+#ifdef AF_INET6
+       } else if (family == AF_INET6) {
+               addr_size = sizeof (struct in6_addr);
+               offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
+#endif
+       } else {
+               return NULL;
+       }
+
+       fd = socket (family, SOCK_STREAM, 0);
+
+       ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
+       ifc.ifc_buf = g_malloc (ifc.ifc_len);
+       if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
+               close (fd);
+               g_free (ifc.ifc_buf);
+               return NULL;
+       }
+
+       count = ifc.ifc_len / sizeof (struct ifreq);
+       *nips = count;
+       if (count == 0) {
+               g_free (ifc.ifc_buf);
+               close (fd);
+               return NULL;
+       }
+
+       for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
+               strcpy (iflags.ifr_name, ifr->ifr_name);
+               if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
+                       continue;
+               }
+
+               if ((iflags.ifr_flags & IFF_UP) == 0) {
+                       ifr->ifr_name [0] = '\0';
+                       continue;
+               }
+
+               if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
+                       ignore_loopback = TRUE;
+               }
+       }
+
+       close (fd);
+       result = g_malloc (addr_size * count);
+       tmp_ptr = result;
+       for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
+               if (ifr->ifr_name [0] == '\0') {
+                       (*nips)--;
+                       continue;
+               }
+
+               if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
+                       (*nips)--;
+                       continue;
+               }
+
+               memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
+               tmp_ptr += addr_size;
+       }
+
+       g_free (ifc.ifc_buf);
+       return result;
+}
+#else
+static void *
+get_local_ips (int family, int *nips)
+{
+       *nips = 0;
+       return NULL;
+}
+
+#endif /* HAVE_SIOCGIFCONF */
+
 #ifndef AF_INET6
 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
                                       MonoArray **h_aliases,
-                                      MonoArray **h_addr_list)
+                                      MonoArray **h_addr_list,
+                                      gboolean add_local_ips)
 {
        MonoDomain *domain = mono_domain_get ();
        int i;
+       struct in_addr *local_in = NULL;
+       int nlocal_in = 0;
 
        if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
                return(FALSE);
@@ -1898,41 +2305,87 @@ static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
                MonoString *alias;
                
                alias=mono_string_new(domain, he->h_aliases[i]);
-               mono_array_set(*h_aliases, MonoString *, i, alias);
+               mono_array_setref (*h_aliases, i, alias);
                i++;
        }
 
-       i=0;
-       while(he->h_addr_list[i]!=NULL) {
-               i++;
+       if (add_local_ips) {
+               local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
+               if (nlocal_in) {
+                       *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
+                       for (i = 0; i < nlocal_in; i++) {
+                               MonoString *addr_string;
+                               char addr [16], *ptr;
+                               
+                               ptr = (char *) &local_in [i];
+                               g_snprintf(addr, 16, "%u.%u.%u.%u",
+                                        (unsigned char) ptr [0],
+                                        (unsigned char) ptr [1],
+                                        (unsigned char) ptr [2],
+                                        (unsigned char) ptr [3]);
+                               
+                               addr_string = mono_string_new (domain, addr);
+                               mono_array_setref (*h_addr_list, i, addr_string);
+                               i++;
+                       }
+
+                       g_free (local_in);
+               }
        }
        
-       *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
-       i=0;
-       while(he->h_addr_list[i]!=NULL) {
-               MonoString *addr_string;
-               char addr[16];
-               
-               g_snprintf(addr, 16, "%u.%u.%u.%u",
-                        (unsigned char)he->h_addr_list[i][0],
-                        (unsigned char)he->h_addr_list[i][1],
-                        (unsigned char)he->h_addr_list[i][2],
-                        (unsigned char)he->h_addr_list[i][3]);
-               
-               addr_string=mono_string_new(domain, addr);
-               mono_array_set(*h_addr_list, MonoString *, i, addr_string);
-               i++;
+       if (nlocal_in == 0) {
+               i = 0;
+               while (he->h_addr_list[i]!=NULL) {
+                       i++;
+               }
+
+               *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
+               i=0;
+               while(he->h_addr_list[i]!=NULL) {
+                       MonoString *addr_string;
+                       char addr[16];
+                       
+                       g_snprintf(addr, 16, "%u.%u.%u.%u",
+                                (unsigned char)he->h_addr_list[i][0],
+                                (unsigned char)he->h_addr_list[i][1],
+                                (unsigned char)he->h_addr_list[i][2],
+                                (unsigned char)he->h_addr_list[i][3]);
+                       
+                       addr_string=mono_string_new(domain, addr);
+                       mono_array_setref (*h_addr_list, i, addr_string);
+                       i++;
+               }
        }
 
        return(TRUE);
 }
+
+static gboolean ipaddr_to_IPHostEntry(const char *addr, MonoString **h_name,
+                                     MonoArray **h_aliases,
+                                     MonoArray **h_addr_list)
+{
+       MonoDomain *domain = mono_domain_get ();
+
+       *h_name=mono_string_new(domain, addr);
+       *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
+       *h_addr_list=mono_array_new(domain, mono_get_string_class (), 1);
+       mono_array_setref (*h_addr_list, 0, *h_name);
+
+       return(TRUE);
+}
 #endif
 
 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
-static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
+                               MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
 {
        MonoDomain *domain = mono_domain_get ();
        int i, host_count, host_index, family_hint;
+       struct in_addr *local_in = NULL;
+       int nlocal_in = 0;
+       struct in6_addr *local_in6 = NULL;
+       int nlocal_in6 = 0;
+       gboolean from_local = FALSE;
 
        family_hint = get_family_hint ();
 
@@ -1971,10 +2424,11 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2,
                        MonoString *alias;
 
                        alias=mono_string_new (domain, he1->h_aliases[i]);
-                       mono_array_set (*h_aliases, MonoString *, i, alias);
+                       mono_array_setref (*h_aliases, i, alias);
                        i++;
                }
-       } else if (family_hint == PF_UNSPEC || family_hint == PF_INET6) {
+       } else if (he2 != NULL && (family_hint == PF_UNSPEC ||
+                                  family_hint == PF_INET6)) {
                *h_name=mono_string_new (domain, he2->h_name);
 
                i=0;
@@ -1989,9 +2443,11 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2,
                        MonoString *alias;
 
                        alias=mono_string_new (domain, he2->h_aliases[i]);
-                       mono_array_set (*h_aliases, MonoString *, i, alias);
+                       mono_array_setref (*h_aliases, i, alias);
                        i++;
                }
+       } else {
+               return(FALSE);
        }
 
        /*
@@ -2019,26 +2475,80 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2,
        /*
         * Fills the array
         */
-       *h_addr_list=mono_array_new (domain, mono_get_string_class (),
-                                    host_count);
-
        host_index = 0;
+       if (add_local_ips) {
+               if (family_hint == PF_UNSPEC || family_hint == PF_INET)
+                       local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
+
+               if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
+                       local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
+
+               if (nlocal_in || nlocal_in6) {
+                       from_local = TRUE;
+                       *h_addr_list = mono_array_new (domain, mono_get_string_class (),
+                                                            nlocal_in + nlocal_in6);
+
+                       if (nlocal_in6) {
+                               int n;
+                               for (n = 0; n < nlocal_in6; n++) {
+                                       MonoString *addr_string;
+                                       const char *ret;
+                                       char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
+
+                                       ret = inet_ntop (AF_INET6, &local_in6 [n], addr, sizeof(addr));
+
+                                       if (ret != NULL) {
+                                               addr_string = mono_string_new (domain, addr);
+                                               mono_array_setref (*h_addr_list, host_index, addr_string);
+                                               host_index++;
+                                       }
+                               }
+                       }
+
+                       if (nlocal_in) {
+                               int n;
+                               for (n = 0; n < nlocal_in; n++) {
+                                       MonoString *addr_string;
+                                       const char *ret;
+                                       char addr[16]; /* INET_ADDRSTRLEN == 16 */
+
+                                       ret = inet_ntop (AF_INET, &local_in [n], addr, sizeof(addr));
+
+                                       if (ret != NULL) {
+                                               addr_string = mono_string_new (domain, addr);
+                                               mono_array_setref (*h_addr_list, host_index, addr_string);
+                                               host_index++;
+                                       }
+                               }
+                       }
+                       g_free (local_in);
+                       g_free (local_in6);
+                       return TRUE;
+               }
+
+               g_free (local_in);
+               g_free (local_in6);
+       }
+
+       *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
 
        if (he2 != NULL && (family_hint == PF_UNSPEC ||
                            family_hint == PF_INET6)) {
                i = 0;
                while(he2->h_addr_list[i] != NULL) {
                        MonoString *addr_string;
-                       char addr[40];
+                       const char *ret;
+                       char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
 
-                       inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
-                                  sizeof(addr));
+                       ret = inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
+                                        sizeof(addr));
 
-                       addr_string = mono_string_new (domain, addr);
-                       mono_array_set (*h_addr_list, MonoString *, host_index,
-                                       addr_string);
-                       i++;
-                       host_index++;
+                       if (ret != NULL) {
+                               addr_string = mono_string_new (domain, addr);
+                               mono_array_setref (*h_addr_list, host_index, addr_string);
+                               i++;
+                               host_index++;
+                       }
                }
        }
 
@@ -2047,16 +2557,18 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2,
                i=0;
                while(he1->h_addr_list[i] != NULL) {
                        MonoString *addr_string;
-                       char addr[17];
+                       const char *ret;
+                       char addr[16]; /* INET_ADDRSTRLEN == 16 */
 
-                       inet_ntop (AF_INET, he1->h_addr_list[i], addr,
-                                  sizeof(addr));
+                       ret = inet_ntop (AF_INET, he1->h_addr_list[i], addr,
+                                        sizeof(addr));
 
-                       addr_string=mono_string_new (domain, addr);
-                       mono_array_set (*h_addr_list, MonoString *, host_index,
-                                       addr_string);
-                       i++;
-                       host_index++;
+                       if (ret != NULL) {
+                               addr_string=mono_string_new (domain, addr);
+                               mono_array_setref (*h_addr_list, host_index, addr_string);
+                               i++;
+                               host_index++;
+                       }
                }
        }
 
@@ -2068,64 +2580,104 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2,
 static gboolean 
 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
                                                MonoArray **h_aliases,
-                                               MonoArray **h_addr_list)
+                                               MonoArray **h_addr_list,
+                                               gboolean add_local_ips)
 {
        gint32 count, i;
        struct addrinfo *ai = NULL;
+       struct in_addr *local_in = NULL;
+       int nlocal_in = 0;
+       struct in6_addr *local_in6 = NULL;
+       int nlocal_in6 = 0;
+       int addr_index;
 
        MonoDomain *domain = mono_domain_get ();
 
+       addr_index = 0;
+       *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
+       if (add_local_ips) {
+               local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
+               local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
+               if (nlocal_in || nlocal_in6) {
+                       *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
+                       if (nlocal_in) {
+                               MonoString *addr_string;
+                               char addr [16];
+                               int i;
+
+                               for (i = 0; i < nlocal_in; i++) {
+                                       inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
+                                       addr_string = mono_string_new (domain, addr);
+                                       mono_array_setref (*h_addr_list, addr_index, addr_string);
+                                       addr_index++;
+                               }
+                       }
+
+                       if (nlocal_in6) {
+                               MonoString *addr_string;
+                               const char *ret;
+                               char addr [48];
+                               int i;
+
+                               for (i = 0; i < nlocal_in6; i++) {
+                                       ret = inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
+                                       if (ret != NULL) {
+                                               addr_string = mono_string_new (domain, addr);
+                                               mono_array_setref (*h_addr_list, addr_index, addr_string);
+                                               addr_index++;
+                                       }
+                               }
+                       }
+
+                       g_free (local_in);
+                       g_free (local_in6);
+                       if (info) {
+                               freeaddrinfo (info);
+                       }
+                       return TRUE;
+               }
+
+               g_free (local_in);
+               g_free (local_in6);
+       }
+
        for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
-               if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
+               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
                        continue;
-               }
 
                count++;
        }
 
-       *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
        *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
 
        for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
                MonoString *addr_string;
                const char *ret;
-               char *buffer;
-               gint32 buffer_size = 0;
+               char buffer [48]; /* Max. size for IPv6 */
 
                if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
                        continue;
                }
 
-               buffer_size = 256;
-               do {
-                       buffer = g_malloc0(buffer_size);
-
-                       if(ai->ai_family == PF_INET) {
-                               ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, buffer_size);
-                       } else {
-                               ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, buffer_size);
-                       }
-
-                       if(ret == 0) {
-                               g_free(buffer);
-                               buffer_size += 256;
-                       }
-               } while(ret == 0 && errno == ENOSPC);
+               if(ai->ai_family == PF_INET) {
+                       ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
+               } else {
+                       ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 48);
+               }
 
                if(ret) {
                        addr_string=mono_string_new(domain, buffer);
-                       g_free(buffer);
                } else {
                        addr_string=mono_string_new(domain, "");
                }
 
-               mono_array_set(*h_addr_list, MonoString *, i, addr_string);
+               mono_array_setref (*h_addr_list, addr_index, addr_string);
 
                if(!i && ai->ai_canonname != NULL) {
                        *h_name=mono_string_new(domain, ai->ai_canonname);
                }
 
-               i++;
+               addr_index++;
        }
 
        if(info) {
@@ -2139,6 +2691,10 @@ addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
 #ifdef AF_INET6
 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
 {
+       gboolean add_local_ips = FALSE;
+#ifdef HAVE_SIOCGIFCONF
+       gchar this_hostname [256];
+#endif
 #if !defined(HAVE_GETHOSTBYNAME2_R)
        struct addrinfo *info = NULL, hints;
        char *hostname;
@@ -2146,7 +2702,13 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo
        MONO_ARCH_SAVE_REGS;
        
        hostname=mono_string_to_utf8 (host);
-       
+#ifdef HAVE_SIOCGIFCONF
+       if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+               if (!strcmp (hostname, this_hostname))
+                       add_local_ips = TRUE;
+       }
+#endif
+
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = get_family_hint ();
        hints.ai_socktype = SOCK_STREAM;
@@ -2158,7 +2720,7 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo
        
        g_free(hostname);
 
-       return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list));
+       return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
 #else
        struct hostent he1,*hp1, he2, *hp2;
        int buffer_size1, buffer_size2;
@@ -2171,6 +2733,13 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo
        
        hostname=mono_string_to_utf8 (host);
 
+#ifdef HAVE_SIOCGIFCONF
+       if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+               if (!strcmp (hostname, this_hostname))
+                       add_local_ips = TRUE;
+       }
+#endif
+
        buffer_size1 = 512;
        buffer_size2 = 512;
        buffer1 = g_malloc0(buffer_size1);
@@ -2194,7 +2763,7 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo
                hp2 = NULL;
 
        return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
-                                              h_addr_list);
+                                              h_addr_list, add_local_ips);
 
        g_free(buffer1);
        g_free(buffer2);
@@ -2208,10 +2777,20 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo
 {
        struct hostent *he;
        char *hostname;
+       gboolean add_local_ips = FALSE;
+#ifdef HAVE_SIOCGIFCONF
+       gchar this_hostname [256];
+#endif
        
        MONO_ARCH_SAVE_REGS;
 
        hostname=mono_string_to_utf8(host);
+#ifdef HAVE_SIOCGIFCONF
+       if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+               if (!strcmp (hostname, this_hostname))
+                       add_local_ips = TRUE;
+       }
+#endif
 
        he = _wapi_gethostbyname (hostname);
        g_free(hostname);
@@ -2220,7 +2799,7 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo
                return(FALSE);
        }
 
-       return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
+       return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
 }
 #endif /* AF_INET6 */
 
@@ -2266,19 +2845,22 @@ inet_pton (int family, const char *address, void *inaddrp)
 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
 {
        char *address;
-
+       gboolean v1;
+       
 #ifdef AF_INET6
        struct sockaddr_in saddr;
        struct sockaddr_in6 saddr6;
        struct addrinfo *info = NULL, hints;
        gint32 family;
        char hostname[1024] = {0};
+       int flags = 0;
 #else
        struct in_addr inaddr;
        struct hostent *he;
+       gboolean ret;
 #endif
 
-       MONO_ARCH_SAVE_REGS;
+       v1 = mono_framework_version () == 1;
 
        address = mono_string_to_utf8 (addr);
 
@@ -2300,16 +2882,26 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a
        }
        g_free(address);
 
+       if (v1) {
+               flags = NI_NAMEREQD;
+       }
+       
        if(family == AF_INET) {
+#if HAVE_SOCKADDR_IN_SIN_LEN
+               saddr.sin_len = sizeof (saddr);
+#endif
                if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
                                hostname, sizeof(hostname), NULL, 0,
-                               NI_NAMEREQD) != 0) {
+                               flags) != 0) {
                        return(FALSE);
                }
        } else if(family == AF_INET6) {
+#if HAVE_SOCKADDR_IN6_SIN_LEN
+               saddr6.sin6_len = sizeof (saddr6);
+#endif
                if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
                                hostname, sizeof(hostname), NULL, 0,
-                               NI_NAMEREQD) != 0) {
+                               flags) != 0) {
                        return(FALSE);
                }
        }
@@ -2323,25 +2915,33 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a
                return(FALSE);
        }
 
-       return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list));
+       return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
 #else
        if (inet_pton (AF_INET, address, &inaddr) <= 0) {
                g_free (address);
                return(FALSE);
        }
-       g_free (address);
 
        if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
-               return(FALSE);
+               if (v1) {
+                       ret = FALSE;
+               } else {
+                       ret = ipaddr_to_IPHostEntry (address, h_name,
+                                                    h_aliases, h_addr_list);
+               }
+       } else {
+               ret = hostent_to_IPHostEntry (he, h_name, h_aliases,
+                                             h_addr_list, FALSE);
        }
 
-       return(hostent_to_IPHostEntry (he, h_name, h_aliases, h_addr_list));
+       g_free (address);
+       return(ret);
 #endif
 }
 
 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
 {
-       guchar hostname[256];
+       gchar hostname[256];
        int ret;
        
        MONO_ARCH_SAVE_REGS;