private void ResolveExtendedServerName(ServerInfo serverInfo, bool aliasLookup, SqlConnectionString options) { if (serverInfo.ExtendedServerName == null) { string host = serverInfo.UserServerName; string protocol = serverInfo.UserProtocol; if (aliasLookup) { // We skip this for UserInstances... // Perform registry lookup to see if host is an alias. It will appropriately set host and protocol, if an Alias. // Check if it was already resolved, during CR reconnection _currentSessionData values will be copied from // _reconnectSessonData of the previous connection if (_currentSessionData != null && !string.IsNullOrEmpty(host)) { Tuple<string, string> hostPortPair; if (_currentSessionData._resolvedAliases.TryGetValue(host, out hostPortPair)) { host = hostPortPair.Item1; protocol = hostPortPair.Item2; } else { TdsParserStaticMethods.AliasRegistryLookup(ref host, ref protocol); _currentSessionData._resolvedAliases.Add(serverInfo.UserServerName, new Tuple<string, string>(host, protocol)); } } else { TdsParserStaticMethods.AliasRegistryLookup(ref host, ref protocol); } // if (options.EnforceLocalHost) { // verify LocalHost for |DataDirectory| usage SqlConnectionString.VerifyLocalHostAndFixup(ref host, true, true /*fix-up to "."*/); } } serverInfo.SetDerivedNames(protocol, host); } }
// Attempt to login to a host that does not have a failover partner // // Will repeatedly attempt to connect, but back off between each attempt so as not to clog the network. // Back off period increases for first few failures: 100ms, 200ms, 400ms, 800ms, then 1000ms for subsequent attempts // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // DEVNOTE: The logic in this method is paralleled by the logic in LoginWithFailover. // Changes to either one should be examined to see if they need to be reflected in the other // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! private void LoginNoFailover(ServerInfo serverInfo, string newPassword, SecureString newSecurePassword, bool redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout) { Debug.Assert(object.ReferenceEquals(connectionOptions, this.ConnectionOptions), "ConnectionOptions argument and property must be the same"); // consider removing the argument int routingAttempts = 0; ServerInfo originalServerInfo = serverInfo; // serverInfo may end up pointing to new object due to routing, original object is used to set CurrentDatasource if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover|ADV> %d#, host=%ls\n", ObjectID, serverInfo.UserServerName); } int sleepInterval = 100; //milliseconds to sleep (back off) between attempts. ResolveExtendedServerName(serverInfo, !redirectedUserInstance, connectionOptions); long timeoutUnitInterval = 0; Boolean isParallel = connectionOptions.MultiSubnetFailover || connectionOptions.TransparentNetworkIPResolution; if(isParallel) { // Determine unit interval if (timeout.IsInfinite) { timeoutUnitInterval = checked((long)(ADP.FailoverTimeoutStep * (1000L * ADP.DefaultConnectionTimeout))); } else { timeoutUnitInterval = checked((long)(ADP.FailoverTimeoutStep * timeout.MillisecondsRemaining)); } } // Only three ways out of this loop: // 1) Successfully connected // 2) Parser threw exception while main timer was expired // 3) Parser threw logon failure-related exception // 4) Parser threw exception in post-initial connect code, // such as pre-login handshake or during actual logon. (parser state != Closed) // // Of these methods, only #1 exits normally. This preserves the call stack on the exception // back into the parser for the error cases. int attemptNumber = 0; TimeoutTimer intervalTimer = null; TimeoutTimer firstTransparentAttemptTimeout = TimeoutTimer.StartMillisecondsTimeout(ADP.FirstTransparentAttemptTimeout); TimeoutTimer attemptOneLoginTimeout = timeout; while(true) { if(isParallel) { attemptNumber++; // Set timeout for this attempt, but don't exceed original timer long nextTimeoutInterval = checked(timeoutUnitInterval * attemptNumber); long milliseconds = timeout.MillisecondsRemaining; if (nextTimeoutInterval > milliseconds) { nextTimeoutInterval = milliseconds; } intervalTimer = TimeoutTimer.StartMillisecondsTimeout(nextTimeoutInterval); } // Re-allocate parser each time to make sure state is known // RFC 50002652 - if parser was created by previous attempt, dispose it to properly close the socket, if created if (_parser != null) _parser.Disconnect(); _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); Debug.Assert(SniContext.Undefined== Parser._physicalStateObj.SniContext, String.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); try { // Boolean isFirstTransparentAttempt = connectionOptions.TransparentNetworkIPResolution && attemptNumber == 1; if(isFirstTransparentAttempt) { attemptOneLoginTimeout = firstTransparentAttemptTimeout; } else { if(isParallel) { attemptOneLoginTimeout = intervalTimer; } } AttemptOneLogin( serverInfo, newPassword, newSecurePassword, !isParallel, // ignore timeout for SniOpen call unless MSF , and TNIR attemptOneLoginTimeout, isFirstTransparentAttempt:isFirstTransparentAttempt); if (connectionOptions.MultiSubnetFailover && null != ServerProvidedFailOverPartner) { // connection succeeded: trigger exception if server sends failover partner and MultiSubnetFailover is used. throw SQL.MultiSubnetFailoverWithFailoverPartner(serverProvidedFailoverPartner: true, internalConnection: this); } if (_routingInfo != null) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover> Routed to %ls", serverInfo.ExtendedServerName); if (routingAttempts > 0) { throw SQL.ROR_RecursiveRoutingNotSupported(this); } if (timeout.IsExpired) { throw SQL.ROR_TimeoutAfterRoutingInfo(this); } serverInfo = new ServerInfo(ConnectionOptions, _routingInfo, serverInfo.ResolvedServerName); timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.RoutingDestination); _originalClientConnectionId = _clientConnectionId; _routingDestination = serverInfo.UserServerName; // restore properties that could be changed by the environment tokens _currentPacketSize = ConnectionOptions.PacketSize; _currentLanguage = _originalLanguage = ConnectionOptions.CurrentLanguage; CurrentDatabase = _originalDatabase = ConnectionOptions.InitialCatalog; _currentFailoverPartner = null; _instanceName = String.Empty; routingAttempts++; continue; // repeat the loop, but skip code reserved for failed connections (after the catch) } else { break; // leave the while loop -- we've successfully connected } } catch (SqlException sqlex) { if (null == _parser || TdsParserState.Closed != _parser.State || IsDoNotRetryConnectError(sqlex) || timeout.IsExpired) { // no more time to try again throw; // Caller will call LoginFailure() } // Check sleep interval to make sure we won't exceed the timeout // Do this in the catch block so we can re-throw the current exception if (timeout.MillisecondsRemaining <= sleepInterval) { throw; } // } // We only get here when we failed to connect, but are going to re-try // Switch to failover logic if the server provided a partner if (null != ServerProvidedFailOverPartner) { if (connectionOptions.MultiSubnetFailover) { // connection failed: do not allow failover to server-provided failover partner if MultiSubnetFailover is set throw SQL.MultiSubnetFailoverWithFailoverPartner(serverProvidedFailoverPartner: true, internalConnection: this); } Debug.Assert(ConnectionOptions.ApplicationIntent != ApplicationIntent.ReadOnly, "FAILOVER+AppIntent=RO: Should already fail (at LOGSHIPNODE in OnEnvChange)"); timeoutErrorInternal.ResetAndRestartPhase(); timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Failover); timeoutErrorInternal.SetFailoverScenario(true); // this is a failover scenario LoginWithFailover( true, // start by using failover partner, since we already failed to connect to the primary serverInfo, ServerProvidedFailOverPartner, newPassword, newSecurePassword, redirectedUserInstance, connectionOptions, credential, timeout); return; // LoginWithFailover successfully connected and handled entire connection setup } // Sleep for a bit to prevent clogging the network with requests, // then update sleep interval for next iteration (max 1 second interval) if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover|ADV> %d#, sleeping %d{milisec}\n", ObjectID, sleepInterval); } Thread.Sleep(sleepInterval); sleepInterval = (sleepInterval < 500) ? sleepInterval * 2 : 1000; } if (null != PoolGroupProviderInfo) { // We must wait for CompleteLogin to finish for to have the // env change from the server to know its designated failover // partner; save this information in _currentFailoverPartner. PoolGroupProviderInfo.FailoverCheck(this, false, connectionOptions, ServerProvidedFailOverPartner); } CurrentDataSource = originalServerInfo.UserServerName; }
// Attempt to login to a host that has a failover partner // // Connection & timeout sequence is // First target, timeout = interval * 1 // second target, timeout = interval * 1 // sleep for 100ms // First target, timeout = interval * 2 // Second target, timeout = interval * 2 // sleep for 200ms // First Target, timeout = interval * 3 // etc. // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // DEVNOTE: The logic in this method is paralleled by the logic in LoginNoFailover. // Changes to either one should be examined to see if they need to be reflected in the other // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! private void LoginWithFailover( bool useFailoverHost, ServerInfo primaryServerInfo, string failoverHost, string newPassword, SecureString newSecurePassword, bool redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout ) { Debug.Assert(!connectionOptions.MultiSubnetFailover, "MultiSubnetFailover should not be set if failover partner is used"); if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover|ADV> %d#, useFailover=%d{bool}, primary=", ObjectID, useFailoverHost); Bid.PutStr(primaryServerInfo.UserServerName); Bid.PutStr(", failover="); Bid.PutStr(failoverHost); Bid.PutStr("\n"); } int sleepInterval = 100; //milliseconds to sleep (back off) between attempts. long timeoutUnitInterval; string protocol = ConnectionOptions.NetworkLibrary; ServerInfo failoverServerInfo = new ServerInfo(connectionOptions, failoverHost); ResolveExtendedServerName(primaryServerInfo, !redirectedUserInstance, connectionOptions); if (null == ServerProvidedFailOverPartner) {// No point in resolving the failover partner when we're going to override it below // Don't resolve aliases if failover == primary // ResolveExtendedServerName(failoverServerInfo, !redirectedUserInstance && failoverHost != primaryServerInfo.UserServerName, connectionOptions); } // Determine unit interval if (timeout.IsInfinite) { timeoutUnitInterval = checked((long) ADP.FailoverTimeoutStep * ADP.TimerFromSeconds(ADP.DefaultConnectionTimeout)); } else { timeoutUnitInterval = checked((long) (ADP.FailoverTimeoutStep * timeout.MillisecondsRemaining)); } // Initialize loop variables bool failoverDemandDone = false; // have we demanded for partner information yet (as necessary)? int attemptNumber = 0; // Only three ways out of this loop: // 1) Successfully connected // 2) Parser threw exception while main timer was expired // 3) Parser threw logon failure-related exception (LOGON_FAILED, PASSWORD_EXPIRED, etc) // // Of these methods, only #1 exits normally. This preserves the call stack on the exception // back into the parser for the error cases. while (true) { // Set timeout for this attempt, but don't exceed original timer long nextTimeoutInterval = checked(timeoutUnitInterval * ((attemptNumber / 2) + 1)); long milliseconds = timeout.MillisecondsRemaining; if (nextTimeoutInterval > milliseconds) { nextTimeoutInterval = milliseconds; } TimeoutTimer intervalTimer = TimeoutTimer.StartMillisecondsTimeout(nextTimeoutInterval); // Re-allocate parser each time to make sure state is known // RFC 50002652 - if parser was created by previous attempt, dispose it to properly close the socket, if created if (_parser != null) _parser.Disconnect(); _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); Debug.Assert(SniContext.Undefined== Parser._physicalStateObj.SniContext, String.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); ServerInfo currentServerInfo; if (useFailoverHost) { if (!failoverDemandDone) { FailoverPermissionDemand(); failoverDemandDone = true; } // Primary server may give us a different failover partner than the connection string indicates. Update it if (null != ServerProvidedFailOverPartner && failoverServerInfo.ResolvedServerName != ServerProvidedFailOverPartner) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover|ADV> %d#, new failover partner=%ls\n", ObjectID, ServerProvidedFailOverPartner); } failoverServerInfo.SetDerivedNames(protocol, ServerProvidedFailOverPartner); } currentServerInfo = failoverServerInfo; timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Failover); } else { currentServerInfo = primaryServerInfo; timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Principle); } try { // Attempt login. Use timerInterval for attempt timeout unless infinite timeout was requested. AttemptOneLogin( currentServerInfo, newPassword, newSecurePassword, false, // Use timeout in SniOpen intervalTimer, withFailover:true ); if (_routingInfo != null) { // We are in login with failover scenation and server sent routing information // If it is read-only routing - we did not supply AppIntent=RO (it should be checked before) // If it is something else, not known yet (future server) - this client is not designed to support this. // In any case, server should not have sent the routing info. Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover> Routed to %ls", _routingInfo.ServerName); throw SQL.ROR_UnexpectedRoutingInfo(this); } break; // leave the while loop -- we've successfully connected } catch (SqlException sqlex) { if (IsDoNotRetryConnectError(sqlex) || timeout.IsExpired) { // no more time to try again throw; // Caller will call LoginFailure() } if (IsConnectionDoomed) { throw; } if (1 == attemptNumber % 2) { // Check sleep interval to make sure we won't exceed the original timeout // Do this in the catch block so we can re-throw the current exception if (timeout.MillisecondsRemaining <= sleepInterval) { throw; } } // } // We only get here when we failed to connect, but are going to re-try // After trying to connect to both servers fails, sleep for a bit to prevent clogging // the network with requests, then update sleep interval for next iteration (max 1 second interval) if (1 == attemptNumber % 2) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover|ADV> %d#, sleeping %d{milisec}\n", ObjectID, sleepInterval); } Thread.Sleep(sleepInterval); sleepInterval = (sleepInterval < 500) ? sleepInterval * 2 : 1000; } // Update attempt number and target host attemptNumber++; useFailoverHost = !useFailoverHost; } // If we get here, connection/login succeeded! Just a few more checks & record-keeping // if connected to failover host, but said host doesn't have DbMirroring set up, throw an error if (useFailoverHost && null == ServerProvidedFailOverPartner) { throw SQL.InvalidPartnerConfiguration(failoverHost, CurrentDatabase); } if (null != PoolGroupProviderInfo) { // We must wait for CompleteLogin to finish for to have the // env change from the server to know its designated failover // partner; save this information in _currentFailoverPartner. PoolGroupProviderInfo.FailoverCheck(this, useFailoverHost, connectionOptions, ServerProvidedFailOverPartner); } CurrentDataSource = (useFailoverHost ? failoverHost : primaryServerInfo.UserServerName); }
private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, SecureString newSecurePassword) { // create a new login record SqlLogin login = new SqlLogin(); // gather all the settings the user set in the connection string or // properties and do the login CurrentDatabase = server.ResolvedDatabaseName; _currentPacketSize = ConnectionOptions.PacketSize; _currentLanguage = ConnectionOptions.CurrentLanguage; int timeoutInSeconds = 0; // If a timeout tick value is specified, compute the timeout based // upon the amount of time left in seconds. if (!timeout.IsInfinite) { long t = timeout.MillisecondsRemaining/1000; if ((long)Int32.MaxValue > t) { timeoutInSeconds = (int)t; } } login.authentication = ConnectionOptions.Authentication; login.timeout = timeoutInSeconds; login.userInstance = ConnectionOptions.UserInstance; login.hostName = ConnectionOptions.ObtainWorkstationId(); login.userName = ConnectionOptions.UserID; login.password = ConnectionOptions.Password; login.applicationName = ConnectionOptions.ApplicationName; login.language = _currentLanguage; if (!login.userInstance) { // Do not send attachdbfilename or database to SSE primary instance login.database = CurrentDatabase;; login.attachDBFilename = ConnectionOptions.AttachDBFilename; } // VSTS#795621 - Ensure ServerName is Sent During TdsLogin To Enable Sql Azure Connectivity. // Using server.UserServerName (versus ConnectionOptions.DataSource) since TdsLogin requires // serverName to always be non-null. login.serverName = server.UserServerName; login.useReplication = ConnectionOptions.Replication; login.useSSPI = ConnectionOptions.IntegratedSecurity || (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && !_fedAuthRequired); login.packetSize = _currentPacketSize; login.newPassword = newPassword; login.readOnlyIntent = ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly; login.credential = _credential; if (newSecurePassword != null) { login.newSecurePassword = newSecurePassword; } TdsEnums.FeatureExtension requestedFeatures = TdsEnums.FeatureExtension.None; if (ConnectionOptions.ConnectRetryCount>0) { requestedFeatures |= TdsEnums.FeatureExtension.SessionRecovery; _sessionRecoveryRequested = true; } // If the workflow being used is Active Directory Password or Active Directory Integrated and server's prelogin response // for FEDAUTHREQUIRED option indicates Federated Authentication is required, we have to insert FedAuth Feature Extension // in Login7, indicating the intent to use Active Directory Authentication Library for SQL Server. if (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryPassword || (ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _fedAuthRequired)) { requestedFeatures |= TdsEnums.FeatureExtension.FedAuth; _federatedAuthenticationInfoRequested = true; _fedAuthFeatureExtensionData = new FederatedAuthenticationFeatureExtensionData { libraryType = TdsEnums.FedAuthLibrary.ADAL, authentication = ConnectionOptions.Authentication, fedAuthRequiredPreLoginResponse = _fedAuthRequired }; } if (_accessTokenInBytes != null) { requestedFeatures |= TdsEnums.FeatureExtension.FedAuth; _fedAuthFeatureExtensionData = new FederatedAuthenticationFeatureExtensionData { libraryType = TdsEnums.FedAuthLibrary.SecurityToken, fedAuthRequiredPreLoginResponse = _fedAuthRequired, accessToken = _accessTokenInBytes }; // No need any further info from the server for token based authentication. So set _federatedAuthenticationRequested to true _federatedAuthenticationRequested = true; } // The TCE and GLOBALTRANSACTIONS feature are implicitly requested requestedFeatures |= TdsEnums.FeatureExtension.Tce | TdsEnums.FeatureExtension.GlobalTransactions; _parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData); }
private void OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, string newPassword, SecureString newSecurePassword, bool redirectedUserInstance) { bool useFailoverPartner; // should we use primary or secondary first ServerInfo dataSource = new ServerInfo(connectionOptions); string failoverPartner; if (null != PoolGroupProviderInfo) { useFailoverPartner = PoolGroupProviderInfo.UseFailoverPartner; failoverPartner = PoolGroupProviderInfo.FailoverPartner; } else { // Only ChangePassword or SSE User Instance comes through this code path. useFailoverPartner = false; failoverPartner = ConnectionOptions.FailoverPartner; } timeoutErrorInternal.SetInternalSourceType(useFailoverPartner ? SqlConnectionInternalSourceType.Failover : SqlConnectionInternalSourceType.Principle); bool hasFailoverPartner = !ADP.IsEmpty(failoverPartner); // Open the connection and Login try { timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); if (hasFailoverPartner) { timeoutErrorInternal.SetFailoverScenario(true); // this is a failover scenario LoginWithFailover( useFailoverPartner, dataSource, failoverPartner, newPassword, newSecurePassword, redirectedUserInstance, connectionOptions, credential, timeout); } else { timeoutErrorInternal.SetFailoverScenario(false); // not a failover scenario LoginNoFailover(dataSource, newPassword, newSecurePassword, redirectedUserInstance, connectionOptions, credential, timeout); } timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); } catch (Exception e) { // if (ADP.IsCatchableExceptionType(e)) { LoginFailure(); } throw; } timeoutErrorInternal.SetAllCompleteMarker(); #if DEBUG _parser._physicalStateObj.InvalidateDebugOnlyCopyOfSniContext(); #endif }
private void AttemptOneLogin(ServerInfo serverInfo, string newPassword, bool ignoreSniOpenTimeout, TimeoutTimer timeout, SqlConnection owningObject) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.AttemptOneLogin|ADV> %d#, timout=%I64d{msec}, server=", base.ObjectID, timeout.MillisecondsRemaining); Bid.PutStr(serverInfo.ExtendedServerName); Bid.Trace("\n"); } this._routingInfo = null; this._parser._physicalStateObj.SniContext = SniContext.Snix_Connect; this._parser.Connect(serverInfo, this, ignoreSniOpenTimeout, timeout.LegacyTimerExpire, base.ConnectionOptions.Encrypt, base.ConnectionOptions.TrustServerCertificate, base.ConnectionOptions.IntegratedSecurity); this._parser._physicalStateObj.SniContext = SniContext.Snix_Login; this.Login(serverInfo, timeout, newPassword); this.CompleteLogin(!base.ConnectionOptions.Pooling); }
private void Login(ServerInfo server, TimeoutTimer timeout) { // create a new login record SqlLogin login = new SqlLogin(); // gather all the settings the user set in the connection string or // properties and do the login CurrentDatabase = server.ResolvedDatabaseName; _currentPacketSize = ConnectionOptions.PacketSize; _currentLanguage = ConnectionOptions.CurrentLanguage; int timeoutInSeconds = 0; // If a timeout tick value is specified, compute the timeout based // upon the amount of time left in seconds. if (!timeout.IsInfinite) { long t = timeout.MillisecondsRemaining / 1000; if ((long)Int32.MaxValue > t) { timeoutInSeconds = (int)t; } } login.timeout = timeoutInSeconds; login.userInstance = ConnectionOptions.UserInstance; login.hostName = ConnectionOptions.ObtainWorkstationId(); login.userName = ConnectionOptions.UserID; login.password = ConnectionOptions.Password; login.applicationName = ConnectionOptions.ApplicationName; login.language = _currentLanguage; if (!login.userInstance) { // Do not send attachdbfilename or database to SSE primary instance login.database = CurrentDatabase; ; login.attachDBFilename = ConnectionOptions.AttachDBFilename; } // VSTS#795621 - Ensure ServerName is Sent During TdsLogin To Enable Sql Azure Connectivity. // Using server.UserServerName (versus ConnectionOptions.DataSource) since TdsLogin requires // serverName to always be non-null. login.serverName = server.UserServerName; login.useReplication = ConnectionOptions.Replication; login.useSSPI = ConnectionOptions.IntegratedSecurity; login.packetSize = _currentPacketSize; login.readOnlyIntent = ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly; TdsEnums.FeatureExtension requestedFeatures = TdsEnums.FeatureExtension.None; if (ConnectionOptions.ConnectRetryCount > 0) { requestedFeatures |= TdsEnums.FeatureExtension.SessionRecovery; _sessionRecoveryRequested = true; } _parser.TdsLogin(login, requestedFeatures, _recoverySessionData); }
internal void Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, bool ignoreSniOpenTimeout, long timerExpire, bool encrypt, bool trustServerCert, bool integratedSecurity, bool withFailover, bool isFirstTransparentAttempt, SqlAuthenticationMethod authType) { if (_state != TdsParserState.Closed) { Debug.Assert(false, "TdsParser.Connect called on non-closed connection!"); return; } _connHandler = connHandler; _loginWithFailover = withFailover; UInt32 sniStatus = SNILoadHandle.SingletonInstance.SNIStatus; if (sniStatus != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); _physicalStateObj.Dispose(); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } //Create LocalDB instance if necessary if (connHandler.ConnectionOptions.LocalDBInstance != null) LocalDBAPI.CreateLocalDBInstance(connHandler.ConnectionOptions.LocalDBInstance); if (integratedSecurity || authType == SqlAuthenticationMethod.ActiveDirectoryIntegrated) { LoadSSPILibrary(); // now allocate proper length of buffer _sniSpnBuffer = new byte[SNINativeMethodWrapper.SniMaxComposedSpnLength]; Bid.Trace("<sc.TdsParser.Connect|SEC> SSPI or Active Directory Authentication Library for SQL Server based integrated authentication\n"); } else { _sniSpnBuffer = null; if (authType == SqlAuthenticationMethod.ActiveDirectoryPassword) { Bid.Trace("<sc.TdsParser.Connect|SEC> Active Directory Password authentication\n"); } else if (authType == SqlAuthenticationMethod.SqlPassword) { Bid.Trace("<sc.TdsParser.Connect|SEC> SQL Password authentication\n"); } else{ Bid.Trace("<sc.TdsParser.Connect|SEC> SQL authentication\n"); } } byte[] instanceName = null; Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); bool fParallel = _connHandler.ConnectionOptions.MultiSubnetFailover; TransparentNetworkResolutionState transparentNetworkResolutionState; if(_connHandler.ConnectionOptions.TransparentNetworkIPResolution) { if(isFirstTransparentAttempt) transparentNetworkResolutionState = TransparentNetworkResolutionState.SequentialMode; else transparentNetworkResolutionState = TransparentNetworkResolutionState.ParallelMode; } else transparentNetworkResolutionState = TransparentNetworkResolutionState.DisabledMode; int totalTimeout = _connHandler.ConnectionOptions.ConnectTimeout; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, false, true, fParallel, transparentNetworkResolutionState, totalTimeout); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); // Since connect failed, free the unmanaged connection memory. // HOWEVER - only free this after the netlib error was processed - if you // don't, the memory for the connection object might not be accurate and thus // a bad error could be returned (as it was when it was freed to early for me). _physicalStateObj.Dispose(); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } _server = serverInfo.ResolvedServerName; if (null != connHandler.PoolGroupProviderInfo) { // If we are pooling, check to see if we were processing an // alias which has changed, which means we need to clean out // the pool. See Webdata 104293. // This should not apply to routing, as it is not an alias change, routed connection // should still use VNN of AlwaysOn cluster as server for pooling purposes. connHandler.PoolGroupProviderInfo.AliasCheck(serverInfo.PreRoutingServerName==null ? serverInfo.ResolvedServerName: serverInfo.PreRoutingServerName); } _state = TdsParserState.OpenNotLoggedIn; _physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; // SQL BU DT 376766 _physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); UInt32 result = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); // Bid.Trace("<sc.TdsParser.Connect|SEC> Sending prelogin handshake\n"); SendPreLoginHandshake(instanceName, encrypt); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); _physicalStateObj.SniContext = SniContext.Snix_PreLogin; Bid.Trace("<sc.TdsParser.Connect|SEC> Consuming prelogin handshake\n"); PreLoginHandshakeStatus status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, out marsCapable, out _connHandler._fedAuthRequired); if (status == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|SEC> Prelogin handshake unsuccessful. Reattempting prelogin handshake\n"); _physicalStateObj.Dispose(); // Close previous connection // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext=SniContext.Snix_Connect; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, true, true, fParallel, transparentNetworkResolutionState, totalTimeout); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); ThrowExceptionAndWarning(_physicalStateObj); } UInt32 retCode = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(retCode == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); Bid.Trace("<sc.TdsParser.Connect|SEC> Sending prelogin handshake\n"); SendPreLoginHandshake(instanceName, encrypt); status = ConsumePreLoginHandshake(authType, encrypt, trustServerCert, integratedSecurity, out marsCapable, out _connHandler._fedAuthRequired); // Don't need to check for Sphinx failure, since we've already consumed // one pre-login packet and know we are connecting to Shiloh. if (status == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Prelogin handshake unsuccessful. Login failure\n"); throw SQL.InstanceFailure(); } } Bid.Trace("<sc.TdsParser.Connect|SEC> Prelogin handshake successful\n"); if (_fMARS && marsCapable) { // if user explictly disables mars or mars not supported, don't create the session pool _sessionPool = new TdsParserSessionPool(this); } else { _fMARS = false; } if (authType == SqlAuthenticationMethod.ActiveDirectoryPassword || (authType == SqlAuthenticationMethod.ActiveDirectoryIntegrated && _connHandler._fedAuthRequired)) { Debug.Assert(!integratedSecurity, "The legacy Integrated Security connection string option cannot be true when using Active Directory Authentication Library for SQL Server Based workflows."); LoadADALLibrary(); if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.Connect|SEC> Active directory authentication.Loaded Active Directory Authentication Library for SQL Server\n"); } } return; }
private void ResolveExtendedServerName(ServerInfo serverInfo, bool aliasLookup, SqlConnectionString options) { if (serverInfo.ExtendedServerName == null) { string host = serverInfo.UserServerName; string protocol = serverInfo.UserProtocol; serverInfo.SetDerivedNames(protocol, host); } }
private void OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, string newPassword, bool redirectedUserInstance) { string failoverPartner; bool useFailoverPartner; ServerInfo primaryServerInfo = new ServerInfo(connectionOptions); if (this.PoolGroupProviderInfo != null) { useFailoverPartner = this.PoolGroupProviderInfo.UseFailoverPartner; failoverPartner = this.PoolGroupProviderInfo.FailoverPartner; } else { useFailoverPartner = false; failoverPartner = base.ConnectionOptions.FailoverPartner; } bool flag2 = !ADP.IsEmpty(failoverPartner); try { if (flag2) { this.LoginWithFailover(useFailoverPartner, primaryServerInfo, failoverPartner, newPassword, redirectedUserInstance, owningObject, connectionOptions, timeout); } else { this.LoginNoFailover(primaryServerInfo, newPassword, redirectedUserInstance, owningObject, connectionOptions, timeout); } } catch (Exception exception) { if (ADP.IsCatchableExceptionType(exception)) { this.LoginFailure(); } throw; } }
private void ResolveExtendedServerName(ServerInfo serverInfo, bool aliasLookup, SqlConnection owningObject) { if (serverInfo.ExtendedServerName == null) { string userServerName = serverInfo.UserServerName; string userProtocol = serverInfo.UserProtocol; if (aliasLookup) { TdsParserStaticMethods.AliasRegistryLookup(ref userServerName, ref userProtocol); if ((owningObject != null) && ((SqlConnectionString) owningObject.UserConnectionOptions).EnforceLocalHost) { SqlConnectionString.VerifyLocalHostAndFixup(ref userServerName, true, true); } } serverInfo.SetDerivedNames(userProtocol, userServerName); } }
private void LoginWithFailover(bool useFailoverHost, ServerInfo primaryServerInfo, string failoverHost, string newPassword, bool redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout) { long num5; if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover|ADV> %d#, useFailover=%d{bool}, primary=", base.ObjectID, useFailoverHost); Bid.PutStr(primaryServerInfo.UserServerName); Bid.PutStr(", failover="); Bid.PutStr(failoverHost); Bid.PutStr("\n"); } int num = 100; string networkLibrary = base.ConnectionOptions.NetworkLibrary; ServerInfo serverInfo = new ServerInfo(connectionOptions, failoverHost); this.ResolveExtendedServerName(primaryServerInfo, !redirectedUserInstance, owningObject); if (this.ServerProvidedFailOverPartner == null) { this.ResolveExtendedServerName(serverInfo, !redirectedUserInstance && (failoverHost != primaryServerInfo.UserServerName), owningObject); } if (timeout.IsInfinite) { ADP.TimerFromSeconds(15); num5 = 0L; } else { num5 = (long) (0.08f * timeout.MillisecondsRemaining); } bool flag = false; int num2 = 0; while (true) { ServerInfo info2; long milliseconds = num5 * ((num2 / 2) + 1); long millisecondsRemaining = timeout.MillisecondsRemaining; if (milliseconds > millisecondsRemaining) { milliseconds = millisecondsRemaining; } TimeoutTimer timer = TimeoutTimer.StartMillisecondsTimeout(milliseconds); if (this._parser != null) { this._parser.Disconnect(); } this._parser = new TdsParser(base.ConnectionOptions.MARS, base.ConnectionOptions.Asynchronous); if (useFailoverHost) { if (!flag) { this.FailoverPermissionDemand(); flag = true; } if ((this.ServerProvidedFailOverPartner != null) && (serverInfo.ResolvedServerName != this.ServerProvidedFailOverPartner)) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover|ADV> %d#, new failover partner=%ls\n", base.ObjectID, this.ServerProvidedFailOverPartner); } serverInfo.SetDerivedNames(networkLibrary, this.ServerProvidedFailOverPartner); } info2 = serverInfo; } else { info2 = primaryServerInfo; } try { this.AttemptOneLogin(info2, newPassword, false, timer, owningObject); if (this._routingInfo != null) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover> Routed to %ls", this._routingInfo.ServerName); throw SQL.ROR_UnexpectedRoutingInfo(); } break; } catch (SqlException exception) { if (this.IsDoNotRetryConnectError(exception) || timeout.IsExpired) { throw; } if (base.IsConnectionDoomed) { throw; } if ((1 == (num2 % 2)) && (timeout.MillisecondsRemaining <= num)) { throw; } } if (1 == (num2 % 2)) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginWithFailover|ADV> %d#, sleeping %d{milisec}\n", base.ObjectID, num); } Thread.Sleep(num); num = (num < 500) ? (num * 2) : 0x3e8; } num2++; useFailoverHost = !useFailoverHost; } if (useFailoverHost && (this.ServerProvidedFailOverPartner == null)) { throw SQL.InvalidPartnerConfiguration(failoverHost, base.CurrentDatabase); } if (this.PoolGroupProviderInfo != null) { this.PoolGroupProviderInfo.FailoverCheck(this, useFailoverHost, connectionOptions, this.ServerProvidedFailOverPartner); } base.CurrentDataSource = useFailoverHost ? failoverHost : primaryServerInfo.UserServerName; }
private void LoginNoFailover(ServerInfo serverInfo, string newPassword, bool redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout) { int num2 = 0; ServerInfo info = serverInfo; if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover|ADV> %d#, host=%ls\n", base.ObjectID, serverInfo.UserServerName); } int num = 100; this.ResolveExtendedServerName(serverInfo, !redirectedUserInstance, owningObject); Label_0032: if (this._parser != null) { this._parser.Disconnect(); } this._parser = new TdsParser(base.ConnectionOptions.MARS, base.ConnectionOptions.Asynchronous); try { this.AttemptOneLogin(serverInfo, newPassword, true, timeout, owningObject); if (connectionOptions.MultiSubnetFailover && (this.ServerProvidedFailOverPartner != null)) { bool serverProvidedFailoverPartner = true; throw SQL.MultiSubnetFailoverWithFailoverPartner(serverProvidedFailoverPartner); } if (this._routingInfo == null) { if (this.PoolGroupProviderInfo != null) { this.PoolGroupProviderInfo.FailoverCheck(this, false, connectionOptions, this.ServerProvidedFailOverPartner); } base.CurrentDataSource = info.UserServerName; return; } Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover> Routed to %ls", serverInfo.ExtendedServerName); if (num2 > 0) { throw SQL.ROR_RecursiveRoutingNotSupported(); } if (timeout.IsExpired) { throw SQL.ROR_TimeoutAfterRoutingInfo(); } serverInfo = new ServerInfo(base.ConnectionOptions, this._routingInfo, serverInfo.ResolvedServerName); this._currentPacketSize = base.ConnectionOptions.PacketSize; this._currentLanguage = this._originalLanguage = base.ConnectionOptions.CurrentLanguage; base.CurrentDatabase = this._originalDatabase = base.ConnectionOptions.InitialCatalog; this._currentFailoverPartner = null; this._instanceName = string.Empty; num2++; goto Label_0032; } catch (SqlException exception) { if (((this._parser == null) || (this._parser.State != TdsParserState.Closed)) || (this.IsDoNotRetryConnectError(exception) || timeout.IsExpired)) { throw; } if (timeout.MillisecondsRemaining <= num) { throw; } } if (this.ServerProvidedFailOverPartner != null) { if (connectionOptions.MultiSubnetFailover) { bool flag = true; throw SQL.MultiSubnetFailoverWithFailoverPartner(flag); } this.LoginWithFailover(true, serverInfo, this.ServerProvidedFailOverPartner, newPassword, redirectedUserInstance, owningObject, connectionOptions, timeout); } else { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover|ADV> %d#, sleeping %d{milisec}\n", base.ObjectID, num); } Thread.Sleep(num); num = (num < 500) ? (num * 2) : 0x3e8; goto Label_0032; } }
private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword) { SqlLogin rec = new SqlLogin(); base.CurrentDatabase = server.ResolvedDatabaseName; this._currentPacketSize = base.ConnectionOptions.PacketSize; this._currentLanguage = base.ConnectionOptions.CurrentLanguage; int num2 = 0; if (!timeout.IsInfinite) { long num = timeout.MillisecondsRemaining / 0x3e8L; if (0x7fffffffL > num) { num2 = (int) num; } } rec.timeout = num2; rec.userInstance = base.ConnectionOptions.UserInstance; rec.hostName = base.ConnectionOptions.ObtainWorkstationId(); rec.userName = base.ConnectionOptions.UserID; rec.password = base.ConnectionOptions.Password; rec.applicationName = base.ConnectionOptions.ApplicationName; rec.language = this._currentLanguage; if (!rec.userInstance) { rec.database = base.CurrentDatabase; rec.attachDBFilename = base.ConnectionOptions.AttachDBFilename; } rec.serverName = server.UserServerName; rec.useReplication = base.ConnectionOptions.Replication; rec.useSSPI = base.ConnectionOptions.IntegratedSecurity; rec.packetSize = this._currentPacketSize; rec.newPassword = newPassword; rec.readOnlyIntent = base.ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly; this._parser.TdsLogin(rec); }
// Common code path for making one attempt to establish a connection and log in to server. private void AttemptOneLogin(ServerInfo serverInfo, string newPassword, SecureString newSecurePassword, bool ignoreSniOpenTimeout, TimeoutTimer timeout, bool withFailover = false, bool isFirstTransparentAttempt = true) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.AttemptOneLogin|ADV> %d#, timout=%I64d{msec}, server=", ObjectID, timeout.MillisecondsRemaining); Bid.PutStr(serverInfo.ExtendedServerName); Bid.Trace("\n"); } _routingInfo = null; // forget routing information _parser._physicalStateObj.SniContext = SniContext.Snix_Connect; _parser.Connect(serverInfo, this, ignoreSniOpenTimeout, timeout.LegacyTimerExpire, ConnectionOptions.Encrypt, ConnectionOptions.TrustServerCertificate, ConnectionOptions.IntegratedSecurity, withFailover, isFirstTransparentAttempt, ConnectionOptions.Authentication); timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); _parser._physicalStateObj.SniContext = SniContext.Snix_Login; this.Login(serverInfo, timeout, newPassword, newSecurePassword); timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PostLogin); CompleteLogin(!ConnectionOptions.Pooling); timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); }
// Common code path for making one attempt to establish a connection and log in to server. private void AttemptOneLogin(ServerInfo serverInfo, bool ignoreSniOpenTimeout, TimeoutTimer timeout, bool withFailover = false) { _routingInfo = null; // forget routing information _parser._physicalStateObj.SniContext = SniContext.Snix_Connect; _parser.Connect(serverInfo, this, ignoreSniOpenTimeout, timeout.LegacyTimerExpire, ConnectionOptions.Encrypt, ConnectionOptions.TrustServerCertificate, ConnectionOptions.IntegratedSecurity, withFailover); _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); _timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); _parser._physicalStateObj.SniContext = SniContext.Snix_Login; this.Login(serverInfo, timeout); _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); _timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PostLogin); CompleteLogin(!ConnectionOptions.Pooling); _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); }
internal void Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, bool ignoreSniOpenTimeout, long timerExpire, bool encrypt, bool trustServerCert, bool integratedSecurity, bool withFailover) { if (_state != TdsParserState.Closed) { Debug.Assert(false, "TdsParser.Connect called on non-closed connection!"); return; } _connHandler = connHandler; _loginWithFailover = withFailover; UInt32 sniStatus = SNILoadHandle.SingletonInstance.SNIStatus; if (sniStatus != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); _physicalStateObj.Dispose(); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } if (integratedSecurity) { LoadSSPILibrary(); // now allocate proper length of buffer _sniSpnBuffer = new byte[SNINativeMethodWrapper.SniMaxComposedSpnLength]; } else { _sniSpnBuffer = null; } byte[] instanceName = null; Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); bool fParallel = _connHandler.ConnectionOptions.MultiSubnetFailover; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, false, true, fParallel); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); // Since connect failed, free the unmanaged connection memory. // HOWEVER - only free this after the netlib error was processed - if you // don't, the memory for the connection object might not be accurate and thus // a bad error could be returned (as it was when it was freed to early for me). _physicalStateObj.Dispose(); ThrowExceptionAndWarning(_physicalStateObj); Debug.Assert(false, "SNI returned status != success, but no error thrown?"); } _server = serverInfo.ResolvedServerName; if (null != connHandler.PoolGroupProviderInfo) { // If we are pooling, check to see if we were processing an // alias which has changed, which means we need to clean out // the pool. See Webdata 104293. // This should not apply to routing, as it is not an alias change, routed connection // should still use VNN of AlwaysOn cluster as server for pooling purposes. connHandler.PoolGroupProviderInfo.AliasCheck(serverInfo.PreRoutingServerName == null ? serverInfo.ResolvedServerName : serverInfo.PreRoutingServerName); } _state = TdsParserState.OpenNotLoggedIn; _physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; _physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.InitializeConnection); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); UInt32 result = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); SendPreLoginHandshake(instanceName, encrypt); _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.SendPreLoginHandshake); _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); _physicalStateObj.SniContext = SniContext.Snix_PreLogin; PreLoginHandshakeStatus status = ConsumePreLoginHandshake(encrypt, trustServerCert, integratedSecurity, out marsCapable); if (status == PreLoginHandshakeStatus.InstanceFailure) { _physicalStateObj.Dispose(); // Close previous connection // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext = SniContext.Snix_Connect; _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, _sniSpnBuffer, true, true, fParallel); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); ThrowExceptionAndWarning(_physicalStateObj); } UInt32 retCode = SNINativeMethodWrapper.SniGetConnectionId(_physicalStateObj.Handle, ref _connHandler._clientConnectionId); Debug.Assert(retCode == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionId"); SendPreLoginHandshake(instanceName, encrypt); status = ConsumePreLoginHandshake(encrypt, trustServerCert, integratedSecurity, out marsCapable); // Don't need to check for Sphinx failure, since we've already consumed // one pre-login packet and know we are connecting to Shiloh. if (status == PreLoginHandshakeStatus.InstanceFailure) { throw SQL.InstanceFailure(); } } if (_fMARS && marsCapable) { // if user explictly disables mars or mars not supported, don't create the session pool _sessionPool = new TdsParserSessionPool(this); } else { _fMARS = false; } return; }
internal void Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, bool ignoreSniOpenTimeout, long timerExpire, bool encrypt, bool trustServerCert, bool integratedSecurity) { if (this._state == TdsParserState.Closed) { this._connHandler = connHandler; if (SNILoadHandle.SingletonInstance.SNIStatus != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); this._physicalStateObj.Dispose(); this.ThrowExceptionAndWarning(); } if (connHandler.ConnectionOptions.LocalDBInstance != null) { LocalDBAPI.CreateLocalDBInstance(connHandler.ConnectionOptions.LocalDBInstance); } if (integratedSecurity) { this.LoadSSPILibrary(); this._sniSpnBuffer = new byte[SNINativeMethodWrapper.SniMaxComposedSpnLength]; Bid.Trace("<sc.TdsParser.Connect|SEC> SSPI authentication\n"); } else { this._sniSpnBuffer = null; Bid.Trace("<sc.TdsParser.Connect|SEC> SQL authentication\n"); } byte[] instanceName = null; bool multiSubnetFailover = this._connHandler.ConnectionOptions.MultiSubnetFailover; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, this._sniSpnBuffer, false, this._fAsync, multiSubnetFailover); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); this._physicalStateObj.Dispose(); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } this._server = serverInfo.ResolvedServerName; if (connHandler.PoolGroupProviderInfo != null) { connHandler.PoolGroupProviderInfo.AliasCheck((serverInfo.PreRoutingServerName == null) ? serverInfo.ResolvedServerName : serverInfo.PreRoutingServerName); } this._state = TdsParserState.OpenNotLoggedIn; this._physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; this._physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; this.SendPreLoginHandshake(instanceName, encrypt); this._physicalStateObj.SniContext = SniContext.Snix_PreLogin; switch (this.ConsumePreLoginHandshake(encrypt, trustServerCert, out marsCapable)) { case PreLoginHandshakeStatus.SphinxFailure: this._fMARS = false; this._physicalStateObj._sniPacket = null; this._physicalStateObj.SniContext = SniContext.Snix_Connect; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, this._sniSpnBuffer, false, this._fAsync, multiSubnetFailover); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } break; case PreLoginHandshakeStatus.InstanceFailure: this._physicalStateObj.Dispose(); this._physicalStateObj.SniContext = SniContext.Snix_Connect; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, this._sniSpnBuffer, true, this._fAsync, multiSubnetFailover); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } this.SendPreLoginHandshake(instanceName, encrypt); if (this.ConsumePreLoginHandshake(encrypt, trustServerCert, out marsCapable) == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); throw SQL.InstanceFailure(); } break; } if (this._fMARS && marsCapable) { this._sessionPool = new TdsParserSessionPool(this); } else { this._fMARS = false; } } }