Skip to content

Commit 6d0993c

Browse files
David-Engelpaulmedynski
authored andcommitted
- Align SqlException Numbers across platforms
- Better capture error scenarios in TCP managed SNI. - Fix logging bug in SqlClientEventSource. - Change nativeError from uint to int
1 parent 2bb2c43 commit 6d0993c

File tree

11 files changed

+99
-31
lines changed

11 files changed

+99
-31
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
15071507
string providerRid = string.Format("SNI_PN{0}", details.Provider);
15081508
string providerName = StringsHelper.GetResourceString(providerRid);
15091509
Debug.Assert(!string.IsNullOrEmpty(providerName), $"invalid providerResourceId '{providerRid}'");
1510-
uint win32ErrorCode = details.NativeError;
1510+
int win32ErrorCode = details.nativeError;
15111511

15121512
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > SNI Native Error Code = {0}", win32ErrorCode);
15131513
if (details.SniErrorNumber == 0)
@@ -1557,7 +1557,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
15571557
// If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code
15581558
if (details.SniErrorNumber == SniErrors.LocalDBErrorCode)
15591559
{
1560-
errorMessage += LocalDbApi.GetLocalDbMessage((int)details.NativeError);
1560+
errorMessage += LocalDbApi.GetLocalDbMessage(details.nativeError);
15611561
win32ErrorCode = 0;
15621562
}
15631563
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Extracting the latest exception from native SNI. errorMessage: {0}", errorMessage);
@@ -1567,10 +1567,10 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
15671567
sqlContextInfo, providerName, (int)details.SniErrorNumber, errorMessage);
15681568

15691569
SqlClientEventSource.Log.TryAdvancedTraceErrorEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > SNI Error Message. Native Error = {0}, Line Number ={1}, Function ={2}, Exception ={3}, Server = {4}",
1570-
(int)details.NativeError, (int)details.LineNumber, details.Function, details.Exception, _server);
1570+
details.nativeError, (int)details.lineNumber, details.function, details.exception, _server);
15711571

1572-
return new SqlError(infoNumber: (int)details.NativeError, errorState: 0x00, TdsEnums.FATAL_ERROR_CLASS, _server,
1573-
errorMessage, details.Function, (int)details.LineNumber, win32ErrorCode: details.NativeError, details.Exception);
1572+
return new SqlError(infoNumber: details.nativeError, errorState: 0x00, TdsEnums.FATAL_ERROR_CLASS, _server,
1573+
errorMessage, details.function, (int)details.lineNumber, win32ErrorCode: details.nativeError, details.exception);
15741574
}
15751575
}
15761576

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal sealed partial class TdsParser
1313
internal struct SNIErrorDetails
1414
{
1515
public string errorMessage;
16-
public uint nativeError;
16+
public int nativeError;
1717
public uint sniErrorNumber;
1818
public int provider;
1919
public uint lineNumber;

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
15881588
string providerRid = string.Format("SNI_PN{0}", (int)details.Provider);
15891589
string providerName = StringsHelper.GetString(providerRid);
15901590
Debug.Assert(!string.IsNullOrEmpty(providerName), $"invalid providerResourceId '{providerRid}'");
1591-
uint win32ErrorCode = details.NativeError;
1591+
int win32ErrorCode = details.nativeError;
15921592

15931593
if (details.SniErrorNumber == 0)
15941594
{
@@ -1626,15 +1626,15 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
16261626
// If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code
16271627
if (details.SniErrorNumber == SniErrors.LocalDBErrorCode)
16281628
{
1629-
errorMessage += LocalDbApi.GetLocalDbMessage((int)details.NativeError);
1629+
errorMessage += LocalDbApi.GetLocalDbMessage(details.nativeError);
16301630
win32ErrorCode = 0;
16311631
}
16321632
}
16331633
errorMessage = string.Format("{0} (provider: {1}, error: {2} - {3})",
16341634
sqlContextInfo, providerName, (int)details.SniErrorNumber, errorMessage);
16351635

1636-
return new SqlError((int)details.NativeError, 0x00, TdsEnums.FATAL_ERROR_CLASS,
1637-
_server, errorMessage, details.Function, (int)details.LineNumber, win32ErrorCode);
1636+
return new SqlError(details.nativeError, 0x00, TdsEnums.FATAL_ERROR_CLASS,
1637+
_server, errorMessage, details.function, (int)details.lineNumber, win32ErrorCode);
16381638
}
16391639

16401640
internal void CheckResetConnection(TdsParserStateObject stateObj)

