Beispiel #1
0
        static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null) {
            Guid connectionId = Guid.Empty;
            var exception = CreateException(errorCollection, serverVersion, connectionId, innerException);
/*
            if (internalConnection != null) { 
                if ((internalConnection.OriginalClientConnectionId != Guid.Empty) && (internalConnection.OriginalClientConnectionId != internalConnection.ClientConnectionId)) {
                    exception.Data.Add(OriginalClientConnectionIdKey, internalConnection.OriginalClientConnectionId);
                }

                if (!string.IsNullOrEmpty(internalConnection.RoutingDestination)) {
                    exception.Data.Add(RoutingDestinationKey, internalConnection.RoutingDestination);
                }
            }
*/
            return exception;
        }
        /// <summary>
        /// Determines if a column value should be transparently decrypted (based on SqlCommand and Connection String settings).
        /// </summary>
        /// <returns>true if the value should be transparently decrypted, false otherwise</returns>
        internal static bool ShouldHonorTceForRead (SqlCommandColumnEncryptionSetting columnEncryptionSetting, 
            SqlInternalConnectionTds connection) {

            // Command leve setting trumps all
            switch (columnEncryptionSetting) {
                case SqlCommandColumnEncryptionSetting.Disabled:
                    return false;
                case SqlCommandColumnEncryptionSetting.Enabled:
                    return true;
                case SqlCommandColumnEncryptionSetting.ResultSetOnly:
                    return true;
                default:
                    // Check connection level setting!
                    Debug.Assert(SqlCommandColumnEncryptionSetting.UseConnectionSetting == columnEncryptionSetting,
                        "Unexpected value for command level override");
                    return (connection != null && connection.ConnectionOptions != null &&
                        connection.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled);
            }
        }
        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;
        }
Beispiel #4
0
 internal static void ContinueTask(Task task,
                                   TaskCompletionSource <object> completion,
                                   Action onSuccess,
                                   SqlInternalConnectionTds connectionToDoom = null,
                                   Action <Exception> onFailure = null,
                                   Action onCancellation        = null,
                                   Func <Exception, Exception> exceptionConverter = null,
                                   SqlConnection connectionToAbort = null
                                   )
 {
     Debug.Assert((connectionToAbort == null) || (connectionToDoom == null), "Should not specify both connectionToDoom and connectionToAbort");
     task.ContinueWith(
         tsk =>
     {
         if (tsk.Exception != null)
         {
             Exception exc = tsk.Exception.InnerException;
             if (exceptionConverter != null)
             {
                 exc = exceptionConverter(exc);
             }
             try
             {
                 if (onFailure != null)
                 {
                     onFailure(exc);
                 }
             }
             finally
             {
                 completion.TrySetException(exc);
             }
         }
         else if (tsk.IsCanceled)
         {
             try
             {
                 if (onCancellation != null)
                 {
                     onCancellation();
                 }
             }
             finally
             {
                 completion.TrySetCanceled();
             }
         }
         else
         {
             try
             {
                 onSuccess();
             }
             catch (Exception e)
             {
                 completion.SetException(e);
             }
         }
     }, TaskScheduler.Default
         );
 }
Beispiel #5
0
 internal static Task CreateContinuationTask <T1, T2>(Task task, Action <T1, T2> onSuccess, T1 arg1, T2 arg2, SqlInternalConnectionTds connectionToDoom = null, Action <Exception> onFailure = null)
 {
     return(CreateContinuationTask(task, () => onSuccess(arg1, arg2), connectionToDoom, onFailure));
 }
Beispiel #6
0
        internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout)
        {
            Task runningReconnect = _currentReconnectionTask;

            // This loop in the end will return not completed reconnect task or null
            while (runningReconnect != null && runningReconnect.IsCompleted)
            {
                // clean current reconnect task (if it is the same one we checked
                Interlocked.CompareExchange <Task>(ref _currentReconnectionTask, null, runningReconnect);
                // make sure nobody started new task (if which case we did not clean it)
                runningReconnect = _currentReconnectionTask;
            }
            if (runningReconnect == null)
            {
                if (_connectRetryCount > 0)
                {
                    SqlInternalConnectionTds tdsConn = GetOpenTdsConnection();
                    if (tdsConn._sessionRecoveryAcknowledged)
                    {
                        TdsParserStateObject stateObj = tdsConn.Parser._physicalStateObj;
                        if (!stateObj.ValidateSNIConnection())
                        {
                            if (tdsConn.Parser._sessionPool != null)
                            {
                                if (tdsConn.Parser._sessionPool.ActiveSessionsCount > 0)
                                {
                                    // >1 MARS session
                                    if (beforeDisconnect != null)
                                    {
                                        beforeDisconnect();
                                    }
                                    OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null);
                                }
                            }
                            SessionData cData = tdsConn.CurrentSessionData;
                            cData.AssertUnrecoverableStateCountIsCorrect();
                            if (cData._unrecoverableStatesCount == 0)
                            {
                                bool callDisconnect = false;
                                lock (_reconnectLock)
                                {
                                    runningReconnect = _currentReconnectionTask; // double check after obtaining the lock
                                    if (runningReconnect == null)
                                    {
                                        if (cData._unrecoverableStatesCount == 0)
                                        { // could change since the first check, but now is stable since connection is know to be broken
                                            _originalConnectionId = ClientConnectionId;
                                            _recoverySessionData  = cData;
                                            if (beforeDisconnect != null)
                                            {
                                                beforeDisconnect();
                                            }
                                            try
                                            {
                                                _supressStateChangeForReconnection = true;
                                                tdsConn.DoomThisConnection();
                                            }
                                            catch (SqlException)
                                            {
                                            }
                                            runningReconnect = Task.Run(() => ReconnectAsync(timeout));
                                            // if current reconnect is not null, somebody already started reconnection task - some kind of race condition
                                            Debug.Assert(_currentReconnectionTask == null, "Duplicate reconnection tasks detected");
                                            _currentReconnectionTask = runningReconnect;
                                        }
                                    }
                                    else
                                    {
                                        callDisconnect = true;
                                    }
                                }
                                if (callDisconnect && beforeDisconnect != null)
                                {
                                    beforeDisconnect();
                                }
                            }
                            else
                            {
                                if (beforeDisconnect != null)
                                {
                                    beforeDisconnect();
                                }
                                OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null);
                            }
                        } // ValidateSNIConnection
                    }     // sessionRecoverySupported
                }         // connectRetryCount>0
            }
            else
            { // runningReconnect = null
                if (beforeDisconnect != null)
                {
                    beforeDisconnect();
                }
            }
            return(runningReconnect);
        }
        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;
                }
            }
        }
Beispiel #8
0
        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;
        }
