internal static TimeoutTimer StartSecondsTimeout(int seconds) { TimeoutTimer timer = new TimeoutTimer(); timer.SetTimeoutSeconds(seconds); return(timer); }
//------------------- // Timeout-setting methods //------------------- // Get a new timer that will expire in the given number of seconds // For input, a value of zero seconds indicates infinite timeout internal static TimeoutTimer StartSecondsTimeout(int seconds) { //-------------------- // Preconditions: None (seconds must conform to SetTimeoutSeconds requirements) //-------------------- // Method body var timeout = new TimeoutTimer(); timeout.SetTimeoutSeconds(seconds); //--------------------- // Postconditions Debug.Assert(timeout != null); // Need a valid timeouttimer if no error return timeout; }
//------------------- // Timeout-setting methods //------------------- // Get a new timer that will expire in the given number of seconds // For input, a value of zero seconds indicates infinite timeout internal static TimeoutTimer StartSecondsTimeout(int seconds) { //-------------------- // Preconditions: None (seconds must conform to SetTimeoutSeconds requirements) //-------------------- // Method body var timeout = new TimeoutTimer(); timeout.SetTimeoutSeconds(seconds); //--------------------- // Postconditions Debug.Assert(timeout != null); // Need a valid timeouttimer if no error return(timeout); }
// Get a new timer that will expire in the given number of milliseconds // No current need to support infinite milliseconds timeout internal static TimeoutTimer StartMillisecondsTimeout(long milliseconds) { //-------------------- // Preconditions Debug.Assert(0 <= milliseconds); //-------------------- // Method body var timeout = new TimeoutTimer(); timeout._timerExpire = checked(ADP.TimerCurrent() + (milliseconds * TimeSpan.TicksPerMillisecond)); timeout._isInfiniteTimeout = false; //--------------------- // Postconditions Debug.Assert(timeout != null); // Need a valid timeouttimer if no error return timeout; }
// Get a new timer that will expire in the given number of milliseconds // No current need to support infinite milliseconds timeout internal static TimeoutTimer StartMillisecondsTimeout(long milliseconds) { //-------------------- // Preconditions Debug.Assert(0 <= milliseconds); //-------------------- // Method body var timeout = new TimeoutTimer(); timeout._timerExpire = checked (ADP.TimerCurrent() + (milliseconds * TimeSpan.TicksPerMillisecond)); timeout._isInfiniteTimeout = false; //--------------------- // Postconditions Debug.Assert(timeout != null); // Need a valid timeouttimer if no error return(timeout); }
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 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; } }
// 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); }
// although the new password is generally not used it must be passed to the c'tor // the new Login7 packet will always write out the new password (or a length of zero and no bytes if not present) // internal SqlInternalConnectionTds( DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, object providerInfo, string newPassword, SecureString newSecurePassword, bool redirectedUserInstance, SqlConnectionString userConnectionOptions = null, // NOTE: userConnectionOptions may be different to connectionOptions if the connection string has been expanded (see SqlConnectionString.Expand) SessionData reconnectSessionData = null, DbConnectionPool pool = null, string accessToken = null, bool applyTransientFaultHandling = false ) : base(connectionOptions) { #if DEBUG if (reconnectSessionData != null) { reconnectSessionData._debugReconnectDataApplied = true; } try { // use this to help validate this object is only created after the following permission has been previously demanded in the current codepath if (userConnectionOptions != null) { // As mentioned above, userConnectionOptions may be different to connectionOptions, so we need to demand on the correct connection string userConnectionOptions.DemandPermission(); } else { connectionOptions.DemandPermission(); } } catch(System.Security.SecurityException) { System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath"); throw; } #endif Debug.Assert(reconnectSessionData == null || connectionOptions.ConnectRetryCount > 0, "Reconnect data supplied with CR turned off"); _dbConnectionPool = pool; if (connectionOptions.ConnectRetryCount > 0) { _recoverySessionData = reconnectSessionData; if (reconnectSessionData == null) { _currentSessionData = new SessionData(); } else { _currentSessionData = new SessionData(_recoverySessionData); _originalDatabase = _recoverySessionData._initialDatabase; _originalLanguage = _recoverySessionData._initialLanguage; } } if (connectionOptions.UserInstance && InOutOfProcHelper.InProc) { throw SQL.UserInstanceNotAvailableInProc(); } if (accessToken != null) { _accessTokenInBytes = System.Text.Encoding.Unicode.GetBytes(accessToken); } _identity = identity; Debug.Assert(newSecurePassword != null || newPassword != null, "cannot have both new secure change password and string based change password to be null"); Debug.Assert(credential == null || (String.IsNullOrEmpty(connectionOptions.UserID) && String.IsNullOrEmpty(connectionOptions.Password)), "cannot mix the new secure password system and the connection string based password"); Debug.Assert(credential == null || !connectionOptions.IntegratedSecurity, "Cannot use SqlCredential and Integrated Security"); Debug.Assert(credential == null || !connectionOptions.ContextConnection, "Cannot use SqlCredential with context connection"); _poolGroupProviderInfo = (SqlConnectionPoolGroupProviderInfo)providerInfo; _fResetConnection = connectionOptions.ConnectionReset; if (_fResetConnection && _recoverySessionData == null) { _originalDatabase = connectionOptions.InitialCatalog; _originalLanguage = connectionOptions.CurrentLanguage; } timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal(); _credential = credential; _parserLock.Wait(canReleaseFromAnyThread:false); ThreadHasParserLockForClose = true; // In case of error, let ourselves know that we already own the parser lock RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG _timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); // If transient fault handling is enabled then we can retry the login upto the ConnectRetryCount. int connectionEstablishCount = applyTransientFaultHandling ? connectionOptions.ConnectRetryCount + 1 : 1; int transientRetryIntervalInMilliSeconds = connectionOptions.ConnectRetryInterval * 1000; // Max value of transientRetryInterval is 60*1000 ms. The max value allowed for ConnectRetryInterval is 60 for (int i = 0; i < connectionEstablishCount; i++) { try { OpenLoginEnlist(_timeout, connectionOptions, credential, newPassword, newSecurePassword, redirectedUserInstance); break; } catch (SqlException sqlex) { if (i + 1 == connectionEstablishCount || !applyTransientFaultHandling || _timeout.IsExpired || _timeout.MillisecondsRemaining < transientRetryIntervalInMilliSeconds || !IsTransientError(sqlex)) { throw sqlex; } else { Thread.Sleep(transientRetryIntervalInMilliSeconds); } } } } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException) { DoomThisConnection(); throw; } catch (System.StackOverflowException) { DoomThisConnection(); throw; } catch (System.Threading.ThreadAbortException) { DoomThisConnection(); throw; } finally { ThreadHasParserLockForClose = false; _parserLock.Release(); } if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.ctor|ADV> %d#, constructed new TDS internal connection\n", ObjectID); } }
// 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 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); }
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 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); }
// 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 static TimeoutTimer StartSecondsTimeout(int seconds) { TimeoutTimer timer = new TimeoutTimer(); timer.SetTimeoutSeconds(seconds); return timer; }