The following is unsynchronized, and it contains a time-of-check time-of-use bug with ConnectionState. There are 3-4 different independent callers of Disconnect() and this could cause a number of unexpected results. Add a lock or semaphore to make sure the whole method is synchronized.
public void Disconnect(string message = null, Exception exception = null)
{
if (State != ConnectionState.Disconnected && State != ConnectionState.Disconnecting)
{
message ??= exception?.Message;
ChangeState(ConnectionState.Disconnecting, message);
InactivityTimer?.Stop();
WatchdogTimer.Stop();
Stream?.Close();
TcpClient?.Close();
ChangeState(ConnectionState.Disconnected, message, exception);
}
}
The associated ChangeState method is well synchronized, but fails to account for the fact that DisconnectTaskCompletionSource will throw if SetException or SetResult are called after the completion source has been completed already. Change these to TrySetException and TrySetResult
protected void ChangeState(ConnectionState state, string message, Exception exception = null)
{
...
else if (State == ConnectionState.Disconnected)
{
...
if (exception != null)
{
DisconnectTaskCompletionSource.SetException(exception);
}
else
{
DisconnectTaskCompletionSource.SetResult(message);
}
}
}
The following is unsynchronized, and it contains a time-of-check time-of-use bug with
ConnectionState. There are 3-4 different independent callers ofDisconnect()and this could cause a number of unexpected results. Add a lock or semaphore to make sure the whole method is synchronized.The associated
ChangeStatemethod is well synchronized, but fails to account for the fact thatDisconnectTaskCompletionSourcewill throw ifSetExceptionorSetResultare called after the completion source has been completed already. Change these toTrySetExceptionandTrySetResult