From 4fb42b60bb6acf589e4d5b8b86cc3c6617db0e05 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Fri, 22 May 2020 11:52:52 -0700 Subject: [PATCH 01/12] Fixed WriteAsync collision on SslStream at Managed SNI --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 43 +++++++++++++++++++ .../Data/SqlClient/SNI/SNINpHandle.cs | 4 +- .../Microsoft/Data/SqlClient/SNI/SNIPacket.cs | 30 +++++++------ .../Data/SqlClient/SNI/SNITcpHandle.cs | 23 +++++++--- 4 files changed, 80 insertions(+), 20 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 94ed2bece1..d4c5db2c26 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 @@ -3,8 +3,11 @@ // See the LICENSE file in the project root for more information. using System; +using System.IO; using System.Net.Security; using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; namespace Microsoft.Data.SqlClient.SNI { @@ -99,6 +102,46 @@ internal enum SNISMUXFlags SMUX_DATA = 8 // SMUX data packet } + internal class SslStreamAsync : SslStream + { + private Task _currentTask; + + #region constructors + public SslStreamAsync(Stream innerStream) : base(innerStream) + { + } + + public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen) : base(innerStream, leaveInnerStreamOpen) + { + } + + public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) + { + } + + public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback) + { + } + + public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback, encryptionPolicy) + { + } + #endregion + + /// + /// Prevent the InvalidOperationException + /// + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (_currentTask != null && _currentTask.Status != TaskStatus.RanToCompletion) + { + _currentTask.Wait(cancellationToken); + } + _currentTask = base.WriteAsync(buffer, offset, count, cancellationToken); + return _currentTask; + } + } + internal class SNICommon { // Each error number maps to SNI_ERROR_* in String.resx diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index d01b22631d..940e89ff44 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -93,7 +93,7 @@ public SNINpHandle(string serverName, string pipeName, long timerExpire, object } _sslOverTdsStream = new SslOverTdsStream(_pipeStream); - _sslStream = new SslStream(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); + _sslStream = new SslStreamAsync(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); _stream = _pipeStream; _status = TdsEnums.SNI_SUCCESS; @@ -310,9 +310,9 @@ public override uint Send(SNIPacket packet) public override uint SendAsync(SNIPacket packet, bool disposePacketAfterSendAsync, SNIAsyncCallback callback = null) { long scopeID = SqlClientEventSource.Log.SNIScopeEnterEvent(""); + SNIAsyncCallback cb = callback ?? _sendCallback; try { - SNIAsyncCallback cb = callback ?? _sendCallback; packet.WriteToStreamAsync(_stream, cb, SNIProviders.NP_PROV, disposePacketAfterSendAsync); return TdsEnums.SNI_SUCCESS_IO_PENDING; } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs index 60e3055998..7a559582da 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs @@ -251,21 +251,25 @@ public void WriteToStream(Stream stream) public async void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false) { uint status = TdsEnums.SNI_SUCCESS; - try - { - await stream.WriteAsync(_data, 0, _dataLength, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception e) - { - SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, SNICommon.InternalExceptionError, e); - status = TdsEnums.SNI_ERROR; - } - callback(this, status); - if (disposeAfterWriteAsync) + await stream.WriteAsync(_data, 0, _dataLength, CancellationToken.None).ContinueWith(t => { - Dispose(); - } + Exception e = t.Exception?.InnerException; + if (e != null) + { + SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, SNICommon.InternalExceptionError, e); + status = TdsEnums.SNI_ERROR; + Release(); + } + callback(this, status); + if (disposeAfterWriteAsync) + { + Dispose(); + } + }, + CancellationToken.None, + TaskContinuationOptions.DenyChildAttach, + TaskScheduler.Default); } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ac4e819d1d..fa81431a8e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Data; using System.IO; using System.Net; using System.Net.Security; @@ -164,7 +166,7 @@ public SNITCPHandle(string serverName, int port, long timerExpire, object callba _tcpStream = new NetworkStream(_socket, true); _sslOverTdsStream = new SslOverTdsStream(_tcpStream); - _sslStream = new SslStream(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); + _sslStream = new SslStreamAsync(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); } catch (SocketException se) { @@ -201,7 +203,7 @@ private static Socket Connect(string serverName, int port, TimeSpan timeout, boo Socket[] sockets = new Socket[2]; CancellationTokenSource cts = null; - + void Cancel() { for (int i = 0; i < sockets.Length; ++i) @@ -225,7 +227,7 @@ void Cancel() } Socket availableSocket = null; - try + try { for (int i = 0; i < sockets.Length; ++i) { @@ -577,12 +579,23 @@ public override void SetAsyncCallbacks(SNIAsyncCallback receiveCallback, SNIAsyn /// SNI error code public override uint SendAsync(SNIPacket packet, bool disposePacketAfterSendAsync, SNIAsyncCallback callback = null) { + long scopeID = SqlClientEventSource.Log.SNIScopeEnterEvent(""); + SNIPacket errorPacket; SNIAsyncCallback cb = callback ?? _sendCallback; - lock (this) + try { packet.WriteToStreamAsync(_stream, cb, SNIProviders.TCP_PROV, disposePacketAfterSendAsync); + return TdsEnums.SNI_SUCCESS_IO_PENDING; + } + catch (Exception e) when (e is ObjectDisposedException || e is InvalidOperationException || e is IOException) + { + errorPacket = packet; + return ReportErrorAndReleasePacket(errorPacket, e); + } + finally + { + SqlClientEventSource.Log.SNIScopeLeaveEvent(scopeID); } - return TdsEnums.SNI_SUCCESS_IO_PENDING; } /// From 717b94d3d558c259ece33838bdf4905a6b139d86 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Sun, 24 May 2020 15:59:42 -0700 Subject: [PATCH 02/12] Added test units --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 4 +- ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + .../SQL/SqlCommand/SqlCommandExecuteTest.cs | 151 ++++++++++++++++++ 3 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs 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 d4c5db2c26..fd29fb6869 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 @@ -128,9 +128,7 @@ public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCerti } #endregion - /// - /// Prevent the InvalidOperationException - /// + // Prevent the WriteAsync's collision public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (_currentTask != null && _currentTask.Status != TaskStatus.RanToCompletion) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 52c66b3d1b..934f2df36a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -62,6 +62,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs new file mode 100644 index 0000000000..a28095d8b2 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public static class SqlCommandExecuteTest + { + [Theory] + [MemberData(nameof(GetConnectionStrings))] + public static void ExecuteReaderAsyncTest(string connectionString) + { + int counter = 100; + while (counter-- > 0) + { + ExecuteReaderAsync(connectionString, CancellationToken.None).GetAwaiter().GetResult(); + } + } + + [Theory] + [MemberData(nameof(GetConnectionStrings))] + public static void ExecuteScalarAsyncTest(string connectionString) + { + int counter = 100; + while (counter-- > 0) + { + ExecuteScalarAsync(connectionString, CancellationToken.None).GetAwaiter().GetResult(); + } + } + + [Theory] + [MemberData(nameof(GetConnectionStrings))] + public static void ExecuteNonQueryAsyncTest(string connectionString) + { + int counter = 100; + while (counter-- > 0) + { + ExecuteNonQueryAsync(connectionString, CancellationToken.None).GetAwaiter().GetResult(); + } + } + + [Theory] + [MemberData(nameof(GetConnectionStrings))] + public static void ExecuteXmlReaderAsyncTest(string connectionString) + { + int counter = 100; + while (counter-- > 0) + { + ExecuteXmlReaderAsync(connectionString, CancellationToken.None).GetAwaiter().GetResult(); + } + } + + #region Execute Async + private static async Task ExecuteReaderAsync(string connectionString, CancellationToken token) + { + using (var connection = new SqlConnection(connectionString)) + { + using (var cmd = GetCommand(connection)) + { + var r = await cmd.ExecuteReaderAsync(token); + while (await r.ReadAsync(token)) + { + await r.GetFieldValueAsync(0); + await r.GetFieldValueAsync(1); + await r.GetFieldValueAsync(2); + } + } + } + } + + private static async Task ExecuteScalarAsync(string connectionString, CancellationToken token) + { + using (var connection = new SqlConnection(connectionString)) + { + using (var cmd = GetCommand(connection)) + { + await cmd.ExecuteScalarAsync(token); + } + } + } + + private static async Task ExecuteNonQueryAsync(string connectionString, CancellationToken token) + { + using (var connection = new SqlConnection(connectionString)) + { + using (var cmd = GetCommand(connection)) + { + await cmd.ExecuteNonQueryAsync(token); + } + } + } + + private static async Task ExecuteXmlReaderAsync(string connectionString, CancellationToken token) + { + using (var connection = new SqlConnection(connectionString)) + { + using (var cmd = GetCommand(connection)) + { + cmd.CommandText += " FOR XML AUTO, XMLDATA"; + var r = await cmd.ExecuteXmlReaderAsync(token); + } + } + } + + private static SqlCommand GetCommand(SqlConnection cnn) + { + string aRecord = "('2455cf1b-ebcf-418d-8cce-88e21e1683e3', 'something', 'updated'),"; + string query = "SELECT * FROM (VALUES" + + string.Concat(Enumerable.Repeat(aRecord, 200)).Substring(0, (aRecord.Length * 200) - 1) + + ") tbl_A ([Id], [Name], [State])"; + cnn.Open(); + using (var cmd = cnn.CreateCommand()) + { + cmd.CommandText = query; + return cmd; + } + } + #endregion + + public static IEnumerable GetConnectionStrings() + { + SqlConnectionStringBuilder builder; + foreach (var item in DataTestUtility.ConnectionStrings) + { + builder = new SqlConnectionStringBuilder(item) + { + TrustServerCertificate = true, + Encrypt = true, + MultipleActiveResultSets = false, + ConnectTimeout = 10, + ConnectRetryCount = 3, + ConnectRetryInterval = 10, + LoadBalanceTimeout = 60, + MaxPoolSize = 10, + MinPoolSize = 0 + }; + yield return new object[] { builder.ConnectionString }; + + builder.TrustServerCertificate = false; + builder.Encrypt = false; + yield return new object[] { builder.ConnectionString }; + } + } + } +} From ce6ece33d29a806dd6b1760302216c649765fb53 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Sun, 24 May 2020 17:26:15 -0700 Subject: [PATCH 03/12] Added Collections.Generic namespace to support debug --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs index 2860fa28d7..cf5f4db8c3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIPacket.cs @@ -6,6 +6,7 @@ using System; using System.Buffers; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Threading; From 35c2dc0cb9b142cf64f040f280dddc11c8f1b941 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Mon, 25 May 2020 08:54:30 -0700 Subject: [PATCH 04/12] Added license --- .../ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs | 6 +++++- .../tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs | 8 +++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs index 8e38bee7c0..96036e5aa9 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs @@ -1,4 +1,8 @@ -using System.Data; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Data; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs index e6810aa025..d33ec4b282 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs @@ -1,8 +1,10 @@ -using System; -using System.Collections.Generic; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Data.SqlTypes; using System.Reflection; -using System.Text; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests From 1f00f84379315b40baf3739b66cc60da5a71d47d Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Thu, 9 Jul 2020 13:18:00 -0700 Subject: [PATCH 05/12] Rename --- .../src/Microsoft/Data/SqlClient/SNI/SNICommon.cs | 12 ++++++------ .../src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 2 +- .../src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs | 2 +- 3 files changed, 8 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 fd29fb6869..74140953d8 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 @@ -102,28 +102,28 @@ internal enum SNISMUXFlags SMUX_DATA = 8 // SMUX data packet } - internal class SslStreamAsync : SslStream + internal class SslStreamProxy : SslStream { private Task _currentTask; #region constructors - public SslStreamAsync(Stream innerStream) : base(innerStream) + public SslStreamProxy(Stream innerStream) : base(innerStream) { } - public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen) : base(innerStream, leaveInnerStreamOpen) + public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen) : base(innerStream, leaveInnerStreamOpen) { } - public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) + public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) { } - public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback) + public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback) { } - public SslStreamAsync(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback, encryptionPolicy) + public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback, encryptionPolicy) { } #endregion diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 26f2dae2cb..92db3380a5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -93,7 +93,7 @@ public SNINpHandle(string serverName, string pipeName, long timerExpire, object } _sslOverTdsStream = new SslOverTdsStream(_pipeStream); - _sslStream = new SslStreamAsync(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); + _sslStream = new SslStreamProxy(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); _stream = _pipeStream; _status = TdsEnums.SNI_SUCCESS; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index 57339c68dc..e6974e24d2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -164,7 +164,7 @@ public SNITCPHandle(string serverName, int port, long timerExpire, object callba _tcpStream = new NetworkStream(_socket, true); _sslOverTdsStream = new SslOverTdsStream(_tcpStream); - _sslStream = new SslStreamAsync(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); + _sslStream = new SslStreamProxy(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); } catch (SocketException se) { From 844521266ec22e8238c88d9872eadc919992f5ed Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:58:25 -0700 Subject: [PATCH 06/12] Update src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs Co-authored-by: Cheena Malhotra --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 24 +++---------------- 1 file changed, 3 insertions(+), 21 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 7a61fed4d7..0f4a28c62e 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 @@ -106,27 +106,9 @@ internal class SslStreamProxy : SslStream { private Task _currentTask; - #region constructors - public SslStreamProxy(Stream innerStream) : base(innerStream) - { - } - - public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen) : base(innerStream, leaveInnerStreamOpen) - { - } - - public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) - { - } - - public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback) - { - } - - public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback, encryptionPolicy) - { - } - #endregion + public SslStreamProxy(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) + : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) + { } // Prevent the WriteAsync's collision public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) From d819928b4cb5d819cd6a157d7ce42d1fda060a4b Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:58:43 -0700 Subject: [PATCH 07/12] Update src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs Co-authored-by: Cheena Malhotra --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 7f3873ec1a..023cee96b9 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -93,7 +93,7 @@ public SNINpHandle(string serverName, string pipeName, long timerExpire, object } _sslOverTdsStream = new SslOverTdsStream(_pipeStream); - _sslStream = new SslStreamProxy(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); + _sslStream = new SslStreamProxy(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate)); _stream = _pipeStream; _status = TdsEnums.SNI_SUCCESS; From 26f34120a012977c3165e34ef854291781e5fd20 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:58:58 -0700 Subject: [PATCH 08/12] Update src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs Co-authored-by: Cheena Malhotra --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ec26f7a8ab..417e8fb54d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -226,7 +226,7 @@ public SNITCPHandle(string serverName, int port, long timerExpire, object callba _tcpStream = new NetworkStream(_socket, true); _sslOverTdsStream = new SslOverTdsStream(_tcpStream); - _sslStream = new SslStreamProxy(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); + _sslStream = new SslStreamProxy(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate)); } catch (SocketException se) { From a9248318050bd1b4dc4660e43b6e3020e88e7513 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:59:15 -0700 Subject: [PATCH 09/12] Update src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs Co-authored-by: Cheena Malhotra --- .../ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs index a28095d8b2..0904214d4c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs @@ -77,11 +77,9 @@ private static async Task ExecuteReaderAsync(string connectionString, Cancellati private static async Task ExecuteScalarAsync(string connectionString, CancellationToken token) { using (var connection = new SqlConnection(connectionString)) + using (var cmd = GetCommand(connection)) { - using (var cmd = GetCommand(connection)) - { - await cmd.ExecuteScalarAsync(token); - } + await cmd.ExecuteScalarAsync(token); } } From bc9af2b173d5f37fd99c6349cd2a6308e7026d45 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:59:25 -0700 Subject: [PATCH 10/12] Update src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs Co-authored-by: Cheena Malhotra --- .../SQL/SqlCommand/SqlCommandExecuteTest.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs index 0904214d4c..fc0bb76cba 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs @@ -60,16 +60,14 @@ public static void ExecuteXmlReaderAsyncTest(string connectionString) private static async Task ExecuteReaderAsync(string connectionString, CancellationToken token) { using (var connection = new SqlConnection(connectionString)) + using (var cmd = GetCommand(connection)) + using (var r = await cmd.ExecuteReaderAsync(token)) { - using (var cmd = GetCommand(connection)) + while (await r.ReadAsync(token)) { - var r = await cmd.ExecuteReaderAsync(token); - while (await r.ReadAsync(token)) - { - await r.GetFieldValueAsync(0); - await r.GetFieldValueAsync(1); - await r.GetFieldValueAsync(2); - } + await r.GetFieldValueAsync(0); + await r.GetFieldValueAsync(1); + await r.GetFieldValueAsync(2); } } } From 81a00261ece4edef1d01f842a6ab17240a267abb Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 23 Sep 2020 16:59:36 -0700 Subject: [PATCH 11/12] Update src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs Co-authored-by: Cheena Malhotra --- .../SQL/SqlCommand/SqlCommandExecuteTest.cs | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs index fc0bb76cba..4af9fdd1e8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandExecuteTest.cs @@ -84,23 +84,19 @@ private static async Task ExecuteScalarAsync(string connectionString, Cancellati private static async Task ExecuteNonQueryAsync(string connectionString, CancellationToken token) { using (var connection = new SqlConnection(connectionString)) + using (var cmd = GetCommand(connection)) { - using (var cmd = GetCommand(connection)) - { - await cmd.ExecuteNonQueryAsync(token); - } + await cmd.ExecuteNonQueryAsync(token); } } private static async Task ExecuteXmlReaderAsync(string connectionString, CancellationToken token) { using (var connection = new SqlConnection(connectionString)) + using (var cmd = GetCommand(connection)) { - using (var cmd = GetCommand(connection)) - { - cmd.CommandText += " FOR XML AUTO, XMLDATA"; - var r = await cmd.ExecuteXmlReaderAsync(token); - } + cmd.CommandText += " FOR XML AUTO, XMLDATA"; + var r = await cmd.ExecuteXmlReaderAsync(token); } } @@ -111,11 +107,9 @@ private static SqlCommand GetCommand(SqlConnection cnn) + string.Concat(Enumerable.Repeat(aRecord, 200)).Substring(0, (aRecord.Length * 200) - 1) + ") tbl_A ([Id], [Name], [State])"; cnn.Open(); - using (var cmd = cnn.CreateCommand()) - { - cmd.CommandText = query; - return cmd; - } + var cmd = cnn.CreateCommand(); + cmd.CommandText = query; + return cmd; } #endregion From 64a50c58ba3ffb2f99064fa214061b96723f9aa2 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 29 Sep 2020 17:11:05 -0700 Subject: [PATCH 12/12] catch exceptions --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 5 +++++ .../netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 023cee96b9..b039d0ce4e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -331,6 +331,11 @@ public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = nul packet.WriteToStreamAsync(_stream, cb, SNIProviders.NP_PROV); return TdsEnums.SNI_SUCCESS_IO_PENDING; } + catch (Exception e) when (e is ObjectDisposedException || e is InvalidOperationException || e is IOException) + { + SNIPacket errorPacket = packet; + return ReportErrorAndReleasePacket(errorPacket, e); + } finally { SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index 417e8fb54d..f9c7c595b3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -707,7 +707,6 @@ public override void SetAsyncCallbacks(SNIAsyncCallback receiveCallback, SNIAsyn public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null) { long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent(""); - SNIPacket errorPacket; SNIAsyncCallback cb = callback ?? _sendCallback; try { @@ -716,7 +715,7 @@ public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = nul } catch (Exception e) when (e is ObjectDisposedException || e is InvalidOperationException || e is IOException) { - errorPacket = packet; + SNIPacket errorPacket = packet; return ReportErrorAndReleasePacket(errorPacket, e); } finally