[System] Added icall SupportsPortReuse.
authorMarcos Henrich <marcos.henrich@xamarin.com>
Mon, 12 Oct 2015 15:45:37 +0000 (16:45 +0100)
committerMarcos Henrich <marcos.henrich@xamarin.com>
Mon, 12 Oct 2015 15:45:37 +0000 (16:45 +0100)
Linux kernels before 3.9 did not support port reuse.
Added private method System.Net.Sockets.Socket.SupportsPortReuse,
which returns true when the runtime is able to bind to the same address
and port multiple times.

mcs/class/System/System.Net.Sockets/Socket.cs
mcs/class/System/Test/System.Net.Sockets/SocketTest.cs
mono/metadata/icall-def.h
mono/metadata/socket-io.c
mono/metadata/socket-io.h

index ba638a9b5db5f1cd3d77dcd9e602a5efb4dedee2..0f5ad52bbe5cb5912786e7c9cf86a1d46359f615 100644 (file)
@@ -3456,6 +3456,9 @@ namespace System.Net.Sockets
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal static extern void cancel_blocking_socket_operation (Thread thread);
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal static extern bool SupportsPortReuse ();
        }
 }
 
index 4f01439cf194f9ac520c8d240c1f675179d6c1f3..c38da6685212ff32b305aeaaf5efa670e7060f91 100755 (executable)
@@ -12,6 +12,7 @@ using System;
 using System.Linq;
 using System.Collections;
 using System.Threading;
+using System.Reflection;
 using System.Text.RegularExpressions;
 using System.Net;
 using System.Net.Sockets;
@@ -3479,35 +3480,16 @@ namespace MonoTests.System.Net.Sockets
                        s.Close ();
                }
 
-               static bool supportsTcpReuse = false;
-               static bool supportsTcpReuseSet = false;
-
-               static bool SupportsTcpReuse ()
+               static bool? supportsPortReuse;
+               static bool SupportsPortReuse ()
                {
-                       if (supportsTcpReuseSet)
-                               return supportsTcpReuse;
-
-                       if (Path.DirectorySeparatorChar == '/') {
-                               /*
-                                * On UNIX OS
-                                * Multiple threads listening to the same address and port are not possible
-                                * before linux 3.9 kernel, where the socket option SO_REUSEPORT was introduced.
-                                */
-                               Regex reg = new Regex(@"^#define\s*SO_REUSEPORT");
-                               foreach (string directory in Directory.GetDirectories ("/usr/include")) {
-                                       var f = Directory.GetFiles (directory, "socket.h").SingleOrDefault ();
-                                       if (f != null && File.ReadLines (f).Any (l => reg.Match (l).Success)) {
-                                               supportsTcpReuse = true;
-                                               break;
-                                       }
-                               }
-                       } else {
-                               supportsTcpReuse = true;
-                       }
-
-                       supportsTcpReuseSet = true;
+                       if (supportsPortReuse.HasValue)
+                               return supportsPortReuse.Value;
 
-                       return supportsTcpReuse;
+                       supportsPortReuse = (bool) typeof (Socket).GetMethod ("SupportsPortReuse",
+                                       BindingFlags.Static | BindingFlags.NonPublic)
+                                       .Invoke (null, new object [] {});
+                       return supportsPortReuse.Value;
                }
 
                // Test case for bug #31557
@@ -3533,7 +3515,7 @@ namespace MonoTests.System.Net.Sockets
                                        ex = e;
                                }
 
-                               Assert.AreEqual (SupportsTcpReuse (), ex == null);
+                               Assert.AreEqual (SupportsPortReuse (), ex == null);
                        }
                }
 
index 890f15b877ab524bf88d09416067cea8070e8a65..9ccd3ffe3f4328367d4e48e5b4d4deb8f536989f 100644 (file)
@@ -441,6 +441,7 @@ ICALL(SOCK_17, "Send_internal(intptr,byte[],int,int,System.Net.Sockets.SocketFla
 ICALL(SOCK_18, "SetSocketOption_internal(intptr,System.Net.Sockets.SocketOptionLevel,System.Net.Sockets.SocketOptionName,object,byte[],int,int&)", ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal)
 ICALL(SOCK_19, "Shutdown_internal(intptr,System.Net.Sockets.SocketShutdown,int&)", ves_icall_System_Net_Sockets_Socket_Shutdown_internal)
 ICALL(SOCK_20, "Socket_internal(System.Net.Sockets.AddressFamily,System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType,int&)", ves_icall_System_Net_Sockets_Socket_Socket_internal)
+ICALL(SOCK_20a, "SupportsPortReuse", ves_icall_System_Net_Sockets_Socket_SupportPortReuse)
 ICALL(SOCK_21a, "cancel_blocking_socket_operation", icall_cancel_blocking_socket_operation)
 
 ICALL_TYPE(SOCKEX, "System.Net.Sockets.SocketException", SOCKEX_1)
index f583341edbbc9de816ff53425813def4453e99ad..091c07fe8bcf63b074907153fe2f32f8f37f9c91 100644 (file)
@@ -2724,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)
 {
index 5e1c7ef43a90e779c97d2d74f6730f8a353b643d..138cc674d5b0f46410add6da353ae36c79a57deb 100644 (file)
@@ -189,6 +189,7 @@ extern MonoBoolean ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET soc
 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error);
 extern gboolean ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags);
 void icall_cancel_blocking_socket_operation (MonoThread *thread);
+extern gboolean ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void);
 
 extern void mono_network_init(void);
 extern void mono_network_cleanup(void);