Beispiel #9
0
        override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
        {
            SqlConnectionString   opt    = (SqlConnectionString)options;
            SqlConnectionPoolKey  key    = (SqlConnectionPoolKey)poolKey;
            SqlInternalConnection result = null;
            SessionData           recoverySessionData = null;

            SqlConnectionString userOpt = null;

            if (userOptions != null)
            {
                userOpt = (SqlConnectionString)userOptions;
            }
            else if (owningConnection != null)
            {
                userOpt = (SqlConnectionString)(((SqlConnection)owningConnection).UserConnectionOptions);
            }

            if (owningConnection != null)
            {
                recoverySessionData = ((SqlConnection)owningConnection)._recoverySessionData;
            }

            bool redirectedUserInstance       = false;
            DbConnectionPoolIdentity identity = null;

            // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security.
            // Used by notifications.
            if (opt.IntegratedSecurity)
            {
                if (pool != null)
                {
                    identity = pool.Identity;
                }
                else
                {
                    identity = DbConnectionPoolIdentity.GetCurrent();
                }
            }

            // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES
            // If "user instance=true" is in the connection string, we're using SSE user instances
            if (opt.UserInstance)
            {
                // opt.DataSource is used to create the SSE connection
                redirectedUserInstance = true;
                string instanceName;

                if ((null == pool) ||
                    (null != pool && pool.Count <= 0))
                { // Non-pooled or pooled and no connections in the pool.
                    SqlInternalConnectionTds sseConnection = null;
                    try
                    {
                        // We throw an exception in case of a failure
                        // NOTE: Cloning connection option opt to set 'UserInstance=True' and 'Enlist=False'
                        //       This first connection is established to SqlExpress to get the instance name
                        //       of the UserInstance.
                        SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, true /* user instance=true */);
                        sseConnection = new SqlInternalConnectionTds(identity, sseopt, null, false);
                        // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance.
                        instanceName = sseConnection.InstanceName;

                        if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal))
                        {
                            throw SQL.NonLocalSSEInstance();
                        }

                        if (null != pool)
                        { // Pooled connection - cache result
                            SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo;
                            // No lock since we are already in creation mutex
                            providerInfo.InstanceName = instanceName;
                        }
                    }
                    finally
                    {
                        if (null != sseConnection)
                        {
                            sseConnection.Dispose();
                        }
                    }
                }
                else
                { // Cached info from pool.
                    SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo;
                    // No lock since we are already in creation mutex
                    instanceName = providerInfo.InstanceName;
                }

                // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was
                //       retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'.
                // options immutable - stored in global hash - don't modify
                opt = new SqlConnectionString(opt, instanceName, false /* user instance=false */);
                poolGroupProviderInfo = null; // null so we do not pass to constructor below...
            }
            result = new SqlInternalConnectionTds(identity, opt, poolGroupProviderInfo, redirectedUserInstance, userOpt, recoverySessionData);
            return(result);
        }
Beispiel #10
0
        internal static SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null)
        {
            Guid connectionId = (internalConnection == null) ? Guid.Empty : internalConnection._clientConnectionId;
            var  exception    = CreateException(errorCollection, serverVersion, connectionId, innerException);

            if (internalConnection != null)
            {
                if ((internalConnection.OriginalClientConnectionId != Guid.Empty) && (internalConnection.OriginalClientConnectionId != internalConnection.ClientConnectionId))
                {
                    exception.Data.Add(OriginalClientConnectionIdKey, internalConnection.OriginalClientConnectionId);
                }

                if (!string.IsNullOrEmpty(internalConnection.RoutingDestination))
                {
                    exception.Data.Add(RoutingDestinationKey, internalConnection.RoutingDestination);
                }
            }

            return(exception);
        }
Beispiel #11
0
        internal Task ValidateAndReconnect(Action beforeDisconnect, int timeout)
        {
            Task runningReconnect = _currentReconnectionTask;

            // This loop in the end will return not completed reconnect task or null
            while (runningReconnect != null && runningReconnect.IsCompleted)
            {
                // clean current reconnect task (if it is the same one we checked
                Interlocked.CompareExchange <Task>(ref _currentReconnectionTask, null, runningReconnect);
                // make sure nobody started new task (if which case we did not clean it)
                runningReconnect = _currentReconnectionTask;
            }
            if (runningReconnect == null)
            {
                if (_connectRetryCount > 0)
                {
                    SqlInternalConnectionTds tdsConn = GetOpenTdsConnection();
                    if (tdsConn._sessionRecoveryAcknowledged)
                    {
                        TdsParser tdsParser = tdsConn.Parser;
                        if (!tdsParser._physicalStateObj.ValidateSNIConnection())
                        {
                            if ((tdsParser._sessionPool != null) && (tdsParser._sessionPool.ActiveSessionsCount > 0))
                            {
                                // >1 MARS session
                                beforeDisconnect?.Invoke();
                                OnError(SQL.CR_UnrecoverableClient(ClientConnectionId), true, null);
                            }

                            SessionData cData = tdsConn.CurrentSessionData;
                            cData.AssertUnrecoverableStateCountIsCorrect();
                            if (cData._unrecoverableStatesCount == 0)
                            {
                                TaskCompletionSource <object> reconnectCompletionSource = new TaskCompletionSource <object>();
                                runningReconnect = Interlocked.CompareExchange(ref _currentReconnectionTask, reconnectCompletionSource.Task, null);
                                if (runningReconnect == null)
                                {
                                    if (cData._unrecoverableStatesCount == 0)
                                    { // could change since the first check, but now is stable since connection is know to be broken
                                        _originalConnectionId = ClientConnectionId;
                                        _recoverySessionData  = cData;
                                        beforeDisconnect?.Invoke();
                                        try
                                        {
                                            _supressStateChangeForReconnection = true;
                                            tdsConn.DoomThisConnection();
                                        }
                                        catch (SqlException)
                                        {
                                        }
                                        Task.Run(() => ReconnectAsync(timeout).ContinueWith(t => {
                                            if (t.IsFaulted)
                                            {
                                                reconnectCompletionSource.SetException(t.Exception);
                                            }
                                            else if (t.IsCanceled)
                                            {
                                                reconnectCompletionSource.SetCanceled();
                                            }
                                            else
                                            {
                                                reconnectCompletionSource.SetResult(null);
                                            }
                                        }));
                                        runningReconnect = reconnectCompletionSource.Task;
                                    }
                                }
                                else
                                {
                                    beforeDisconnect?.Invoke();
                                }
                            }
                            else
                            {
                                beforeDisconnect?.Invoke();
                                OnError(SQL.CR_UnrecoverableServer(ClientConnectionId), true, null);
                            }
                        } // ValidateSNIConnection
                    }     // sessionRecoverySupported
                }         // connectRetryCount>0
            }
            else
            { // runningReconnect = null
                beforeDisconnect?.Invoke();
            }
            return(runningReconnect);
        }
        override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
        {
            SqlConnectionString   opt    = (SqlConnectionString)options;
            SqlConnectionPoolKey  key    = (SqlConnectionPoolKey)poolKey;
            SqlInternalConnection result = null;
            SessionData           recoverySessionData = null;
            SqlConnection         sqlOwningConnection = owningConnection as SqlConnection;
            bool applyTransientFaultHandling          = sqlOwningConnection != null ? sqlOwningConnection._applyTransientFaultHandling : false;

            SqlConnectionString userOpt = null;

            if (userOptions != null)
            {
                userOpt = (SqlConnectionString)userOptions;
            }
            else if (sqlOwningConnection != null)
            {
                userOpt = (SqlConnectionString)(sqlOwningConnection.UserConnectionOptions);
            }

            if (sqlOwningConnection != null)
            {
                recoverySessionData = sqlOwningConnection._recoverySessionData;
            }

            if (opt.ContextConnection)
            {
                result = GetContextConnection(opt, poolGroupProviderInfo);
            }
            else
            {
                bool redirectedUserInstance       = false;
                DbConnectionPoolIdentity identity = null;

                // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security.
                // Used by notifications.
                if (opt.IntegratedSecurity || opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
                {
                    if (pool != null)
                    {
                        identity = pool.Identity;
                    }
                    else
                    {
                        identity = DbConnectionPoolIdentity.GetCurrent();
                    }
                }

                // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES
                // If "user instance=true" is in the connection string, we're using SSE user instances
                if (opt.UserInstance)
                {
                    // opt.DataSource is used to create the SSE connection
                    redirectedUserInstance = true;
                    string instanceName;

                    if ((null == pool) ||
                        (null != pool && pool.Count <= 0))     // Non-pooled or pooled and no connections in the pool.

                    {
                        SqlInternalConnectionTds sseConnection = null;
                        try {
                            // What about a failure - throw?  YES!
                            //



                            SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, true /* user instance=true */, false /* set Enlist = false */);
                            sseConnection = new SqlInternalConnectionTds(identity, sseopt, key.Credential, null, "", null, false, applyTransientFaultHandling: applyTransientFaultHandling);
                            // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance.
                            instanceName = sseConnection.InstanceName;

                            if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal))
                            {
                                throw SQL.NonLocalSSEInstance();
                            }

                            if (null != pool)   // Pooled connection - cache result
                            {
                                SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo;
                                // No lock since we are already in creation mutex
                                providerInfo.InstanceName = instanceName;
                            }
                        }
                        finally {
                            if (null != sseConnection)
                            {
                                sseConnection.Dispose();
                            }
                        }
                    }
                    else   // Cached info from pool.
                    {
                        SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo;
                        // No lock since we are already in creation mutex
                        instanceName = providerInfo.InstanceName;
                    }

                    // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was
                    //       retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'.
                    // options immutable - stored in global hash - don't modify
                    opt = new SqlConnectionString(opt, instanceName, false /* user instance=false */, null /* do not modify the Enlist value */);
                    poolGroupProviderInfo = null; // null so we do not pass to constructor below...
                }
                result = new SqlInternalConnectionTds(identity, opt, key.Credential, poolGroupProviderInfo, "", null, redirectedUserInstance, userOpt, recoverySessionData, pool, key.AccessToken, applyTransientFaultHandling: applyTransientFaultHandling);
            }
            return(result);
        }
 public static void ChangePassword(string connectionString, string newPassword)
 {
     IntPtr ptr;
     Bid.ScopeEnter(out ptr, "<sc.SqlConnection.ChangePassword|API>");
     try
     {
         if (ADP.IsEmpty(connectionString))
         {
             throw SQL.ChangePasswordArgumentMissing("connectionString");
         }
         if (ADP.IsEmpty(newPassword))
         {
             throw SQL.ChangePasswordArgumentMissing("newPassword");
         }
         if (0x80 < newPassword.Length)
         {
             throw ADP.InvalidArgumentLength("newPassword", 0x80);
         }
         SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(connectionString);
         if (connectionOptions.IntegratedSecurity)
         {
             throw SQL.ChangePasswordConflictsWithSSPI();
         }
         if (!ADP.IsEmpty(connectionOptions.AttachDBFilename))
         {
             throw SQL.ChangePasswordUseOfUnallowedKey("attachdbfilename");
         }
         if (connectionOptions.ContextConnection)
         {
             throw SQL.ChangePasswordUseOfUnallowedKey("context connection");
         }
         connectionOptions.CreatePermissionSet().Demand();
         using (SqlInternalConnectionTds tds = new SqlInternalConnectionTds(null, connectionOptions, null, newPassword, null, false))
         {
             if (!tds.IsYukonOrNewer)
             {
                 throw SQL.ChangePasswordRequiresYukon();
             }
         }
         SqlConnectionFactory.SingletonInstance.ClearPool(connectionString);
     }
     finally
     {
         Bid.ScopeLeave(ref ptr);
     }
 }
 static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null)
 {
     throw new PlatformNotSupportedException(EXCEPTION_MESSAGE);
 }
        internal static object GetNullSqlValue(
                SqlBuffer nullVal, 
                SqlMetaDataPriv md, 
                SqlCommandColumnEncryptionSetting columnEncryptionSetting,
                SqlInternalConnectionTds connection) {
            SqlDbType type = md.type;

            if (type == SqlDbType.VarBinary && // if its a varbinary
                md.isEncrypted &&// and encrypted
                ShouldHonorTceForRead(columnEncryptionSetting, connection)){
                type = md.baseTI.type; // the use the actual (plaintext) type
            }

            switch (type) {
                case SqlDbType.Real:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Single);
                    break;

                case SqlDbType.Float:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Double);
                    break;

                case SqlDbType.Udt:
                case SqlDbType.Binary:
                case SqlDbType.VarBinary:
                case SqlDbType.Image:
                    nullVal.SqlBinary = SqlBinary.Null;
                    break;

                case SqlDbType.UniqueIdentifier:
                    nullVal.SqlGuid = SqlGuid.Null;
                    break;

                case SqlDbType.Bit:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Boolean);
                    break;

                case SqlDbType.TinyInt:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Byte);
                    break;

                case SqlDbType.SmallInt:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Int16);
                    break;

                case SqlDbType.Int:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Int32);
                    break;

                case SqlDbType.BigInt:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Int64);
                    break;

                case SqlDbType.Char:
                case SqlDbType.VarChar:
                case SqlDbType.NChar:
                case SqlDbType.NVarChar:
                case SqlDbType.Text:
                case SqlDbType.NText:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.String);
                    break;

                case SqlDbType.Decimal:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Decimal);
                    break;

                case SqlDbType.DateTime:
                case SqlDbType.SmallDateTime:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime);
                    break;

                case SqlDbType.Money:
                case SqlDbType.SmallMoney:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Money);
                    break;

                case SqlDbType.Variant:
                    // DBNull.Value will have to work here
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Empty);
                    break;

                case SqlDbType.Xml:
                    nullVal.SqlCachedBuffer = SqlCachedBuffer.Null;
                    break;

                case SqlDbType.Date:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Date);
                    break;

                case SqlDbType.Time:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.Time);
                    break;
                    
                case SqlDbType.DateTime2:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime2);
                    break;
                    
                case SqlDbType.DateTimeOffset:
                    nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTimeOffset);
                    break;

                case SqlDbType.Timestamp:
                    // Dev10 Bug #479607 - this should have been the same as SqlDbType.Binary, but it's a rejected breaking change
                    // Dev10 Bug #752790 - don't assert when it does happen
                    break;

                default:
                    Debug.Assert(false, "unknown null sqlType!" + md.type.ToString());
                    break;
            }

            return nullVal;
        }