src/Microsoft.Data.SqlClient/src/Interop/Windows/Sni/SniError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal struct SniError
1212
internal Provider provider;
1313
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 261)]
1414
internal string errorMessage;
15-
internal uint nativeError;
15+
internal int nativeError;
1616
internal uint sniError;
1717
[MarshalAs(UnmanagedType.LPWStr)]
1818
internal string fileName;

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ManagedSni/SniCommon.netcore.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ internal static IPAddress[] GetDnsIpAddresses(string serverName)
189189
/// <param name="sniError">SNI error code</param>
190190
/// <param name="errorMessage">Error message</param>
191191
/// <returns></returns>
192-
internal static uint ReportSNIError(SniProviders provider, uint nativeError, uint sniError, string errorMessage)
192+
internal static uint ReportSNIError(SniProviders provider, int nativeError, uint sniError, string errorMessage)
193193
{
194194
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniCommon), EventType.ERR, "Provider = {0}, native Error = {1}, SNI Error = {2}, Error Message = {3}", args0: provider, args1: nativeError, args2: sniError, args3: errorMessage);
195195
return ReportSNIError(new SniError(provider, nativeError, sniError, errorMessage));
@@ -203,7 +203,7 @@ internal static uint ReportSNIError(SniProviders provider, uint nativeError, uin
203203
/// <param name="sniException">SNI Exception</param>
204204
/// <param name="nativeErrorCode">Native SNI error code</param>
205205
/// <returns></returns>
206-
internal static uint ReportSNIError(SniProviders provider, uint sniError, Exception sniException, uint nativeErrorCode = 0)
206+
internal static uint ReportSNIError(SniProviders provider, uint sniError, Exception sniException, int nativeErrorCode = 0)
207207
{
208208
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniCommon), EventType.ERR, "Provider = {0}, SNI Error = {1}, Exception = {2}", args0: provider, args1: sniError, args2: sniException?.Message);
209209
return ReportSNIError(new SniError(provider, sniError, sniException, nativeErrorCode));

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ManagedSni/SniError.netcore.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#if NET
66

77
using System;
8+
using System.ComponentModel;
9+
using System.Net.Sockets;
810

911
namespace Microsoft.Data.SqlClient.ManagedSni
1012
{
@@ -14,17 +16,18 @@ namespace Microsoft.Data.SqlClient.ManagedSni
1416
internal class SniError
1517
{
1618
// Error numbers from native SNI implementation
17-
internal const uint CertificateValidationErrorCode = 2148074277;
19+
// This is signed int representation of the error code 0x80090325
20+
internal const int CertificateValidationErrorCode = -2146893019;
1821

1922
public readonly SniProviders provider;
2023
public readonly string errorMessage;
21-
public readonly uint nativeError;
24+
public readonly int nativeError;
2225
public readonly uint sniError;
2326
public readonly string function;
2427
public readonly uint lineNumber;
2528
public readonly Exception exception;
2629

27-
public SniError(SniProviders provider, uint nativeError, uint sniErrorCode, string errorMessage)
30+
public SniError(SniProviders provider, int nativeError, uint sniErrorCode, string errorMessage)
2831
{
2932
lineNumber = 0;
3033
function = string.Empty;
@@ -35,12 +38,25 @@ public SniError(SniProviders provider, uint nativeError, uint sniErrorCode, stri
3538
exception = null;
3639
}
3740

38-
public SniError(SniProviders provider, uint sniErrorCode, Exception sniException, uint nativeErrorCode = 0)
41+
public SniError(SniProviders provider, uint sniErrorCode, Exception sniException, int nativeErrorCode = 0)
3942
{
4043
lineNumber = 0;
4144
function = string.Empty;
4245
this.provider = provider;
4346
nativeError = nativeErrorCode;
47+
if (nativeErrorCode == 0)
48+
{
49+
if (sniException is SocketException socketException)
50+
{
51+
// SocketErrorCode values are cross-plat consistent in .NET (matching native Windows error codes)
52+
// underlying type of SocketErrorCode is int
53+
nativeError = (int)socketException.SocketErrorCode;
54+
}
55+
else if (sniException is Win32Exception win32Exception)
56+
{
57+
nativeError = win32Exception.NativeErrorCode; // Replicates native SNI behavior
58+
}
59+
}
4460
sniError = sniErrorCode;
4561
errorMessage = string.Empty;
4662
exception = sniException;

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ManagedSni/SniNpHandle.netcore.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ public override uint Receive(out SniPacket packet, int timeout)
203203
packet = null;
204204
var e = new Win32Exception();
205205
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniNpHandle), EventType.ERR, "Connection Id {0}, Packet length found 0, Win32 exception raised: {1}", args0: _connectionId, args1: e?.Message);
206-
return ReportErrorAndReleasePacket(errorPacket, (uint)e.NativeErrorCode, 0, e.Message);
206+
return ReportErrorAndReleasePacket(errorPacket, e.NativeErrorCode, 0, e.Message);
207207
}
208208
}
209209
catch (ObjectDisposedException ode)
@@ -413,7 +413,7 @@ private uint ReportErrorAndReleasePacket(SniPacket packet, Exception sniExceptio
413413
return SniCommon.ReportSNIError(SniProviders.NP_PROV, SniCommon.InternalExceptionError, sniException);
414414
}
415415

