Skip to content

Commit

Permalink
[Release 2.1] Fix missing error messages in Managed SNI (#883)
Browse files Browse the repository at this point in the history
  • Loading branch information
cheenamalhotra committed Jan 18, 2021
1 parent 57fa416 commit c20d6cd
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 36 deletions.
Expand Up @@ -88,6 +88,25 @@ internal static uint MapLocalDBErrorStateToCode(LocalDBErrorState errorState)
}
}

internal static string MapLocalDBErrorStateToErrorMessage(LocalDBErrorState errorState)
{
switch (errorState)
{
case LocalDBErrorState.NO_INSTALLATION:
return Strings.SNI_ERROR_52;
case LocalDBErrorState.INVALID_CONFIG:
return Strings.SNI_ERROR_53;
case LocalDBErrorState.NO_SQLUSERINSTANCEDLL_PATH:
return Strings.SNI_ERROR_54;
case LocalDBErrorState.INVALID_SQLUSERINSTANCEDLL_PATH:
return Strings.SNI_ERROR_55;
case LocalDBErrorState.NONE:
return Strings.SNI_ERROR_50;
default:
return Strings.SNI_ERROR_53;
}
}

/// <summary>
/// Loads the User Instance dll.
/// </summary>
Expand Down Expand Up @@ -117,15 +136,15 @@ private bool LoadUserInstanceDll()
// If there was no DLL path found, then there is an error.
if (dllPath == null)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, MapLocalDBErrorStateToCode(registryQueryErrorState), string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, MapLocalDBErrorStateToCode(registryQueryErrorState), MapLocalDBErrorStateToErrorMessage(registryQueryErrorState));
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.LocalDB.Windows.LoadUserInstanceDll |SNI|ERR >User instance DLL path is null.");
return false;
}

// In case the registry had an empty path for dll
if (string.IsNullOrWhiteSpace(dllPath))
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBInvalidSqlUserInstanceDllPath, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBInvalidSqlUserInstanceDllPath, Strings.SNI_ERROR_55);
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.LocalDB.Windows.LoadUserInstanceDll |SNI|ERR > User instance DLL path is invalid. DLL path ={0}", dllPath);
return false;
}
Expand All @@ -135,7 +154,7 @@ private bool LoadUserInstanceDll()

if (libraryHandle.IsInvalid)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBFailedToLoadDll, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBFailedToLoadDll, Strings.SNI_ERROR_56);
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.LocalDB.Windows.LoadUserInstanceDll |SNI|ERR > Library Handle is invalid. Could not load the dll.");
libraryHandle.Dispose();
return false;
Expand All @@ -146,7 +165,7 @@ private bool LoadUserInstanceDll()

if (_startInstanceHandle == IntPtr.Zero)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBBadRuntime, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBBadRuntime, Strings.SNI_ERROR_57);
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.LocalDB.Windows.LoadUserInstanceDll |SNI|ERR > Was not able to load the PROC from DLL. Bad Runtime.");
libraryHandle.Dispose();
return false;
Expand All @@ -157,7 +176,7 @@ private bool LoadUserInstanceDll()

if (localDBStartInstanceFunc == null)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBBadRuntime, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBBadRuntime, Strings.SNI_ERROR_57);
libraryHandle.Dispose();
_startInstanceHandle = IntPtr.Zero;
return false;
Expand Down
Expand Up @@ -75,7 +75,7 @@ public uint StartReceive()
return TdsEnums.SNI_SUCCESS_IO_PENDING;
}
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.SNIMarsConnection.StartReceive |SNI|ERR> Connection not useable.");
return SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnNotUsableError, string.Empty);
return SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnNotUsableError, Strings.SNI_ERROR_19);
}
finally
{
Expand Down Expand Up @@ -293,7 +293,7 @@ public void HandleReceiveComplete(SNIPacket packet, uint sniErrorCode)

if (!_sessions.ContainsKey(_currentHeader.sessionId))
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, Strings.SNI_ERROR_5);
HandleReceiveError(packet);
_lowerHandle.Dispose();
_lowerHandle = null;
Expand Down
Expand Up @@ -530,7 +530,7 @@ public override uint Receive(out SNIPacket packet, int timeoutInMilliseconds)

