From dcd629b293d0cc9a3957c1456d67da82a936fb41 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Sun, 12 Dec 2021 21:39:01 -0800 Subject: [PATCH 01/32] Added UDP Broadcast to SSRP Added UDP Broadcast to SSRP --- .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index 0147b29f17..b413a29ad3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -15,6 +15,11 @@ internal class SSRP { private const char SemicolonSeparator = ';'; private const int SqlServerBrowserPort = 1434; + private const int SubsequentTimeoutsForCLNT_BCAST_EX = 15000; + private const int ServerResponseHeader = 3; + private const int ValidResponseSize = 4096; + private const int FirstTimeoutForCLNT_BCAST_EX = 5000; + private const int CLNT_BCAST_EX = 2; /// /// Finds instance port number for given instance name. @@ -169,5 +174,38 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re return responsePacket; } } + + /// + /// Sends request to server, and recieves response from server by UDP + /// + /// string constaning list of SVR_RESP(just RESP_DATA) + internal static string SendBroadcastUDPRequest() + { + StringBuilder response = new StringBuilder(); + byte[] CLNT_BCAST_EX_Request = new byte[1] { CLNT_BCAST_EX }; + IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 0); + int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; + + using (TrySNIEventScope.Create(nameof(SSRP))) + { + using (UdpClient clientListener = new UdpClient()) + { + Task sendTask = clientListener.SendAsync(CLNT_BCAST_EX_Request, CLNT_BCAST_EX_Request.Length, new IPEndPoint(IPAddress.Broadcast, SqlServerBrowserPort)); + Task receiveTask = null; + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Waiting for UDP Client to fetch list of instances."); + + while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && receiveTask != null) + { + currentTimeOut = SubsequentTimeoutsForCLNT_BCAST_EX; + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); + if (receiveTask.Result.Buffer.Length < ValidResponseSize) //discard invalid response + { + response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeader, receiveTask.Result.Buffer.Length - ServerResponseHeader)); + } + } + } + } + return response.ToString(); + } } } From 742107ca12cf1631d9065bbef663e3f9f846d9b6 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Tue, 21 Dec 2021 09:54:30 -0800 Subject: [PATCH 02/32] Added SqlDataSourceEnumerator Public API and AppContext for Helpers (Native and Managed) Added SqlDataSourceEnumerator Public API and AppContext for Helpers (Native and Managed) --- .../Interop/SNINativeMethodWrapper.Windows.cs | 9 + .../src/Microsoft.Data.SqlClient.csproj | 9 + .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 10 +- .../Data/SqlClient/TdsParserStaticMethods.cs | 4 + .../netfx/src/Microsoft.Data.SqlClient.csproj | 6 + .../Interop/SNINativeManagedWrapperX64.cs | 9 + .../Interop/SNINativeManagedWrapperX86.cs | 9 + .../Data/Interop/SNINativeMethodWrapper.cs | 20 ++ .../Data/SqlClient/TdsParserStaticMethods.cs | 5 + .../src/Microsoft/Data/Common/AdapterUtil.cs | 4 +- .../Data/Sql/SqlDataSourceEnumerator.cs | 50 +++++ .../SqlDataSourceEnumeratorManagedHelper.cs | 88 +++++++++ .../SqlDataSourceEnumeratorNativeHelper.cs | 177 ++++++++++++++++++ .../Microsoft.Data.SqlClient.Tests.csproj | 2 + .../SqlDataSourceEnumeratorTest.cs | 22 +++ 15 files changed, 416 insertions(+), 8 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index 7f1b3e17ea..c8f1980e22 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -200,6 +200,15 @@ internal struct SNI_Error #endregion #region DLL Imports + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] + internal static extern IntPtr SNIServerEnumOpen(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] + internal static extern void SNIServerEnumClose([In] IntPtr packet); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] + internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo); 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 5b808d9b78..a4a0b1388f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -692,6 +692,15 @@ + + Microsoft\Data\Sql\SqlDataSourceEnumerator.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index b413a29ad3..b69a839548 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -16,8 +16,8 @@ internal class SSRP private const char SemicolonSeparator = ';'; private const int SqlServerBrowserPort = 1434; private const int SubsequentTimeoutsForCLNT_BCAST_EX = 15000; - private const int ServerResponseHeader = 3; - private const int ValidResponseSize = 4096; + private const int ServerResponseHeaderSizeForCLNT_BCAST_EX = 3; + private const int ValidResponseSizeForCLNT_BCAST_EX = 4096; private const int FirstTimeoutForCLNT_BCAST_EX = 5000; private const int CLNT_BCAST_EX = 2; @@ -170,7 +170,6 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re responsePacket = receiveTask.Result.Buffer; } } - return responsePacket; } } @@ -183,7 +182,6 @@ internal static string SendBroadcastUDPRequest() { StringBuilder response = new StringBuilder(); byte[] CLNT_BCAST_EX_Request = new byte[1] { CLNT_BCAST_EX }; - IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 0); int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; using (TrySNIEventScope.Create(nameof(SSRP))) @@ -198,9 +196,9 @@ internal static string SendBroadcastUDPRequest() { currentTimeOut = SubsequentTimeoutsForCLNT_BCAST_EX; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); - if (receiveTask.Result.Buffer.Length < ValidResponseSize) //discard invalid response + if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response { - response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeader, receiveTask.Result.Buffer.Length - ServerResponseHeader)); + response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs index e17a65be95..d1d8f4ab13 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs @@ -180,5 +180,9 @@ internal static int GetRemainingTimeout(int timeout, long start) return checked((int)remaining); } } + static internal long GetTimeoutSeconds(int timeout) + { + return GetTimeout((long)timeout * 1000L); + } } } 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 df8e73b2d3..82fdf68576 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -119,6 +119,12 @@ Microsoft\Data\Sql\SqlNotificationRequest.cs + + Microsoft\Data\Sql\SqlDataSourceEnumerator.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs + Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs index abbfda7ede..d851c01eda 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -134,5 +134,14 @@ internal static extern unsafe uint SNISecGenClientContextWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] + internal static extern IntPtr SNIServerEnumOpen(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] + internal static extern void SNIServerEnumClose([In] IntPtr packet); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] + internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs index b700e4b108..276e8cdc29 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -134,5 +134,14 @@ internal static extern unsafe uint SNISecGenClientContextWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] + internal static extern IntPtr SNIServerEnumOpen(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] + internal static extern void SNIServerEnumClose([In] IntPtr packet); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] + internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index d1fb0ad3e5..39ba5c5259 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -760,6 +760,26 @@ internal static uint SNIInitialize() return SNIInitialize(LocalAppContextSwitches.UseSystemDefaultSecureProtocols, IntPtr.Zero); } + internal static IntPtr SNIServerEnumOpen() => s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIServerEnumOpen() : + SNINativeManagedWrapperX86.SNIServerEnumOpen(); + + internal static int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readbuffer, int bufferLength, out bool more) => s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more) : + SNINativeManagedWrapperX86.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); + + internal static void SNIServerEnumClose([In] IntPtr packet) + { + if (s_is64bitProcess) + { + SNINativeManagedWrapperX64.SNIServerEnumClose(packet); + } + else + { + SNINativeManagedWrapperX86.SNIServerEnumClose(packet); + } + } + internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo) { // initialize consumer info for MARS diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs index 025ea7d020..0241220560 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs @@ -221,6 +221,11 @@ internal static long GetTimeout(long timeoutMilliseconds) return result; } + static internal long GetTimeoutSeconds(int timeout) + { + return GetTimeout((long)timeout * 1000L); + } + internal static bool TimeoutHasExpired(long timeoutTime) { bool result = false; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index f7e3715ccc..9bfedadddc 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -1201,6 +1201,8 @@ static internal Exception InvalidMixedUsageOfCredentialAndAccessToken() => InvalidOperation(StringsHelper.GetString(Strings.ADP_InvalidMixedUsageOfCredentialAndAccessToken)); #endregion + internal static bool IsEmpty(string str) => string.IsNullOrEmpty(str); + internal static readonly IntPtr s_ptrZero = IntPtr.Zero; // IntPtr.Zero #if NETFRAMEWORK #region netfx project only internal static Task CreatedTaskWithException(Exception ex) @@ -1355,7 +1357,6 @@ internal static InvalidOperationException ComputerNameEx(int lastError) internal const float FailoverTimeoutStepForTnir = 0.125F; // Fraction of timeout to use in case of Transparent Network IP resolution. internal const int MinimumTimeoutForTnirMs = 500; // The first login attempt in Transparent network IP Resolution - internal static readonly IntPtr s_ptrZero = IntPtr.Zero; // IntPtr.Zero internal static readonly int s_ptrSize = IntPtr.Size; internal static readonly IntPtr s_invalidPtr = new(-1); // use for INVALID_HANDLE @@ -1446,7 +1447,6 @@ internal static IntPtr IntPtrOffset(IntPtr pbase, int offset) return (IntPtr)checked(pbase.ToInt64() + offset); } - internal static bool IsEmpty(string str) => string.IsNullOrEmpty(str); #endregion #else #region netcore project only diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs new file mode 100644 index 0000000000..9b6f2dca76 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -0,0 +1,50 @@ +using System; +using System.Data; +using System.Data.Common; +using Microsoft.Data.SqlClient.Server; + +namespace Microsoft.Data.Sql +{ + /// + /// Provides a mechanism for enumerating all available instances of SQL Server within the local network + /// + public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator + { + private const string UseManagedNetworkingOnWindows = "Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows"; + private static bool shouldUseManagedSNI; + private static readonly SqlDataSourceEnumerator SingletonInstance = new SqlDataSourceEnumerator(); + internal const string ServerName = "ServerName"; + internal const string InstanceName = "InstanceName"; + internal const string IsClustered = "IsClustered"; + internal const string Version = "Version"; + + private SqlDataSourceEnumerator() : base() + { + } + + /// + /// Set Appcontext switch to Use Managed SNI. Otherwise Native SNI.dll will be used by default. + /// + private static bool UseManagedSNI => + AppContext.TryGetSwitch(UseManagedNetworkingOnWindows, out shouldUseManagedSNI) ? + shouldUseManagedSNI : false; + + /// + /// Gets an instance of the SqlDataSourceEnumerator, which can be used to retrieve information about available SQL Server instances. + /// + public static SqlDataSourceEnumerator Instance => SqlDataSourceEnumerator.SingletonInstance; + + /// + /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. + /// + /// + override public DataTable GetDataSources() + { +#if NETFRAMEWORK + return SqlDataSourceEnumeratorNativeHelper.GetDataSources(); +#else + return UseManagedSNI ? SqlDataSourceEnumeratorManagedHelper.GetDataSources(): SqlDataSourceEnumeratorNativeHelper.GetDataSources(); +#endif + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs new file mode 100644 index 0000000000..9d810594ad --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using Microsoft.Data.SqlClient.SNI; + +namespace Microsoft.Data.SqlClient.Server +{ + /// + /// Provides a mechanism for enumerating all available instances of SQL Server within the local network + /// + internal static class SqlDataSourceEnumeratorManagedHelper + { + internal const string ServerName = "ServerName"; + internal const string InstanceName = "InstanceName"; + internal const string IsClustered = "IsClustered"; + internal const string Version = "Version"; + internal const string endOfServerInstanceDelimiter = ";;"; + internal const char instanceKeysDelimiter = ';'; + + /// + /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. + /// + /// DataTable with ServerName,InstanceName,IsClustered and Version + internal static DataTable GetDataSources() + { + return ParseServerEnumString(SSRP.SendBroadcastUDPRequest()); + } + + static private System.Data.DataTable ParseServerEnumString(string serverInstances) + { + DataTable dataTable = new DataTable("SqlDataSources"); + dataTable.Locale = CultureInfo.InvariantCulture; + dataTable.Columns.Add(ServerName, typeof(string)); + dataTable.Columns.Add(InstanceName, typeof(string)); + dataTable.Columns.Add(IsClustered, typeof(string)); + dataTable.Columns.Add(Version, typeof(string)); + DataRow dataRow; + + if (serverInstances.Length == 0) + { + return dataTable; + } + + string[] numOfServerInstances = serverInstances.Split(new[] { endOfServerInstanceDelimiter }, StringSplitOptions.None); + + foreach (string currentServerInstance in numOfServerInstances) + { + Dictionary InstanceDetails = new Dictionary(); + string[] delimitedKeyValues = currentServerInstance.Split(instanceKeysDelimiter); + string currentKey = String.Empty; + + for (int keyvalue = 0; keyvalue < delimitedKeyValues.Length; keyvalue++) + { + if (keyvalue % 2 == 0) + { + currentKey = delimitedKeyValues[keyvalue]; + } + else if (currentKey != String.Empty) + { + InstanceDetails.Add(currentKey, delimitedKeyValues[keyvalue]); + } + } + + if (InstanceDetails.Count > 0) + { + dataRow = dataTable.NewRow(); + dataRow[0] = InstanceDetails.ContainsKey(ServerName) == true ? + InstanceDetails[ServerName] : String.Empty; + dataRow[1] = InstanceDetails.ContainsKey(InstanceName) == true ? + InstanceDetails[InstanceName] : String.Empty; + dataRow[2] = InstanceDetails.ContainsKey(IsClustered) == true ? + InstanceDetails[IsClustered] : String.Empty; + dataRow[3] = InstanceDetails.ContainsKey(Version) == true ? + InstanceDetails[Version] : String.Empty; + + dataTable.Rows.Add(dataRow); + } + } + + foreach (DataColumn column in dataTable.Columns) + { + column.ReadOnly = true; + } + return dataTable; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs new file mode 100644 index 0000000000..2c9d2e6c91 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -0,0 +1,177 @@ +using System; +using System.Data; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Security; +using System.Text; +using Microsoft.Data.Common; +using Microsoft.Data.SqlClient; + +namespace Microsoft.Data.Sql +{ + /// + /// Provides a mechanism for enumerating all available instances of SQL Server within the local network + /// + internal class SqlDataSourceEnumeratorNativeHelper + { + internal const string ServerName = "ServerName"; + internal const string InstanceName = "InstanceName"; + internal const string IsClustered = "IsClustered"; + internal const string Version = "Version"; + private static string _Version = "Version:"; + private static string _Cluster = "Clustered:"; + private static int _clusterLength = _Cluster.Length; + private static int _versionLength = _Version.Length; + private const int timeoutSeconds = ADP.DefaultCommandTimeout; + private static long timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire + + /// + /// Retrieves a DataTable containing information about all visible SQL Server instances + /// + /// + internal static DataTable GetDataSources() + { + (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304 + char[] buffer = null; + StringBuilder strbldr = new StringBuilder(); + + Int32 bufferSize = 1024; + Int32 readLength = 0; + buffer = new char[bufferSize]; + bool more = true; + bool failure = false; + IntPtr handle = ADP.s_ptrZero; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(timeoutSeconds); + RuntimeHelpers.PrepareConstrainedRegions(); + try + { } + finally + { + handle = SNINativeMethodWrapper.SNIServerEnumOpen(); + } + + if (handle != ADP.s_ptrZero) + { + while (more && !TdsParserStaticMethods.TimeoutHasExpired(timeoutTime)) + { +#if NETFRAMEWORK + readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); +#else + readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); +#endif + if (readLength > bufferSize) + { + failure = true; + more = false; + } + else if (0 < readLength) + { + strbldr.Append(buffer, 0, readLength); + } + } + } + } + finally + { + if (handle != ADP.s_ptrZero) + { + SNINativeMethodWrapper.SNIServerEnumClose(handle); + } + } + + if (failure) + { + Debug.Assert(false, "GetDataSources:SNIServerEnumRead returned bad length"); + SqlClientEventSource.Log.TryTraceEvent(" GetDataSources:SNIServerEnumRead returned bad length, requested %d, received %d", bufferSize, readLength); + throw ADP.ArgumentOutOfRange("readLength"); + } + return ParseServerEnumString(strbldr.ToString()); + } + + static private System.Data.DataTable ParseServerEnumString(string serverInstances) + { + DataTable dataTable = new DataTable("SqlDataSources"); + dataTable.Locale = CultureInfo.InvariantCulture; + dataTable.Columns.Add(ServerName, typeof(string)); + dataTable.Columns.Add(InstanceName, typeof(string)); + dataTable.Columns.Add(IsClustered, typeof(string)); + dataTable.Columns.Add(Version, typeof(string)); + DataRow dataRow = null; + string serverName = null; + string instanceName = null; + string isClustered = null; + string version = null; + + // Every row comes in the format "serverName\instanceName;Clustered:[Yes|No];Version:.." + // Every row is terminated by a null character. + // Process one row at a time + foreach (string instance in serverInstances.Split(new string[] { "\0\0\0" }, StringSplitOptions.None)) + { + // string value = instance.Trim('\0'); // MDAC 91934 + string value = instance.Replace("\0", ""); + if (0 == value.Length) + { + continue; + } + foreach (string instance2 in value.Split(';')) + { + if (serverName == null) + { + foreach (string instance3 in instance2.Split('\\')) + { + if (serverName == null) + { + serverName = instance3; + continue; + } + Debug.Assert(instanceName == null); + instanceName = instance3; + } + continue; + } + if (isClustered == null) + { + Debug.Assert(String.Compare(_Cluster, 0, instance2, 0, _clusterLength, StringComparison.OrdinalIgnoreCase) == 0); + isClustered = instance2.Substring(_clusterLength); + continue; + } + Debug.Assert(version == null); + Debug.Assert(String.Compare(_Version, 0, instance2, 0, _versionLength, StringComparison.OrdinalIgnoreCase) == 0); + version = instance2.Substring(_versionLength); + } + + string query = "ServerName='" + serverName + "'"; + + if (!ADP.IsEmpty(instanceName)) + { // SQL BU DT 20006584: only append instanceName if present. + query += " AND InstanceName='" + instanceName + "'"; + } + + // SNI returns dupes - do not add them. SQL BU DT 290323 + if (dataTable.Select(query).Length == 0) + { + dataRow = dataTable.NewRow(); + dataRow[0] = serverName; + dataRow[1] = instanceName; + dataRow[2] = isClustered; + dataRow[3] = version; + dataTable.Rows.Add(dataRow); + } + serverName = null; + instanceName = null; + isClustered = null; + version = null; + } + foreach (DataColumn column in dataTable.Columns) + { + column.ReadOnly = true; + } + return dataTable; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 97336390d6..13d14c63dd 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -46,6 +46,7 @@ + @@ -68,6 +69,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs new file mode 100644 index 0000000000..7bf5116dd0 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs @@ -0,0 +1,22 @@ +using System; +using System.Data; +using System.ServiceProcess; +using Microsoft.Data.Sql; +using Xunit; + +namespace Microsoft.Data.SqlClient.Tests +{ + public class SqlDataSourceEnumeratorTest + { + [PlatformSpecific(TestPlatforms.Windows)] + public void SqlDataSourceEnumerator_VerfifyDataTableSize() + { + ServiceController sc = new("SQLBrowser"); + Assert.Equal(ServiceControllerStatus.Running, sc.Status); + + SqlDataSourceEnumerator instance = SqlDataSourceEnumerator.Instance; + DataTable table = instance.GetDataSources(); + Assert.NotEmpty(table.Rows); + } + } +} From 837424092796d10ececa6b8509f2c9a61075ba7d Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Tue, 21 Dec 2021 11:43:55 -0800 Subject: [PATCH 03/32] Added AppContext change to unit test Added AppContext change to unit test --- .../tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs index 7bf5116dd0..0ef15087c8 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs @@ -8,6 +8,7 @@ namespace Microsoft.Data.SqlClient.Tests { public class SqlDataSourceEnumeratorTest { + [Fact] [PlatformSpecific(TestPlatforms.Windows)] public void SqlDataSourceEnumerator_VerfifyDataTableSize() { @@ -17,6 +18,10 @@ public void SqlDataSourceEnumerator_VerfifyDataTableSize() SqlDataSourceEnumerator instance = SqlDataSourceEnumerator.Instance; DataTable table = instance.GetDataSources(); Assert.NotEmpty(table.Rows); + + AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); + System.Data.DataTable table2 = instance.GetDataSources(); + Assert.NotEmpty(table2.Rows); } } } From d629a1c934663edac75cb530a375327e532ccdea Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Mon, 7 Feb 2022 09:57:01 -0800 Subject: [PATCH 04/32] Increased recieve buffer size to match to native recieve buffer size to avoid heap corruption issue --- .../Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index 2c9d2e6c91..e77904cfdf 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -36,7 +36,7 @@ internal static DataTable GetDataSources() char[] buffer = null; StringBuilder strbldr = new StringBuilder(); - Int32 bufferSize = 1024; + Int32 bufferSize = 65536; Int32 readLength = 0; buffer = new char[bufferSize]; bool more = true; @@ -58,7 +58,7 @@ internal static DataTable GetDataSources() if (handle != ADP.s_ptrZero) { while (more && !TdsParserStaticMethods.TimeoutHasExpired(timeoutTime)) - { + { #if NETFRAMEWORK readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); #else From 0bc15f841d77f3d29b5561bfeac7612cf7ae4c69 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Mon, 7 Feb 2022 11:45:19 -0800 Subject: [PATCH 05/32] reset to d629a1c --- .../Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index e77904cfdf..cf891f5c49 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -58,7 +58,7 @@ internal static DataTable GetDataSources() if (handle != ADP.s_ptrZero) { while (more && !TdsParserStaticMethods.TimeoutHasExpired(timeoutTime)) - { + { #if NETFRAMEWORK readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); #else From e2cca89dea461a4e6df9c56ad55f5d85ae14e9ca Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Mon, 7 Feb 2022 12:26:29 -0800 Subject: [PATCH 06/32] Added stopwatch to track time elapsed for max timeouts in recieve data from SQL Browser --- .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index b69a839548..f02b39bc33 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -15,7 +15,8 @@ internal class SSRP { private const char SemicolonSeparator = ';'; private const int SqlServerBrowserPort = 1434; - private const int SubsequentTimeoutsForCLNT_BCAST_EX = 15000; + private const int recieveMAXTimeoutsForCLNT_BCAST_EX = 15000; + private const int recieveTimeoutsForCLNT_BCAST_EX = 1000; private const int ServerResponseHeaderSizeForCLNT_BCAST_EX = 3; private const int ValidResponseSizeForCLNT_BCAST_EX = 4096; private const int FirstTimeoutForCLNT_BCAST_EX = 5000; @@ -191,16 +192,24 @@ internal static string SendBroadcastUDPRequest() Task sendTask = clientListener.SendAsync(CLNT_BCAST_EX_Request, CLNT_BCAST_EX_Request.Length, new IPEndPoint(IPAddress.Broadcast, SqlServerBrowserPort)); Task receiveTask = null; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Waiting for UDP Client to fetch list of instances."); - - while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && receiveTask != null) - { - currentTimeOut = SubsequentTimeoutsForCLNT_BCAST_EX; - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); - if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response + Stopwatch sw = new Stopwatch(); + sw.Start(); + try + { + while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && sw.ElapsedMilliseconds < recieveMAXTimeoutsForCLNT_BCAST_EX && receiveTask != null) { - response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); + currentTimeOut = recieveTimeoutsForCLNT_BCAST_EX; + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); + if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response + { + response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); + } } } + finally + { + sw.Stop(); + } } } return response.ToString(); From f47181afd73c2e48ceb27ebc8f8c8856d621f3c7 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 10 Feb 2022 15:36:49 -0800 Subject: [PATCH 07/32] license license --- .../src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs | 3 +++ .../Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs | 3 +++ .../Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs | 3 +++ .../tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index 9b6f2dca76..982ff7be3d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -1,3 +1,6 @@ +// 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; using System.Data.Common; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index 9d810594ad..1a942bbd3c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -1,3 +1,6 @@ +// 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.Collections.Generic; using System.Data; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index cf891f5c49..1cba3cccba 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -1,3 +1,6 @@ +// 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; using System.Diagnostics; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs index 0ef15087c8..2ea4f9964a 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs @@ -1,3 +1,6 @@ +// 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; using System.ServiceProcess; From ec6e6231f0a981d8a13e8e04ac8809f3dd2e1d74 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 10 Feb 2022 15:38:54 -0800 Subject: [PATCH 08/32] exclude appcontext test exclude appcontext test --- .../tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs index 2ea4f9964a..547c3429f4 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs @@ -21,10 +21,6 @@ public void SqlDataSourceEnumerator_VerfifyDataTableSize() SqlDataSourceEnumerator instance = SqlDataSourceEnumerator.Instance; DataTable table = instance.GetDataSources(); Assert.NotEmpty(table.Rows); - - AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); - System.Data.DataTable table2 = instance.GetDataSources(); - Assert.NotEmpty(table2.Rows); } } } From a61186317566e4deabd0b91c8097c281c22306a4 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Fri, 18 Feb 2022 11:19:36 -0800 Subject: [PATCH 09/32] Comments and url references Comments and url references --- .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index f02b39bc33..61ef085d1d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -14,13 +14,13 @@ namespace Microsoft.Data.SqlClient.SNI internal class SSRP { private const char SemicolonSeparator = ';'; - private const int SqlServerBrowserPort = 1434; - private const int recieveMAXTimeoutsForCLNT_BCAST_EX = 15000; - private const int recieveTimeoutsForCLNT_BCAST_EX = 1000; - private const int ServerResponseHeaderSizeForCLNT_BCAST_EX = 3; - private const int ValidResponseSizeForCLNT_BCAST_EX = 4096; - private const int FirstTimeoutForCLNT_BCAST_EX = 5000; - private const int CLNT_BCAST_EX = 2; + private const int SqlServerBrowserPort = 1434; //port SQL Server Browser + private const int recieveMAXTimeoutsForCLNT_BCAST_EX = 15000; //Default max time for response wait + private const int recieveTimeoutsForCLNT_BCAST_EX = 1000; //subsequent wait time for response after intial wait + private const int ServerResponseHeaderSizeForCLNT_BCAST_EX = 3;//(SVR_RESP + RESP_SIZE) https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/2e1560c9-5097-4023-9f5e-72b9ff1ec3b1 + private const int ValidResponseSizeForCLNT_BCAST_EX = 4096; //valid reponse size should be less than 4096 + private const int FirstTimeoutForCLNT_BCAST_EX = 5000;//wait for first response for 5 seconds + private const int CLNT_BCAST_EX = 2;//request packet /// /// Finds instance port number for given instance name. @@ -176,14 +176,16 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re } /// - /// Sends request to server, and recieves response from server by UDP + /// Sends request to server, and recieves response from server (SQLBrowser) on port 1434 by UDP + /// Request (https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/a3035afa-c268-4699-b8fd-4f351e5c8e9e) + /// Response (https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/2e1560c9-5097-4023-9f5e-72b9ff1ec3b1) /// /// string constaning list of SVR_RESP(just RESP_DATA) internal static string SendBroadcastUDPRequest() { StringBuilder response = new StringBuilder(); - byte[] CLNT_BCAST_EX_Request = new byte[1] { CLNT_BCAST_EX }; - int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; + byte[] CLNT_BCAST_EX_Request = new byte[1] { CLNT_BCAST_EX }; //0x02 + int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; //wait 5 secs for first response and every 1 sec upto 15 secs (https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/f2640a2d-3beb-464b-a443-f635842ebc3e#Appendix_A_3) using (TrySNIEventScope.Create(nameof(SSRP))) { @@ -192,17 +194,17 @@ internal static string SendBroadcastUDPRequest() Task sendTask = clientListener.SendAsync(CLNT_BCAST_EX_Request, CLNT_BCAST_EX_Request.Length, new IPEndPoint(IPAddress.Broadcast, SqlServerBrowserPort)); Task receiveTask = null; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Waiting for UDP Client to fetch list of instances."); - Stopwatch sw = new Stopwatch(); + Stopwatch sw = new Stopwatch(); //for waiting until 15 sec elapsed sw.Start(); try { - while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && sw.ElapsedMilliseconds < recieveMAXTimeoutsForCLNT_BCAST_EX && receiveTask != null) + while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && sw.ElapsedMilliseconds <= recieveMAXTimeoutsForCLNT_BCAST_EX && receiveTask != null) { currentTimeOut = recieveTimeoutsForCLNT_BCAST_EX; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response { - response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); + response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); //RESP_DATA(VARIABLE) - 3 (RESP_SIZE + SVR_RESP) } } } From a4d9de67691f5e0fb2b90156d698875cf9234a90 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Fri, 18 Feb 2022 13:50:21 -0800 Subject: [PATCH 10/32] review comment review comment --- .../Microsoft/Data/Sql/SqlDataSourceEnumerator.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index 982ff7be3d..34ee230f06 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -1,7 +1,6 @@ // 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; using System.Data.Common; using Microsoft.Data.SqlClient.Server; @@ -13,8 +12,6 @@ namespace Microsoft.Data.Sql /// public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator { - private const string UseManagedNetworkingOnWindows = "Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows"; - private static bool shouldUseManagedSNI; private static readonly SqlDataSourceEnumerator SingletonInstance = new SqlDataSourceEnumerator(); internal const string ServerName = "ServerName"; internal const string InstanceName = "InstanceName"; @@ -25,13 +22,6 @@ private SqlDataSourceEnumerator() : base() { } - /// - /// Set Appcontext switch to Use Managed SNI. Otherwise Native SNI.dll will be used by default. - /// - private static bool UseManagedSNI => - AppContext.TryGetSwitch(UseManagedNetworkingOnWindows, out shouldUseManagedSNI) ? - shouldUseManagedSNI : false; - /// /// Gets an instance of the SqlDataSourceEnumerator, which can be used to retrieve information about available SQL Server instances. /// @@ -46,7 +36,7 @@ override public DataTable GetDataSources() #if NETFRAMEWORK return SqlDataSourceEnumeratorNativeHelper.GetDataSources(); #else - return UseManagedSNI ? SqlDataSourceEnumeratorManagedHelper.GetDataSources(): SqlDataSourceEnumeratorNativeHelper.GetDataSources(); + return SqlClient.TdsParserStateObjectFactory.UseManagedSNI ? SqlDataSourceEnumeratorManagedHelper.GetDataSources() : SqlDataSourceEnumeratorNativeHelper.GetDataSources(); #endif } } From 968183b7cd16eea3511f2afdf01154dd15f345fb Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Tue, 22 Feb 2022 13:36:06 -0800 Subject: [PATCH 11/32] fix strbuilder overwrite fix strbuilder overwrite --- .../Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index 1cba3cccba..34a5a8c2fd 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -74,7 +74,7 @@ internal static DataTable GetDataSources() } else if (0 < readLength) { - strbldr.Append(buffer, 0, readLength); + strbldr.Append(buffer); } } } From efa3d74eefeeeb8449858f64a53b816dff7f13bf Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Wed, 23 Feb 2022 13:45:48 -0800 Subject: [PATCH 12/32] VS Suggestions VS Suggestions --- .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 11 +++--- .../Data/Sql/SqlDataSourceEnumerator.cs | 4 +- .../SqlDataSourceEnumeratorManagedHelper.cs | 28 +++++++------- .../SqlDataSourceEnumeratorNativeHelper.cs | 37 +++++++++---------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index 61ef085d1d..0f3d54e474 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -15,8 +15,8 @@ internal class SSRP { private const char SemicolonSeparator = ';'; private const int SqlServerBrowserPort = 1434; //port SQL Server Browser - private const int recieveMAXTimeoutsForCLNT_BCAST_EX = 15000; //Default max time for response wait - private const int recieveTimeoutsForCLNT_BCAST_EX = 1000; //subsequent wait time for response after intial wait + private const int RecieveMAXTimeoutsForCLNT_BCAST_EX = 15000; //Default max time for response wait + private const int RecieveTimeoutsForCLNT_BCAST_EX = 1000; //subsequent wait time for response after intial wait private const int ServerResponseHeaderSizeForCLNT_BCAST_EX = 3;//(SVR_RESP + RESP_SIZE) https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/2e1560c9-5097-4023-9f5e-72b9ff1ec3b1 private const int ValidResponseSizeForCLNT_BCAST_EX = 4096; //valid reponse size should be less than 4096 private const int FirstTimeoutForCLNT_BCAST_EX = 5000;//wait for first response for 5 seconds @@ -155,8 +155,7 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re const int sendTimeOutMs = 1000; const int receiveTimeOutMs = 1000; - IPAddress address = null; - bool isIpAddress = IPAddress.TryParse(browserHostname, out address); + bool isIpAddress = IPAddress.TryParse(browserHostname, out IPAddress address); byte[] responsePacket = null; using (UdpClient client = new UdpClient(!isIpAddress ? AddressFamily.InterNetwork : address.AddressFamily)) @@ -198,9 +197,9 @@ internal static string SendBroadcastUDPRequest() sw.Start(); try { - while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && sw.ElapsedMilliseconds <= recieveMAXTimeoutsForCLNT_BCAST_EX && receiveTask != null) + while ((receiveTask = clientListener.ReceiveAsync()).Wait(currentTimeOut) && sw.ElapsedMilliseconds <= RecieveMAXTimeoutsForCLNT_BCAST_EX && receiveTask != null) { - currentTimeOut = recieveTimeoutsForCLNT_BCAST_EX; + currentTimeOut = RecieveTimeoutsForCLNT_BCAST_EX; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index 34ee230f06..2a04d1848c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -12,7 +12,7 @@ namespace Microsoft.Data.Sql /// public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator { - private static readonly SqlDataSourceEnumerator SingletonInstance = new SqlDataSourceEnumerator(); + private static readonly SqlDataSourceEnumerator s_singletonInstance = new(); internal const string ServerName = "ServerName"; internal const string InstanceName = "InstanceName"; internal const string IsClustered = "IsClustered"; @@ -25,7 +25,7 @@ private SqlDataSourceEnumerator() : base() /// /// Gets an instance of the SqlDataSourceEnumerator, which can be used to retrieve information about available SQL Server instances. /// - public static SqlDataSourceEnumerator Instance => SqlDataSourceEnumerator.SingletonInstance; + public static SqlDataSourceEnumerator Instance => SqlDataSourceEnumerator.s_singletonInstance; /// /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index 1a942bbd3c..2dde209c30 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -18,8 +18,8 @@ internal static class SqlDataSourceEnumeratorManagedHelper internal const string InstanceName = "InstanceName"; internal const string IsClustered = "IsClustered"; internal const string Version = "Version"; - internal const string endOfServerInstanceDelimiter = ";;"; - internal const char instanceKeysDelimiter = ';'; + internal const string EndOfServerInstanceDelimiter = ";;"; + internal const char InstanceKeysDelimiter = ';'; /// /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. @@ -32,8 +32,10 @@ internal static DataTable GetDataSources() static private System.Data.DataTable ParseServerEnumString(string serverInstances) { - DataTable dataTable = new DataTable("SqlDataSources"); - dataTable.Locale = CultureInfo.InvariantCulture; + DataTable dataTable = new("SqlDataSources") + { + Locale = CultureInfo.InvariantCulture + }; dataTable.Columns.Add(ServerName, typeof(string)); dataTable.Columns.Add(InstanceName, typeof(string)); dataTable.Columns.Add(IsClustered, typeof(string)); @@ -45,13 +47,13 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance return dataTable; } - string[] numOfServerInstances = serverInstances.Split(new[] { endOfServerInstanceDelimiter }, StringSplitOptions.None); + string[] numOfServerInstances = serverInstances.Split(new[] { EndOfServerInstanceDelimiter }, StringSplitOptions.None); foreach (string currentServerInstance in numOfServerInstances) { - Dictionary InstanceDetails = new Dictionary(); - string[] delimitedKeyValues = currentServerInstance.Split(instanceKeysDelimiter); - string currentKey = String.Empty; + Dictionary InstanceDetails = new(); + string[] delimitedKeyValues = currentServerInstance.Split(InstanceKeysDelimiter); + string currentKey = string.Empty; for (int keyvalue = 0; keyvalue < delimitedKeyValues.Length; keyvalue++) { @@ -59,7 +61,7 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance { currentKey = delimitedKeyValues[keyvalue]; } - else if (currentKey != String.Empty) + else if (currentKey != string.Empty) { InstanceDetails.Add(currentKey, delimitedKeyValues[keyvalue]); } @@ -69,13 +71,13 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance { dataRow = dataTable.NewRow(); dataRow[0] = InstanceDetails.ContainsKey(ServerName) == true ? - InstanceDetails[ServerName] : String.Empty; + InstanceDetails[ServerName] : string.Empty; dataRow[1] = InstanceDetails.ContainsKey(InstanceName) == true ? - InstanceDetails[InstanceName] : String.Empty; + InstanceDetails[InstanceName] : string.Empty; dataRow[2] = InstanceDetails.ContainsKey(IsClustered) == true ? - InstanceDetails[IsClustered] : String.Empty; + InstanceDetails[IsClustered] : string.Empty; dataRow[3] = InstanceDetails.ContainsKey(Version) == true ? - InstanceDetails[Version] : String.Empty; + InstanceDetails[Version] : string.Empty; dataTable.Rows.Add(dataRow); } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index 34a5a8c2fd..537eb94b3e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -22,12 +22,12 @@ internal class SqlDataSourceEnumeratorNativeHelper internal const string InstanceName = "InstanceName"; internal const string IsClustered = "IsClustered"; internal const string Version = "Version"; - private static string _Version = "Version:"; - private static string _Cluster = "Clustered:"; - private static int _clusterLength = _Cluster.Length; - private static int _versionLength = _Version.Length; - private const int timeoutSeconds = ADP.DefaultCommandTimeout; - private static long timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire + private static readonly string s_version = "Version:"; + private static readonly string s_cluster = "Clustered:"; + private static readonly int s_clusterLength = s_cluster.Length; + private static readonly int s_versionLength = s_version.Length; + private const int TimeoutSeconds = ADP.DefaultCommandTimeout; + private static long s_timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire /// /// Retrieves a DataTable containing information about all visible SQL Server instances @@ -37,10 +37,10 @@ internal static DataTable GetDataSources() { (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304 char[] buffer = null; - StringBuilder strbldr = new StringBuilder(); + StringBuilder strbldr = new(); - Int32 bufferSize = 65536; - Int32 readLength = 0; + int bufferSize = 65536; + int readLength = 0; buffer = new char[bufferSize]; bool more = true; bool failure = false; @@ -49,7 +49,7 @@ internal static DataTable GetDataSources() RuntimeHelpers.PrepareConstrainedRegions(); try { - timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(timeoutSeconds); + s_timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(TimeoutSeconds); RuntimeHelpers.PrepareConstrainedRegions(); try { } @@ -60,13 +60,13 @@ internal static DataTable GetDataSources() if (handle != ADP.s_ptrZero) { - while (more && !TdsParserStaticMethods.TimeoutHasExpired(timeoutTime)) + while (more && !TdsParserStaticMethods.TimeoutHasExpired(s_timeoutTime)) { #if NETFRAMEWORK readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); #else readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); -#endif +#endif if (readLength > bufferSize) { failure = true; @@ -98,13 +98,12 @@ internal static DataTable GetDataSources() static private System.Data.DataTable ParseServerEnumString(string serverInstances) { - DataTable dataTable = new DataTable("SqlDataSources"); + DataTable dataTable = new("SqlDataSources"); dataTable.Locale = CultureInfo.InvariantCulture; dataTable.Columns.Add(ServerName, typeof(string)); dataTable.Columns.Add(InstanceName, typeof(string)); dataTable.Columns.Add(IsClustered, typeof(string)); dataTable.Columns.Add(Version, typeof(string)); - DataRow dataRow = null; string serverName = null; string instanceName = null; string isClustered = null; @@ -139,13 +138,13 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance } if (isClustered == null) { - Debug.Assert(String.Compare(_Cluster, 0, instance2, 0, _clusterLength, StringComparison.OrdinalIgnoreCase) == 0); - isClustered = instance2.Substring(_clusterLength); + Debug.Assert(string.Compare(s_cluster, 0, instance2, 0, s_clusterLength, StringComparison.OrdinalIgnoreCase) == 0); + isClustered = instance2.Substring(s_clusterLength); continue; } Debug.Assert(version == null); - Debug.Assert(String.Compare(_Version, 0, instance2, 0, _versionLength, StringComparison.OrdinalIgnoreCase) == 0); - version = instance2.Substring(_versionLength); + Debug.Assert(string.Compare(s_version, 0, instance2, 0, s_versionLength, StringComparison.OrdinalIgnoreCase) == 0); + version = instance2.Substring(s_versionLength); } string query = "ServerName='" + serverName + "'"; @@ -158,7 +157,7 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance // SNI returns dupes - do not add them. SQL BU DT 290323 if (dataTable.Select(query).Length == 0) { - dataRow = dataTable.NewRow(); + DataRow dataRow = dataTable.NewRow(); dataRow[0] = serverName; dataRow[1] = instanceName; dataRow[2] = isClustered; From 5bb8130912830dec29a9144892fa15acca9dd6d6 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Wed, 23 Feb 2022 14:46:20 -0800 Subject: [PATCH 13/32] EventSource Trace EventSource Trace --- .../Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs | 1 + .../Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index 2dde209c30..1bdfd074ed 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -48,6 +48,7 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance } string[] numOfServerInstances = serverInstances.Split(new[] { EndOfServerInstanceDelimiter }, StringSplitOptions.None); + SqlClientEventSource.Log.TryTraceEvent(" Number of server instances results recieved are {0}", numOfServerInstances.Length); foreach (string currentServerInstance in numOfServerInstances) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index 537eb94b3e..0135715efe 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -66,7 +66,8 @@ internal static DataTable GetDataSources() readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); #else readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); -#endif +#endif + SqlClientEventSource.Log.TryTraceEvent(" GetDataSources:SNIServerEnumRead returned readlength {0}", readLength); if (readLength > bufferSize) { failure = true; @@ -108,11 +109,13 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance string instanceName = null; string isClustered = null; string version = null; + string[] serverinstanceslist = serverInstances.Split(new string[] { "\0\0\0" }, StringSplitOptions.None); + SqlClientEventSource.Log.TryTraceEvent(" Number of server instances results recieved are {0}", serverinstanceslist.Length); // Every row comes in the format "serverName\instanceName;Clustered:[Yes|No];Version:.." // Every row is terminated by a null character. // Process one row at a time - foreach (string instance in serverInstances.Split(new string[] { "\0\0\0" }, StringSplitOptions.None)) + foreach (string instance in serverinstanceslist) { // string value = instance.Trim('\0'); // MDAC 91934 string value = instance.Replace("\0", ""); From 8315240695db495345fe97956a348f9404dc7b0a Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 00:09:27 -0800 Subject: [PATCH 14/32] Documentation and ref Documentation and ref --- doc/samples/SqlDataSourceEnumeratorExample.cs | 31 +++++++++ .../SqlDataSourceEnumeratorVersionExample.cs | 23 +++++++ .../SqlDataSourceEnumerator.xml | 67 +++++++++++++++++++ .../netcore/ref/Microsoft.Data.SqlClient.cs | 9 +++ .../netfx/ref/Microsoft.Data.SqlClient.cs | 9 +++ .../Data/Sql/SqlDataSourceEnumerator.cs | 13 +--- 6 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 doc/samples/SqlDataSourceEnumeratorExample.cs create mode 100644 doc/samples/SqlDataSourceEnumeratorVersionExample.cs create mode 100644 doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml diff --git a/doc/samples/SqlDataSourceEnumeratorExample.cs b/doc/samples/SqlDataSourceEnumeratorExample.cs new file mode 100644 index 0000000000..1989bc0c66 --- /dev/null +++ b/doc/samples/SqlDataSourceEnumeratorExample.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.Data.Sql; + +class Program +{ + static void Main() + { + // Retrieve the enumerator instance and then the data. + SqlDataSourceEnumerator instance = + SqlDataSourceEnumerator.Instance; + System.Data.DataTable table = instance.GetDataSources(); + + // Display the contents of the table. + DisplayData(table); + + Console.WriteLine("Press any key to continue."); + Console.ReadKey(); + } + + private static void DisplayData(System.Data.DataTable table) + { + foreach (System.Data.DataRow row in table.Rows) + { + foreach (System.Data.DataColumn col in table.Columns) + { + Console.WriteLine("{0} = {1}", col.ColumnName, row[col]); + } + Console.WriteLine("============================"); + } + } +} \ No newline at end of file diff --git a/doc/samples/SqlDataSourceEnumeratorVersionExample.cs b/doc/samples/SqlDataSourceEnumeratorVersionExample.cs new file mode 100644 index 0000000000..4e119d755d --- /dev/null +++ b/doc/samples/SqlDataSourceEnumeratorVersionExample.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.Data.Sql; + +class Program +{ + static void Main() + { + // Retrieve the enumerator instance, and + // then retrieve the data sources. + SqlDataSourceEnumerator instance = + SqlDataSourceEnumerator.Instance; + System.Data.DataTable table = instance.GetDataSources(); + + // Filter the sources to just show SQL Server 2005 instances. + System.Data.DataRow[] rows = table.Select("Version LIKE '9%'"); + foreach (System.Data.DataRow row in rows) + { + Console.WriteLine(row["ServerName"]); + } + Console.WriteLine("Press any key to continue."); + Console.ReadKey(); + } +} \ No newline at end of file diff --git a/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml b/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml new file mode 100644 index 0000000000..a0e2e19e50 --- /dev/null +++ b/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml @@ -0,0 +1,67 @@ + + + + + Provides a mechanism for enumerating all available instances of SQL Server within the local network. + + class exposes this information to the application developer, providing a containing information about all the available servers. This returned table contains a list of server instances that matches the list provided when a user attempts to create a new connection, and on the `Connection Properties` dialog box, expands the drop-down list containing all the available servers. + + ]]> + + Enumerating Instances of SQL Server + + + Retrieves a containing information about all visible SQL Server instances. + A containing information about the visible SQL Server instances. + +
10.0.xx for SQL Server 2008
10.50.x for SQL Server 2008 R2
11.0.xx for SQL Server 2012
12.0.xx for SQL Server 2014
13.0.xx for SQL Server 2016
14.0.xx for SQL Server 2017| + +> [!NOTE] +> Due to the nature of the mechanism used by to locate data sources on a network, the method will not always return a complete list of the available servers, and the list might not be the same on every call. If you plan to use this function to let users select a server from a list, make sure that you always also supply an option to type in a name that is not in the list, in case the server enumeration does not return all the available servers. In addition, this method may take a significant amount of time to execute, so be careful about calling it when performance is critical. + + + +## Examples + The following console application retrieves information about all the visible SQL Server instances and displays the information in the console window. + +[!code-csharp[SqlDataSourceEnumerator.Example#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorExample.cs#1)] + + ]]>
+
+ Enumerating Instances of SQL Server +
+ + Gets an instance of the , which can be used to retrieve information about available SQL Server instances. + An instance of the used to retrieve information about available SQL Server instances. + + class does not provide a constructor. Use the property to retrieve an instance of the class instead. + +[!code-csharp[SqlDataSourceEnumeratorExample#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorExample.cs#1)] + +## Examples + The following console application displays a list of all the available SQL Server 2005 instances within the local network. This code uses the method to filter the rows in the table returned by the method. + [!code-csharp[SqlDataSourceEnumeratorVersionExample#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorVersionExample.cs#1)] + + ]]> + + Enumerating Instances of SQL Server + + +
+
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs index 3d63a3f9db..12e8094ff0 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs @@ -29,6 +29,15 @@ public SqlNotificationRequest(string userData, string options, int timeout) { } /// public string UserData { get { throw null; } set { } } } + + /// + public sealed class SqlDataSourceEnumerator : System.Data.Common.DbDataSourceEnumerator + { + /// + public static SqlDataSourceEnumerator Instance { get; } + /// + public override System.Data.DataTable GetDataSources() { throw null; } + } } namespace Microsoft.Data.SqlTypes { diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs index 6a6ae668e7..d5ac6b0611 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs @@ -34,6 +34,15 @@ public SqlNotificationRequest(string userData, string options, int timeout) { } /// public string UserData { get { throw null; } set { } } } + + /// + public sealed class SqlDataSourceEnumerator : System.Data.Common.DbDataSourceEnumerator + { + /// + public static SqlDataSourceEnumerator Instance {get;} + /// + public override System.Data.DataTable GetDataSources(){ throw null; } + } } namespace Microsoft.Data.SqlClient diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index 2a04d1848c..d7f776ec87 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -7,9 +7,7 @@ namespace Microsoft.Data.Sql { - /// - /// Provides a mechanism for enumerating all available instances of SQL Server within the local network - /// + /// public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator { private static readonly SqlDataSourceEnumerator s_singletonInstance = new(); @@ -22,15 +20,10 @@ private SqlDataSourceEnumerator() : base() { } - /// - /// Gets an instance of the SqlDataSourceEnumerator, which can be used to retrieve information about available SQL Server instances. - /// + /// public static SqlDataSourceEnumerator Instance => SqlDataSourceEnumerator.s_singletonInstance; - /// - /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. - /// - /// + /// override public DataTable GetDataSources() { #if NETFRAMEWORK From 62d67d938067840f5af1594ae4f64ac7eba10d42 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 13:11:10 -0800 Subject: [PATCH 15/32] moved sni native wrapper methods from windows to common moved sni native wrapper methods from windows to common --- .../Interop/SNINativeMethodWrapper.Common.cs | 14 +++++++++++++ .../Interop/SNINativeMethodWrapper.Windows.cs | 10 ---------- .../src/Microsoft.Data.SqlClient.csproj | 20 +++++++++---------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs index ed33b6897a..7c16bb0afb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs @@ -3,11 +3,15 @@ // See the LICENSE file in the project root for more information. using Microsoft.Data.SqlClient.SNI; +using System; +using System.Runtime.InteropServices; namespace Microsoft.Data.SqlClient { internal static partial class SNINativeMethodWrapper { + private const string SNI = "Microsoft.Data.SqlClient.SNI.dll"; + internal enum SniSpecialErrors : uint { LocalDBErrorCode = SNICommon.LocalDBErrorCode, @@ -20,5 +24,15 @@ internal enum SniSpecialErrors : uint // max error code value MaxErrorValue = SNICommon.MaxErrorValue } + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] + internal static extern IntPtr SNIServerEnumOpen(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] + internal static extern void SNIServerEnumClose([In] IntPtr packet); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] + internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); + } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index c8f1980e22..b49299d826 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -12,8 +12,6 @@ namespace Microsoft.Data.SqlClient { internal static partial class SNINativeMethodWrapper { - private const string SNI = "Microsoft.Data.SqlClient.SNI.dll"; - private static int s_sniMaxComposedSpnLength = -1; private const int SniOpenTimeOut = -1; // infinite @@ -200,14 +198,6 @@ internal struct SNI_Error #endregion #region DLL Imports - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] - internal static extern IntPtr SNIServerEnumOpen(); - - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] - internal static extern void SNIServerEnumClose([In] IntPtr packet); - - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] - internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo); 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 0986cdd700..2ef1331bc3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -45,6 +45,15 @@ Microsoft\Data\Common\ActivityCorrelator.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumerator.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs Microsoft\Data\Common\DbConnectionStringCommon.cs @@ -696,15 +705,6 @@ - - Microsoft\Data\Sql\SqlDataSourceEnumerator.cs - - - Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs - - - Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs - @@ -931,7 +931,7 @@ - + From d12608532e6149a71d70d45db040131b049745d8 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 13:19:36 -0800 Subject: [PATCH 16/32] reverting back test nuget version reverting back test nuget version --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2ef1331bc3..7d7bd5833d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -931,7 +931,7 @@ - + From d1a95edac7c798a6d698f6390d12f62a98b96042 Mon Sep 17 00:00:00 2001 From: Parminder Kaur <88398605+Kaur-Parminder@users.noreply.github.com> Date: Thu, 24 Feb 2022 14:08:07 -0800 Subject: [PATCH 17/32] Apply suggestions from code review Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> --- doc/samples/SqlDataSourceEnumeratorExample.cs | 4 +++- .../SqlDataSourceEnumeratorVersionExample.cs | 8 ++++--- .../SqlDataSourceEnumerator.xml | 22 +++++++++---------- .../Data/Interop/SNINativeMethodWrapper.cs | 14 +++--------- .../src/Microsoft/Data/Common/AdapterUtil.cs | 4 ++-- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/doc/samples/SqlDataSourceEnumeratorExample.cs b/doc/samples/SqlDataSourceEnumeratorExample.cs index 1989bc0c66..279881c672 100644 --- a/doc/samples/SqlDataSourceEnumeratorExample.cs +++ b/doc/samples/SqlDataSourceEnumeratorExample.cs @@ -1,4 +1,5 @@ using System; +// using Microsoft.Data.Sql; class Program @@ -28,4 +29,5 @@ private static void DisplayData(System.Data.DataTable table) Console.WriteLine("============================"); } } -} \ No newline at end of file +} +// diff --git a/doc/samples/SqlDataSourceEnumeratorVersionExample.cs b/doc/samples/SqlDataSourceEnumeratorVersionExample.cs index 4e119d755d..73eefc1235 100644 --- a/doc/samples/SqlDataSourceEnumeratorVersionExample.cs +++ b/doc/samples/SqlDataSourceEnumeratorVersionExample.cs @@ -1,4 +1,5 @@ using System; +// using Microsoft.Data.Sql; class Program @@ -11,8 +12,8 @@ static void Main() SqlDataSourceEnumerator.Instance; System.Data.DataTable table = instance.GetDataSources(); - // Filter the sources to just show SQL Server 2005 instances. - System.Data.DataRow[] rows = table.Select("Version LIKE '9%'"); + // Filter the sources to just show SQL Server 2012 instances. + System.Data.DataRow[] rows = table.Select("Version LIKE '11%'"); foreach (System.Data.DataRow row in rows) { Console.WriteLine(row["ServerName"]); @@ -20,4 +21,5 @@ static void Main() Console.WriteLine("Press any key to continue."); Console.ReadKey(); } -} \ No newline at end of file +} +// diff --git a/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml b/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml index a0e2e19e50..55e1f2c057 100644 --- a/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml +++ b/doc/snippets/Microsoft.Data.Sql/SqlDataSourceEnumerator.xml @@ -7,8 +7,8 @@ class exposes this information to the application developer, providing a containing information about all the available servers. This returned table contains a list of server instances that matches the list provided when a user attempts to create a new connection, and on the `Connection Properties` dialog box, expands the drop-down list containing all the available servers. - +SQL Server makes it possible for applications to determine the existence of its instances within the current network. The class exposes this information to the application developer, providing a containing information about all the available servers. This returned table contains a list of server instances that matches the list provided when a user attempts to create a new connection, and on the `Connection Properties` dialog box, expands the drop-down list containing all the available servers. + ]]> Enumerating Instances of SQL Server @@ -20,8 +20,8 @@
10.0.xx for SQL Server 2008
10.50.x for SQL Server 2008 R2
11.0.xx for SQL Server 2012
12.0.xx for SQL Server 2014
13.0.xx for SQL Server 2016
14.0.xx for SQL Server 2017| > [!NOTE] -> Due to the nature of the mechanism used by to locate data sources on a network, the method will not always return a complete list of the available servers, and the list might not be the same on every call. If you plan to use this function to let users select a server from a list, make sure that you always also supply an option to type in a name that is not in the list, in case the server enumeration does not return all the available servers. In addition, this method may take a significant amount of time to execute, so be careful about calling it when performance is critical. - - - +> Due to the nature of the mechanism used by to locate data sources on a network, the method will not always return a complete list of the available servers, and the list might not be the same on every call. If you plan to use this function to let users select a server from a list, make sure that you always also supply an option to type in a name that is not in the list, in case the server enumeration does not return all the available servers. In addition, this method may take a significant amount of time to execute, so be careful about calling it when performance is critical. + ## Examples The following console application retrieves information about all the visible SQL Server instances and displays the information in the console window. @@ -50,12 +48,12 @@ class does not provide a constructor. Use the property to retrieve an instance of the class instead. - +The class does not provide a constructor. Use the property to retrieve an instance of the class instead. + [!code-csharp[SqlDataSourceEnumeratorExample#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorExample.cs#1)] - + ## Examples - The following console application displays a list of all the available SQL Server 2005 instances within the local network. This code uses the method to filter the rows in the table returned by the method. +The following console application displays a list of all the available SQL Server 2005 instances within the local network. This code uses the method to filter the rows in the table returned by the method. [!code-csharp[SqlDataSourceEnumeratorVersionExample#1](~/../sqlclient/doc/samples/SqlDataSourceEnumeratorVersionExample.cs#1)] ]]> diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 39ba5c5259..f064aabdd1 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -768,17 +768,9 @@ internal static int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readb SNINativeManagedWrapperX64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more) : SNINativeManagedWrapperX86.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); - internal static void SNIServerEnumClose([In] IntPtr packet) - { - if (s_is64bitProcess) - { - SNINativeManagedWrapperX64.SNIServerEnumClose(packet); - } - else - { - SNINativeManagedWrapperX86.SNIServerEnumClose(packet); - } - } + internal static void SNIServerEnumClose([In] IntPtr packet) => s_is64bitProcess ? + SNINativeManagedWrapperX64.SNIServerEnumClose(packet) : + SNINativeManagedWrapperX86.SNIServerEnumClose(packet); internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index bb834f172e..8db89b51b7 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -1228,7 +1228,7 @@ static internal Exception InvalidMixedUsageOfCredentialAndAccessToken() #endregion internal static bool IsEmpty(string str) => string.IsNullOrEmpty(str); - internal static readonly IntPtr s_ptrZero = IntPtr.Zero; // IntPtr.Zero + internal static readonly IntPtr s_ptrZero = IntPtr.Zero; #if NETFRAMEWORK #region netfx project only internal static Task CreatedTaskWithException(Exception ex) @@ -1473,7 +1473,7 @@ internal static IntPtr IntPtrOffset(IntPtr pbase, int offset) return (IntPtr)checked(pbase.ToInt64() + offset); } - #endregion +#endregion #else #region netcore project only internal static Timer UnsafeCreateTimer(TimerCallback callback, object state, int dueTime, int period) From b4b0d75b0a5995337e5e36af189e44c19cda83bf Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 14:29:46 -0800 Subject: [PATCH 18/32] removing body expression from SNIServerEnumClose removing body expression from SNIServerEnumClose --- .../Data/Interop/SNINativeMethodWrapper.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index f064aabdd1..39ba5c5259 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -768,9 +768,17 @@ internal static int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readb SNINativeManagedWrapperX64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more) : SNINativeManagedWrapperX86.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); - internal static void SNIServerEnumClose([In] IntPtr packet) => s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIServerEnumClose(packet) : - SNINativeManagedWrapperX86.SNIServerEnumClose(packet); + internal static void SNIServerEnumClose([In] IntPtr packet) + { + if (s_is64bitProcess) + { + SNINativeManagedWrapperX64.SNIServerEnumClose(packet); + } + else + { + SNINativeManagedWrapperX86.SNIServerEnumClose(packet); + } + } internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo) { From 2255f1acd12c0d1f66e840e72b586c04a15eaa73 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 15:49:43 -0800 Subject: [PATCH 19/32] body expression for GetTimeoutSeconds body expression for GetTimeoutSeconds --- .../src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs | 5 +---- .../src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs index d1d8f4ab13..6f67764f9a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs @@ -180,9 +180,6 @@ internal static int GetRemainingTimeout(int timeout, long start) return checked((int)remaining); } } - static internal long GetTimeoutSeconds(int timeout) - { - return GetTimeout((long)timeout * 1000L); - } + internal static long GetTimeoutSeconds(int timeout) => GetTimeout((long)timeout * 1000L); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs index 0241220560..7be7f61bb4 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStaticMethods.cs @@ -221,10 +221,7 @@ internal static long GetTimeout(long timeoutMilliseconds) return result; } - static internal long GetTimeoutSeconds(int timeout) - { - return GetTimeout((long)timeout * 1000L); - } + internal static long GetTimeoutSeconds(int timeout) => GetTimeout((long)timeout * 1000L); internal static bool TimeoutHasExpired(long timeoutTime) { From ce39cd70580ae59900f7643120c0c44c53abc019 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 16:47:38 -0800 Subject: [PATCH 20/32] created util for sqldatasourceenumerator created util for sqldatasourceenumerator --- .../src/Microsoft.Data.SqlClient.csproj | 3 ++ .../netfx/src/Microsoft.Data.SqlClient.csproj | 3 ++ .../Data/Sql/SqlDataSourceEnumerator.cs | 4 --- .../SqlDataSourceEnumeratorManagedHelper.cs | 29 +++++++++---------- .../SqlDataSourceEnumeratorNativeHelper.cs | 24 +++++---------- .../Data/Sql/SqlDataSourceEnumeratorUtil.cs | 17 +++++++++++ 6 files changed, 44 insertions(+), 36 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs 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 7d7bd5833d..6f145b073a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -55,6 +55,9 @@ Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs + + Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs + Microsoft\Data\Common\DbConnectionStringCommon.cs 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 e6d8a2df73..e731eda557 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -125,6 +125,9 @@ Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs + + Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs + Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index d7f776ec87..a5e840a2ec 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -11,10 +11,6 @@ namespace Microsoft.Data.Sql public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator { private static readonly SqlDataSourceEnumerator s_singletonInstance = new(); - internal const string ServerName = "ServerName"; - internal const string InstanceName = "InstanceName"; - internal const string IsClustered = "IsClustered"; - internal const string Version = "Version"; private SqlDataSourceEnumerator() : base() { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index 1bdfd074ed..a51e4d1c63 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Data; using System.Globalization; +using Microsoft.Data.Sql; using Microsoft.Data.SqlClient.SNI; namespace Microsoft.Data.SqlClient.Server @@ -14,10 +15,6 @@ namespace Microsoft.Data.SqlClient.Server ///
internal static class SqlDataSourceEnumeratorManagedHelper { - internal const string ServerName = "ServerName"; - internal const string InstanceName = "InstanceName"; - internal const string IsClustered = "IsClustered"; - internal const string Version = "Version"; internal const string EndOfServerInstanceDelimiter = ";;"; internal const char InstanceKeysDelimiter = ';'; @@ -36,10 +33,10 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance { Locale = CultureInfo.InvariantCulture }; - dataTable.Columns.Add(ServerName, typeof(string)); - dataTable.Columns.Add(InstanceName, typeof(string)); - dataTable.Columns.Add(IsClustered, typeof(string)); - dataTable.Columns.Add(Version, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.ServerName, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.InstanceName, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.IsClustered, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.Version, typeof(string)); DataRow dataRow; if (serverInstances.Length == 0) @@ -71,14 +68,14 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance if (InstanceDetails.Count > 0) { dataRow = dataTable.NewRow(); - dataRow[0] = InstanceDetails.ContainsKey(ServerName) == true ? - InstanceDetails[ServerName] : string.Empty; - dataRow[1] = InstanceDetails.ContainsKey(InstanceName) == true ? - InstanceDetails[InstanceName] : string.Empty; - dataRow[2] = InstanceDetails.ContainsKey(IsClustered) == true ? - InstanceDetails[IsClustered] : string.Empty; - dataRow[3] = InstanceDetails.ContainsKey(Version) == true ? - InstanceDetails[Version] : string.Empty; + dataRow[0] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.ServerName) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.ServerName] : string.Empty; + dataRow[1] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.InstanceName) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.InstanceName] : string.Empty; + dataRow[2] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.IsClustered) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.IsClustered] : string.Empty; + dataRow[3] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.Version) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.Version] : string.Empty; dataTable.Rows.Add(dataRow); } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index 0135715efe..d85ebe41d9 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -18,14 +18,6 @@ namespace Microsoft.Data.Sql ///
internal class SqlDataSourceEnumeratorNativeHelper { - internal const string ServerName = "ServerName"; - internal const string InstanceName = "InstanceName"; - internal const string IsClustered = "IsClustered"; - internal const string Version = "Version"; - private static readonly string s_version = "Version:"; - private static readonly string s_cluster = "Clustered:"; - private static readonly int s_clusterLength = s_cluster.Length; - private static readonly int s_versionLength = s_version.Length; private const int TimeoutSeconds = ADP.DefaultCommandTimeout; private static long s_timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire @@ -101,10 +93,10 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance { DataTable dataTable = new("SqlDataSources"); dataTable.Locale = CultureInfo.InvariantCulture; - dataTable.Columns.Add(ServerName, typeof(string)); - dataTable.Columns.Add(InstanceName, typeof(string)); - dataTable.Columns.Add(IsClustered, typeof(string)); - dataTable.Columns.Add(Version, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.ServerName, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.InstanceName, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.IsClustered, typeof(string)); + dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.Version, typeof(string)); string serverName = null; string instanceName = null; string isClustered = null; @@ -141,13 +133,13 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance } if (isClustered == null) { - Debug.Assert(string.Compare(s_cluster, 0, instance2, 0, s_clusterLength, StringComparison.OrdinalIgnoreCase) == 0); - isClustered = instance2.Substring(s_clusterLength); + Debug.Assert(string.Compare(SqlDataSourceEnumeratorUtil.s_cluster, 0, instance2, 0, SqlDataSourceEnumeratorUtil.s_clusterLength, StringComparison.OrdinalIgnoreCase) == 0); + isClustered = instance2.Substring(SqlDataSourceEnumeratorUtil.s_clusterLength); continue; } Debug.Assert(version == null); - Debug.Assert(string.Compare(s_version, 0, instance2, 0, s_versionLength, StringComparison.OrdinalIgnoreCase) == 0); - version = instance2.Substring(s_versionLength); + Debug.Assert(string.Compare(SqlDataSourceEnumeratorUtil.s_version, 0, instance2, 0, SqlDataSourceEnumeratorUtil.s_versionLength, StringComparison.OrdinalIgnoreCase) == 0); + version = instance2.Substring(SqlDataSourceEnumeratorUtil.s_versionLength); } string query = "ServerName='" + serverName + "'"; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs new file mode 100644 index 0000000000..df3feeee5f --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs @@ -0,0 +1,17 @@ +namespace Microsoft.Data.Sql +{ + /// + /// const values for SqlDataSourceEnumerator + /// + internal class SqlDataSourceEnumeratorUtil + { + internal const string ServerName = "ServerName"; + internal const string InstanceName = "InstanceName"; + internal const string IsClustered = "IsClustered"; + internal const string Version = "Version"; + internal static readonly string s_version = "Version:"; + internal static readonly string s_cluster = "Clustered:"; + internal static readonly int s_clusterLength = s_cluster.Length; + internal static readonly int s_versionLength = s_version.Length; + } +} From 67f0bbff088d2821401824d8e891de9c8bc486e9 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Thu, 24 Feb 2022 17:16:15 -0800 Subject: [PATCH 21/32] more utils more utils --- .../Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs | 7 ++----- .../Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs | 11 ++++------- .../Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs | 4 ++++ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index a51e4d1c63..7d093d487d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -15,9 +15,6 @@ namespace Microsoft.Data.SqlClient.Server ///
internal static class SqlDataSourceEnumeratorManagedHelper { - internal const string EndOfServerInstanceDelimiter = ";;"; - internal const char InstanceKeysDelimiter = ';'; - /// /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. /// @@ -44,13 +41,13 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance return dataTable; } - string[] numOfServerInstances = serverInstances.Split(new[] { EndOfServerInstanceDelimiter }, StringSplitOptions.None); + string[] numOfServerInstances = serverInstances.Split(new[] { SqlDataSourceEnumeratorUtil.EndOfServerInstanceDelimiterManaged }, StringSplitOptions.None); SqlClientEventSource.Log.TryTraceEvent(" Number of server instances results recieved are {0}", numOfServerInstances.Length); foreach (string currentServerInstance in numOfServerInstances) { Dictionary InstanceDetails = new(); - string[] delimitedKeyValues = currentServerInstance.Split(InstanceKeysDelimiter); + string[] delimitedKeyValues = currentServerInstance.Split(SqlDataSourceEnumeratorUtil.InstanceKeysDelimiter); string currentKey = string.Empty; for (int keyvalue = 0; keyvalue < delimitedKeyValues.Length; keyvalue++) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index d85ebe41d9..016dea0f2e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -18,9 +18,6 @@ namespace Microsoft.Data.Sql /// internal class SqlDataSourceEnumeratorNativeHelper { - private const int TimeoutSeconds = ADP.DefaultCommandTimeout; - private static long s_timeoutTime; // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire - /// /// Retrieves a DataTable containing information about all visible SQL Server instances /// @@ -41,7 +38,7 @@ internal static DataTable GetDataSources() RuntimeHelpers.PrepareConstrainedRegions(); try { - s_timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(TimeoutSeconds); + long s_timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(ADP.DefaultCommandTimeout); RuntimeHelpers.PrepareConstrainedRegions(); try { } @@ -101,7 +98,7 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance string instanceName = null; string isClustered = null; string version = null; - string[] serverinstanceslist = serverInstances.Split(new string[] { "\0\0\0" }, StringSplitOptions.None); + string[] serverinstanceslist = serverInstances.Split(new string[] { SqlDataSourceEnumeratorUtil.EndOfServerInstanceDelimiterNative }, StringSplitOptions.None); SqlClientEventSource.Log.TryTraceEvent(" Number of server instances results recieved are {0}", serverinstanceslist.Length); // Every row comes in the format "serverName\instanceName;Clustered:[Yes|No];Version:.." @@ -115,11 +112,11 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance { continue; } - foreach (string instance2 in value.Split(';')) + foreach (string instance2 in value.Split(SqlDataSourceEnumeratorUtil.InstanceKeysDelimiter)) { if (serverName == null) { - foreach (string instance3 in instance2.Split('\\')) + foreach (string instance3 in instance2.Split(SqlDataSourceEnumeratorUtil.ServerNamesAndInstanceDelimiter)) { if (serverName == null) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs index df3feeee5f..e1179e73fe 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs @@ -13,5 +13,9 @@ internal class SqlDataSourceEnumeratorUtil internal static readonly string s_cluster = "Clustered:"; internal static readonly int s_clusterLength = s_cluster.Length; internal static readonly int s_versionLength = s_version.Length; + internal const string EndOfServerInstanceDelimiterManaged = ";;"; + internal const char InstanceKeysDelimiter = ';'; + internal const string EndOfServerInstanceDelimiterNative = "\0\0\0"; + internal const char ServerNamesAndInstanceDelimiter = '\\'; } } From 3f9ad321710938a7d03583311f8953b8dcd28d46 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Fri, 25 Feb 2022 10:41:33 -0800 Subject: [PATCH 22/32] license for util file license for util file --- .../src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs index e1179e73fe..bac35525e2 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs @@ -1,3 +1,6 @@ +// 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. namespace Microsoft.Data.Sql { /// From d93127c1c7953442b195b1e7301dfbe5166e9fb4 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 2 Mar 2022 11:51:03 -0800 Subject: [PATCH 23/32] fix (#2) native sni managed sni unicode --- .../Interop/SNINativeMethodWrapper.Common.cs | 7 +- .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 16 ++-- .../Interop/SNINativeManagedWrapperX64.cs | 7 +- .../Interop/SNINativeManagedWrapperX86.cs | 7 +- .../SqlDataSourceEnumeratorManagedHelper.cs | 46 ++++------ .../SqlDataSourceEnumeratorNativeHelper.cs | 84 ++++++++++--------- .../Data/Sql/SqlDataSourceEnumeratorUtil.cs | 55 +++++++++--- 7 files changed, 131 insertions(+), 91 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs index 7c16bb0afb..7f181d89d4 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs @@ -31,8 +31,11 @@ internal enum SniSpecialErrors : uint [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] internal static extern void SNIServerEnumClose([In] IntPtr packet); - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] - internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)] + internal static extern int SNIServerEnumRead([In] IntPtr packet, + [In][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer, + [In] int bufferLength, + [MarshalAs(UnmanagedType.Bool)] out bool more); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index 0f3d54e474..a171752ebf 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -11,7 +11,7 @@ namespace Microsoft.Data.SqlClient.SNI { - internal class SSRP + internal sealed class SSRP { private const char SemicolonSeparator = ';'; private const int SqlServerBrowserPort = 1434; //port SQL Server Browser @@ -78,11 +78,11 @@ private static byte[] CreateInstanceInfoRequest(string instanceName) { const byte ClntUcastInst = 0x04; instanceName += char.MinValue; - int byteCount = Encoding.ASCII.GetByteCount(instanceName); + int byteCount = Encoding.UTF7.GetByteCount(instanceName); byte[] requestPacket = new byte[byteCount + 1]; requestPacket[0] = ClntUcastInst; - Encoding.ASCII.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 1); + Encoding.UTF7.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 1); return requestPacket; } @@ -127,12 +127,12 @@ private static byte[] CreateDacPortInfoRequest(string instanceName) const byte ClntUcastDac = 0x0F; const byte ProtocolVersion = 0x01; instanceName += char.MinValue; - int byteCount = Encoding.ASCII.GetByteCount(instanceName); + int byteCount = Encoding.UTF7.GetByteCount(instanceName); byte[] requestPacket = new byte[byteCount + 2]; requestPacket[0] = ClntUcastDac; requestPacket[1] = ProtocolVersion; - Encoding.ASCII.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 2); + Encoding.UTF7.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 2); return requestPacket; } @@ -184,7 +184,9 @@ internal static string SendBroadcastUDPRequest() { StringBuilder response = new StringBuilder(); byte[] CLNT_BCAST_EX_Request = new byte[1] { CLNT_BCAST_EX }; //0x02 - int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; //wait 5 secs for first response and every 1 sec upto 15 secs (https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/f2640a2d-3beb-464b-a443-f635842ebc3e#Appendix_A_3) + // Waits 5 seconds for the first response and every 1 second up to 15 seconds + // https://docs.microsoft.com/en-us/openspecs/windows_protocols/mc-sqlr/f2640a2d-3beb-464b-a443-f635842ebc3e#Appendix_A_3 + int currentTimeOut = FirstTimeoutForCLNT_BCAST_EX; using (TrySNIEventScope.Create(nameof(SSRP))) { @@ -203,7 +205,7 @@ internal static string SendBroadcastUDPRequest() SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received instnace info from UDP Client."); if (receiveTask.Result.Buffer.Length < ValidResponseSizeForCLNT_BCAST_EX) //discard invalid response { - response.Append(Encoding.ASCII.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); //RESP_DATA(VARIABLE) - 3 (RESP_SIZE + SVR_RESP) + response.Append(Encoding.UTF7.GetString(receiveTask.Result.Buffer, ServerResponseHeaderSizeForCLNT_BCAST_EX, receiveTask.Result.Buffer.Length - ServerResponseHeaderSizeForCLNT_BCAST_EX)); //RESP_DATA(VARIABLE) - 3 (RESP_SIZE + SVR_RESP) } } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs index d851c01eda..13e35363a8 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -141,7 +141,10 @@ internal static extern unsafe uint SNISecGenClientContextWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] internal static extern void SNIServerEnumClose([In] IntPtr packet); - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] - internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)] + internal static extern int SNIServerEnumRead([In] IntPtr packet, + [In, Out][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer, + [In] int bufferLength, + [MarshalAs(UnmanagedType.Bool)] out bool more); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs index 276e8cdc29..5517ba8c0e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -141,7 +141,10 @@ internal static extern unsafe uint SNISecGenClientContextWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] internal static extern void SNIServerEnumClose([In] IntPtr packet); - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper")] - internal static extern int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readBuffer, int bufferLength, out bool more); + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)] + internal static extern int SNIServerEnumRead([In] IntPtr packet, + [In, Out][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer, + [In] int bufferLength, + [MarshalAs(UnmanagedType.Bool)] out bool more); } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index 7d093d487d..02ed400aea 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -1,10 +1,8 @@ // 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.Collections.Generic; using System.Data; -using System.Globalization; using Microsoft.Data.Sql; using Microsoft.Data.SqlClient.SNI; @@ -13,27 +11,21 @@ namespace Microsoft.Data.SqlClient.Server /// /// Provides a mechanism for enumerating all available instances of SQL Server within the local network /// - internal static class SqlDataSourceEnumeratorManagedHelper + internal static class SqlDataSourceEnumeratorManagedHelper { /// /// Provides a mechanism for enumerating all available instances of SQL Server within the local network. /// /// DataTable with ServerName,InstanceName,IsClustered and Version internal static DataTable GetDataSources() - { + { return ParseServerEnumString(SSRP.SendBroadcastUDPRequest()); } - static private System.Data.DataTable ParseServerEnumString(string serverInstances) + private static DataTable ParseServerEnumString(string serverInstances) { - DataTable dataTable = new("SqlDataSources") - { - Locale = CultureInfo.InvariantCulture - }; - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.ServerName, typeof(string)); - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.InstanceName, typeof(string)); - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.IsClustered, typeof(string)); - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.Version, typeof(string)); + System.Console.WriteLine(serverInstances); + DataTable dataTable = SqlDataSourceEnumeratorUtil.PrepareDataTable(); DataRow dataRow; if (serverInstances.Length == 0) @@ -41,8 +33,9 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance return dataTable; } - string[] numOfServerInstances = serverInstances.Split(new[] { SqlDataSourceEnumeratorUtil.EndOfServerInstanceDelimiterManaged }, StringSplitOptions.None); - SqlClientEventSource.Log.TryTraceEvent(" Number of server instances results recieved are {0}", numOfServerInstances.Length); + string[] numOfServerInstances = serverInstances.Split(SqlDataSourceEnumeratorUtil.s_endOfServerInstanceDelimiter_Managed, System.StringSplitOptions.None); + SqlClientEventSource.Log.TryTraceEvent(" Number of recieved server instances are {2}", + nameof(SqlDataSourceEnumeratorManagedHelper), nameof(ParseServerEnumString), numOfServerInstances.Length); foreach (string currentServerInstance in numOfServerInstances) { @@ -65,24 +58,19 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance if (InstanceDetails.Count > 0) { dataRow = dataTable.NewRow(); - dataRow[0] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.ServerName) == true ? - InstanceDetails[SqlDataSourceEnumeratorUtil.ServerName] : string.Empty; - dataRow[1] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.InstanceName) == true ? - InstanceDetails[SqlDataSourceEnumeratorUtil.InstanceName] : string.Empty; - dataRow[2] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.IsClustered) == true ? - InstanceDetails[SqlDataSourceEnumeratorUtil.IsClustered] : string.Empty; - dataRow[3] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.Version) == true ? - InstanceDetails[SqlDataSourceEnumeratorUtil.Version] : string.Empty; + dataRow[0] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.ServerNameCol) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.ServerNameCol] : string.Empty; + dataRow[1] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.InstanceNameCol) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.InstanceNameCol] : string.Empty; + dataRow[2] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.IsClusteredCol) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.IsClusteredCol] : string.Empty; + dataRow[3] = InstanceDetails.ContainsKey(SqlDataSourceEnumeratorUtil.VersionNameCol) == true ? + InstanceDetails[SqlDataSourceEnumeratorUtil.VersionNameCol] : string.Empty; dataTable.Rows.Add(dataRow); } } - - foreach (DataColumn column in dataTable.Columns) - { - column.ReadOnly = true; - } - return dataTable; + return dataTable.SetColumnsReadOnly(); } } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index 016dea0f2e..db40a6439e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -1,22 +1,23 @@ // 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; using System.Diagnostics; -using System.Globalization; using System.Runtime.CompilerServices; using System.Security; using System.Text; using Microsoft.Data.Common; using Microsoft.Data.SqlClient; +using static Microsoft.Data.Sql.SqlDataSourceEnumeratorUtil; namespace Microsoft.Data.Sql { /// /// Provides a mechanism for enumerating all available instances of SQL Server within the local network /// - internal class SqlDataSourceEnumeratorNativeHelper + internal static class SqlDataSourceEnumeratorNativeHelper { /// /// Retrieves a DataTable containing information about all visible SQL Server instances @@ -28,7 +29,7 @@ internal static DataTable GetDataSources() char[] buffer = null; StringBuilder strbldr = new(); - int bufferSize = 65536; + int bufferSize = 1024; int readLength = 0; buffer = new char[bufferSize]; bool more = true; @@ -45,26 +46,31 @@ internal static DataTable GetDataSources() finally { handle = SNINativeMethodWrapper.SNIServerEnumOpen(); + SqlClientEventSource.Log.TryTraceEvent(" {3} returned handle = {4}.", + nameof(SqlDataSourceEnumeratorNativeHelper), + nameof(GetDataSources), + nameof(SNINativeMethodWrapper.SNIServerEnumOpen), handle); } if (handle != ADP.s_ptrZero) { while (more && !TdsParserStaticMethods.TimeoutHasExpired(s_timeoutTime)) { -#if NETFRAMEWORK - readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); -#else readLength = SNINativeMethodWrapper.SNIServerEnumRead(handle, buffer, bufferSize, out more); -#endif - SqlClientEventSource.Log.TryTraceEvent(" GetDataSources:SNIServerEnumRead returned readlength {0}", readLength); + + SqlClientEventSource.Log.TryTraceEvent(" {2} returned 'readlength':{3}, and 'more':{4} with 'bufferSize' of {5}", + nameof(SqlDataSourceEnumeratorNativeHelper), + nameof(GetDataSources), + nameof(SNINativeMethodWrapper.SNIServerEnumRead), + readLength, more, bufferSize); if (readLength > bufferSize) { failure = true; more = false; } - else if (0 < readLength) + else if (readLength > 0) { - strbldr.Append(buffer); + strbldr.Append(buffer, 0, readLength); } } } @@ -74,69 +80,75 @@ internal static DataTable GetDataSources() if (handle != ADP.s_ptrZero) { SNINativeMethodWrapper.SNIServerEnumClose(handle); + SqlClientEventSource.Log.TryTraceEvent(" {3} called.", + nameof(SqlDataSourceEnumeratorNativeHelper), + nameof(GetDataSources), + nameof(SNINativeMethodWrapper.SNIServerEnumClose)); } } if (failure) { - Debug.Assert(false, "GetDataSources:SNIServerEnumRead returned bad length"); - SqlClientEventSource.Log.TryTraceEvent(" GetDataSources:SNIServerEnumRead returned bad length, requested %d, received %d", bufferSize, readLength); - throw ADP.ArgumentOutOfRange("readLength"); + Debug.Assert(false, $"{nameof(GetDataSources)}:{nameof(SNINativeMethodWrapper.SNIServerEnumRead)} returned bad length"); + SqlClientEventSource.Log.TryTraceEvent(" {2} returned bad length, requested buffer {3}, received {4}", + nameof(SqlDataSourceEnumeratorNativeHelper), + nameof(GetDataSources), + nameof(SNINativeMethodWrapper.SNIServerEnumRead), + bufferSize, readLength); + + throw ADP.ArgumentOutOfRange(StringsHelper.GetString(Strings.ADP_ParameterValueOutOfRange, readLength), nameof(readLength)); } return ParseServerEnumString(strbldr.ToString()); } - static private System.Data.DataTable ParseServerEnumString(string serverInstances) + private static DataTable ParseServerEnumString(string serverInstances) { - DataTable dataTable = new("SqlDataSources"); - dataTable.Locale = CultureInfo.InvariantCulture; - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.ServerName, typeof(string)); - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.InstanceName, typeof(string)); - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.IsClustered, typeof(string)); - dataTable.Columns.Add(SqlDataSourceEnumeratorUtil.Version, typeof(string)); + DataTable dataTable = PrepareDataTable(); string serverName = null; string instanceName = null; string isClustered = null; string version = null; - string[] serverinstanceslist = serverInstances.Split(new string[] { SqlDataSourceEnumeratorUtil.EndOfServerInstanceDelimiterNative }, StringSplitOptions.None); - SqlClientEventSource.Log.TryTraceEvent(" Number of server instances results recieved are {0}", serverinstanceslist.Length); + string[] serverinstanceslist = serverInstances.Split(EndOfServerInstanceDelimiter_Native); + SqlClientEventSource.Log.TryTraceEvent(" Number of recieved server instances are {2}", + nameof(SqlDataSourceEnumeratorNativeHelper), nameof(ParseServerEnumString), serverinstanceslist.Length); // Every row comes in the format "serverName\instanceName;Clustered:[Yes|No];Version:.." // Every row is terminated by a null character. // Process one row at a time foreach (string instance in serverinstanceslist) { - // string value = instance.Trim('\0'); // MDAC 91934 - string value = instance.Replace("\0", ""); - if (0 == value.Length) + string value = instance.Trim(EndOfServerInstanceDelimiter_Native); // MDAC 91934 + if (value.Length == 0) { continue; } - foreach (string instance2 in value.Split(SqlDataSourceEnumeratorUtil.InstanceKeysDelimiter)) + foreach (string instance2 in value.Split(InstanceKeysDelimiter)) { if (serverName == null) { - foreach (string instance3 in instance2.Split(SqlDataSourceEnumeratorUtil.ServerNamesAndInstanceDelimiter)) + foreach (string instance3 in instance2.Split(ServerNamesAndInstanceDelimiter)) { if (serverName == null) { serverName = instance3; continue; } - Debug.Assert(instanceName == null); + Debug.Assert(instanceName == null, $"{nameof(instanceName)}({instanceName}) is not null."); instanceName = instance3; } continue; } if (isClustered == null) { - Debug.Assert(string.Compare(SqlDataSourceEnumeratorUtil.s_cluster, 0, instance2, 0, SqlDataSourceEnumeratorUtil.s_clusterLength, StringComparison.OrdinalIgnoreCase) == 0); - isClustered = instance2.Substring(SqlDataSourceEnumeratorUtil.s_clusterLength); + Debug.Assert(string.Compare(Clustered, 0, instance2, 0, s_clusteredLength, StringComparison.OrdinalIgnoreCase) == 0, + $"{nameof(Clustered)} ({Clustered}) doesn't equal {nameof(instance2)} ({instance2})"); + isClustered = instance2.Substring(s_clusteredLength); continue; } - Debug.Assert(version == null); - Debug.Assert(string.Compare(SqlDataSourceEnumeratorUtil.s_version, 0, instance2, 0, SqlDataSourceEnumeratorUtil.s_versionLength, StringComparison.OrdinalIgnoreCase) == 0); - version = instance2.Substring(SqlDataSourceEnumeratorUtil.s_versionLength); + Debug.Assert(version == null, $"{nameof(version)}({version}) is not null."); + Debug.Assert(string.Compare(SqlDataSourceEnumeratorUtil.Version, 0, instance2, 0, s_versionLength, StringComparison.OrdinalIgnoreCase) == 0, + $"{nameof(SqlDataSourceEnumeratorUtil.Version)} ({SqlDataSourceEnumeratorUtil.Version}) doesn't equal {nameof(instance2)} ({instance2})"); + version = instance2.Substring(s_versionLength); } string query = "ServerName='" + serverName + "'"; @@ -161,11 +173,7 @@ static private System.Data.DataTable ParseServerEnumString(string serverInstance isClustered = null; version = null; } - foreach (DataColumn column in dataTable.Columns) - { - column.ReadOnly = true; - } - return dataTable; + return dataTable.SetColumnsReadOnly(); } } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs index e1179e73fe..fb6972d8cf 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorUtil.cs @@ -1,21 +1,54 @@ +// 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 System.Globalization; + namespace Microsoft.Data.Sql { /// /// const values for SqlDataSourceEnumerator /// - internal class SqlDataSourceEnumeratorUtil + internal static class SqlDataSourceEnumeratorUtil { - internal const string ServerName = "ServerName"; - internal const string InstanceName = "InstanceName"; - internal const string IsClustered = "IsClustered"; - internal const string Version = "Version"; - internal static readonly string s_version = "Version:"; - internal static readonly string s_cluster = "Clustered:"; - internal static readonly int s_clusterLength = s_cluster.Length; - internal static readonly int s_versionLength = s_version.Length; - internal const string EndOfServerInstanceDelimiterManaged = ";;"; + internal const string ServerNameCol = "ServerName"; + internal const string InstanceNameCol = "InstanceName"; + internal const string IsClusteredCol = "IsClustered"; + internal const string VersionNameCol = "Version"; + + internal const string Version = "Version:"; + internal const string Clustered = "Clustered:"; + internal static readonly int s_versionLength = Version.Length; + internal static readonly int s_clusteredLength = Clustered.Length; + + internal static readonly string[] s_endOfServerInstanceDelimiter_Managed = new[] { ";;" }; + internal const char EndOfServerInstanceDelimiter_Native = '\0'; internal const char InstanceKeysDelimiter = ';'; - internal const string EndOfServerInstanceDelimiterNative = "\0\0\0"; internal const char ServerNamesAndInstanceDelimiter = '\\'; + + internal static DataTable PrepareDataTable() + { + DataTable dataTable = new("SqlDataSources"); + dataTable.Locale = CultureInfo.InvariantCulture; + dataTable.Columns.Add(ServerNameCol, typeof(string)); + dataTable.Columns.Add(InstanceNameCol, typeof(string)); + dataTable.Columns.Add(IsClusteredCol, typeof(string)); + dataTable.Columns.Add(VersionNameCol, typeof(string)); + + return dataTable; + } + + /// + /// Sets all columns read-only. + /// + internal static DataTable SetColumnsReadOnly(this DataTable dataTable) + { + foreach (DataColumn column in dataTable.Columns) + { + column.ReadOnly = true; + } + return dataTable; + } } } From 4ae25f263325ce1ce921e45a95bc343d8d5f54ef Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Wed, 2 Mar 2022 13:32:51 -0800 Subject: [PATCH 24/32] changing back encoding to ASCII for SRRP except UDPbroadcast menthod --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index a171752ebf..d182a8d31f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -78,11 +78,11 @@ private static byte[] CreateInstanceInfoRequest(string instanceName) { const byte ClntUcastInst = 0x04; instanceName += char.MinValue; - int byteCount = Encoding.UTF7.GetByteCount(instanceName); + int byteCount = Encoding.ASCII.GetByteCount(instanceName); byte[] requestPacket = new byte[byteCount + 1]; requestPacket[0] = ClntUcastInst; - Encoding.UTF7.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 1); + Encoding.ASCII.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 1); return requestPacket; } @@ -127,12 +127,12 @@ private static byte[] CreateDacPortInfoRequest(string instanceName) const byte ClntUcastDac = 0x0F; const byte ProtocolVersion = 0x01; instanceName += char.MinValue; - int byteCount = Encoding.UTF7.GetByteCount(instanceName); + int byteCount = Encoding.ASCII.GetByteCount(instanceName); byte[] requestPacket = new byte[byteCount + 2]; requestPacket[0] = ClntUcastDac; requestPacket[1] = ProtocolVersion; - Encoding.UTF7.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 2); + Encoding.ASCII.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 2); return requestPacket; } From 39273408e4ca2ca1b9e11b0613ada6ddde79a935 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Fri, 4 Mar 2022 12:25:08 -0800 Subject: [PATCH 25/32] Noimplementation exception for Managed SNI and test update for same --- .../Microsoft/Data/Sql/SqlDataSourceEnumerator.cs | 3 ++- .../FunctionalTests/SqlDataSourceEnumeratorTest.cs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index a5e840a2ec..7f8393a360 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -1,6 +1,7 @@ // 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; using System.Data.Common; using Microsoft.Data.SqlClient.Server; @@ -25,7 +26,7 @@ override public DataTable GetDataSources() #if NETFRAMEWORK return SqlDataSourceEnumeratorNativeHelper.GetDataSources(); #else - return SqlClient.TdsParserStateObjectFactory.UseManagedSNI ? SqlDataSourceEnumeratorManagedHelper.GetDataSources() : SqlDataSourceEnumeratorNativeHelper.GetDataSources(); + return SqlClient.TdsParserStateObjectFactory.UseManagedSNI ? throw new NotImplementedException() : SqlDataSourceEnumeratorNativeHelper.GetDataSources(); #endif } } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs index 547c3429f4..60215d27a6 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs @@ -17,10 +17,17 @@ public void SqlDataSourceEnumerator_VerfifyDataTableSize() { ServiceController sc = new("SQLBrowser"); Assert.Equal(ServiceControllerStatus.Running, sc.Status); - + SqlDataSourceEnumerator instance = SqlDataSourceEnumerator.Instance; - DataTable table = instance.GetDataSources(); - Assert.NotEmpty(table.Rows); + if (AppContext.TryGetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", out bool isEnabled)) + { + Assert.Throws(() => instance.GetDataSources()); + } + else + { + DataTable table = instance.GetDataSources(); + Assert.NotEmpty(table.Rows); + } } } } From 7aebf45737714e5fa2b1e8e7d3193b78f0d27da3 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Mon, 7 Mar 2022 09:49:11 -0800 Subject: [PATCH 26/32] SNI Update SNI Update --- tools/props/Versions.props | 6 +++--- tools/specs/Microsoft.Data.SqlClient.nuspec | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 44002cbbae..d58b93e218 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -6,7 +6,7 @@ 5.0.0.0 - 5.0.0-dev + 5.0.0-preview1.22062.1 $(NugetPackageVersion) @@ -20,7 +20,7 @@ - 4.0.0 + 5.0.0-preview1.22062.1 4.3.1 4.3.0 @@ -38,7 +38,7 @@ 5.0.0 - 4.0.0 + 5.0.0-preview1.22062.1 5.0.0 5.0.0 5.0.0 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 750ee2f48a..7f5ed91f43 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. sqlclient microsoft.data.sqlclient - + @@ -42,7 +42,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -60,7 +60,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -78,7 +78,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From e7931b534e06d5eae68421c3eb5d7e52ee19d6e0 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Mon, 7 Mar 2022 10:11:45 -0800 Subject: [PATCH 27/32] Revert "SNI Update" This reverts commit 7aebf45737714e5fa2b1e8e7d3193b78f0d27da3. --- tools/props/Versions.props | 6 +++--- tools/specs/Microsoft.Data.SqlClient.nuspec | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/props/Versions.props b/tools/props/Versions.props index d58b93e218..44002cbbae 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -6,7 +6,7 @@ 5.0.0.0 - 5.0.0-preview1.22062.1 + 5.0.0-dev $(NugetPackageVersion) @@ -20,7 +20,7 @@ - 5.0.0-preview1.22062.1 + 4.0.0 4.3.1 4.3.0 @@ -38,7 +38,7 @@ 5.0.0 - 5.0.0-preview1.22062.1 + 4.0.0 5.0.0 5.0.0 5.0.0 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 7f5ed91f43..750ee2f48a 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. sqlclient microsoft.data.sqlclient - + @@ -42,7 +42,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -60,7 +60,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -78,7 +78,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From 7ff8220e697e12e356f050b362b3be2e99ddd303 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 8 Mar 2022 14:02:32 -0800 Subject: [PATCH 28/32] Fix | SqlDSEnumerator net core (#3) SqlDataSourceEnumerator test update and different file for unix, windows --- .../Interop/SNINativeMethodWrapper.Common.cs | 13 ------ .../Interop/SNINativeMethodWrapper.Windows.cs | 14 ++++++- .../src/Microsoft.Data.SqlClient.csproj | 10 +++-- .../Data/Sql/SqlDataSourceEnumerator.Unix.cs | 15 +++++++ .../netfx/src/Microsoft.Data.SqlClient.csproj | 3 ++ .../Sql/SqlDataSourceEnumerator.Windows.cs | 22 ++++++++++ .../Data/Sql/SqlDataSourceEnumerator.cs | 22 ++++------ .../SqlDataSourceEnumeratorManagedHelper.cs | 4 +- .../Microsoft.Data.SqlClient.Tests.csproj | 1 - .../SqlDataSourceEnumeratorTest.cs | 33 --------------- ....Data.SqlClient.ManualTesting.Tests.csproj | 5 ++- .../SqlDataSourceEnumeratorTest.cs | 40 +++++++++++++++++++ 12 files changed, 112 insertions(+), 70 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs delete mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs index 7f181d89d4..0b09ea3341 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Common.cs @@ -24,18 +24,5 @@ internal enum SniSpecialErrors : uint // max error code value MaxErrorValue = SNICommon.MaxErrorValue } - - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] - internal static extern IntPtr SNIServerEnumOpen(); - - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] - internal static extern void SNIServerEnumClose([In] IntPtr packet); - - [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)] - internal static extern int SNIServerEnumRead([In] IntPtr packet, - [In][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer, - [In] int bufferLength, - [MarshalAs(UnmanagedType.Bool)] out bool more); - } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index b49299d826..4e84fdc406 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -305,7 +305,19 @@ private static extern unsafe uint SNISecGenClientContextWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] private static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket); - #endregion + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] + internal static extern IntPtr SNIServerEnumOpen(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] + internal static extern void SNIServerEnumClose([In] IntPtr packet); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)] + internal static extern int SNIServerEnumRead([In] IntPtr packet, + [In][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer, + [In] int bufferLength, + [MarshalAs(UnmanagedType.Bool)] out bool more); + #endregion internal static uint SniGetConnectionId(SNIHandle pConn, ref Guid connId) { 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 6f145b073a..ec72b3a856 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -51,9 +51,6 @@ Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs - - - Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs @@ -645,6 +642,12 @@ + + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs + @@ -873,6 +876,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs new file mode 100644 index 0000000000..6ee3fe3329 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Unix.cs @@ -0,0 +1,15 @@ +// 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 System.Data.Common; +using Microsoft.Data.SqlClient.Server; + +namespace Microsoft.Data.Sql +{ + /// + public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator + { + private partial DataTable GetDataSourcesInternal() => SqlDataSourceEnumeratorManagedHelper.GetDataSources(); + } +} 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 e731eda557..fe4e7b13da 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -122,6 +122,9 @@ Microsoft\Data\Sql\SqlDataSourceEnumerator.cs + + Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs new file mode 100644 index 0000000000..83ce5085e7 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs @@ -0,0 +1,22 @@ +// 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 System.Data.Common; +using Microsoft.Data.SqlClient.Server; + +namespace Microsoft.Data.Sql +{ + /// + public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator + { + private partial DataTable GetDataSourcesInternal() + { +#if NETFRAMEWORK + return SqlDataSourceEnumeratorNativeHelper.GetDataSources(); +#else + return SqlClient.TdsParserStateObjectFactory.UseManagedSNI ? SqlDataSourceEnumeratorManagedHelper.GetDataSources() : SqlDataSourceEnumeratorNativeHelper.GetDataSources(); +#endif + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index 7f8393a360..e8f7aac29c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -4,30 +4,22 @@ using System; using System.Data; using System.Data.Common; -using Microsoft.Data.SqlClient.Server; namespace Microsoft.Data.Sql { /// - public sealed class SqlDataSourceEnumerator : DbDataSourceEnumerator + public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator { - private static readonly SqlDataSourceEnumerator s_singletonInstance = new(); + private static readonly Lazy s_singletonInstance = new(() => new SqlDataSourceEnumerator()); - private SqlDataSourceEnumerator() : base() - { - } + private SqlDataSourceEnumerator() : base(){} /// - public static SqlDataSourceEnumerator Instance => SqlDataSourceEnumerator.s_singletonInstance; + public static SqlDataSourceEnumerator Instance => s_singletonInstance.Value; /// - override public DataTable GetDataSources() - { -#if NETFRAMEWORK - return SqlDataSourceEnumeratorNativeHelper.GetDataSources(); -#else - return SqlClient.TdsParserStateObjectFactory.UseManagedSNI ? throw new NotImplementedException() : SqlDataSourceEnumeratorNativeHelper.GetDataSources(); -#endif - } + override public DataTable GetDataSources() => GetDataSourcesInternal(); + + private partial DataTable GetDataSourcesInternal(); } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index 02ed400aea..c2ab7dab19 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Data; using Microsoft.Data.Sql; -using Microsoft.Data.SqlClient.SNI; namespace Microsoft.Data.SqlClient.Server { @@ -19,7 +18,8 @@ internal static class SqlDataSourceEnumeratorManagedHelper /// DataTable with ServerName,InstanceName,IsClustered and Version internal static DataTable GetDataSources() { - return ParseServerEnumString(SSRP.SendBroadcastUDPRequest()); + // TODO: Implement multicast request besides the implemented broadcast request. + throw new System.NotImplementedException(StringsHelper.net_MethodNotImplementedException); } private static DataTable ParseServerEnumString(string serverInstances) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 79f679abf4..a9f2a1ef8d 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -47,7 +47,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs deleted file mode 100644 index 60215d27a6..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataSourceEnumeratorTest.cs +++ /dev/null @@ -1,33 +0,0 @@ -// 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; -using System.ServiceProcess; -using Microsoft.Data.Sql; -using Xunit; - -namespace Microsoft.Data.SqlClient.Tests -{ - public class SqlDataSourceEnumeratorTest - { - [Fact] - [PlatformSpecific(TestPlatforms.Windows)] - public void SqlDataSourceEnumerator_VerfifyDataTableSize() - { - ServiceController sc = new("SQLBrowser"); - Assert.Equal(ServiceControllerStatus.Running, sc.Status); - - SqlDataSourceEnumerator instance = SqlDataSourceEnumerator.Instance; - if (AppContext.TryGetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", out bool isEnabled)) - { - Assert.Throws(() => instance.GetDataSources()); - } - else - { - DataTable table = instance.GetDataSources(); - Assert.NotEmpty(table.Rows); - } - } - } -} 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 ab9ad736bf..e08b05dc38 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 @@ -29,7 +29,7 @@ TCECryptoNativeBaselineRsa.txt - + @@ -158,6 +158,7 @@ + @@ -239,7 +240,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs new file mode 100644 index 0000000000..c7bbb773b7 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs @@ -0,0 +1,40 @@ +// 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.ServiceProcess; +using Microsoft.Data.Sql; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class SqlDataSourceEnumeratorTest + { + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsNotUsingManagedSNIOnWindows))] + [PlatformSpecific(TestPlatforms.Windows)] + public void SqlDataSourceEnumerator_NativeSNI() + { + // The returned rows depends on the running services which could be zero or more. + int count = GetDSEnumerator().GetDataSources().Rows.Count; + Assert.InRange(count, 0, 65536); + } + + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsUsingManagedSNI))] + [PlatformSpecific(TestPlatforms.Windows)] + public void SqlDataSourceEnumerator_ManagedSNI() + { + // after adding the managed SNI support, this test should have the same result as SqlDataSourceEnumerator_NativeSNI + Assert.Throws(() => GetDSEnumerator().GetDataSources()); + } + + private SqlDataSourceEnumerator GetDSEnumerator() + { + ServiceController sc = new("SQLBrowser"); + Assert.Equal(ServiceControllerStatus.Running, sc.Status); + + return SqlDataSourceEnumerator.Instance; + } + } +} From 54b3c36a90259707cf24cd41af410a170f38f535 Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Tue, 8 Mar 2022 16:52:25 -0800 Subject: [PATCH 29/32] added test dependcy for ServiceController.dll --- .../tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj | 1 - .../Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 1 + tools/props/Versions.props | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index a9f2a1ef8d..721d8a5c91 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -69,7 +69,6 @@ - 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 e08b05dc38..07cec012f6 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 @@ -320,6 +320,7 @@ + diff --git a/tools/props/Versions.props b/tools/props/Versions.props index eb18b2115d..51f0a31e2e 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -78,6 +78,7 @@ 161.41011.9 10.50.1600.1 0.12.1 + 4.4.1 $(NugetPackageVersion) From f09becc3455d91f1111ecdd4fd0ae4840b2345ad Mon Sep 17 00:00:00 2001 From: Kaur-Parminder Date: Tue, 8 Mar 2022 18:20:58 -0800 Subject: [PATCH 30/32] review comments --- .../Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs | 1 - tools/props/Versions.props | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs index c2ab7dab19..43be666e0d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorManagedHelper.cs @@ -24,7 +24,6 @@ internal static DataTable GetDataSources() private static DataTable ParseServerEnumString(string serverInstances) { - System.Console.WriteLine(serverInstances); DataTable dataTable = SqlDataSourceEnumeratorUtil.PrepareDataTable(); DataRow dataRow; diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 51f0a31e2e..ac93368fa7 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -78,7 +78,7 @@ 161.41011.9 10.50.1600.1 0.12.1 - 4.4.1 + 6.0.0 $(NugetPackageVersion) From c0f6bad70771c1c8116dde32709f54c7ebf63440 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 9 Mar 2022 10:57:20 -0800 Subject: [PATCH 31/32] Fix build issue --- .../Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 2 ++ .../SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) 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 07cec012f6..bb5ae0d8b5 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 @@ -158,6 +158,8 @@ + + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs index c7bbb773b7..abb0710e0d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs @@ -25,12 +25,14 @@ public void SqlDataSourceEnumerator_NativeSNI() [PlatformSpecific(TestPlatforms.Windows)] public void SqlDataSourceEnumerator_ManagedSNI() { - // after adding the managed SNI support, this test should have the same result as SqlDataSourceEnumerator_NativeSNI + // After adding the managed SNI support, this test should have the same result as SqlDataSourceEnumerator_NativeSNI Assert.Throws(() => GetDSEnumerator().GetDataSources()); } private SqlDataSourceEnumerator GetDSEnumerator() { + // SQL Server Browser runs as a Windows service. + // TODO: This assessment can be done on CI. ServiceController sc = new("SQLBrowser"); Assert.Equal(ServiceControllerStatus.Running, sc.Status); From 36d6adead99170a72dbd78d8aa0490336c636784 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 9 Mar 2022 13:08:45 -0800 Subject: [PATCH 32/32] use TargetsWindows --- .../Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 2 +- .../SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) 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 bb5ae0d8b5..44ff1f1ce7 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 @@ -159,7 +159,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs index abb0710e0d..118a2412c3 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs @@ -9,6 +9,9 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests { +#if NET50_OR_LATER + [System.Runtime.Versioning.SupportedOSPlatform("windows")] +#endif public class SqlDataSourceEnumeratorTest { [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsNotUsingManagedSNIOnWindows))]