diff --git a/iothub/device/src/Transport/RetryDelegatingHandler.cs b/iothub/device/src/Transport/RetryDelegatingHandler.cs index 62eefaabc3..be8d84a5ef 100644 --- a/iothub/device/src/Transport/RetryDelegatingHandler.cs +++ b/iothub/device/src/Transport/RetryDelegatingHandler.cs @@ -13,6 +13,12 @@ namespace Microsoft.Azure.Devices.Client.Transport { + internal enum ClientTransportStatus + { + Closed = 0, + Open = 1, + } + internal class RetryDelegatingHandler : DefaultDelegatingHandler { // RetryCount is used for testing purpose and is equal to MaxValue in prod. @@ -37,7 +43,7 @@ internal class RetryDelegatingHandler : DefaultDelegatingHandler private bool _eventsEnabled; private bool _deviceReceiveMessageEnabled; private bool _isDisposing; - private long _isOpened; // store the opened status in an int which can be accessed via Interlocked class. opened = 1, closed = 0. + private long _clientTransportState; // references the current client transport status as the int value of ClientTransportStatus private Task _transportClosedTask; @@ -763,6 +769,7 @@ public override async Task CloseAsync(CancellationToken cancellationToken) } finally { + SetClientTransportStatus(ClientTransportStatus.Closed); Dispose(true); if (Logging.IsEnabled) @@ -785,7 +792,7 @@ private async Task EnsureOpenedAsync(bool withRetry, CancellationToken cancellat throw new ObjectDisposedException("IoT client", ClientDisposedMessage); } - if (Interlocked.Read(ref _isOpened) == 1) + if (GetClientTransportStatus() == ClientTransportStatus.Open) { return; } @@ -793,7 +800,7 @@ private async Task EnsureOpenedAsync(bool withRetry, CancellationToken cancellat await _clientOpenSemaphore.WaitAsync(operationCts.Token).ConfigureAwait(false); try { - if (Interlocked.Read(ref _isOpened) == 0) + if (GetClientTransportStatus() == ClientTransportStatus.Closed) { Logging.Info(this, "Opening connection", nameof(EnsureOpenedAsync)); @@ -811,7 +818,7 @@ private async Task EnsureOpenedAsync(bool withRetry, CancellationToken cancellat if (!_disposed) { - _ = Interlocked.Exchange(ref _isOpened, 1); // set the state to "opened" + SetClientTransportStatus(ClientTransportStatus.Open); _openCalled = true; // Send the request for transport close notification. @@ -853,7 +860,7 @@ private async Task EnsureOpenedAsync(bool withRetry, TimeoutHelper timeoutHelper throw new ObjectDisposedException("IoT client", ClientDisposedMessage); } - if (Interlocked.Read(ref _isOpened) == 1) + if (GetClientTransportStatus() == ClientTransportStatus.Open) { return; } @@ -862,7 +869,7 @@ private async Task EnsureOpenedAsync(bool withRetry, TimeoutHelper timeoutHelper try { - if (Interlocked.Read(ref _isOpened) == 0) + if (GetClientTransportStatus() == ClientTransportStatus.Closed) { Logging.Info(this, "Opening connection", nameof(EnsureOpenedAsync)); @@ -880,7 +887,7 @@ private async Task EnsureOpenedAsync(bool withRetry, TimeoutHelper timeoutHelper if (!_disposed) { - _ = Interlocked.Exchange(ref _isOpened, 1); // set the state to "opened" + SetClientTransportStatus(ClientTransportStatus.Open); _openCalled = true; // Send the request for transport close notification. @@ -1042,7 +1049,7 @@ private async Task HandleDisconnectAsync() Logging.Info(this, "Transport disconnected: unexpected.", nameof(HandleDisconnectAsync)); await _clientOpenSemaphore.WaitAsync().ConfigureAwait(false); - _ = Interlocked.Exchange(ref _isOpened, 0); // set the state to "closed" + SetClientTransportStatus(ClientTransportStatus.Closed); try { @@ -1111,7 +1118,7 @@ await _internalRetryPolicy.ExecuteAsync(async () => // Send the request for transport close notification. _transportClosedTask = HandleDisconnectAsync(); - _ = Interlocked.Exchange(ref _isOpened, 1); // set the state to "opened" + SetClientTransportStatus(ClientTransportStatus.Open); _onConnectionStatusChanged(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok); Logging.Info(this, "Subscriptions recovered.", nameof(HandleDisconnectAsync)); @@ -1175,6 +1182,16 @@ private void HandleConnectionStatusExceptions(Exception exception, bool connectF Logging.Info(this, $"Connection status change: status={status}, reason={reason}", nameof(HandleConnectionStatusExceptions)); } + private ClientTransportStatus GetClientTransportStatus() + { + return (ClientTransportStatus)Interlocked.Read(ref _clientTransportState); + } + + private void SetClientTransportStatus(ClientTransportStatus clientTransportStatus) + { + _ = Interlocked.Exchange(ref _clientTransportState, (int)clientTransportStatus); + } + protected override void Dispose(bool disposing) { try @@ -1187,8 +1204,10 @@ protected override void Dispose(bool disposing) if (!_disposed) { _isDisposing = true; + SetClientTransportStatus(ClientTransportStatus.Closed); base.Dispose(disposing); + if (disposing) { var disposables = new List