Prevent pipes from being closed prematurely on OS X and Linux

This change fixes the in-process marshalling of TCP handles on Mac and Linux
that is used to support having multiple threads accepting connections from
multiple loops.

On these two platforms, the ReadStart callback somtimes gets called with a
status and pipe_pending_count equal to zero. Now when the status is zero
just exit the callback without closing the pipe.

This change more closely follows the example at
https://nikhilm.github.io/uvbook/processes.html#sending-file-descriptors-over-pipes
This commit is contained in:
Stephen Halter 2015-08-20 20:13:10 -07:00
parent 8a6495364e
commit 2041e4d08b
5 changed files with 35 additions and 6 deletions

View File

@ -3,15 +3,13 @@
using System;
using System.Diagnostics;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class Connection : ConnectionContext, IConnectionControl
{
private const int EOF = -4095;
private const int ECONNRESET = -4077;
private static readonly Action<UvStreamHandle, int, Exception, object> _readCallback = ReadCallback;
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
@ -60,7 +58,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
SocketInput.Unpin(status);
var normalRead = error == null && status > 0;
var normalDone = status == 0 || status == ECONNRESET || status == EOF;
var normalDone = status == 0 || status == Constants.ECONNRESET || status == Constants.EOF;
var errorDone = !(normalDone || normalRead);
if (normalRead)

View File

@ -1,11 +1,12 @@
// 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 Microsoft.AspNet.Server.Kestrel.Networking;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
@ -60,13 +61,26 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
(_1, _2, _3) => buf,
(_1, status2, error2, state2) =>
{
if (status2 == 0)
if (status2 < 0)
{
if (status2 != Constants.EOF)
{
Exception ex;
Thread.Loop.Libuv.Check(status2, out ex);
// TODO: Replace Trace.WriteLine with real logging
Trace.WriteLine("DispatchPipe.ReadStart " + ex.Message);
}
DispatchPipe.Dispose();
Marshal.FreeHGlobal(ptr);
return;
}
if (DispatchPipe.PendingCount() == 0)
{
return;
}
var acceptSocket = CreateAcceptSocket();
try

View File

@ -7,6 +7,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
{
public const int ListenBacklog = 128;
public const int EOF = -4095;
public const int ECONNRESET = -4077;
/// <summary>
/// Prefix of host name used to specify Unix sockets in the configuration.
/// </summary>

View File

@ -252,6 +252,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
Check(_uv_pipe_connect(req, handle, name, cb));
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
unsafe protected delegate int uv_pipe_pending_count(UvPipeHandle handle);
protected uv_pipe_pending_count _uv_pipe_pending_count = default(uv_pipe_pending_count);
unsafe public int pipe_pending_count(UvPipeHandle handle)
{
handle.Validate();
return _uv_pipe_pending_count(handle);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void uv_alloc_cb(IntPtr server, int suggested_size, out uv_buf_t buf);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]

View File

@ -32,5 +32,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
{
_uv.pipe_bind(this, name);
}
public int PendingCount()
{
return _uv.pipe_pending_count(this);
}
}
}