diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 350fa8c9bf..5d19cc3a23 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -659,7 +659,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index bb9008f017..80d58289da 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -26,43 +26,10 @@ namespace Microsoft.Data.SqlClient { - - internal struct SNIErrorDetails - { - public string errorMessage; - public uint nativeError; - public uint sniErrorNumber; - public int provider; - public uint lineNumber; - public string function; - public Exception exception; - } - // The TdsParser Object controls reading/writing to the netlib, parsing the tds, // and surfacing objects to the user. internal sealed partial class TdsParser { - internal struct ReliabilitySection - { - /// - /// This is a no-op in netcore version. Only needed for merging with netfx codebase. - /// - [Conditional("NETFRAMEWORK")] - internal static void Assert(string message) - { - } - - [Conditional("NETFRAMEWORK")] - internal void Start() - { - } - - [Conditional("NETFRAMEWORK")] - internal void Stop() - { - } - } - private static int _objectTypeCount; // EventSource counter private readonly SqlClientLogger _logger = new SqlClientLogger(); @@ -1959,8 +1926,6 @@ internal void PrepareResetConnection(bool preserveTransaction) _fPreserveTransaction = preserveTransaction; } - - internal bool Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) { bool syncOverAsync = stateObj._syncOverAsync; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs similarity index 54% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.NetCoreApp.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs index 95dd0d9731..f6e639c5f9 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs @@ -10,6 +10,38 @@ namespace Microsoft.Data.SqlClient { internal sealed partial class TdsParser { + internal struct SNIErrorDetails + { + public string errorMessage; + public uint nativeError; + public uint sniErrorNumber; + public int provider; + public uint lineNumber; + public string function; + public Exception exception; + } + + internal struct ReliabilitySection + { + /// + /// This is a no-op in netcore version. Only needed for merging with netfx codebase. + /// + [Conditional("NETFRAMEWORK")] + internal static void Assert(string message) + { + } + + [Conditional("NETFRAMEWORK")] + internal void Start() + { + } + + [Conditional("NETFRAMEWORK")] + internal void Stop() + { + } + } + internal static void FillGuidBytes(Guid guid, Span buffer) => guid.TryWriteBytes(buffer); internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 10fdb263b9..69bf5a85cd 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -841,6 +841,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 03889347ae..ea5e5a8bbc 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -66,89 +66,7 @@ internal int ObjectID /// Verify client encryption possibility. /// private bool ClientOSEncryptionSupport => SNILoadHandle.SingletonInstance.ClientOSEncryptionSupport; - - // ReliabilitySection Usage: - // - // #if DEBUG - // TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - // - // RuntimeHelpers.PrepareConstrainedRegions(); - // try { - // tdsReliabilitySection.Start(); - // #else - // { - // #endif //DEBUG - // - // // code that requires reliability - // - // } - // #if DEBUG - // finally { - // tdsReliabilitySection.Stop(); - // } - // #endif //DEBUG - - internal struct ReliabilitySection - { -#if DEBUG - // do not allocate TLS data in RETAIL bits - [ThreadStatic] - private static int s_reliabilityCount; // initialized to 0 by CLR - - private bool m_started; // initialized to false (not started) by CLR -#endif //DEBUG - - [Conditional("DEBUG")] - internal void Start() - { -#if DEBUG - Debug.Assert(!m_started); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - ++s_reliabilityCount; - m_started = true; - } -#endif //DEBUG - } - - [Conditional("DEBUG")] - internal void Stop() - { -#if DEBUG - // cannot assert m_started - ThreadAbortException can be raised before Start is called - - if (m_started) - { - Debug.Assert(s_reliabilityCount > 0); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - --s_reliabilityCount; - m_started = false; - } - } -#endif //DEBUG - } - - // you need to setup for a thread abort somewhere before you call this method - [Conditional("DEBUG")] - internal static void Assert(string message) - { -#if DEBUG - Debug.Assert(s_reliabilityCount > 0, message); -#endif //DEBUG - } - } - + // Default state object for parser internal TdsParserStateObject _physicalStateObj = null; // Default stateObj and connection for Dbnetlib and non-MARS SNI. @@ -805,60 +723,6 @@ internal void Connect(ServerInfo serverInfo, return; } - // Retrieve the IP and port number from native SNI for TCP protocol. The IP information is stored temporarily in the - // pendingSQLDNSObject but not in the DNS Cache at this point. We only add items to the DNS Cache after we receive the - // IsSupported flag as true in the feature ext ack from server. - internal void AssignPendingDNSInfo(string userProtocol, string DNSCacheKey) - { - UInt32 result; - ushort portFromSNI = 0; - string IPStringFromSNI = string.Empty; - IPAddress IPFromSNI; - isTcpProtocol = false; - Provider providerNumber = Provider.INVALID_PROV; - - if (string.IsNullOrEmpty(userProtocol)) - { - - result = SNINativeMethodWrapper.SniGetProviderNumber(_physicalStateObj.Handle, ref providerNumber); - Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetProviderNumber"); - isTcpProtocol = (providerNumber == Provider.TCP_PROV); - } - else if (userProtocol == TdsEnums.TCP) - { - isTcpProtocol = true; - } - - // serverInfo.UserProtocol could be empty - if (isTcpProtocol) - { - result = SNINativeMethodWrapper.SniGetConnectionPort(_physicalStateObj.Handle, ref portFromSNI); - Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionPort"); - - - result = SNINativeMethodWrapper.SniGetConnectionIPString(_physicalStateObj.Handle, ref IPStringFromSNI); - Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionIPString"); - - _connHandler.pendingSQLDNSObject = new SQLDNSInfo(DNSCacheKey, null, null, portFromSNI.ToString()); - - if (IPAddress.TryParse(IPStringFromSNI, out IPFromSNI)) - { - if (System.Net.Sockets.AddressFamily.InterNetwork == IPFromSNI.AddressFamily) - { - _connHandler.pendingSQLDNSObject.AddrIPv4 = IPStringFromSNI; - } - else if (System.Net.Sockets.AddressFamily.InterNetworkV6 == IPFromSNI.AddressFamily) - { - _connHandler.pendingSQLDNSObject.AddrIPv6 = IPStringFromSNI; - } - } - } - else - { - _connHandler.pendingSQLDNSObject = null; - } - } - internal void RemoveEncryption() { Debug.Assert((_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.LOGIN, "Invalid encryption option state"); @@ -989,41 +853,6 @@ internal void PutSession(TdsParserStateObject session) } } - // This is called from a ThreadAbort - ensure that it can be run from a CER Catch - internal void BestEffortCleanup() - { - _state = TdsParserState.Broken; - - var stateObj = _physicalStateObj; - if (stateObj != null) - { - var stateObjHandle = stateObj.Handle; - if (stateObjHandle != null) - { - stateObjHandle.Dispose(); - } - } - - if (_fMARS) - { - var sessionPool = _sessionPool; - if (sessionPool != null) - { - sessionPool.BestEffortCleanup(); - } - - var marsStateObj = _pMarsPhysicalConObj; - if (marsStateObj != null) - { - var marsStateObjHandle = marsStateObj.Handle; - if (marsStateObjHandle != null) - { - marsStateObjHandle.Dispose(); - } - } - } - } - private void SendPreLoginHandshake( byte[] instanceName, SqlConnectionEncryptOption encrypt, @@ -2248,44 +2077,6 @@ internal void PrepareResetConnection(bool preserveTransaction) _fPreserveTransaction = preserveTransaction; } - internal bool RunReliably(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) - { - RuntimeHelpers.PrepareConstrainedRegions(); - try - { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#endif //DEBUG - return Run(runBehavior, cmdHandler, dataStream, bulkCopyHandler, stateObj); -#if DEBUG - } - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG - } - catch (OutOfMemoryException) - { - _connHandler.DoomThisConnection(); - throw; - } - catch (StackOverflowException) - { - _connHandler.DoomThisConnection(); - throw; - } - catch (ThreadAbortException) - { - _connHandler.DoomThisConnection(); - throw; - } - } - internal bool Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) { bool syncOverAsync = stateObj._syncOverAsync; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs new file mode 100644 index 0000000000..98101a2bc4 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.netfx.cs @@ -0,0 +1,221 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System; +using System.Net; +using System.Threading; +using Interop.Windows.Sni; + +namespace Microsoft.Data.SqlClient +{ + internal sealed partial class TdsParser + { + // ReliabilitySection Usage: + // + // #if DEBUG + // TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + // + // RuntimeHelpers.PrepareConstrainedRegions(); + // try { + // tdsReliabilitySection.Start(); + // #else + // { + // #endif //DEBUG + // + // // code that requires reliability + // + // } + // #if DEBUG + // finally { + // tdsReliabilitySection.Stop(); + // } + // #endif //DEBUG + + internal struct ReliabilitySection + { +#if DEBUG + // do not allocate TLS data in RETAIL bits + [ThreadStatic] + private static int s_reliabilityCount; // initialized to 0 by CLR + + private bool m_started; // initialized to false (not started) by CLR +#endif //DEBUG + + [Conditional("DEBUG")] + internal void Start() + { +#if DEBUG + Debug.Assert(!m_started); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + ++s_reliabilityCount; + m_started = true; + } +#endif //DEBUG + } + + [Conditional("DEBUG")] + internal void Stop() + { +#if DEBUG + // cannot assert m_started - ThreadAbortException can be raised before Start is called + + if (m_started) + { + Debug.Assert(s_reliabilityCount > 0); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + --s_reliabilityCount; + m_started = false; + } + } +#endif //DEBUG + } + + // you need to setup for a thread abort somewhere before you call this method + [Conditional("DEBUG")] + internal static void Assert(string message) + { +#if DEBUG + Debug.Assert(s_reliabilityCount > 0, message); +#endif //DEBUG + } + } + + // This is called from a ThreadAbort - ensure that it can be run from a CER Catch + internal void BestEffortCleanup() + { + _state = TdsParserState.Broken; + + var stateObj = _physicalStateObj; + if (stateObj != null) + { + var stateObjHandle = stateObj.Handle; + if (stateObjHandle != null) + { + stateObjHandle.Dispose(); + } + } + + if (_fMARS) + { + var sessionPool = _sessionPool; + if (sessionPool != null) + { + sessionPool.BestEffortCleanup(); + } + + var marsStateObj = _pMarsPhysicalConObj; + if (marsStateObj != null) + { + var marsStateObjHandle = marsStateObj.Handle; + if (marsStateObjHandle != null) + { + marsStateObjHandle.Dispose(); + } + } + } + } + + // Retrieve the IP and port number from native SNI for TCP protocol. The IP information is stored temporarily in the + // pendingSQLDNSObject but not in the DNS Cache at this point. We only add items to the DNS Cache after we receive the + // IsSupported flag as true in the feature ext ack from server. + internal void AssignPendingDNSInfo(string userProtocol, string DNSCacheKey) + { + uint result; + ushort portFromSNI = 0; + string IPStringFromSNI = string.Empty; + IPAddress IPFromSNI; + isTcpProtocol = false; + Provider providerNumber = Provider.INVALID_PROV; + + if (string.IsNullOrEmpty(userProtocol)) + { + + result = SNINativeMethodWrapper.SniGetProviderNumber(_physicalStateObj.Handle, ref providerNumber); + Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetProviderNumber"); + isTcpProtocol = (providerNumber == Provider.TCP_PROV); + } + else if (userProtocol == TdsEnums.TCP) + { + isTcpProtocol = true; + } + + // serverInfo.UserProtocol could be empty + if (isTcpProtocol) + { + result = SNINativeMethodWrapper.SniGetConnectionPort(_physicalStateObj.Handle, ref portFromSNI); + Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionPort"); + + + result = SNINativeMethodWrapper.SniGetConnectionIPString(_physicalStateObj.Handle, ref IPStringFromSNI); + Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionIPString"); + + _connHandler.pendingSQLDNSObject = new SQLDNSInfo(DNSCacheKey, null, null, portFromSNI.ToString()); + + if (IPAddress.TryParse(IPStringFromSNI, out IPFromSNI)) + { + if (System.Net.Sockets.AddressFamily.InterNetwork == IPFromSNI.AddressFamily) + { + _connHandler.pendingSQLDNSObject.AddrIPv4 = IPStringFromSNI; + } + else if (System.Net.Sockets.AddressFamily.InterNetworkV6 == IPFromSNI.AddressFamily) + { + _connHandler.pendingSQLDNSObject.AddrIPv6 = IPStringFromSNI; + } + } + } + else + { + _connHandler.pendingSQLDNSObject = null; + } + } + + internal bool RunReliably(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) + { + RuntimeHelpers.PrepareConstrainedRegions(); + try + { +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#endif //DEBUG + return Run(runBehavior, cmdHandler, dataStream, bulkCopyHandler, stateObj); +#if DEBUG + } + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (OutOfMemoryException) + { + _connHandler.DoomThisConnection(); + throw; + } + catch (StackOverflowException) + { + _connHandler.DoomThisConnection(); + throw; + } + catch (ThreadAbortException) + { + _connHandler.DoomThisConnection(); + throw; + } + } + } +}