Fixed race in sockets transport (#2279)
- Based on the changes you made earlier (f4d27e6), we trigger OnConnectionClosed before the socket is disposed in the SocketTransport. This moves the call to Output.Complete to happen after and thus fixes the race.
This commit is contained in:
parent
bbe8851f32
commit
50b396cec6
|
|
@ -57,13 +57,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
|
|
||||||
public async Task StartAsync(IConnectionHandler connectionHandler)
|
public async Task StartAsync(IConnectionHandler connectionHandler)
|
||||||
{
|
{
|
||||||
|
Exception sendError = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connectionHandler.OnConnection(this);
|
connectionHandler.OnConnection(this);
|
||||||
|
|
||||||
// Spawn send and receive logic
|
// Spawn send and receive logic
|
||||||
Task receiveTask = DoReceive();
|
Task receiveTask = DoReceive();
|
||||||
Task sendTask = DoSend();
|
Task<Exception> sendTask = DoSend();
|
||||||
|
|
||||||
// If the sending task completes then close the receive
|
// If the sending task completes then close the receive
|
||||||
// We don't need to do this in the other direction because the kestrel
|
// We don't need to do this in the other direction because the kestrel
|
||||||
|
|
@ -76,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
|
|
||||||
// Now wait for both to complete
|
// Now wait for both to complete
|
||||||
await receiveTask;
|
await receiveTask;
|
||||||
await sendTask;
|
sendError = await sendTask;
|
||||||
|
|
||||||
// Dispose the socket(should noop if already called)
|
// Dispose the socket(should noop if already called)
|
||||||
_socket.Dispose();
|
_socket.Dispose();
|
||||||
|
|
@ -85,6 +86,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
{
|
{
|
||||||
_trace.LogError(0, ex, $"Unexpected exception in {nameof(SocketConnection)}.{nameof(StartAsync)}.");
|
_trace.LogError(0, ex, $"Unexpected exception in {nameof(SocketConnection)}.{nameof(StartAsync)}.");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Complete the output after disposing the socket
|
||||||
|
Output.Complete(sendError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DoReceive()
|
private async Task DoReceive()
|
||||||
|
|
@ -181,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DoSend()
|
private async Task<Exception> DoSend()
|
||||||
{
|
{
|
||||||
Exception error = null;
|
Exception error = null;
|
||||||
|
|
||||||
|
|
@ -233,8 +239,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Output.Complete(error);
|
|
||||||
|
|
||||||
// Make sure to close the connection only after the _aborted flag is set.
|
// Make sure to close the connection only after the _aborted flag is set.
|
||||||
// Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when
|
// Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when
|
||||||
// a BadHttpRequestException is thrown instead of a TaskCanceledException.
|
// a BadHttpRequestException is thrown instead of a TaskCanceledException.
|
||||||
|
|
@ -242,6 +246,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
_trace.ConnectionWriteFin(ConnectionId);
|
_trace.ConnectionWriteFin(ConnectionId);
|
||||||
_socket.Shutdown(SocketShutdown.Both);
|
_socket.Shutdown(SocketShutdown.Both);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue