Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data / System / Data / SqlClient / TdsParserStaticMethods.cs
blob3935e1b523e60c89e603c6e56e5f2eece915a450
1 //------------------------------------------------------------------------------
2 // <copyright file="TdsParserStaticFunctionality.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 namespace System.Data.SqlClient {
10 using System;
11 using System.Data.Common;
12 using System.Data.ProviderBase;
13 using System.Data.Sql;
14 using System.Data.SqlTypes;
15 using System.Diagnostics;
16 using System.Globalization;
17 using System.Runtime.CompilerServices;
18 using System.Runtime.InteropServices;
19 using System.Security;
20 using System.Security.Permissions;
21 using System.Text;
22 using System.Threading;
23 using System.Runtime.Versioning;
25 internal sealed class TdsParserStaticMethods {
27 private TdsParserStaticMethods() { /* prevent utility class from being insantiated*/ }
29 // Static methods
32 // SxS: this method accesses registry to resolve the alias.
33 [ResourceExposure(ResourceScope.None)]
34 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
35 static internal void AliasRegistryLookup(ref string host, ref string protocol) {
36 #if !MOBILE
37 if (!ADP.IsEmpty(host)) {
38 const String folder = "SOFTWARE\\Microsoft\\MSSQLServer\\Client\\ConnectTo";
39 // Put a try...catch... around this so we don't abort ANY connection if we can't read the registry.
40 string aliasLookup = (string) ADP.LocalMachineRegistryValue(folder, host);
41 if (!ADP.IsEmpty(aliasLookup)) {
42 /* Result will be in the form of: "DBNMPNTW,\\blained1\pipe\sql\query". or
43 Result will be in the form of: "DBNETLIB, via:\\blained1\pipe\sql\query".
45 supported formats:
46 tcp - DBMSSOCN,[server|server\instance][,port]
47 np - DBNMPNTW,[\\server\pipe\sql\query | \\server\pipe\MSSQL$instance\sql\query]
48 where \sql\query is the pipename and can be replaced with any other pipe name
49 via - [DBMSGNET,server,port | DBNETLIB, via:server, port]
50 sm - DBMSLPCN,server
52 unsupported formats:
53 rpc - DBMSRPCN,server,[parameters] where parameters could be "username,password"
54 bv - DBMSVINN,service@group@organization
55 appletalk - DBMSADSN,objectname@zone
56 spx - DBMSSPXN,[service | address,port,network]
58 // We must parse into the two component pieces, then map the first protocol piece to the
59 // appropriate value.
60 int index = aliasLookup.IndexOf(',');
62 // If we found the key, but there was no "," in the string, it is a bad Alias so return.
63 if (-1 != index) {
64 string parsedProtocol = aliasLookup.Substring(0, index).ToLower(CultureInfo.InvariantCulture);
66 // If index+1 >= length, Alias consisted of "FOO," which is a bad alias so return.
67 if (index+1 < aliasLookup.Length) {
68 string parsedAliasName = aliasLookup.Substring(index+1);
70 // Fix bug 298286
71 if ("dbnetlib" == parsedProtocol) {
72 index = parsedAliasName.IndexOf(':');
73 if (-1 != index && index + 1 < parsedAliasName.Length) {
74 parsedProtocol = parsedAliasName.Substring (0, index);
75 if (SqlConnectionString.ValidProtocal (parsedProtocol)) {
76 protocol = parsedProtocol;
77 host = parsedAliasName.Substring(index + 1);
81 else {
82 protocol = (string)SqlConnectionString.NetlibMapping()[parsedProtocol];
83 if (null != protocol) {
84 host = parsedAliasName;
91 #endif
94 // Encrypt password to be sent to SQL Server
95 // Note: The same logic is used in SNIPacketSetData (SniManagedWrapper) to encrypt passwords stored in SecureString
96 // If this logic changed, SNIPacketSetData needs to be changed as well
97 static internal Byte[] EncryptPassword(string password) {
98 Byte[] bEnc = new Byte[password.Length << 1];
99 int s;
100 byte bLo;
101 byte bHi;
103 for (int i = 0; i < password.Length; i ++) {
104 s = (int) password[i];
105 bLo = (byte) (s & 0xff);
106 bHi = (byte) ((s >> 8) & 0xff);
107 bEnc[i<<1] = (Byte) ( (((bLo & 0x0f) << 4) | (bLo >> 4)) ^ 0xa5 );
108 bEnc[(i<<1)+1] = (Byte) ( (((bHi & 0x0f) << 4) | (bHi >> 4)) ^ 0xa5);
110 return bEnc;
113 [ResourceExposure(ResourceScope.None)] // SxS: we use this method for TDS login only
114 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
115 static internal int GetCurrentProcessIdForTdsLoginOnly() {
116 #if MOBILE
117 return 0;
118 #else
119 return SafeNativeMethods.GetCurrentProcessId();
120 #endif
124 [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
125 [ResourceExposure(ResourceScope.None)] // SxS: we use this method for TDS login only
126 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
127 static internal Int32 GetCurrentThreadIdForTdsLoginOnly() {
128 #pragma warning disable 618
129 return AppDomain.GetCurrentThreadId(); // don't need this to be support fibres;
130 #pragma warning restore 618
134 [ResourceExposure(ResourceScope.None)] // SxS: we use MAC address for TDS login only
135 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
136 static internal byte[] GetNetworkPhysicalAddressForTdsLoginOnly() {
137 // NIC address is stored in NetworkAddress key. However, if NetworkAddressLocal key
138 // has a value that is not zero, then we cannot use the NetworkAddress key and must
139 // instead generate a random one. I do not fully understand why, this is simply what
140 // the native providers do. As for generation, I use a random number generator, which
141 // means that different processes on the same machine will have different NIC address
142 // values on the server. It is not ideal, but native does not have the same value for
143 // different processes either.
145 const string key = "NetworkAddress";
146 const string localKey = "NetworkAddressLocal";
147 const string folder = "SOFTWARE\\Description\\Microsoft\\Rpc\\UuidTemporaryData";
149 int result = 0;
150 byte[] nicAddress = null;
152 object temp = ADP.LocalMachineRegistryValue(folder, localKey);
153 if (temp is int) {
154 result = (int) temp;
157 if (result <= 0) {
158 temp = ADP.LocalMachineRegistryValue(folder, key);
159 if (temp is byte[]) {
160 nicAddress = (byte[]) temp;
164 if (null == nicAddress) {
165 nicAddress = new byte[TdsEnums.MAX_NIC_SIZE];
166 Random random = new Random();
167 random.NextBytes(nicAddress);
170 return nicAddress;
172 // translates remaining time in stateObj (from user specified timeout) to timout value for SNI
173 static internal Int32 GetTimeoutMilliseconds(long timeoutTime) {
174 // User provided timeout t | timeout value for SNI | meaning
175 // ------------------------+-----------------------+------------------------------
176 // t == long.MaxValue | -1 | infinite timeout (no timeout)
177 // t>0 && t<int.MaxValue | t |
178 // t>int.MaxValue | int.MaxValue | must not exceed int.MaxValue
180 if (Int64.MaxValue == timeoutTime) {
181 return -1; // infinite timeout
184 long msecRemaining = ADP.TimerRemainingMilliseconds(timeoutTime);
186 if (msecRemaining < 0) {
187 return 0;
189 if (msecRemaining > (long)Int32.MaxValue) {
190 return Int32.MaxValue;
192 return (Int32)msecRemaining;
195 static internal long GetTimeoutSeconds(int timeout) {
196 return GetTimeout((long)timeout * 1000L);
199 static internal long GetTimeout(long timeoutMilliseconds) {
200 long result;
201 if (timeoutMilliseconds <= 0) {
202 result = Int64.MaxValue; // no timeout...
204 else {
207 result = checked(ADP.TimerCurrent() + ADP.TimerFromMilliseconds(timeoutMilliseconds));
209 catch (OverflowException)
211 // In case of overflow, set to 'infinite' timeout
212 result = Int64.MaxValue;
215 return result;
218 static internal bool TimeoutHasExpired(long timeoutTime) {
219 bool result = false;
221 if (0 != timeoutTime && Int64.MaxValue != timeoutTime) {
222 result = ADP.TimerHasExpired(timeoutTime);
224 return result;
227 static internal int NullAwareStringLength(string str) {
228 if (str == null) {
229 return 0;
231 else {
232 return str.Length;
236 static internal int GetRemainingTimeout(int timeout, long start) {
237 if (timeout <= 0) {
238 return timeout;
240 long remaining = ADP.TimerRemainingSeconds(start + ADP.TimerFromSeconds(timeout));
241 if (remaining <= 0) {
242 return 1;
244 else {
245 return checked((int)remaining);