Improve connection disposal.

This commit is contained in:
Christian Kratky
2019-04-22 10:50:47 +02:00
parent 5c903e6fbf
commit 6399172582
20 changed files with 179 additions and 165 deletions
@@ -23,7 +23,7 @@ namespace MQTTnet.Implementations
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
}
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
public async Task StartAsync(IMqttServerOptions options)
{
@@ -39,7 +39,7 @@ namespace MQTTnet.Implementations
_listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay;
_listener.Control.KeepAlive = true;
_listener.Control.QualityOfService = SocketQualityOfService.LowLatency;
_listener.ConnectionReceived += AcceptDefaultEndpointConnectionsAsync;
_listener.ConnectionReceived += OnConnectionReceivedAsync;
await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket);
}
@@ -54,30 +54,51 @@ namespace MQTTnet.Implementations
{
if (_listener != null)
{
_listener.ConnectionReceived -= AcceptDefaultEndpointConnectionsAsync;
_listener.ConnectionReceived -= OnConnectionReceivedAsync;
}
_listener?.Dispose();
_listener = null;
return Task.FromResult(0);
}
public void Dispose()
{
StopAsync().GetAwaiter().GetResult();
_listener?.Dispose();
_listener = null;
}
private void AcceptDefaultEndpointConnectionsAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
private async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
try
{
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger);
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
var clientHandler = ClientHandler;
if (clientHandler != null)
{
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger))
{
await clientHandler(clientAdapter).ConfigureAwait(false);
}
}
}
catch (Exception exception)
{
_logger.Error(exception, "Error while accepting connection at default endpoint.");
if (exception is ObjectDisposedException)
{
// It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
return;
}
_logger.Error(exception, "Error while handling client connection.");
}
finally
{
try
{
args.Socket.Dispose();
}
catch (Exception exception)
{
_logger.Error(exception, "Error while cleaning up client connection");
}
}
}
}
@@ -26,7 +26,7 @@ namespace MQTTnet.Implementations
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
}
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
public Task StartAsync(IMqttServerOptions options)
{
@@ -89,7 +89,7 @@ namespace MQTTnet.Implementations
_cancellationTokenSource.Token,
_logger)
{
ClientAcceptedHandler = OnClientAccepted
ClientHandler = OnClientAcceptedAsync
};
listenerV4.Start();
@@ -105,7 +105,7 @@ namespace MQTTnet.Implementations
_cancellationTokenSource.Token,
_logger)
{
ClientAcceptedHandler = OnClientAccepted
ClientHandler = OnClientAcceptedAsync
};
listenerV6.Start();
@@ -113,9 +113,15 @@ namespace MQTTnet.Implementations
}
}
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs)
private Task OnClientAcceptedAsync(IMqttChannelAdapter channelAdapter)
{
ClientAcceptedHandler?.Invoke(eventArgs);
var clientHandler = ClientHandler;
if (clientHandler == null)
{
return Task.FromResult(0);
}
return clientHandler(channelAdapter);
}
}
}
@@ -43,7 +43,7 @@ namespace MQTTnet.Implementations
}
}
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
public void Start()
{
@@ -97,11 +97,14 @@ namespace MQTTnet.Implementations
private async Task TryHandleClientConnectionAsync(Socket clientSocket)
{
Stream stream = null;
EndPoint remoteEndPoint = null;
try
{
remoteEndPoint = clientSocket.RemoteEndPoint;
_logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.",
clientSocket.RemoteEndPoint,
remoteEndPoint,
_socket.LocalEndPoint,
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
@@ -116,8 +119,14 @@ namespace MQTTnet.Implementations
stream = sslStream;
}
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream), new MqttPacketFormatterAdapter(), _logger);
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
var clientHandler = ClientHandler;
if (clientHandler != null)
{
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream), new MqttPacketFormatterAdapter(), _logger))
{
await clientHandler(clientAdapter).ConfigureAwait(false);
}
}
}
catch (Exception exception)
{
@@ -127,20 +136,29 @@ namespace MQTTnet.Implementations
return;
}
if (exception is SocketException socketException && socketException.SocketErrorCode == SocketError.OperationAborted)
if (exception is SocketException socketException &&
socketException.SocketErrorCode == SocketError.OperationAborted)
{
return;
}
_logger.Error(exception, "Error while handling client connection.");
}
finally
{
try
{
// Dispose already allocated resources.
stream?.Dispose();
clientSocket?.Dispose();
_logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.",
remoteEndPoint,
_socket.LocalEndPoint,
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
}
catch (Exception disposeException)
{
_logger.Error(disposeException, "Error while cleanup of broken connection.");
_logger.Error(disposeException, "Error while cleaning up client connection");
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using System.Net;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;