if (!_packetEvent.Wait(timeoutInMilliseconds))
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnTimeoutError, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnTimeoutError, Strings.SNI_ERROR_11);
return TdsEnums.SNI_WAIT_TIMEOUT;
}
}
Expand Down
Expand Up @@ -22,7 +22,6 @@ internal sealed class SNINpHandle : SNIPhysicalHandle
private const int MAX_PIPE_INSTANCES = 255;

private readonly string _targetServer;
private readonly object _callbackObject;
private readonly object _sendSync;

private Stream _stream;
Expand All @@ -38,15 +37,14 @@ internal sealed class SNINpHandle : SNIPhysicalHandle
private int _bufferSize = TdsEnums.DEFAULT_LOGIN_PACKET_SIZE;
private readonly Guid _connectionId = Guid.NewGuid();

public SNINpHandle(string serverName, string pipeName, long timerExpire, object callbackObject)
public SNINpHandle(string serverName, string pipeName, long timerExpire)
{
long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent("<sc.SNI.SNINpHandle.SNINpHandle |SNI|INFO|SCOPE> Constructor");
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.SNINpHandle.SNINpHandle |SNI|INFO> Constructor. server name = {0}, pipe name = {1}", serverName, pipeName);
try
{
_sendSync = new object();
_targetServer = serverName;
_callbackObject = callbackObject;

try
{
Expand Down Expand Up @@ -86,7 +84,7 @@ public SNINpHandle(string serverName, string pipeName, long timerExpire, object

if (!_pipeStream.IsConnected || !_pipeStream.CanWrite || !_pipeStream.CanRead)
{
SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.ConnOpenFailedError, string.Empty);
SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.ConnOpenFailedError, Strings.SNI_ERROR_40);
_status = TdsEnums.SNI_ERROR;
SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.SNINpHandle.SNINpHandle |SNI|ERR> Pipe stream is not connected or cannot write or read to/from it.");
return;
Expand Down
Expand Up @@ -278,7 +278,7 @@ private void ReadFromStreamAsyncContinuation(Task<int> t, object state)

if (_dataLength == 0)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.ConnTerminatedError, Strings.SNI_ERROR_2);
error = true;
}
}
Expand Down
Expand Up @@ -241,7 +241,6 @@ internal uint WritePacket(SNIHandle handle, SNIPacket packet, bool sync)
/// <summary>
/// Create a SNI connection handle
/// </summary>
/// <param name="callbackObject">Asynchronous I/O callback object</param>
/// <param name="fullServerName">Full server name from connection string</param>
/// <param name="ignoreSniOpenTimeout">Ignore open timeout</param>
/// <param name="timerExpire">Timer expiration</param>
Expand All @@ -254,7 +253,7 @@ internal uint WritePacket(SNIHandle handle, SNIPacket packet, bool sync)
/// <param name="cachedFQDN">Used for DNS Cache</param>
/// <param name="pendingDNSInfo">Used for DNS Cache</param>
/// <returns>SNI handle</returns>
internal SNIHandle CreateConnectionHandle(object callbackObject, string fullServerName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, ref byte[] spnBuffer, bool flushCache, bool async, bool parallel, bool isIntegratedSecurity, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo)
internal SNIHandle CreateConnectionHandle(string fullServerName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, ref byte[] spnBuffer, bool flushCache, bool async, bool parallel, bool isIntegratedSecurity, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo)
{
instanceName = new byte[1];

Expand All @@ -281,10 +280,10 @@ internal SNIHandle CreateConnectionHandle(object callbackObject, string fullServ
case DataSource.Protocol.Admin:
case DataSource.Protocol.None: // default to using tcp if no protocol is provided
case DataSource.Protocol.TCP:
sniHandle = CreateTcpHandle(details, timerExpire, callbackObject, parallel, cachedFQDN, ref pendingDNSInfo);
sniHandle = CreateTcpHandle(details, timerExpire, parallel, cachedFQDN, ref pendingDNSInfo);
break;
case DataSource.Protocol.NP:
sniHandle = CreateNpHandle(details, timerExpire, callbackObject, parallel);
sniHandle = CreateNpHandle(details, timerExpire, parallel);
break;
default:
Debug.Fail($"Unexpected connection protocol: {details._connectionProtocol}");
Expand Down Expand Up @@ -365,12 +364,11 @@ private static byte[] GetSqlServerSPN(string hostNameOrAddress, string portOrIns
/// </summary>
/// <param name="details">Data source</param>
/// <param name="timerExpire">Timer expiration</param>
/// <param name="callbackObject">Asynchronous I/O callback object</param>
/// <param name="parallel">Should MultiSubnetFailover be used</param>
/// <param name="cachedFQDN">Key for DNS Cache</param>
/// <param name="pendingDNSInfo">Used for DNS Cache</param>
/// <returns>SNITCPHandle</returns>
private SNITCPHandle CreateTcpHandle(DataSource details, long timerExpire, object callbackObject, bool parallel, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo)
private SNITCPHandle CreateTcpHandle(DataSource details, long timerExpire, bool parallel, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo)
{
// TCP Format:
// tcp:<host name>\<instance name>
Expand All @@ -379,7 +377,7 @@ private SNITCPHandle CreateTcpHandle(DataSource details, long timerExpire, objec
string hostName = details.ServerName;
if (string.IsNullOrWhiteSpace(hostName))
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, 0, SNICommon.InvalidConnStringError, Strings.SNI_ERROR_25);
return null;
}

Expand Down Expand Up @@ -408,7 +406,7 @@ private SNITCPHandle CreateTcpHandle(DataSource details, long timerExpire, objec
port = isAdminConnection ? DefaultSqlServerDacPort : DefaultSqlServerPort;
}

return new SNITCPHandle(hostName, port, timerExpire, callbackObject, parallel, cachedFQDN, ref pendingDNSInfo);
return new SNITCPHandle(hostName, port, timerExpire, parallel, cachedFQDN, ref pendingDNSInfo);
}


Expand All @@ -418,17 +416,17 @@ private SNITCPHandle CreateTcpHandle(DataSource details, long timerExpire, objec
/// </summary>
/// <param name="details">Data source</param>
/// <param name="timerExpire">Timer expiration</param>
/// <param name="callbackObject">Asynchronous I/O callback object</param>
/// <param name="parallel">Should MultiSubnetFailover be used. Only returns an error for named pipes.</param>
/// <returns>SNINpHandle</returns>
private SNINpHandle CreateNpHandle(DataSource details, long timerExpire, object callbackObject, bool parallel)
private SNINpHandle CreateNpHandle(DataSource details, long timerExpire, bool parallel)
{
if (parallel)
{
SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, string.Empty);
// Connecting to a SQL Server instance using the MultiSubnetFailover connection option is only supported when using the TCP protocol
SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, Strings.SNI_ERROR_49);
return null;
}
return new SNINpHandle(details.PipeHostName, details.PipeName, timerExpire, callbackObject);
return new SNINpHandle(details.PipeHostName, details.PipeName, timerExpire);
}

/// <summary>
Expand Down Expand Up @@ -632,7 +630,7 @@ internal static string GetLocalDBInstance(string dataSource, out bool error)
}
else
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBNoInstanceName, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBNoInstanceName, Strings.SNI_ERROR_51);
error = true;
return null;
}
Expand Down Expand Up @@ -758,7 +756,7 @@ private bool InferConnectionDetails()

private void ReportSNIError(SNIProviders provider)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, 0, SNICommon.InvalidConnStringError, string.Empty);
SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, 0, SNICommon.InvalidConnStringError, Strings.SNI_ERROR_25);
IsBadDataSource = true;
}

Expand Down
Expand Up @@ -23,7 +23,6 @@ namespace Microsoft.Data.SqlClient.SNI
internal sealed class SNITCPHandle : SNIPhysicalHandle
{
private readonly string _targetServer;
private readonly object _callbackObject;
private readonly object _sendSync;
private readonly Socket _socket;
private NetworkStream _tcpStream;
Expand Down Expand Up @@ -114,13 +113,11 @@ public override int ProtocolVersion
/// <param name="serverName">Server name</param>
/// <param name="port">TCP port number</param>
/// <param name="timerExpire">Connection timer expiration</param>
/// <param name="callbackObject">Callback object</param>
/// <param name="parallel">Parallel executions</param>
/// <param name="cachedFQDN">Key for DNS Cache</param>
/// <param name="pendingDNSInfo">Used for DNS Cache</param>
public SNITCPHandle(string serverName, int port, long timerExpire, object callbackObject, bool parallel, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo)
public SNITCPHandle(string serverName, int port, long timerExpire, bool parallel, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo)
{
_callbackObject = callbackObject;
_targetServer = serverName;
_sendSync = new object();

Expand Down Expand Up @@ -217,7 +214,7 @@ public SNITCPHandle(string serverName, int port, long timerExpire, object callba

if (reportError)
{
ReportTcpSNIError(0, SNICommon.ConnOpenFailedError, string.Empty);
ReportTcpSNIError(0, SNICommon.ConnOpenFailedError, Strings.SNI_ERROR_40);
}
return;
}
Expand Down Expand Up @@ -259,7 +256,7 @@ private Socket TryConnectParallel(string hostName, int port, TimeSpan ts, bool i
{
// Fail if above 64 to match legacy behavior
callerReportError = false;
ReportTcpSNIError(0, SNICommon.MultiSubnetFailoverWithMoreThan64IPs, string.Empty);
ReportTcpSNIError(0, SNICommon.MultiSubnetFailoverWithMoreThan64IPs, Strings.SNI_ERROR_47);
return availableSocket;
}

Expand Down Expand Up @@ -288,7 +285,7 @@ private Socket TryConnectParallel(string hostName, int port, TimeSpan ts, bool i
if (!(isInfiniteTimeOut ? connectTask.Wait(-1) : connectTask.Wait(ts)))
{
callerReportError = false;
ReportTcpSNIError(0, SNICommon.ConnOpenFailedError, string.Empty);
ReportTcpSNIError(0, SNICommon.ConnOpenFailedError, Strings.SNI_ERROR_40);
return availableSocket;
}

Expand Down Expand Up @@ -644,7 +641,7 @@ public override uint Receive(out SNIPacket packet, int timeoutInMilliseconds)
else
{
// otherwise it is timeout for 0 or less than -1
ReportTcpSNIError(0, SNICommon.ConnTimeoutError, string.Empty);
ReportTcpSNIError(0, SNICommon.ConnTimeoutError, Strings.SNI_ERROR_11);
return TdsEnums.SNI_WAIT_TIMEOUT;
}

Expand Down
Expand Up @@ -51,7 +51,7 @@ protected override uint SNIPacketGetData(PacketHandle packet, byte[] _inBuff, re

internal override void CreatePhysicalSNIHandle(string serverName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, ref byte[] spnBuffer, bool flushCache, bool async, bool parallel, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo, bool isIntegratedSecurity)
{
_sessionHandle = SNIProxy.GetInstance().CreateConnectionHandle(this, serverName, ignoreSniOpenTimeout, timerExpire, out instanceName, ref spnBuffer, flushCache, async, parallel, isIntegratedSecurity, cachedFQDN, ref pendingDNSInfo);
_sessionHandle = SNIProxy.GetInstance().CreateConnectionHandle(serverName, ignoreSniOpenTimeout, timerExpire, out instanceName, ref spnBuffer, flushCache, async, parallel, isIntegratedSecurity, cachedFQDN, ref pendingDNSInfo);
if (_sessionHandle == null)
{
_parser.ProcessSNIError(this);
Expand Down

0 comments on commit c20d6cd

Please sign in to comment.