416-
private uint ReportErrorAndReleasePacket(SniPacket packet, uint nativeError, uint sniError, string errorMessage)
416+
private uint ReportErrorAndReleasePacket(SniPacket packet, int nativeError, uint sniError, string errorMessage)
417417
{
418418
if (packet != null)
419419
{

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ManagedSni/SniTcpHandle.netcore.cs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ private static Socket Connect(string serverName, int port, TimeoutTimer timeout,
375375

376376
IEnumerable<IPAddress> ipAddresses = GetHostAddressesSortedByPreference(serverName, ipPreference);
377377

378+
SocketException lastSocketException = null;
379+
378380
foreach (IPAddress ipAddress in ipAddresses)
379381
{
380382
bool isSocketSelected = false;
@@ -426,7 +428,7 @@ private static Socket Connect(string serverName, int port, TimeoutTimer timeout,
426428
{
427429
if (timeout.IsExpired)
428430
{
429-
return null;
431+
throw new Win32Exception(258, "The operation has timed out.");
430432
}
431433

432434
int socketSelectTimeout =
@@ -442,10 +444,24 @@ private static Socket Connect(string serverName, int port, TimeoutTimer timeout,
442444

443445
Socket.Select(checkReadLst, checkWriteLst, checkErrorLst, socketSelectTimeout);
444446
// nothing selected means timeout
447+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniTcpHandle), EventType.INFO,
448+
"Socket.Select results: checkReadLst.Count: {0}, checkWriteLst.Count: {1}, checkErrorLst.Count: {2}",
449+
checkReadLst.Count, checkWriteLst.Count, checkErrorLst.Count);
445450
} while (checkReadLst.Count == 0 && checkWriteLst.Count == 0 && checkErrorLst.Count == 0);
446451

447452
// workaround: false positive socket.Connected on linux: https://github.com/dotnet/runtime/issues/55538
448453
isConnected = socket.Connected && checkErrorLst.Count == 0;
454+
if (!isConnected)
455+
{
456+
// Retrieve the socket error code
457+
int socketErrorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
458+
SocketError socketError = (SocketError)socketErrorCode;
459+
460+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniTcpHandle), EventType.ERR,
461+
"Socket connection failed. SocketError: {0} ({1})", socketError, socketErrorCode);
462+
463+
lastSocketException = new SocketException(socketErrorCode);
464+
}
449465
}
450466

451467
if (isConnected)
@@ -463,6 +479,8 @@ private static Socket Connect(string serverName, int port, TimeoutTimer timeout,
463479
}
464480
pendingDNSInfo = new SQLDNSInfo(cachedFQDN, iPv4String, iPv6String, port.ToString());
465481
isSocketSelected = true;
482+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniTcpHandle), EventType.INFO,
483+
"Connected to socket: {0}", socket.RemoteEndPoint);
466484
return socket;
467485
}
468486
}
@@ -471,6 +489,7 @@ private static Socket Connect(string serverName, int port, TimeoutTimer timeout,
471489
SqlClientEventSource.Log.TryAdvancedTraceEvent(
472490
"{0}.{1}{2}THIS EXCEPTION IS BEING SWALLOWED: {3}",
473491
nameof(SniTcpHandle), nameof(Connect), EventType.ERR, e);
492+
lastSocketException = e;
474493
}
475494
finally
476495
{
@@ -479,6 +498,14 @@ private static Socket Connect(string serverName, int port, TimeoutTimer timeout,
479498
}
480499
}
481500

501+
if (lastSocketException != null)
502+
{
503+
SqlClientEventSource.Log.TryAdvancedTraceEvent(
504+
"{0}.{1}{2}Last Socket Exception: {3}",
505+
nameof(SniTcpHandle), nameof(Connect), EventType.ERR, lastSocketException);
506+
throw lastSocketException;
507+
}
508+
482509
return null;
483510
}
484511
}
@@ -574,6 +601,20 @@ private static Socket ParallelConnect(IPAddress[] serverAddresses, int port, Tim
574601
Socket.Select(checkReadLst, checkWriteLst, checkErrorLst, socketSelectTimeout);
575602
// nothing selected means select timed out
576603
} while (checkReadLst.Count == 0 && checkWriteLst.Count == 0 && checkErrorLst.Count == 0 && !timeout.IsExpired);
604+
foreach (Socket socket in checkErrorLst)
605+
{
606+
// Retrieve the socket error code
607+
int socketErrorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
608+
SocketError socketError = (SocketError)socketErrorCode;
609+
610+
// Log any failed sockets
611+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniTcpHandle), EventType.INFO,
612+
"Socket connection failed for {0}. SocketError: {1} ({2})",
613+
sockets[socket], socketError, socketErrorCode);
614+
615+
lastError = new SocketException(socketErrorCode);
616+
}
617+
577618
}
578619
catch (SocketException e)
579620
{
@@ -588,6 +629,7 @@ private static Socket ParallelConnect(IPAddress[] serverAddresses, int port, Tim
588629
{
589630
SqlClientEventSource.Log.TryAdvancedTraceEvent(
590631
"{0}.{1}{2}ParallelConnect timeout expired.", nameof(SniTcpHandle), nameof(ParallelConnect), EventType.INFO);
632+
// We will throw below after cleanup
591633
break;
592634
}
593635

@@ -654,9 +696,19 @@ private static Socket ParallelConnect(IPAddress[] serverAddresses, int port, Tim
654696

655697
if (connectedSocket == null)
656698
{
699+
if (timeout.IsExpired)
700+
{
701+
throw new Win32Exception(258, "The operation has timed out.");
702+
}
703+
657704
SqlClientEventSource.Log.TryAdvancedTraceEvent(
658-
"{0}.{1}{2}No socket connections succeeded. Last error: {3}",
705+
"{0}.{1}{2} No socket connections succeeded. Last error: {3}",
659706
nameof(SniTcpHandle), nameof(ParallelConnect), EventType.ERR, lastError);
707+
708+
if (lastError != null)
709+
{
710+
throw lastError;
711+
}
660712
}
661713

662714
return connectedSocket;
@@ -861,7 +913,7 @@ public override uint Receive(out SniPacket packet, int timeoutInMilliseconds)
861913
packet = null;
862914
var e = new Win32Exception();
863915
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniTcpHandle), EventType.ERR, "Connection Id {0}, Win32 exception occurred: {1}", args0: _connectionId, args1: e?.Message);
864-
return ReportErrorAndReleasePacket(errorPacket, (uint)e.NativeErrorCode, 0, e.Message);
916+
return ReportErrorAndReleasePacket(errorPacket, e.NativeErrorCode, 0, e.Message);
865917
}
866918

867919
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniTcpHandle), EventType.INFO, "Connection Id {0}, Data read from stream synchronously", args0: _connectionId);
@@ -992,13 +1044,13 @@ public override uint CheckConnection()
9921044
return TdsEnums.SNI_SUCCESS;
9931045
}
9941046

995-
private uint ReportTcpSNIError(Exception sniException, uint nativeErrorCode = 0)
1047+
private uint ReportTcpSNIError(Exception sniException, int nativeErrorCode = 0)
9961048
{
9971049
_status = TdsEnums.SNI_ERROR;
9981050
return SniCommon.ReportSNIError(SniProviders.TCP_PROV, SniCommon.InternalExceptionError, sniException, nativeErrorCode);
9991051
}
10001052

1001-
private uint ReportTcpSNIError(uint nativeError, uint sniError, string errorMessage)
1053+
private uint ReportTcpSNIError(int nativeError, uint sniError, string errorMessage)
10021054
{
10031055
_status = TdsEnums.SNI_ERROR;
10041056
return SniCommon.ReportSNIError(SniProviders.TCP_PROV, nativeError, sniError, errorMessage);
@@ -1013,7 +1065,7 @@ private uint ReportErrorAndReleasePacket(SniPacket packet, Exception sniExceptio
10131065
return ReportTcpSNIError(sniException);
10141066
}
10151067

1016-
private uint ReportErrorAndReleasePacket(SniPacket packet, uint nativeError, uint sniError, string errorMessage)
1068+
private uint ReportErrorAndReleasePacket(SniPacket packet, int nativeError, uint sniError, string errorMessage)
10171069
{
10181070
if (packet != null)
10191071
{

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ internal long TryScopeEnterEvent(string className, [System.Runtime.CompilerServi
424424
{
425425
StringBuilder sb = new StringBuilder(className);
426426
sb.Append(".").Append(memberName).Append(" | INFO | SCOPE | Entering Scope {0}");
427-
return SNIScopeEnter(sb.ToString());
427+
return ScopeEnter(sb.ToString());
428428
}
429429
return 0;
430430
}

0 commit comments

Comments
 (0)