Beispiel #16
0
        private void EnlistNonNull(Transaction tx)
        {
            Debug.Assert(null != tx, "null transaction?");

            bool hasDelegatedTransaction = false;

            // Promotable transactions are only supported on Yukon
            // servers or newer.
            SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx);

            try
            {
                // NOTE: System.Transactions claims to resolve all
                // potential race conditions between multiple delegate
                // requests of the same transaction to different
                // connections in their code, such that only one
                // attempt to delegate will succeed.

                // NOTE: PromotableSinglePhaseEnlist will eventually
                // make a round trip to the server; doing this inside
                // a lock is not the best choice.  We presume that you
                // aren't trying to enlist concurrently on two threads
                // and leave it at that -- We don't claim any thread
                // safety with regard to multiple concurrent requests
                // to enlist the same connection in different
                // transactions, which is good, because we don't have
                // it anyway.

                // PromotableSinglePhaseEnlist may not actually promote
                // the transaction when it is already delegated (this is
                // the way they resolve the race condition when two
                // threads attempt to delegate the same Lightweight
                // Transaction)  In that case, we can safely ignore
                // our delegated transaction, and proceed to enlist
                // in the promoted one.

                // NOTE: Global Transactions is an Azure SQL DB only
                // feature where the Transaction Manager (TM) is not
                // MS-DTC. Sys.Tx added APIs to support Non MS-DTC
                // promoter types/TM in .NET 4.6.1. Following directions
                // from .NETFX shiproom, to avoid a "hard-dependency"
                // (compile time) on Sys.Tx, we use reflection to invoke
                // the new APIs. Further, the _isGlobalTransaction flag
                // indicates that this is an Azure SQL DB Transaction
                // that could be promoted to a Global Transaction (it's
                // always false for on-prem Sql Server). The Promote()
                // call in SqlDelegatedTransaction makes sure that the
                // right Sys.Tx.dll is loaded and that Global Transactions
                // are actually allowed for this Azure SQL DB.

                if (_isGlobalTransaction)
                {
                    if (SysTxForGlobalTransactions.EnlistPromotableSinglePhase == null)
                    {
                        // This could be a local Azure SQL DB transaction.
                        hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction);
                    }
                    else
                    {
                        hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, _globalTransactionTMID });
                    }
                }
                else
                {
                    // This is an MS-DTC distributed transaction
                    hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction);
                }

                if (hasDelegatedTransaction)
                {
                    this.DelegatedTransaction = delegatedTransaction;
                }
            }
            catch (SqlException e)
            {
                // we do not want to eat the error if it is a fatal one
                if (e.Class >= TdsEnums.FATAL_ERROR_CLASS)
                {
                    throw;
                }

                // if the parser is null or its state is not openloggedin, the connection is no longer good.
                SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds;
                if (tdsConnection != null)
                {
                    TdsParser parser = tdsConnection.Parser;
                    if (parser == null || parser.State != TdsParserState.OpenLoggedIn)
                    {
                        throw;
                    }
                }

                // In this case, SqlDelegatedTransaction.Initialize
                // failed and we don't necessarily want to reject
                // things -- there may have been a legitimate reason
                // for the failure.
            }

            if (!hasDelegatedTransaction)
            {
                byte[] cookie = null;

                if (_isGlobalTransaction)
                {
                    if (SysTxForGlobalTransactions.GetPromotedToken == null)
                    {
                        throw SQL.UnsupportedSysTxForGlobalTransactions();
                    }

                    cookie = (byte[])SysTxForGlobalTransactions.GetPromotedToken.Invoke(tx, null);
                }
                else
                {
                    if (null == _whereAbouts)
                    {
                        byte[] dtcAddress = GetDTCAddress();

                        if (null == dtcAddress)
                        {
                            throw SQL.CannotGetDTCAddress();
                        }
                        _whereAbouts = dtcAddress;
                    }
                    cookie = GetTransactionCookie(tx, _whereAbouts);
                }

                // send cookie to server to finish enlistment
                PropagateTransactionCookie(cookie);

                _isEnlistedInTransaction = true;
            }

            EnlistedTransaction = tx; // Tell the base class about our enlistment


            // If we're on a Yukon or newer server, and we we delegate the
            // transaction successfully, we will have done a begin transaction,
            // which produces a transaction id that we should execute all requests
            // on.  The TdsParser or SmiEventSink will store this information as
            // the current transaction.
            //
            // Likewise, propagating a transaction to a Yukon or newer server will
            // produce a transaction id that The TdsParser or SmiEventSink will
            // store as the current transaction.
            //
            // In either case, when we're working with a Yukon or newer server
            // we better have a current transaction by now.

            Debug.Assert(null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?");
        }
		static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null)
		{
			throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
		}
