internal static bool Stop(string connectionString, string queue, bool useDefaults, bool startFailed) { IntPtr hscp; Bid.NotificationsScopeEnter(out hscp, "<sc.SqlDependency.Stop|DEP> AppDomainKey: '%ls', queue: '%ls'", AppDomainKey, queue); try { // The following code exists in Stop as well. It exists here to demand permissions as high in the stack // as possible. if (InOutOfProcHelper.InProc) { throw SQL.SqlDepCannotBeCreatedInProc(); } if (ADP.IsEmpty(connectionString)) { if (null == connectionString) { throw ADP.ArgumentNull("connectionString"); } else { throw ADP.Argument("connectionString"); } } if (!useDefaults && ADP.IsEmpty(queue)) { // If specified but null or empty, use defaults. useDefaults = true; queue = null; // Force to null - for proper hashtable comparison for default case. } // Create new connection options for demand on their connection string. We modify the connection string // and assert on our modified string when we create the container. SqlConnectionString connectionStringObject = new SqlConnectionString(connectionString); connectionStringObject.DemandPermission(); if (connectionStringObject.LocalDBInstance!=null) { LocalDBAPI.DemandLocalDBPermissions(); } // End duplicate Start/Stop logic. bool result = false; lock (_startStopLock) { if (null != _processDispatcher) { // If _processDispatcher null, no Start has been called. try { string server = null; DbConnectionPoolIdentity identity = null; string user = null; string database = null; string service = null; if (useDefaults) { bool appDomainStop = false; RuntimeHelpers.PrepareConstrainedRegions(); try { // CER to ensure that if Stop succeeds we remove from hash completing teardown. // Start using process wide default service/queue & database from connection string. result = _processDispatcher.Stop( connectionString, out server, out identity, out user, out database, ref service, _appDomainKey, out appDomainStop); } finally { if (appDomainStop && !startFailed) { // If success, remove from hashtable. Debug.Assert(!ADP.IsEmpty(server) && !ADP.IsEmpty(database), "Server or Database null/Empty upon successfull Stop()!"); IdentityUserNamePair identityUser = new IdentityUserNamePair(identity, user); DatabaseServicePair databaseService = new DatabaseServicePair(database, service); RemoveFromServerUserHash(server, identityUser, databaseService); } } } else { bool ignored = false; result = _processDispatcher.Stop( connectionString, out server, out identity, out user, out database, ref queue, _appDomainKey, out ignored); // No need to call RemoveFromServerDatabaseHash since if not using default queue user is required // to provide options themselves. } } catch (Exception e) { if (!ADP.IsCatchableExceptionType(e)) { throw; } ADP.TraceExceptionWithoutRethrow(e); // Discard failure, but trace for now. } } } return result; } finally { Bid.ScopeLeave(ref hscp); } }
// 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); } }
internal static bool Start(string connectionString, string queue, bool useDefaults) { IntPtr hscp; Bid.NotificationsScopeEnter(out hscp, "<sc.SqlDependency.Start|DEP> AppDomainKey: '%ls', queue: '%ls'", AppDomainKey, queue); try { // The following code exists in Stop as well. It exists here to demand permissions as high in the stack // as possible. if (InOutOfProcHelper.InProc) { throw SQL.SqlDepCannotBeCreatedInProc(); } if (ADP.IsEmpty(connectionString)) { if (null == connectionString) { throw ADP.ArgumentNull("connectionString"); } else { throw ADP.Argument("connectionString"); } } if (!useDefaults && ADP.IsEmpty(queue)) { // If specified but null or empty, use defaults. useDefaults = true; queue = null; // Force to null - for proper hashtable comparison for default case. } // Create new connection options for demand on their connection string. We modify the connection string // and assert on our modified string when we create the container. SqlConnectionString connectionStringObject = new SqlConnectionString(connectionString); connectionStringObject.DemandPermission(); if (connectionStringObject.LocalDBInstance!=null) { LocalDBAPI.DemandLocalDBPermissions(); } // End duplicate Start/Stop logic. bool errorOccurred = false; bool result = false; lock (_startStopLock) { try { if (null == _processDispatcher) { // Ensure _processDispatcher reference is present - inside lock. ObtainProcessDispatcher(); } if (useDefaults) { // Default listener. string server = null; DbConnectionPoolIdentity identity = null; string user = null; string database = null; string service = null; bool appDomainStart = false; RuntimeHelpers.PrepareConstrainedRegions(); try { // CER to ensure that if Start succeeds we add to hash completing setup. // Start using process wide default service/queue & database from connection string. result = _processDispatcher.StartWithDefault( connectionString, out server, out identity, out user, out database, ref service, _appDomainKey, SqlDependencyPerAppDomainDispatcher.SingletonInstance, out errorOccurred, out appDomainStart); Bid.NotificationsTrace("<sc.SqlDependency.Start|DEP> Start (defaults) returned: '%d', with service: '%ls', server: '%ls', database: '%ls'\n", result, service, server, database); } finally { if (appDomainStart && !errorOccurred) { // If success, add to hashtable. IdentityUserNamePair identityUser = new IdentityUserNamePair(identity, user); DatabaseServicePair databaseService = new DatabaseServicePair(database, service); if (!AddToServerUserHash(server, identityUser, databaseService)) { try { Stop(connectionString, queue, useDefaults, true); } catch (Exception e) { // Discard stop failure! if (!ADP.IsCatchableExceptionType(e)) { throw; } ADP.TraceExceptionWithoutRethrow(e); // Discard failure, but trace for now. Bid.NotificationsTrace("<sc.SqlDependency.Start|DEP|ERR> Exception occurred from Stop() after duplicate was found on Start().\n"); } throw SQL.SqlDependencyDuplicateStart(); } } } } else { // Start with specified service/queue & database. result = _processDispatcher.Start(connectionString, queue, _appDomainKey, SqlDependencyPerAppDomainDispatcher.SingletonInstance); Bid.NotificationsTrace("<sc.SqlDependency.Start|DEP> Start (user provided queue) returned: '%d'\n", result); // No need to call AddToServerDatabaseHash since if not using default queue user is required // to provide options themselves. } } catch (Exception e) { if (!ADP.IsCatchableExceptionType(e)) { throw; } ADP.TraceExceptionWithoutRethrow(e); // Discard failure, but trace for now. Bid.NotificationsTrace("<sc.SqlDependency.Start|DEP|ERR> Exception occurred from _processDispatcher.Start(...), calling Invalidate(...).\n"); throw; } } return result; } finally { Bid.ScopeLeave(ref hscp); } }