Ejemplo n.º 1
0
        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);
            }
        }
Ejemplo n.º 3
0
        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);
            }
        }