Beispiel #18
0
        //
        // MultiSubnetFailover
        //

        /// <summary>
        /// used to block two scenarios if MultiSubnetFailover is true:
        /// * server-provided failover partner - raising SqlException in this case
        /// * connection string with failover partner and MultiSubnetFailover=true - raising argument one in this case with the same message
        /// </summary>
        static internal Exception MultiSubnetFailoverWithFailoverPartner(bool serverProvidedFailoverPartner, SqlInternalConnectionTds internalConnection)
        {
            string msg = Res.GetString(Res.SQLMSF_FailoverPartnerNotSupported);

            if (serverProvidedFailoverPartner)
            {
                // Replacing InvalidOperation with SQL exception
                SqlErrorCollection errors = new SqlErrorCollection();
                errors.Add(new SqlError(0, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, null, msg, "", 0));
                SqlException exc = SqlException.CreateException(errors, null, internalConnection);
                exc._doNotReconnect = true; // disable open retry logic on this error
                return(exc);
            }
            else
            {
                return(ADP.Argument(msg));
            }
        }
        override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) {
            SqlConnectionString opt = (SqlConnectionString)options;
            SqlConnectionPoolKey key = (SqlConnectionPoolKey) poolKey;
            SqlInternalConnection result = null;
            SessionData recoverySessionData = null;

            SqlConnectionString userOpt = null;
            if (userOptions != null) {
                userOpt = (SqlConnectionString)userOptions;
            }
            else if (owningConnection != null) {
                userOpt = (SqlConnectionString)(((SqlConnection)owningConnection).UserConnectionOptions);                
            }

            if (owningConnection != null) {
                recoverySessionData = ((SqlConnection)owningConnection)._recoverySessionData;
            }

            if (opt.ContextConnection) {
                result = GetContextConnection(opt, poolGroupProviderInfo);
            }
            else {
                bool redirectedUserInstance       = false;
                DbConnectionPoolIdentity identity = null;

                // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security.
                // Used by notifications.
                if (opt.IntegratedSecurity) {
                    if (pool != null) {
                        identity = pool.Identity;
                    }
                    else {
                        identity = DbConnectionPoolIdentity.GetCurrent();
                    }
                }

                // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES
                // If "user instance=true" is in the connection string, we're using SSE user instances
                if (opt.UserInstance) {
                    // opt.DataSource is used to create the SSE connection
                    redirectedUserInstance = true;
                    string instanceName;

                    if ( (null == pool) || 
                         (null != pool && pool.Count <= 0) ) { // Non-pooled or pooled and no connections in the pool.

                        SqlInternalConnectionTds sseConnection = null;
                        try {
                            // What about a failure - throw?  YES!
                            // 



                            SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, true /* user instance=true */, false /* set Enlist = false */);
                            sseConnection = new SqlInternalConnectionTds(identity, sseopt, key.Credential, null, "", null, false);
                            // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance.
                            instanceName = sseConnection.InstanceName;

                            if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal)) {
                                throw SQL.NonLocalSSEInstance();
                            }

                            if (null != pool) { // Pooled connection - cache result
                                SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo) pool.ProviderInfo;
                                // No lock since we are already in creation mutex
                                providerInfo.InstanceName = instanceName;
                            }
                        }
                        finally {
                            if (null != sseConnection) {
                                sseConnection.Dispose();
                            }
                        }
                    }
                    else { // Cached info from pool.
                        SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo) pool.ProviderInfo;
                        // No lock since we are already in creation mutex
                        instanceName = providerInfo.InstanceName;
                    }

                    // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was
                    //       retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'.
                    // options immutable - stored in global hash - don't modify
                    opt = new SqlConnectionString(opt, instanceName, false /* user instance=false */, null /* do not modify the Enlist value */);
                    poolGroupProviderInfo = null; // null so we do not pass to constructor below...
                }
                result = new SqlInternalConnectionTds(identity, opt, key.Credential, poolGroupProviderInfo, "", null, redirectedUserInstance, userOpt, recoverySessionData);            
            }
            return result;
        }
        private void EnlistNonNull(Transaction tx)
        {
            if (Bid.AdvancedOn)
            {
                Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode());
            }
            bool flag = false;

            if (this.IsYukonOrNewer)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID);
                }
                SqlDelegatedTransaction promotableSinglePhaseNotification = new SqlDelegatedTransaction(this, tx);
                try
                {
                    if (tx.EnlistPromotableSinglePhase(promotableSinglePhaseNotification))
                    {
                        flag = true;
                        this.DelegatedTransaction = promotableSinglePhaseNotification;
                        if (Bid.AdvancedOn)
                        {
                            long transactionId = 0L;
                            int  objectID      = 0;
                            if (this.CurrentTransaction != null)
                            {
                                transactionId = this.CurrentTransaction.TransactionId;
                                objectID      = this.CurrentTransaction.ObjectID;
                            }
                            Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, objectID, transactionId);
                        }
                    }
                }
                catch (SqlException exception)
                {
                    if (exception.Class >= 20)
                    {
                        throw;
                    }
                    SqlInternalConnectionTds tds = this as SqlInternalConnectionTds;
                    if (tds != null)
                    {
                        TdsParser parser = tds.Parser;
                        if ((parser == null) || (parser.State != TdsParserState.OpenLoggedIn))
                        {
                            throw;
                        }
                    }
                    ADP.TraceExceptionWithoutRethrow(exception);
                }
            }
            if (!flag)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID);
                }
                byte[] transactionCookie = null;
                if (this._whereAbouts == null)
                {
                    byte[] dTCAddress = this.GetDTCAddress();
                    if (dTCAddress == null)
                    {
                        throw SQL.CannotGetDTCAddress();
                    }
                    this._whereAbouts = dTCAddress;
                }
                transactionCookie = GetTransactionCookie(tx, this._whereAbouts);
                this.PropagateTransactionCookie(transactionCookie);
                this._isEnlistedInTransaction = true;
                if (Bid.AdvancedOn)
                {
                    long num2 = 0L;
                    int  num  = 0;
                    if (this.CurrentTransaction != null)
                    {
                        num2 = this.CurrentTransaction.TransactionId;
                        num  = this.CurrentTransaction.ObjectID;
                    }
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, num, num2);
                }
            }
            base.EnlistedTransaction = tx;
        }