From 9eaa99f51b690d04b32a0592812a32ba8afd8fe1 Mon Sep 17 00:00:00 2001 From: Matt Zion Date: Wed, 14 Oct 2020 16:01:46 -0500 Subject: [PATCH] Following feedback on https://github.com/dotnet/SqlClient/pull/579 (https://github.com/dotnet/SqlClient/pull/579#discussion_r500418080), implemented synchronization using SemaphoreSlim to avoid race conditions on completion of _currentTask.Wait. --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index 0f4a28c62e..edf8da9565 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -104,21 +104,33 @@ internal enum SNISMUXFlags internal class SslStreamProxy : SslStream { - private Task _currentTask; + private readonly SemaphoreSlim _semaphore; - public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) + public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) - { } + { + _semaphore = new SemaphoreSlim(1); /* granting one concurrent write on innerStream */ + } // Prevent the WriteAsync's collision - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - if (_currentTask != null && _currentTask.Status != TaskStatus.RanToCompletion) + await _semaphore.WaitAsync(cancellationToken); + try { - _currentTask.Wait(cancellationToken); + await base.WriteAsync(buffer, offset, count, cancellationToken); } - _currentTask = base.WriteAsync(buffer, offset, count, cancellationToken); - return _currentTask; + finally + { + _semaphore.Release(); + } + return; + } + + protected override void Dispose(bool disposing) + { + _semaphore?.Dispose(); + base.Dispose(disposing); } }