Prevent double-close race condition in ListenHandleTests.CanListenToOpenTcpSocketHandle() (#2666)
This commit is contained in:
parent
13663e1e15
commit
35d9590f3c
|
|
@ -14,26 +14,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
[OSSkipCondition(OperatingSystems.Windows, SkipReason = "Listening to open TCP socket and/or pipe handles is not supported on Windows.")]
|
[OSSkipCondition(OperatingSystems.Windows, SkipReason = "Listening to open TCP socket and/or pipe handles is not supported on Windows.")]
|
||||||
public class ListenHandleTests : LoggedTest
|
public class ListenHandleTests : LoggedTest
|
||||||
{
|
{
|
||||||
|
// The Socket.Handle will be passed into libuv, which calls close() on the file descriptor when TestServer is disposed. If
|
||||||
|
// the managed Socket is also disposed or finalized, it will try to call close() again on the file descriptor, which may lead to
|
||||||
|
// race condition bugs (test hangs) if the file descriptor has been re-used for another resource. In .NET Core, objects
|
||||||
|
// assigned to static fields should never be disposed or finalized (even at process shutdown).
|
||||||
|
// https://github.com/aspnet/KestrelHttpServer/issues/2597
|
||||||
|
private static readonly Socket _canListenToOpenTcpSocketHandleSocket =
|
||||||
|
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task CanListenToOpenTcpSocketHandle()
|
public async Task CanListenToOpenTcpSocketHandle()
|
||||||
{
|
{
|
||||||
using (var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
_canListenToOpenTcpSocketHandleSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||||
|
|
||||||
|
using (var server = new TestServer(_ => Task.CompletedTask, new TestServiceContext(LoggerFactory),
|
||||||
|
new ListenOptions((ulong)_canListenToOpenTcpSocketHandleSocket.Handle)))
|
||||||
{
|
{
|
||||||
listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
using (var connection = new TestConnection(((IPEndPoint)_canListenToOpenTcpSocketHandleSocket.LocalEndPoint).Port))
|
||||||
|
|
||||||
using (var server = new TestServer(_ => Task.CompletedTask, new TestServiceContext(LoggerFactory), new ListenOptions((ulong)listenSocket.Handle)))
|
|
||||||
{
|
{
|
||||||
using (var connection = new TestConnection(((IPEndPoint)listenSocket.LocalEndPoint).Port))
|
await connection.SendEmptyGet();
|
||||||
{
|
|
||||||
await connection.SendEmptyGet();
|
|
||||||
|
|
||||||
await connection.Receive(
|
await connection.Receive(
|
||||||
"HTTP/1.1 200 OK",
|
"HTTP/1.1 200 OK",
|
||||||
$"Date: {server.Context.DateHeaderValue}",
|
$"Date: {server.Context.DateHeaderValue}",
|
||||||
"Content-Length: 0",
|
"Content-Length: 0",
|
||||||
"",
|
"",
|
||||||
"");
|
"");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue