parent
ebca8db7dc
commit
75adbc18a2
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Networking;
|
using Microsoft.AspNetCore.Server.Kestrel.Networking;
|
||||||
|
|
@ -11,7 +12,7 @@ using Microsoft.Extensions.Logging;
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A primary listener waits for incoming connections on a specified socket. Incoming
|
/// A primary listener waits for incoming connections on a specified socket. Incoming
|
||||||
/// connections may be passed to a secondary listener to handle.
|
/// connections may be passed to a secondary listener to handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ListenerPrimary : Listener
|
public abstract class ListenerPrimary : Listener
|
||||||
|
|
@ -19,8 +20,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
private readonly List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>();
|
private readonly List<UvPipeHandle> _dispatchPipes = new List<UvPipeHandle>();
|
||||||
private int _dispatchIndex;
|
private int _dispatchIndex;
|
||||||
private string _pipeName;
|
private string _pipeName;
|
||||||
|
private IntPtr _fileCompletionInfoPtr;
|
||||||
|
private bool _tryDetachFromIOCP = PlatformApis.IsWindows;
|
||||||
|
|
||||||
// this message is passed to write2 because it must be non-zero-length,
|
// this message is passed to write2 because it must be non-zero-length,
|
||||||
// but it has no other functional significance
|
// but it has no other functional significance
|
||||||
private readonly ArraySegment<ArraySegment<byte>> _dummyMessage = new ArraySegment<ArraySegment<byte>>(new[] { new ArraySegment<byte>(new byte[] { 1, 2, 3, 4 }) });
|
private readonly ArraySegment<ArraySegment<byte>> _dummyMessage = new ArraySegment<ArraySegment<byte>>(new[] { new ArraySegment<byte>(new byte[] { 1, 2, 3, 4 }) });
|
||||||
|
|
||||||
|
|
@ -37,6 +40,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
{
|
{
|
||||||
_pipeName = pipeName;
|
_pipeName = pipeName;
|
||||||
|
|
||||||
|
if (_fileCompletionInfoPtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var fileCompletionInfo = new FILE_COMPLETION_INFORMATION() { Key = IntPtr.Zero, Port = IntPtr.Zero };
|
||||||
|
_fileCompletionInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fileCompletionInfo));
|
||||||
|
Marshal.StructureToPtr(fileCompletionInfo, _fileCompletionInfoPtr, false);
|
||||||
|
}
|
||||||
|
|
||||||
await StartAsync(address, thread).ConfigureAwait(false);
|
await StartAsync(address, thread).ConfigureAwait(false);
|
||||||
|
|
||||||
await Thread.PostAsync(state => ((ListenerPrimary)state).PostCallback(),
|
await Thread.PostAsync(state => ((ListenerPrimary)state).PostCallback(),
|
||||||
|
|
@ -85,6 +95,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
DetachFromIOCP(socket);
|
||||||
var dispatchPipe = _dispatchPipes[index];
|
var dispatchPipe = _dispatchPipes[index];
|
||||||
var write = new UvWriteReq(Log);
|
var write = new UvWriteReq(Log);
|
||||||
write.Init(Thread.Loop);
|
write.Init(Thread.Loop);
|
||||||
|
|
@ -92,7 +103,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
dispatchPipe,
|
dispatchPipe,
|
||||||
_dummyMessage,
|
_dummyMessage,
|
||||||
socket,
|
socket,
|
||||||
(write2, status, error, state) =>
|
(write2, status, error, state) =>
|
||||||
{
|
{
|
||||||
write2.Dispose();
|
write2.Dispose();
|
||||||
((UvStreamHandle)state).Dispose();
|
((UvStreamHandle)state).Dispose();
|
||||||
|
|
@ -101,12 +112,59 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DetachFromIOCP(UvHandle handle)
|
||||||
|
{
|
||||||
|
if (!_tryDetachFromIOCP)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff728840(v=vs.85).aspx
|
||||||
|
const int FileReplaceCompletionInformation = 61;
|
||||||
|
// https://msdn.microsoft.com/en-us/library/cc704588.aspx
|
||||||
|
const uint STATUS_INVALID_INFO_CLASS = 0xC0000003;
|
||||||
|
|
||||||
|
var statusBlock = new IO_STATUS_BLOCK();
|
||||||
|
var socket = IntPtr.Zero;
|
||||||
|
Thread.Loop.Libuv.uv_fileno(handle, ref socket);
|
||||||
|
|
||||||
|
if (NtSetInformationFile(socket, out statusBlock, _fileCompletionInfoPtr,
|
||||||
|
(uint)Marshal.SizeOf<FILE_COMPLETION_INFORMATION>(), FileReplaceCompletionInformation) == STATUS_INVALID_INFO_CLASS)
|
||||||
|
{
|
||||||
|
// Replacing IOCP information is only supported on Windows 8.1 or newer
|
||||||
|
_tryDetachFromIOCP = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct IO_STATUS_BLOCK
|
||||||
|
{
|
||||||
|
uint status;
|
||||||
|
ulong information;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct FILE_COMPLETION_INFORMATION
|
||||||
|
{
|
||||||
|
public IntPtr Port;
|
||||||
|
public IntPtr Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("NtDll.dll")]
|
||||||
|
private static extern uint NtSetInformationFile(IntPtr FileHandle,
|
||||||
|
out IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, uint Length,
|
||||||
|
int FileInformationClass);
|
||||||
|
|
||||||
public override async Task DisposeAsync()
|
public override async Task DisposeAsync()
|
||||||
{
|
{
|
||||||
// Call base first so the ListenSocket gets closed and doesn't
|
// Call base first so the ListenSocket gets closed and doesn't
|
||||||
// try to dispatch connections to closed pipes.
|
// try to dispatch connections to closed pipes.
|
||||||
await base.DisposeAsync().ConfigureAwait(false);
|
await base.DisposeAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (_fileCompletionInfoPtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(_fileCompletionInfoPtr);
|
||||||
|
_fileCompletionInfoPtr = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
if (Thread.FatalError == null && ListenPipe != null)
|
if (Thread.FatalError == null && ListenPipe != null)
|
||||||
{
|
{
|
||||||
await Thread.PostAsync(state =>
|
await Thread.PostAsync(state =>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue