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
+1 -1
View File
@@ -6,7 +6,7 @@ namespace MQTTnet.Adapter
{
public interface IMqttServerAdapter : IDisposable
{
Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
Task StartAsync(IMqttServerOptions options);
Task StopAsync();
@@ -1,17 +0,0 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Adapter
{
public class MqttServerAdapterClientAcceptedEventArgs : EventArgs
{
public MqttServerAdapterClientAcceptedEventArgs(IMqttChannelAdapter channelAdapter)
{
ChannelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
}
public IMqttChannelAdapter ChannelAdapter { get; }
public Task SessionTask { get; set; }
}
}
@@ -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;
@@ -27,12 +27,12 @@ namespace MQTTnet.Server
private readonly IMqttNetChildLogger _logger;
private readonly IMqttServerOptions _serverOptions;
private Task<MqttClientDisconnectType> _packageReceiverTask;
private readonly IMqttChannelAdapter _channelAdapter;
private readonly IMqttDataConverter _dataConverter;
private readonly string _endpoint;
private readonly MqttConnectPacket _connectPacket;
private Task<MqttClientDisconnectType> _packageReceiverTask;
private DateTime _lastPacketReceivedTimestamp;
private DateTime _lastNonKeepAlivePacketReceivedTimestamp;
@@ -78,7 +78,7 @@ namespace MQTTnet.Server
StopInternal();
var task = _packageReceiverTask;
if (task != null && !task.IsCompleted)
if (task != null)
{
await task.ConfigureAwait(false);
}
@@ -103,13 +103,6 @@ namespace MQTTnet.Server
status.BytesReceived = _channelAdapter.BytesReceived;
}
//public void ClearPendingApplicationMessages()
//{
// Session.ApplicationMessagesQueue.Clear();
// //_applicationMessagesQueue.Clear();
//}
public void Dispose()
{
_cancellationToken.Dispose();
@@ -57,9 +57,9 @@ namespace MQTTnet.Server
}
}
public Task HandleConnectionAsync(IMqttChannelAdapter clientAdapter)
public Task HandleClientAsync(IMqttChannelAdapter clientAdapter)
{
return HandleConnectionAsync(clientAdapter, _cancellationToken);
return HandleClientAsync(clientAdapter, _cancellationToken);
}
public Task<IList<IMqttClientStatus>> GetClientStatusAsync()
@@ -221,7 +221,7 @@ namespace MQTTnet.Server
}
}
private async Task HandleConnectionAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
private async Task HandleClientAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
{
var disconnectType = MqttClientDisconnectType.NotClean;
var clientId = string.Empty;
@@ -376,10 +376,6 @@ namespace MQTTnet.Server
{
_logger.Error(exception, "Error while disconnecting client channel.");
}
finally
{
channelAdapter.Dispose();
}
}
}
}
+4 -4
View File
@@ -127,7 +127,7 @@ namespace MQTTnet.Server
foreach (var adapter in _adapters)
{
adapter.ClientAcceptedHandler = OnClientAccepted;
adapter.ClientHandler = OnHandleClient;
await adapter.StartAsync(Options).ConfigureAwait(false);
}
@@ -155,7 +155,7 @@ namespace MQTTnet.Server
foreach (var adapter in _adapters)
{
adapter.ClientAcceptedHandler = null;
adapter.ClientHandler = null;
await adapter.StopAsync().ConfigureAwait(false);
}
@@ -184,9 +184,9 @@ namespace MQTTnet.Server
return _retainedMessagesManager?.ClearMessagesAsync();
}
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs)
private Task OnHandleClient(IMqttChannelAdapter channelAdapter)
{
eventArgs.SessionTask = _clientSessionsManager.HandleConnectionAsync(eventArgs.ChannelAdapter);
return _clientSessionsManager.HandleClientAsync(channelAdapter);
}
}
}