Merge pull request #2106 from lambdageek/dev/bug-29108-part1
[mono.git] / mono / metadata / socket-io.c
index f3f712fe81e5cc7e9c2a9cb45f578c4a5fb94dde..091c07fe8bcf63b074907153fe2f32f8f37f9c91 100644 (file)
 #define LOGDEBUG(...)  
 /* define LOGDEBUG(...) g_message(__VA_ARGS__)  */
 
+static void
+abort_syscall (gpointer data)
+{
+       MonoThreadInfo *info = data;
+
+       if (mono_threads_core_needs_abort_syscall ())
+               mono_threads_core_abort_syscall (info);
+}
+
 static gint32
 convert_family (MonoAddressFamily mono_family)
 {
@@ -735,10 +744,17 @@ ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock, gboolean bloc
 gpointer
 ves_icall_System_Net_Sockets_Socket_Accept_internal (SOCKET sock, gint32 *error, gboolean blocking)
 {
+       gboolean interrupted;
        SOCKET newsock;
 
        *error = 0;
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return NULL;
+       }
+
        MONO_PREPARE_BLOCKING;
 
 #ifdef HOST_WIN32
@@ -754,6 +770,12 @@ ves_icall_System_Net_Sockets_Socket_Accept_internal (SOCKET sock, gint32 *error,
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return NULL;
+       }
+
        if(newsock==INVALID_SOCKET) {
                *error = WSAGetLastError ();
                return(NULL);
@@ -1160,6 +1182,7 @@ ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
        MonoInternalThread *thread = mono_thread_internal_current ();
        mono_pollfd *pfds;
        int ret;
+       gboolean interrupted;
        time_t start;
 
        *error = 0;
@@ -1177,12 +1200,26 @@ ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
        start = time (NULL);
 
        do {
+               mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+               if (interrupted) {
+                       g_free (pfds);
+                       *error = WSAEINTR;
+                       return FALSE;
+               }
+
                MONO_PREPARE_BLOCKING;
 
                ret = mono_poll (pfds, 1, timeout);
 
                MONO_FINISH_BLOCKING;
 
+               mono_thread_info_uninstall_interrupt (&interrupted);
+               if (interrupted) {
+                       g_free (pfds);
+                       *error = WSAEINTR;
+                       return FALSE;
+               }
+
                if (timeout > 0 && ret < 0) {
                        int err = errno;
                        int sec = time (NULL) - start;
@@ -1228,7 +1265,8 @@ ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *s
        struct sockaddr *sa;
        socklen_t sa_size;
        int ret;
-       
+       gboolean interrupted;
+
        *error = 0;
 
        sa = create_sockaddr_from_object(sockaddr, &sa_size, error);
@@ -1237,12 +1275,24 @@ ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *s
 
        LOGDEBUG (g_message("%s: connecting to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)));
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = _wapi_connect (sock, sa, sa_size);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return;
+       }
+
        if (ret == SOCKET_ERROR)
                *error = WSAGetLastError ();
 
@@ -1272,6 +1322,7 @@ ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolea
        GUID trans_guid = WSAID_TRANSMITFILE;
        LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
        LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
+       gboolean interrupted;
 
        *error = 0;
 
@@ -1314,6 +1365,12 @@ ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolea
                        _wapi_transmitfile = NULL;
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        if (_wapi_disconnectex != NULL) {
@@ -1327,6 +1384,10 @@ ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolea
        }
 
        MONO_FINISH_BLOCKING;
+
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted)
+               *error = WSAEINTR;
 }
 
 gint32
@@ -1336,6 +1397,7 @@ ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *bu
        guchar *buf;
        gint32 alen;
        int recvflags=0;
+       gboolean interrupted;
        MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
        
        *error = 0;
@@ -1353,6 +1415,10 @@ ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *bu
                return (0);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted)
+               return 0;
+
        MONO_PREPARE_BLOCKING;
 
 #ifdef HOST_WIN32
@@ -1367,6 +1433,12 @@ ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *bu
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        if(ret==SOCKET_ERROR) {
                *error = WSAGetLastError ();
                return(0);
@@ -1379,6 +1451,7 @@ gint32
 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
 {
        int ret, count;
+       gboolean interrupted;
        DWORD recv;
        WSABUF *wsabufs;
        DWORD recvflags = 0;
@@ -1394,12 +1467,24 @@ ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArr
                return(0);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        if (ret == SOCKET_ERROR) {
                *error = WSAGetLastError ();
                return 0;
@@ -1417,6 +1502,7 @@ ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray
        int recvflags=0;
        struct sockaddr *sa;
        socklen_t sa_size;
+       gboolean interrupted;
        
        *error = 0;
        
@@ -1438,12 +1524,26 @@ ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray
                return (0);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               g_free(sa);
+               *error = WSAEINTR;
+               return 0;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               g_free(sa);
+               *error = WSAEINTR;
+               return 0;
+       }
+
        if(ret==SOCKET_ERROR) {
                g_free(sa);
                *error = WSAGetLastError ();
@@ -1471,6 +1571,7 @@ ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffe
        guchar *buf;
        gint32 alen;
        int sendflags=0;
+       gboolean interrupted;
        
        *error = 0;
        
@@ -1491,12 +1592,24 @@ ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffe
                return (0);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = _wapi_send (sock, buf, count, sendflags);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        if(ret==SOCKET_ERROR) {
                *error = WSAGetLastError ();
                return(0);
@@ -1512,6 +1625,7 @@ ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *
        DWORD sent;
        WSABUF *wsabufs;
        DWORD sendflags = 0;
+       gboolean interrupted;
        
        *error = 0;
        
@@ -1524,12 +1638,24 @@ ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *
                return(0);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return 0;
+       }
+
        if (ret == SOCKET_ERROR) {
                *error = WSAGetLastError ();
                return(0);
@@ -1547,6 +1673,7 @@ ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buff
        int sendflags=0;
        struct sockaddr *sa;
        socklen_t sa_size;
+       gboolean interrupted;
        
        *error = 0;
        
@@ -1573,12 +1700,26 @@ ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buff
                return (0);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               g_free (sa);
+               *error = WSAEINTR;
+               return 0;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               g_free (sa);
+               *error = WSAEINTR;
+               return 0;
+       }
+
        if(ret==SOCKET_ERROR) {
                *error = WSAGetLastError ();
        }
@@ -1617,6 +1758,7 @@ ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32
        MonoArray *socks;
        time_t start;
        uintptr_t socks_size;
+       gboolean interrupted;
 
        *error = 0;
        
@@ -1647,12 +1789,26 @@ ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32
        timeout = (timeout >= 0) ? (timeout / 1000) : -1;
        start = time (NULL);
        do {
+               mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+               if (interrupted) {
+                       g_free (pfds);
+                       *error = WSAEINTR;
+                       return;
+               }
+
                MONO_PREPARE_BLOCKING;
 
                ret = mono_poll (pfds, nfds, timeout);
 
                MONO_FINISH_BLOCKING;
 
+               mono_thread_info_uninstall_interrupt (&interrupted);
+               if (interrupted) {
+                       g_free (pfds);
+                       *error = WSAEINTR;
+                       return;
+               }
+
                if (timeout > 0 && ret < 0) {
                        int err = errno;
                        int sec = time (NULL) - start;
@@ -2208,9 +2364,16 @@ void
 ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock, gint32 how, gint32 *error)
 {
        int ret;
+       gboolean interrupted;
 
        *error = 0;
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
@@ -2218,6 +2381,12 @@ ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock, gint32 how, g
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               *error = WSAEINTR;
+               return;
+       }
+
        if (ret == SOCKET_ERROR)
                *error = WSAGetLastError ();
 }
@@ -2501,6 +2670,7 @@ ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *
        HANDLE file;
        gint32 error;
        gboolean ret;
+       gboolean interrupted;
        TRANSMIT_FILE_BUFFERS buffers;
 
        if (filename == NULL)
@@ -2525,12 +2695,26 @@ ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *
                buffers.TailLength = mono_array_length (post_buffer);
        }
 
+       mono_thread_info_install_interrupt (abort_syscall, mono_thread_info_current (), &interrupted);
+       if (interrupted) {
+               CloseHandle (file);
+               SetLastError (WSAEINTR);
+               return FALSE;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        ret = TransmitFile (sock, file, 0, 0, NULL, &buffers, flags);
 
        MONO_FINISH_BLOCKING;
 
+       mono_thread_info_uninstall_interrupt (&interrupted);
+       if (interrupted) {
+               CloseHandle (file);
+               SetLastError (WSAEINTR);
+               return FALSE;
+       }
+
        MONO_PREPARE_BLOCKING;
 
        CloseHandle (file);
@@ -2540,6 +2724,16 @@ ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *
        return ret;
 }
 
+gboolean
+ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void)
+{
+#if defined (SO_REUSEPORT) || defined (HOST_WIN32)
+    return TRUE;
+#else
+    return FALSE;
+#endif
+}
+
 void
 mono_network_init(void)
 {