Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/Microsoft.AspNet.Server.Kestrel/Networking/Libuv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public Libuv()
_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;
Expand Down Expand Up @@ -68,6 +69,7 @@ public Libuv()
_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;
Expand Down Expand Up @@ -172,6 +174,15 @@ public void unref(UvHandle handle)
_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<IntPtr, uv_close_cb> _uv_close;
Expand Down Expand Up @@ -216,6 +227,54 @@ public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags)
{
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 SOL_SOCKET = 0xffff; // options for socket level
const int SO_SNDBUF = 0x1001; // send buffer size
const int WSAEOPNOTSUPP = 10000 + 45; // (WSABASEERR+45)
const int SOCKET_ERROR = -1;

IntPtr 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
int True = -1;
uint dwBytes = 0;

var result = NativeMethods.WSAIoctl(socket, SIO_LOOPBACK_FAST_PATH, &True, 4, 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);
}
}

// Only use application buffers for send buffer don't buffer at winsock level
// i.e. don't copy the data twice as overlapped I/O and multiple sends are used
// https://github.com/libuv/libuv/issues/74
int zero = 0;
result = NativeMethods.setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char*)&zero, sizeof(int));
if (result == SOCKET_ERROR)
{
var errorId = NativeMethods.WSAGetLastError();
Check(errorId);
}
}

protected Func<UvTcpHandle, IntPtr, int> _uv_tcp_open;
Expand Down Expand Up @@ -496,6 +555,9 @@ private static class NativeMethods
[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);

Expand Down Expand Up @@ -582,6 +644,25 @@ private static class NativeMethods

[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)]
public unsafe static extern int setsockopt(IntPtr s, int level, int optname, char* optval, int optlen);

[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
Expand All @@ -604,6 +685,9 @@ private static class NativeDarwinMonoMethods
[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);

Expand Down