@@ -222,8 +222,11 @@ namespace MQTTnet.Client | |||||
try | try | ||||
{ | { | ||||
await WaitForTaskAsync(_packetReceiverTask, sender).ConfigureAwait(false); | |||||
await WaitForTaskAsync(_keepAliveMessageSenderTask, sender).ConfigureAwait(false); | |||||
if (!(exception is MqttCommunicationClosedGracefullyException)) | |||||
{ | |||||
await WaitForTaskAsync(_packetReceiverTask, sender).ConfigureAwait(false); | |||||
await WaitForTaskAsync(_keepAliveMessageSenderTask, sender).ConfigureAwait(false); | |||||
} | |||||
if (_adapter != null) | if (_adapter != null) | ||||
{ | { | ||||
@@ -87,8 +87,14 @@ namespace MQTTnet.Implementations | |||||
public void Dispose() | public void Dispose() | ||||
{ | { | ||||
TryDispose(_stream, () => _stream = null); | |||||
TryDispose(_socket, () => _socket = null); | |||||
Cleanup(ref _stream, (s) => s.Dispose()); | |||||
Cleanup(ref _socket, (s) => { | |||||
if (s.Connected) | |||||
{ | |||||
s.Shutdown(SocketShutdown.Both); | |||||
} | |||||
s.Dispose(); | |||||
}); | |||||
} | } | ||||
private bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) | private bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) | ||||
@@ -157,11 +163,16 @@ namespace MQTTnet.Implementations | |||||
} | } | ||||
} | } | ||||
private static void TryDispose(IDisposable disposable, Action afterDispose) | |||||
private static void Cleanup<T>(ref T item, Action<T> handler) where T : class | |||||
{ | { | ||||
var temp = item; | |||||
item = null; | |||||
try | try | ||||
{ | { | ||||
disposable?.Dispose(); | |||||
if (temp != null) | |||||
{ | |||||
handler(temp); | |||||
} | |||||
} | } | ||||
catch (ObjectDisposedException) | catch (ObjectDisposedException) | ||||
{ | { | ||||
@@ -169,10 +180,6 @@ namespace MQTTnet.Implementations | |||||
catch (NullReferenceException) | catch (NullReferenceException) | ||||
{ | { | ||||
} | } | ||||
finally | |||||
{ | |||||
afterDispose(); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -29,6 +29,7 @@ namespace MQTTnet.Server | |||||
private MqttApplicationMessage _willMessage; | private MqttApplicationMessage _willMessage; | ||||
private bool _wasCleanDisconnect; | private bool _wasCleanDisconnect; | ||||
private IMqttChannelAdapter _adapter; | private IMqttChannelAdapter _adapter; | ||||
private Task<bool> _run; | |||||
public MqttClientSession( | public MqttClientSession( | ||||
string clientId, | string clientId, | ||||
@@ -65,7 +66,13 @@ namespace MQTTnet.Server | |||||
status.LastNonKeepAlivePacketReceived = _keepAliveMonitor.LastNonKeepAlivePacketReceived; | status.LastNonKeepAlivePacketReceived = _keepAliveMonitor.LastNonKeepAlivePacketReceived; | ||||
} | } | ||||
public async Task<bool> RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) | |||||
public Task<bool> RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) | |||||
{ | |||||
_run = RunInternalAsync(connectPacket, adapter); | |||||
return _run; | |||||
} | |||||
private async Task<bool> RunInternalAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) | |||||
{ | { | ||||
if (connectPacket == null) throw new ArgumentNullException(nameof(connectPacket)); | if (connectPacket == null) throw new ArgumentNullException(nameof(connectPacket)); | ||||
if (adapter == null) throw new ArgumentNullException(nameof(adapter)); | if (adapter == null) throw new ArgumentNullException(nameof(adapter)); | ||||
@@ -122,6 +129,16 @@ namespace MQTTnet.Server | |||||
{ | { | ||||
_adapter.ReadingPacketStarted -= OnAdapterReadingPacketStarted; | _adapter.ReadingPacketStarted -= OnAdapterReadingPacketStarted; | ||||
_adapter.ReadingPacketCompleted -= OnAdapterReadingPacketCompleted; | _adapter.ReadingPacketCompleted -= OnAdapterReadingPacketCompleted; | ||||
try | |||||
{ | |||||
await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false); | |||||
_adapter.Dispose(); | |||||
} | |||||
catch (Exception exception) | |||||
{ | |||||
_logger.Error(exception, exception.Message); | |||||
} | |||||
} | } | ||||
_adapter = null; | _adapter = null; | ||||
@@ -153,6 +170,8 @@ namespace MQTTnet.Server | |||||
} | } | ||||
_willMessage = null; | _willMessage = null; | ||||
_run?.GetAwaiter().GetResult(); | |||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
@@ -249,16 +249,6 @@ namespace MQTTnet.Server | |||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
try | |||||
{ | |||||
await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false); | |||||
clientAdapter.Dispose(); | |||||
} | |||||
catch (Exception exception) | |||||
{ | |||||
_logger.Error(exception, exception.Message); | |||||
} | |||||
if (!_options.EnablePersistentSessions) | if (!_options.EnablePersistentSessions) | ||||
{ | { | ||||
DeleteSession(clientId); | DeleteSession(clientId); | ||||
@@ -106,14 +106,14 @@ namespace MQTTnet.Server | |||||
_cancellationTokenSource.Cancel(false); | _cancellationTokenSource.Cancel(false); | ||||
_clientSessionsManager.Stop(); | |||||
foreach (var adapter in _adapters) | foreach (var adapter in _adapters) | ||||
{ | { | ||||
adapter.ClientAccepted -= OnClientAccepted; | adapter.ClientAccepted -= OnClientAccepted; | ||||
await adapter.StopAsync().ConfigureAwait(false); | await adapter.StopAsync().ConfigureAwait(false); | ||||
} | } | ||||
_clientSessionsManager.Stop(); | |||||
_logger.Info("Stopped."); | _logger.Info("Stopped."); | ||||
Stopped?.Invoke(this, EventArgs.Empty); | Stopped?.Invoke(this, EventArgs.Empty); | ||||
} | } | ||||
@@ -253,9 +253,11 @@ namespace MQTTnet.Core.Tests | |||||
await c1.ConnectAsync(clientOptions); | await c1.ConnectAsync(clientOptions); | ||||
await Task.Delay(500); | |||||
await s.StopAsync(); | await s.StopAsync(); | ||||
await Task.Delay(500); | |||||
await Task.Delay(1000); | |||||
Assert.IsTrue(disconnectCalled); | Assert.IsTrue(disconnectCalled); | ||||
} | } | ||||