Merge pull request #3528 from BrzVlad/fix-sgen-check-before-collections
[mono.git] / mono / metadata / socket-io.c
index eb272c241d6a56f46d0c307ab2aa1047c33005cf..d4d168da76691a76c3f041b40cf2c45dde95d775 100644 (file)
@@ -62,6 +62,7 @@
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/networking.h>
+#include <mono/utils/w32handle.h>
 
 #include <time.h>
 #ifdef HAVE_SYS_TIME_H
@@ -773,16 +774,15 @@ ves_icall_System_Net_Sockets_Socket_Accept_internal (SOCKET sock, gint32 *werror
 
        MONO_EXIT_GC_SAFE;
 
+       if (newsock == INVALID_SOCKET)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
+       if (interrupted)
                *werror = WSAEINTR;
-               return NULL;
-       }
 
-       if (newsock == INVALID_SOCKET) {
-               *werror = WSAGetLastError ();
+       if (*werror)
                return NULL;
-       }
        
        return GUINT_TO_POINTER (newsock);
 }
@@ -1335,15 +1335,13 @@ ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *s
 
        MONO_EXIT_GC_SAFE;
 
-       mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
-               *werror = WSAEINTR;
-               return;
-       }
-
        if (ret == SOCKET_ERROR)
                *werror = WSAGetLastError ();
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted)
+               *werror = WSAEINTR;
+
        g_free (sa);
 }
 
@@ -1422,10 +1420,10 @@ ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolea
        MONO_ENTER_GC_SAFE;
 
        if (_wapi_disconnectex != NULL) {
-               if (!_wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0))
+               if (!_wapi_disconnectex (sock, NULL, reuse ? TF_REUSE_SOCKET : 0, 0))
                        *werror = WSAGetLastError ();
        } else if (_wapi_transmitfile != NULL) {
-               if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET))
+               if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | (reuse ? TF_REUSE_SOCKET : 0)))
                        *werror = WSAGetLastError ();
        } else {
                *werror = ERROR_NOT_SUPPORTED;
@@ -1480,16 +1478,15 @@ ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *bu
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
+       if (interrupted)
                *werror = WSAEINTR;
-               return 0;
-       }
 
-       if (ret == SOCKET_ERROR) {
-               *werror = WSAGetLastError ();
+       if (*werror)
                return 0;
-       }
 
        return ret;
 }
@@ -1526,16 +1523,15 @@ ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArr
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
+       if (interrupted)
                *werror = WSAEINTR;
-               return 0;
-       }
 
-       if (ret == SOCKET_ERROR) {
-               *werror = WSAGetLastError ();
+       if (*werror)
                return 0;
-       }
 
        return recv;
 }
@@ -1587,16 +1583,16 @@ ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
-               g_free (sa);
+
+       if (interrupted)
                *werror = WSAEINTR;
-               return 0;
-       }
 
-       if (ret==SOCKET_ERROR) {
-               g_free (sa);
-               *werror = WSAGetLastError ();
+       if (*werror) {
+               g_free(sa);
                return 0;
        }
 
@@ -1659,16 +1655,15 @@ ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffe
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
+       if (interrupted)
                *werror = WSAEINTR;
-               return 0;
-       }
 
-       if (ret == SOCKET_ERROR) {
-               *werror = WSAGetLastError ();
+       if (*werror)
                return 0;
-       }
 
        return ret;
 }
@@ -1705,17 +1700,16 @@ ves_icall_System_Net_Sockets_Socket_Send_array_internal (SOCKET sock, MonoArray
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
+       if (interrupted)
                *werror = WSAEINTR;
-               return 0;
-       }
 
-       if (ret == SOCKET_ERROR) {
-               *werror = WSAGetLastError ();
+       if (*werror)
                return 0;
-       }
-       
+
        return sent;
 }
 
@@ -1772,18 +1766,18 @@ ves_icall_System_Net_Sockets_Socket_SendTo_internal (SOCKET sock, MonoArray *buf
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
-       if (interrupted) {
-               g_free (sa);
+       if (interrupted)
                *werror = WSAEINTR;
-               return 0;
-       }
 
-       if (ret == SOCKET_ERROR)
-               *werror = WSAGetLastError ();
+       g_free(sa);
+
+       if (*werror)
+               return 0;
 
-       g_free (sa);
-       
        return ret;
 }
 
@@ -1960,7 +1954,7 @@ ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (SOCKET sock, g
        int system_level = 0;
        int system_name = 0;
        int ret;
-       int val;
+       int val = 0;
        socklen_t valsize = sizeof (val);
        struct linger linger;
        socklen_t lingersize = sizeof (linger);
@@ -2453,14 +2447,14 @@ ves_icall_System_Net_Sockets_Socket_Shutdown_internal (SOCKET sock, gint32 how,
 
        MONO_EXIT_GC_SAFE;
 
+       if (ret == SOCKET_ERROR)
+               *werror = WSAGetLastError ();
+
        mono_thread_info_uninstall_interrupt (&interrupted);
        if (interrupted) {
                *werror = WSAEINTR;
-               return;
        }
 
-       if (ret == SOCKET_ERROR)
-               *werror = WSAGetLastError ();
 }
 
 gint
@@ -2647,13 +2641,16 @@ get_addrinfo_family_hint (MonoError *error)
 MonoBoolean
 ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
 {
+       MonoError error;
        gboolean add_local_ips = FALSE, add_info_ok = TRUE;
        gchar this_hostname [256];
        MonoAddressInfo *info = NULL;
-       char *hostname = mono_string_to_utf8 (host);
-       MonoError error;
        int hint;
 
+       char *hostname = mono_string_to_utf8_checked (host, &error);
+       if (mono_error_set_pending_exception (&error))
+               return FALSE;
+
        hint = get_addrinfo_family_hint (&error);
        if (!mono_error_ok (&error)) {
                mono_error_set_pending_exception (&error);
@@ -2672,8 +2669,16 @@ ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **
                }
        }
 
+#ifdef HOST_WIN32
+       // Win32 APIs already returns local interface addresses for empty hostname ("")
+       // so we never want to add them manually.
+       add_local_ips = FALSE;
+       if (mono_get_address_info(hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
+               add_info_ok = FALSE;
+#else
        if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
                add_info_ok = FALSE;
+#endif
 
        g_free(hostname);
 
@@ -2697,7 +2702,9 @@ ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **
        gchar hostname [NI_MAXHOST] = { 0 };
        gboolean ret;
 
-       address = mono_string_to_utf8 (addr);
+       address = mono_string_to_utf8_checked (addr, &error);
+       if (mono_error_set_pending_exception (&error))
+               return FALSE;
 
        if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
                family = AF_INET;
@@ -2827,12 +2834,17 @@ ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *
 }
 
 gboolean
-ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void)
+ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
 {
 #if defined (SO_REUSEPORT) || defined (HOST_WIN32)
-    return TRUE;
+       return TRUE;
 #else
-    return FALSE;
+#ifdef __linux__
+       /* Linux always supports double binding for UDP, even on older kernels. */
+       if (proto == ProtocolType_Udp)
+               return TRUE;
+#endif
+       return FALSE;
 #endif
 }