From 020e0b9dc54fa0c2034ec92dbc756a2d7ecb3c0d Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 22 Nov 2015 12:00:15 +0000 Subject: [PATCH 1/2] Enable TCP Loopback Fast Path (Windows) Enable TCP Loopback Fast Path; where the IP layer is skipped, for lower latency for localhost comms, like HttpPlatformHandler+IIS reverse proxy http://blogs.technet.com/b/wincat/archive/2012/12/05/fast-tcp-loopback-performance-and-low-latency-with-windows-server-2012-tcp-loopback-fast-path.aspx Have to do it this way due to open issue in libuv Loopback fast path: libuv/libuv#489 Related: "Confirm HttpPlatformHandler uses Fast TCP Loopback" aspnet/IISIntegration#29 --- .../Networking/Libuv.cs | 67 +++++++++++++++++++ .../EngineTests.cs | 33 +++++++++ .../MultipleLoopTests.cs | 16 +++++ .../NetworkingTests.cs | 48 +++++++++++++ .../TestConnection.cs | 17 +++++ 5 files changed, 181 insertions(+) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Networking/Libuv.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Networking/Libuv.cs index 279d4885cf..a7022d8fc4 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Networking/Libuv.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Networking/Libuv.cs @@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking _uv_stop = NativeDarwinMonoMethods.uv_stop; _uv_ref = NativeDarwinMonoMethods.uv_ref; _uv_unref = NativeDarwinMonoMethods.uv_unref; + _uv_fileno = NativeDarwinMonoMethods.uv_fileno; _uv_close = NativeDarwinMonoMethods.uv_close; _uv_async_init = NativeDarwinMonoMethods.uv_async_init; _uv_async_send = NativeDarwinMonoMethods.uv_async_send; @@ -68,6 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking _uv_stop = NativeMethods.uv_stop; _uv_ref = NativeMethods.uv_ref; _uv_unref = NativeMethods.uv_unref; + _uv_fileno = NativeMethods.uv_fileno; _uv_close = NativeMethods.uv_close; _uv_async_init = NativeMethods.uv_async_init; _uv_async_send = NativeMethods.uv_async_send; @@ -177,6 +179,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking _uv_unref(handle); } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + protected delegate int uv_fileno_func(UvHandle handle, ref IntPtr socket); + protected uv_fileno_func _uv_fileno; + public int uv_fileno(UvHandle handle, ref IntPtr socket) + { + handle.Validate(); + return Check(_uv_fileno(handle, ref socket)); + } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void uv_close_cb(IntPtr handle); protected Action _uv_close; @@ -221,6 +232,40 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking { handle.Validate(); Check(_uv_tcp_bind(handle, ref addr, flags)); + if (PlatformApis.IsWindows) + { + tcp_bind_windows_extras(handle); + } + } + + private unsafe void tcp_bind_windows_extras(UvTcpHandle handle) + { + const int SIO_LOOPBACK_FAST_PATH = -1744830448; // IOC_IN | IOC_WS2 | 16; + const int WSAEOPNOTSUPP = 10000 + 45; // (WSABASEERR+45) + const int SOCKET_ERROR = -1; + + var socket = IntPtr.Zero; + Check(_uv_fileno(handle, ref socket)); + + // Enable loopback fast-path for lower latency for localhost comms, like HttpPlatformHandler fronting + // http://blogs.technet.com/b/wincat/archive/2012/12/05/fast-tcp-loopback-performance-and-low-latency-with-windows-server-2012-tcp-loopback-fast-path.aspx + // https://github.com/libuv/libuv/issues/489 + var optionValue = 1; + uint dwBytes = 0u; + + var result = NativeMethods.WSAIoctl(socket, SIO_LOOPBACK_FAST_PATH, &optionValue, sizeof(int), null, 0, out dwBytes, IntPtr.Zero, IntPtr.Zero); + if (result == SOCKET_ERROR) + { + var errorId = NativeMethods.WSAGetLastError(); + if (errorId == WSAEOPNOTSUPP) + { + // This system is not >= Windows Server 2012, and the call is not supported. + } + else + { + Check(errorId); + } + } } protected Func _uv_tcp_open; @@ -501,6 +546,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] public static extern void uv_unref(UvHandle handle); + [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] + public static extern int uv_fileno(UvHandle handle, ref IntPtr socket); + [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] public static extern void uv_close(IntPtr handle, uv_close_cb close_cb); @@ -587,6 +635,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] unsafe public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg); + + [DllImport("WS2_32.dll", CallingConvention = CallingConvention.Winapi)] + unsafe public static extern int WSAIoctl( + IntPtr socket, + int dwIoControlCode, + int* lpvInBuffer, + uint cbInBuffer, + int* lpvOutBuffer, + int cbOutBuffer, + out uint lpcbBytesReturned, + IntPtr lpOverlapped, + IntPtr lpCompletionRoutine + ); + + [DllImport("WS2_32.dll", CallingConvention = CallingConvention.Winapi)] + public static extern int WSAGetLastError(); } private static class NativeDarwinMonoMethods @@ -609,6 +673,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] public static extern void uv_unref(UvHandle handle); + [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] + public static extern int uv_fileno(UvHandle handle, ref IntPtr socket); + [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] public static extern void uv_close(IntPtr handle, uv_close_cb close_cb); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs index 42315796d5..d75ec82902 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Filter; using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; +using Microsoft.AspNetCore.Server.Kestrel.Networking; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Xunit; @@ -118,6 +119,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Console.WriteLine("Started"); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.NoDelay = true; socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World")); socket.Shutdown(SocketShutdown.Send); @@ -475,6 +492,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests using (var server = new TestServer(App, testContext)) { var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.NoDelay = true; socket.Connect(IPAddress.Loopback, server.Port); await Task.Delay(200); socket.Dispose(); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs index 6c4d2e8ed0..16ebbd3421 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs @@ -235,6 +235,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests serverConnectionPipeAcceptedEvent.WaitOne(); var socket = new Socket(SocketType.Stream, ProtocolType.IP); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.NoDelay = true; socket.Connect(IPAddress.Loopback, 54321); socket.Send(new byte[] { 6, 7, 8, 9 }); socket.Shutdown(SocketShutdown.Send); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs index 642d4c7729..c8824c70c7 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs @@ -93,6 +93,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.NoDelay = true; #if DNX451 await Task.Factory.FromAsync( socket.BeginConnect, @@ -147,6 +163,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.NoDelay = true; #if DNX451 await Task.Factory.FromAsync( socket.BeginConnect, @@ -234,6 +266,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.NoDelay = true; #if DNX451 await Task.Factory.FromAsync( socket.BeginConnect, diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs index 5b6e857fd0..8e2ac64f69 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.Kestrel.Networking; using Xunit; namespace Microsoft.AspNetCore.Server.KestrelTests @@ -29,6 +30,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests public void Create(int port) { _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = (-1744830448); + var optionInValue = BitConverter.GetBytes(1); + try + { + _socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + _socket.NoDelay = true; _socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); _stream = new NetworkStream(_socket, false); From ffa8f3f09249af3aaa2045331aa0492281a0a4db Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 14 Feb 2016 08:11:17 +0000 Subject: [PATCH 2/2] Helper function for test socket creation --- .../RequestTests.cs | 3 +- .../TestConnection.cs | 35 ++++++++ .../EngineTests.cs | 38 +------- .../MultipleLoopTests.cs | 22 +---- .../NetworkingTests.cs | 89 +------------------ .../TestConnection.cs | 41 +++++---- 6 files changed, 68 insertions(+), 160 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/TestConnection.cs diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs index 3f9b0870dd..3f9cf20a75 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs @@ -158,9 +158,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { host.Start(); - using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + using (var socket = TestConnection.CreateConnectedLoopbackSocket(port)) { - socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); socket.Send(Encoding.ASCII.GetBytes("GET /%41%CC%8A/A/../B/%41%CC%8A HTTP/1.1\r\n\r\n")); socket.Shutdown(SocketShutdown.Send); diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/TestConnection.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/TestConnection.cs new file mode 100644 index 0000000000..db602658f0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/TestConnection.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net; +using System.Net.Sockets; +using Microsoft.AspNetCore.Server.Kestrel.Networking; + +namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests +{ + public class TestConnection + { + public static Socket CreateConnectedLoopbackSocket(int port) + { + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = -1744830448; + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); + return socket; + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs index d75ec82902..ea1cfe638c 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs @@ -118,24 +118,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var started = engine.CreateServer(address); Console.WriteLine("Started"); - var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - socket.NoDelay = true; - socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); + var socket = TestConnection.CreateConnectedLoopbackSocket(port); socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World")); socket.Shutdown(SocketShutdown.Send); var buffer = new byte[8192]; @@ -491,24 +474,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { using (var server = new TestServer(App, testContext)) { - var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - socket.NoDelay = true; - socket.Connect(IPAddress.Loopback, server.Port); + var socket = TestConnection.CreateConnectedLoopbackSocket(server.Port); await Task.Delay(200); socket.Dispose(); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs index 16ebbd3421..fedc72e6b0 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/MultipleLoopTests.cs @@ -124,6 +124,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { var pipeName = @"\\.\pipe\ServerPipeDispatchConnections" + Guid.NewGuid().ToString("n"); + var port = TestServer.GetNextPort(); var loop = new UvLoopHandle(_logger); loop.Init(_uv); @@ -153,7 +154,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var serverListenTcp = new UvTcpHandle(_logger); serverListenTcp.Init(loop); - var address = ServerAddress.FromUrl("http://localhost:54321/"); + var address = ServerAddress.FromUrl($"http://localhost:{port}/"); serverListenTcp.Bind(address); serverListenTcp.Listen(128, (_1, status, error, _2) => { @@ -234,24 +235,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { serverConnectionPipeAcceptedEvent.WaitOne(); - var socket = new Socket(SocketType.Stream, ProtocolType.IP); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - socket.NoDelay = true; - socket.Connect(IPAddress.Loopback, 54321); + var socket = TestConnection.CreateConnectedLoopbackSocket(port); socket.Send(new byte[] { 6, 7, 8, 9 }); socket.Shutdown(SocketShutdown.Send); var cb = socket.Receive(new byte[64]); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs index c8824c70c7..35faf85266 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/NetworkingTests.cs @@ -87,38 +87,9 @@ namespace Microsoft.AspNetCore.Server.KestrelTests tcp2.Dispose(); stream.Dispose(); }, null); - var t = Task.Run(async () => + var t = Task.Run(() => { - var socket = new Socket( - AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - socket.NoDelay = true; -#if DNX451 - await Task.Factory.FromAsync( - socket.BeginConnect, - socket.EndConnect, - new IPEndPoint(IPAddress.Loopback, port), - null, - TaskCreationOptions.None); -#else - await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, port)); -#endif + var socket = TestConnection.CreateConnectedLoopbackSocket(port); socket.Dispose(); }); loop.Run(); @@ -159,33 +130,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Console.WriteLine("Task.Run"); var t = Task.Run(async () => { - var socket = new Socket( - AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - socket.NoDelay = true; + var socket = TestConnection.CreateConnectedLoopbackSocket(port); #if DNX451 - await Task.Factory.FromAsync( - socket.BeginConnect, - socket.EndConnect, - new IPEndPoint(IPAddress.Loopback, port), - null, - TaskCreationOptions.None); await Task.Factory.FromAsync( socket.BeginSend, socket.EndSend, @@ -194,7 +140,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests null, TaskCreationOptions.None); #else - await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, port)); await socket.SendAsync(new[] { new ArraySegment(new byte[] { 1, 2, 3, 4, 5 }) }, SocketFlags.None); #endif @@ -262,33 +207,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Console.WriteLine("Task.Run"); var t = Task.Run(async () => { - var socket = new Socket( - AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - socket.NoDelay = true; + var socket = TestConnection.CreateConnectedLoopbackSocket(port); #if DNX451 - await Task.Factory.FromAsync( - socket.BeginConnect, - socket.EndConnect, - new IPEndPoint(IPAddress.Loopback, port), - null, - TaskCreationOptions.None); await Task.Factory.FromAsync( socket.BeginSend, socket.EndSend, @@ -297,7 +217,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests null, TaskCreationOptions.None); #else - await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, port)); await socket.SendAsync(new[] { new ArraySegment(new byte[] { 1, 2, 3, 4, 5 }) }, SocketFlags.None); #endif diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs index 8e2ac64f69..f7f3e36b4e 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestConnection.cs @@ -29,24 +29,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests public void Create(int port) { - _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - if (PlatformApis.IsWindows) - { - const int SIO_LOOPBACK_FAST_PATH = (-1744830448); - var optionInValue = BitConverter.GetBytes(1); - try - { - _socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); - } - catch - { - // If the operating system version on this machine did - // not support SIO_LOOPBACK_FAST_PATH (i.e. version - // prior to Windows 8 / Windows Server 2012), handle the exception - } - } - _socket.NoDelay = true; - _socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); + _socket = CreateConnectedLoopbackSocket(port); _stream = new NetworkStream(_socket, false); _reader = new StreamReader(_stream, Encoding.ASCII); @@ -142,5 +125,27 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var text = new string(ch, 0, count); Assert.Equal("", text); } + + public static Socket CreateConnectedLoopbackSocket(int port) + { + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (PlatformApis.IsWindows) + { + const int SIO_LOOPBACK_FAST_PATH = -1744830448; + var optionInValue = BitConverter.GetBytes(1); + try + { + socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); + } + catch + { + // If the operating system version on this machine did + // not support SIO_LOOPBACK_FAST_PATH (i.e. version + // prior to Windows 8 / Windows Server 2012), handle the exception + } + } + socket.Connect(new IPEndPoint(IPAddress.Loopback, port)); + return socket; + } } }