public void OnError(SqlException exception, TdsParserState state) { if (state == TdsParserState.Broken) { _fUsableState = false; } if (null != Connection) { Connection.OnError(exception, state); } else if (exception.Class >= TdsEnums.MIN_ERROR_CLASS) { // It is an error, and should be thrown. Class of TdsEnums.MINERRORCLASS // or above is an error, below TdsEnums.MINERRORCLASS denotes an info message. throw exception; } }
// Used to close the connection and then free the memory allocated for the netlib connection. internal void Disconnect() { if (null != _sessionPool) { // MARSOn may be true, but _sessionPool not yet created _sessionPool.Dispose(); } // Can close the connection if its open or broken if (_state != TdsParserState.Closed) { //benign assert - the user could close the connection before consuming all the data //Debug.Assert(_physicalStateObj._inBytesUsed == _physicalStateObj._inBytesRead && _physicalStateObj._outBytesUsed == _physicalStateObj._inputHeaderLen, "TDSParser closed with data not fully sent or consumed."); _state = TdsParserState.Closed; try { // If the _physicalStateObj has an owner, we will delay the disposal until the owner is finished with it if (!_physicalStateObj.HasOwner) { _physicalStateObj.SniContext = SniContext.Snix_Close; #if DEBUG _physicalStateObj.InvalidateDebugOnlyCopyOfSniContext(); #endif _physicalStateObj.Dispose(); } else { // Remove the "initial" callback (this will allow the stateObj to be GC collected if need be) _physicalStateObj.DecrementPendingCallbacks(false); } // Not allocated until MARS is actually enabled in SNI. if (null != _pMarsPhysicalConObj) { _pMarsPhysicalConObj.Dispose(); } } finally { _pMarsPhysicalConObj = null; } } }
private void ProcessAttention(TdsParserStateObject stateObj) { if (_state == TdsParserState.Closed || _state == TdsParserState.Broken) { return; } Debug.Assert(stateObj._attentionSent, "invalid attempt to ProcessAttention, attentionSent == false!"); // Attention processing scenarios: // 1) EOM packet with header ST_AACK bit plus DONE with status DONE_ATTN // 2) Packet without ST_AACK header bit but has DONE with status DONE_ATTN // 3) Secondary timeout occurs while reading, break connection // Since errors can occur and we need to cancel prior to throwing those errors, we // cache away error state and then process TDS for the attention. We restore those // errors after processing. stateObj.StoreErrorAndWarningForAttention(); try { // Call run loop to process looking for attention ack. Run(RunBehavior.Attention, null, null, null, stateObj); } catch (Exception e) { if (!ADP.IsCatchableExceptionType(e)) { throw; } // If an exception occurs - break the connection. // Attention error will not be thrown in this case by Run(), but other failures may. _state = TdsParserState.Broken; _connHandler.BreakConnection(); throw; } stateObj.RestoreErrorAndWarningAfterAttention(); Debug.Assert(!stateObj._attentionSent, "Invalid attentionSent state at end of ProcessAttention"); }
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; }
private bool TryProcessLoginAck(TdsParserStateObject stateObj, out SqlLoginAck sqlLoginAck) { SqlLoginAck a = new SqlLoginAck(); sqlLoginAck = null; // read past interface type and version if (!stateObj.TrySkipBytes(1)) { return false; } byte[] b = new byte[TdsEnums.VERSION_SIZE]; if (!stateObj.TryReadByteArray(b, 0, b.Length)) { return false; } a.tdsVersion = (UInt32)((((((b[0] << 8) | b[1]) << 8) | b[2]) << 8) | b[3]); // bytes are in motorola order (high byte first) UInt32 majorMinor = a.tdsVersion & 0xff00ffff; UInt32 increment = (a.tdsVersion >> 16) & 0xff; // Server responds: // 0x07000000 -> Sphinx // Notice server response format is different for bwd compat // 0x07010000 -> Shiloh RTM // Notice server response format is different for bwd compat // 0x71000001 -> Shiloh SP1 // 0x72xx0002 -> Yukon RTM // information provided by S. Ashwin switch (majorMinor) { case TdsEnums.YUKON_MAJOR << 24 | TdsEnums.YUKON_RTM_MINOR: // Yukon if (increment != TdsEnums.YUKON_INCREMENT) { throw SQL.InvalidTDSVersion(); } break; case TdsEnums.KATMAI_MAJOR << 24 | TdsEnums.KATMAI_MINOR: if (increment != TdsEnums.KATMAI_INCREMENT) { throw SQL.InvalidTDSVersion(); } _isKatmai = true; break; case TdsEnums.DENALI_MAJOR << 24 | TdsEnums.DENALI_MINOR: if (increment != TdsEnums.DENALI_INCREMENT) { throw SQL.InvalidTDSVersion(); } _isDenali = true; break; default: throw SQL.InvalidTDSVersion(); } _isKatmai |= _isDenali; stateObj._outBytesUsed = stateObj._outputHeaderLen; byte len; if (!stateObj.TryReadByte(out len)) { return false; } if (!stateObj.TrySkipBytes(len * ADP.CharSize)) { return false; } if (!stateObj.TryReadByte(out a.majorVersion)) { return false; } if (!stateObj.TryReadByte(out a.minorVersion)) { return false; } byte buildNumHi, buildNumLo; if (!stateObj.TryReadByte(out buildNumHi)) { return false; } if (!stateObj.TryReadByte(out buildNumLo)) { return false; } a.buildNum = (short)((buildNumHi << 8) + buildNumLo); Debug.Assert(_state == TdsParserState.OpenNotLoggedIn, "ProcessLoginAck called with state not TdsParserState.OpenNotLoggedIn"); _state = TdsParserState.OpenLoggedIn; { if (_fMARS) { _resetConnectionEvent = new AutoResetEvent(true); } } // Fail if SSE UserInstance and we have not received this info. if (_connHandler.ConnectionOptions.UserInstance && ADP.IsEmpty(_connHandler.InstanceName)) { stateObj.AddError(new SqlError(0, 0, TdsEnums.FATAL_ERROR_CLASS, Server, SQLMessage.UserInstanceFailure(), "", 0)); ThrowExceptionAndWarning(stateObj); } sqlLoginAck = a; return true; }
// Main parse loop for the top-level tds tokens, calls back into the I*Handler interfaces internal bool TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, out bool dataReady) { Debug.Assert((SniContext.Undefined != stateObj.SniContext) && // SniContext must not be Undefined ((stateObj._attentionSent) || ((SniContext.Snix_Execute != stateObj.SniContext) && (SniContext.Snix_SendRows != stateObj.SniContext))), // SniContext should not be Execute or SendRows unless attention was sent (and, therefore, we are looking for an ACK) String.Format("Unexpected SniContext on call to TryRun; SniContext={0}", stateObj.SniContext)); if (TdsParserState.Broken == State || TdsParserState.Closed == State) { dataReady = true; return true; // Just in case this is called in a loop, expecting data to be returned. } dataReady = false; do { // If there is data ready, but we didn't exit the loop, then something is wrong Debug.Assert(!dataReady, "dataReady not expected - did we forget to skip the row?"); if (stateObj._internalTimeout) { runBehavior = RunBehavior.Attention; } if (TdsParserState.Broken == State || TdsParserState.Closed == State) break; // jump out of the loop if the state is already broken or closed. if (!stateObj._accumulateInfoEvents && (stateObj._pendingInfoEvents != null)) { if (RunBehavior.Clean != (RunBehavior.Clean & runBehavior)) { SqlConnection connection = null; if (_connHandler != null) connection = _connHandler.Connection; // SqlInternalConnection holds the user connection object as a weak ref // We are omitting checks for error.Class in the code below (see processing of INFO) since we know (and assert) that error class // error.Class < TdsEnums.MIN_ERROR_CLASS for info message. // Also we know that TdsEnums.MIN_ERROR_CLASS<TdsEnums.MAX_USER_CORRECTABLE_ERROR_CLASS if ((connection != null) && connection.FireInfoMessageEventOnUserErrors) { foreach (SqlError error in stateObj._pendingInfoEvents) FireInfoMessageEvent(connection, stateObj, error); } else foreach (SqlError error in stateObj._pendingInfoEvents) stateObj.AddWarning(error); } stateObj._pendingInfoEvents = null; } byte token; if (!stateObj.TryReadByte(out token)) { return false; } if (!IsValidTdsToken(token)) { Debug.Assert(false, String.Format((IFormatProvider)null, "unexpected token; token = {0,-2:X2}", token)); _state = TdsParserState.Broken; _connHandler.BreakConnection(); throw SQL.ParsingError(); } int tokenLength; if (!TryGetTokenLength(token, stateObj, out tokenLength)) { return false; } switch (token) { case TdsEnums.SQLERROR: case TdsEnums.SQLINFO: { if (token == TdsEnums.SQLERROR) { stateObj._errorTokenReceived = true; // Keep track of the fact error token was received - for Done processing. } SqlError error; if (!TryProcessError(token, stateObj, out error)) { return false; } if (token == TdsEnums.SQLINFO && stateObj._accumulateInfoEvents) { Debug.Assert(error.Class < TdsEnums.MIN_ERROR_CLASS, "INFO with class > TdsEnums.MIN_ERROR_CLASS"); if (stateObj._pendingInfoEvents == null) stateObj._pendingInfoEvents = new List<SqlError>(); stateObj._pendingInfoEvents.Add(error); stateObj._syncOverAsync = true; break; } if (RunBehavior.Clean != (RunBehavior.Clean & runBehavior)) { // If FireInfoMessageEventOnUserErrors is true, we have to fire event without waiting. // Otherwise we can go ahead and add it to errors/warnings collection. SqlConnection connection = null; if (_connHandler != null) connection = _connHandler.Connection; // SqlInternalConnection holds the user connection object as a weak ref if ((connection != null) && (connection.FireInfoMessageEventOnUserErrors == true) && (error.Class <= TdsEnums.MAX_USER_CORRECTABLE_ERROR_CLASS)) { // Fire SqlInfoMessage here FireInfoMessageEvent(connection, stateObj, error); } else { // insert error/info into the appropriate exception - warning if info, exception if error if (error.Class < TdsEnums.MIN_ERROR_CLASS) { stateObj.AddWarning(error); } else if (error.Class < TdsEnums.FATAL_ERROR_CLASS) { // Continue results processing for all non-fatal errors (<20) stateObj.AddError(error); // Add it to collection - but do NOT change run behavior UNLESS // we are in an ExecuteReader call - at which time we will be throwing // anyways so we need to consume all errors. This is not the case // if we have already given out a reader. If we have already given out // a reader we need to throw the error but not halt further processing. We used to // halt processing. if (null != dataStream) { if (!dataStream.IsInitialized) { runBehavior = RunBehavior.UntilDone; } } } else { stateObj.AddError(error); // Else we have a fatal error and we need to change the behavior // since we want the complete error information in the exception. // Besides - no further results will be received. runBehavior = RunBehavior.UntilDone; } } } else if (error.Class >= TdsEnums.FATAL_ERROR_CLASS) { stateObj.AddError(error); } break; } case TdsEnums.SQLCOLINFO: { if (null != dataStream) { _SqlMetaDataSet metaDataSet; if (!TryProcessColInfo(dataStream.MetaData, dataStream, stateObj, out metaDataSet)) { return false; } if (!dataStream.TrySetMetaData(metaDataSet, false)) { return false; } dataStream.BrowseModeInfoConsumed = true; } else { // no dataStream if (!stateObj.TrySkipBytes(tokenLength)) { return false; } } break; } case TdsEnums.SQLDONE: case TdsEnums.SQLDONEPROC: case TdsEnums.SQLDONEINPROC: { // RunBehavior can be modified if (!TryProcessDone(cmdHandler, dataStream, ref runBehavior, stateObj)) { return false; } if ((token == TdsEnums.SQLDONEPROC) && (cmdHandler != null)) { cmdHandler.OnDoneProc(); } break; } case TdsEnums.SQLORDER: { // don't do anything with the order token so read off the pipe if (!stateObj.TrySkipBytes(tokenLength)) { return false; } break; } case TdsEnums.SQLALTMETADATA: { stateObj.CloneCleanupAltMetaDataSetArray(); if (stateObj._cleanupAltMetaDataSetArray == null) { // create object on demand (lazy creation) stateObj._cleanupAltMetaDataSetArray = new _SqlMetaDataSetCollection(); } _SqlMetaDataSet cleanupAltMetaDataSet; if (!TryProcessAltMetaData(tokenLength, stateObj, out cleanupAltMetaDataSet)) { return false; } stateObj._cleanupAltMetaDataSetArray.SetAltMetaData(cleanupAltMetaDataSet); if (null != dataStream) { byte metadataConsumedByte; if (!stateObj.TryPeekByte(out metadataConsumedByte)) { return false; } if (!dataStream.TrySetAltMetaDataSet(cleanupAltMetaDataSet, (TdsEnums.SQLALTMETADATA != metadataConsumedByte))) { return false; } } break; } case TdsEnums.SQLALTROW: { if (!stateObj.TryStartNewRow(isNullCompressed: false)) { // altrows are not currently null compressed return false; } // read will call run until dataReady. Must not read any data if returnimmetiately set if (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior)) { ushort altRowId; if (!stateObj.TryReadUInt16(out altRowId)) { // get altRowId return false; } if (!TrySkipRow(stateObj._cleanupAltMetaDataSetArray.GetAltMetaData(altRowId), stateObj)) { // skip altRow return false; } } else { dataReady = true; } break; } case TdsEnums.SQLENVCHANGE: { // ENVCHANGE must be processed synchronously (since it can modify the state of many objects) stateObj._syncOverAsync = true; SqlEnvChange[] env; if (!TryProcessEnvChange(tokenLength, stateObj, out env)) { return false; } for (int ii = 0; ii < env.Length; ii++) { if (env[ii] != null && !this.Connection.IgnoreEnvChange) { switch (env[ii].type) { case TdsEnums.ENV_BEGINTRAN: // When we get notification from the server of a new // transaction, we move any pending transaction over to // the current transaction, then we store the token in it. // if there isn't a pending transaction, then it's either // a TSQL transaction or a distributed transaction. Debug.Assert(null == _currentTransaction, "non-null current transaction with an ENV Change"); _currentTransaction = _pendingTransaction; _pendingTransaction = null; if (null != _currentTransaction) { _currentTransaction.TransactionId = env[ii].newLongValue; // this is defined as a ULongLong in the server and in the TDS Spec. } else { TransactionType transactionType = TransactionType.LocalFromTSQL; _currentTransaction = new SqlInternalTransaction(_connHandler, transactionType, null, env[ii].newLongValue); } if (null != _statistics && !_statisticsIsInTransaction) { _statistics.SafeIncrement(ref _statistics._transactions); } _statisticsIsInTransaction = true; break; case TdsEnums.ENV_COMMITTRAN: // SQLHOT 483 // Must clear the retain id if the server-side transaction ends by anything other // than rollback. goto case TdsEnums.ENV_ROLLBACKTRAN; case TdsEnums.ENV_ROLLBACKTRAN: // When we get notification of a completed transaction // we null out the current transaction. if (null != _currentTransaction) { #if DEBUG // Check null for case where Begin and Rollback obtained in the same message. if (SqlInternalTransaction.NullTransactionId != _currentTransaction.TransactionId) { Debug.Assert(_currentTransaction.TransactionId != env[ii].newLongValue, "transaction id's are not equal!"); } #endif if (TdsEnums.ENV_COMMITTRAN == env[ii].type) { _currentTransaction.Completed(TransactionState.Committed); } else if (TdsEnums.ENV_ROLLBACKTRAN == env[ii].type) { // Hold onto transaction id if distributed tran is rolled back. This must // be sent to the server on subsequent executions even though the transaction // is considered to be rolled back. _currentTransaction.Completed(TransactionState.Aborted); } else { _currentTransaction.Completed(TransactionState.Unknown); } _currentTransaction = null; } _statisticsIsInTransaction = false; break; case TdsEnums.ENV_ENLISTDTC: case TdsEnums.ENV_DEFECTDTC: case TdsEnums.ENV_TRANSACTIONENDED: Debug.Assert(false, "Should have thrown if DTC token encountered"); break; default: _connHandler.OnEnvChange(env[ii]); break; } } } break; } case TdsEnums.SQLLOGINACK: { SqlLoginAck ack; if (!TryProcessLoginAck(stateObj, out ack)) { return false; } _connHandler.OnLoginAck(ack); break; } case TdsEnums.SQLFEATUREEXTACK: { if (!TryProcessFeatureExtAck(stateObj)) { return false; } break; } case TdsEnums.SQLSESSIONSTATE: { if (!TryProcessSessionState(stateObj, tokenLength, _connHandler._currentSessionData)) { return false; } break; } case TdsEnums.SQLCOLMETADATA: { if (tokenLength != TdsEnums.VARNULL) { _SqlMetaDataSet metadata; if (!TryProcessMetaData(tokenLength, stateObj, out metadata)) { return false; } stateObj._cleanupMetaData = metadata; } else { if (cmdHandler != null) { stateObj._cleanupMetaData = cmdHandler.MetaData; } } if (null != dataStream) { byte peekedToken; if (!stateObj.TryPeekByte(out peekedToken)) { // temporarily cache next byte return false; } if (!dataStream.TrySetMetaData(stateObj._cleanupMetaData, (TdsEnums.SQLTABNAME == peekedToken || TdsEnums.SQLCOLINFO == peekedToken))) { return false; } } else if (null != bulkCopyHandler) { bulkCopyHandler.SetMetaData(stateObj._cleanupMetaData); } break; } case TdsEnums.SQLROW: case TdsEnums.SQLNBCROW: { Debug.Assert(stateObj._cleanupMetaData != null, "Reading a row, but the metadata is null"); if (token == TdsEnums.SQLNBCROW) { if (!stateObj.TryStartNewRow(isNullCompressed: true, nullBitmapColumnsCount: stateObj._cleanupMetaData.Length)) { return false; } } else { if (!stateObj.TryStartNewRow(isNullCompressed: false)) { return false; } } if (null != bulkCopyHandler) { if (!TryProcessRow(stateObj._cleanupMetaData, bulkCopyHandler.CreateRowBuffer(), bulkCopyHandler.CreateIndexMap(), stateObj)) { return false; } } else if (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior)) { if (!TrySkipRow(stateObj._cleanupMetaData, stateObj)) { // skip rows return false; } } else { dataReady = true; } if (_statistics != null) { _statistics.WaitForDoneAfterRow = true; } break; } case TdsEnums.SQLRETURNSTATUS: int status; if (!stateObj.TryReadInt32(out status)) { return false; } if (cmdHandler != null) { cmdHandler.OnReturnStatus(status); } break; case TdsEnums.SQLRETURNVALUE: { SqlReturnValue returnValue; if (!TryProcessReturnValue(tokenLength, stateObj, out returnValue)) { return false; } if (cmdHandler != null) { cmdHandler.OnReturnValue(returnValue); } break; } case TdsEnums.SQLSSPI: { // token length is length of SSPI data - call ProcessSSPI with it Debug.Assert(stateObj._syncOverAsync, "ProcessSSPI does not support retry, do not attempt asynchronously"); stateObj._syncOverAsync = true; ProcessSSPI(tokenLength); break; } case TdsEnums.SQLTABNAME: { { if (!stateObj.TrySkipBytes(tokenLength)) { return false; } } break; } default: Debug.Assert(false, "Unhandled token: " + token.ToString(CultureInfo.InvariantCulture)); break; } Debug.Assert(stateObj._pendingData || !dataReady, "dataReady is set, but there is no pending data"); } // Loop while data pending & runbehavior not return immediately, OR // if in attention case, loop while no more pending data & attention has not yet been // received. while ((stateObj._pendingData && (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior))) || (!stateObj._pendingData && stateObj._attentionSent && !stateObj._attentionReceived)); #if DEBUG if ((stateObj._pendingData) && (!dataReady)) { byte token; if (!stateObj.TryPeekByte(out token)) { return false; } Debug.Assert(IsValidTdsToken(token), string.Format("DataReady is false, but next token is not valid: {0,-2:X2}", token)); } #endif if (!stateObj._pendingData) { if (null != CurrentTransaction) { CurrentTransaction.Activate(); } } // if we recieved an attention (but this thread didn't send it) then // we throw an Operation Cancelled error if (stateObj._attentionReceived) { // Dev11 #344723: SqlClient stress hang System_Data!Tcp::ReadSync via a call to SqlDataReader::Close // Spin until SendAttention has cleared _attentionSending, this prevents a race condition between receiving the attention ACK and setting _attentionSent SpinWait.SpinUntil(() => !stateObj._attentionSending); Debug.Assert(stateObj._attentionSent, "Attention ACK has been received without attention sent"); if (stateObj._attentionSent) { // Reset attention state. stateObj._attentionSent = false; stateObj._attentionReceived = false; if (RunBehavior.Clean != (RunBehavior.Clean & runBehavior) && !stateObj._internalTimeout) { // Add attention error to collection - if not RunBehavior.Clean! stateObj.AddError(new SqlError(0, 0, TdsEnums.MIN_ERROR_CLASS, _server, SQLMessage.OperationCancelled(), "", 0)); } } } if (stateObj.HasErrorOrWarning) { ThrowExceptionAndWarning(stateObj); } return true; }
internal void ThrowExceptionAndWarning(TdsParserStateObject stateObj, bool callerHasConnectionLock = false, bool asyncClose = false) { Debug.Assert(!callerHasConnectionLock || _connHandler._parserLock.ThreadMayHaveLock(), "Caller claims to have lock, but connection lock is not taken"); SqlException exception = null; bool breakConnection; // This function should only be called when there was an error or warning. If there aren't any // errors, the handler will be called for the warning(s). If there was an error, the warning(s) will // be copied to the end of the error collection so that the user may see all the errors and also the // warnings that occurred. // can be deleted) SqlErrorCollection temp = stateObj.GetFullErrorAndWarningCollection(out breakConnection); Debug.Assert(temp.Count > 0, "TdsParser::ThrowExceptionAndWarning called with no exceptions or warnings!"); Debug.Assert(_connHandler != null, "TdsParser::ThrowExceptionAndWarning called with null connectionHandler!"); // Don't break the connection if it is already closed breakConnection &= (TdsParserState.Closed != _state); if (breakConnection) { if ((_state == TdsParserState.OpenNotLoggedIn) && (_connHandler.ConnectionOptions.MultiSubnetFailover || _loginWithFailover) && (temp.Count == 1) && ((temp[0].Number == TdsEnums.TIMEOUT_EXPIRED) || (temp[0].Number == TdsEnums.SNI_WAIT_TIMEOUT))) { // For Multisubnet Failover we slice the timeout to make reconnecting faster (with the assumption that the server will not failover instantaneously) // However, when timeout occurs we need to not doom the internal connection and also to mark the TdsParser as closed such that the login will be will retried breakConnection = false; Disconnect(); } else { _state = TdsParserState.Broken; } } Debug.Assert(temp != null, "TdsParser::ThrowExceptionAndWarning: 0 errors in collection"); if (temp != null && temp.Count > 0) { // Construct the exception now that we've collected all the errors string serverVersion = null; if (_state == TdsParserState.OpenLoggedIn) { serverVersion = _connHandler.ServerVersion; } exception = SqlException.CreateException(temp, serverVersion, _connHandler); } // call OnError outside of _ErrorCollectionLock to avoid deadlock if (exception != null) { if (breakConnection) { // report exception to pending async operation // before OnConnectionClosed overrides the exception // due to connection close notification through references var taskSource = stateObj._networkPacketTaskSource; if (taskSource != null) { taskSource.TrySetException(ADP.ExceptionWithStackTrace(exception)); } } if (asyncClose) { // Wait until we have the parser lock, then try to close var connHandler = _connHandler; Action<Action> wrapCloseAction = closeAction => { Task.Factory.StartNew(() => { connHandler._parserLock.Wait(canReleaseFromAnyThread: false); connHandler.ThreadHasParserLockForClose = true; try { closeAction(); } finally { connHandler.ThreadHasParserLockForClose = false; connHandler._parserLock.Release(); } }); }; _connHandler.OnError(exception, breakConnection, wrapCloseAction); } else { // Let close know that we already have the _parserLock bool threadAlreadyHadParserLockForClose = _connHandler.ThreadHasParserLockForClose; if (callerHasConnectionLock) { _connHandler.ThreadHasParserLockForClose = true; } try { // the following handler will throw an exception or generate a warning event _connHandler.OnError(exception, breakConnection); } finally { if (callerHasConnectionLock) { _connHandler.ThreadHasParserLockForClose = threadAlreadyHadParserLockForClose; } } } } }
internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, out SqlReturnValue returnValue) { returnValue = null; SqlReturnValue rec = new SqlReturnValue(); rec.length = length; // In Yukon this length is -1 ushort parameterIndex; if (!stateObj.TryReadUInt16(out parameterIndex)) { return false; } byte len; if (!stateObj.TryReadByte(out len)) { // Length of parameter name return false; } if (len > 0) { if (!stateObj.TryReadString(len, out rec.parameter)) { return false; } } // read status and ignore byte ignored; if (!stateObj.TryReadByte(out ignored)) { return false; } UInt32 userType; // read user type - 4 bytes Yukon, 2 backwards if (!stateObj.TryReadUInt32(out userType)) { return false; } // read off the flags ushort ignoredFlags; if (!stateObj.TryReadUInt16(out ignoredFlags)) { return false; } // read the type byte tdsType; if (!stateObj.TryReadByte(out tdsType)) { return false; } // read the MaxLen // For xml datatypes, there is no tokenLength int tdsLen; if (tdsType == TdsEnums.SQLXMLTYPE) { tdsLen = TdsEnums.SQL_USHORTVARMAXLEN; } else if (IsVarTimeTds(tdsType)) tdsLen = 0; // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN else if (tdsType == TdsEnums.SQLDATE) { tdsLen = 3; } else { if (!TryGetTokenLength(tdsType, stateObj, out tdsLen)) { return false; } } rec.metaType = MetaType.GetSqlDataType(tdsType, userType, tdsLen); rec.type = rec.metaType.SqlDbType; // always use the nullable type for parameters if Shiloh or later // Sphinx sometimes sends fixed length return values rec.tdsType = rec.metaType.NullableType; rec.isNullable = true; if (tdsLen == TdsEnums.SQL_USHORTVARMAXLEN) { rec.metaType = MetaType.GetMaxMetaTypeFromMetaType(rec.metaType); } if (rec.type == SqlDbType.Decimal) { if (!stateObj.TryReadByte(out rec.precision)) { return false; } if (!stateObj.TryReadByte(out rec.scale)) { return false; } } if (rec.metaType.IsVarTime) { if (!stateObj.TryReadByte(out rec.scale)) { return false; } } if (tdsType == TdsEnums.SQLUDT) { _state = TdsParserState.Broken; _connHandler.BreakConnection(); throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString()); } if (rec.type == SqlDbType.Xml) { // Read schema info byte schemapresent; if (!stateObj.TryReadByte(out schemapresent)) { return false; } if ((schemapresent & 1) != 0) { if (!stateObj.TryReadByte(out len)) { return false; } if (len != 0) { if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionDatabase)) { return false; } } if (!stateObj.TryReadByte(out len)) { return false; } if (len != 0) { if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionOwningSchema)) { return false; } } short slen; if (!stateObj.TryReadInt16(out slen)) { return false; } if (slen != 0) { if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollectionName)) { return false; } } } } else if (rec.metaType.IsCharType) { // read the collation for 8.x servers if (!TryProcessCollation(stateObj, out rec.collation)) { return false; } int codePage = GetCodePage(rec.collation, stateObj); // if the column lcid is the same as the default, use the default encoder if (codePage == _defaultCodePage) { rec.codePage = _defaultCodePage; rec.encoding = _defaultEncoding; } else { rec.codePage = codePage; rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage); } } // for now we coerce return values into a SQLVariant, not good... bool isNull = false; ulong valLen; if (!TryProcessColumnHeaderNoNBC(rec, stateObj, out isNull, out valLen)) { return false; } // always read as sql types Debug.Assert(valLen < (ulong)(Int32.MaxValue), "ProcessReturnValue received data size > 2Gb"); int intlen = valLen > (ulong)(Int32.MaxValue) ? Int32.MaxValue : (int)valLen; if (rec.metaType.IsPlp) { intlen = Int32.MaxValue; // If plp data, read it all } if (isNull) { GetNullSqlValue(rec.value, rec); } else { if (!TryReadSqlValue(rec.value, rec, intlen, stateObj)) { return false; } } returnValue = rec; return true; }
// This is called from a ThreadAbort - ensure that it can be run from a CER Catch internal void BestEffortCleanup() { _state = TdsParserState.Broken; var stateObj = _physicalStateObj; if (stateObj != null) { var stateObjHandle = stateObj.Handle; if (stateObjHandle != null) { stateObjHandle.Dispose(); } } if (_fMARS) { var sessionPool = _sessionPool; if (sessionPool != null) { sessionPool.BestEffortCleanup(); } var marsStateObj = _pMarsPhysicalConObj; if (marsStateObj != null) { var marsStateObjHandle = marsStateObj.Handle; if (marsStateObjHandle != null) { marsStateObjHandle.Dispose(); } } } }
internal void Disconnect() { if (this._sessionPool != null) { this._sessionPool.Dispose(); } if (this._state != TdsParserState.Closed) { this._state = TdsParserState.Closed; this._physicalStateObj.SniContext = SniContext.Snix_Close; if (this._fMARS) { try { this._physicalStateObj.Dispose(); if (this._pMarsPhysicalConObj != null) { this._pMarsPhysicalConObj.Dispose(); } return; } finally { this._pMarsPhysicalConObj = null; } } this._physicalStateObj.Dispose(); } }
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; }
internal void ThrowExceptionAndWarning() { lock (this._ErrorCollectionLock) { if ((this._errors == null) && (this._warnings == null)) { Bid.Trace("<sc.TdsParser.ThrowExceptionAndWarning|ERR> Potential multi-threaded misuse of connection, unexpectedly empty warnings/errors under lock %d#\n", this.ObjectID); } SqlErrorCollection temp = null; bool breakConnection = this.AddSqlErrorToCollection(ref temp, ref this._errors) | this.AddSqlErrorToCollection(ref temp, ref this._attentionErrors); breakConnection |= this.AddSqlErrorToCollection(ref temp, ref this._warnings); breakConnection |= this.AddSqlErrorToCollection(ref temp, ref this._attentionWarnings); if (breakConnection) { this._state = TdsParserState.Broken; } if ((temp != null) && (temp.Count > 0)) { string serverVersion = null; if (this._state == TdsParserState.OpenLoggedIn) { serverVersion = this._connHandler.ServerVersion; } SqlException exception = SqlException.CreateException(temp, serverVersion); this._connHandler.OnError(exception, breakConnection); } } }
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; } } }
internal bool Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) { if ((TdsParserState.Broken == this.State) || (this.State == TdsParserState.Closed)) { return true; } bool flag = false; Label_0016: if (stateObj._internalTimeout) { runBehavior = RunBehavior.Attention; } if ((TdsParserState.Broken == this.State) || (this.State == TdsParserState.Closed)) { goto Label_0705; } byte token = stateObj.ReadByte(); if ((((((token != 170) && (token != 0xab)) && ((token != 0xad) && (token != 0xe3))) && (((token != 0xac) && (token != 0x79)) && ((token != 160) && (token != 0xa1)))) && ((((token != 0x81) && (token != 0x88)) && ((token != 0xa4) && (token != 0xa5))) && (((token != 0xa9) && (token != 0xd3)) && ((token != 0xd1) && (token != 0xfd))))) && ((((token != 0xfe) && (token != 0xff)) && ((token != 0x39) && (token != 0xed))) && (((token != 0xae) && (token != 0x7c)) && ((token != 120) && (token != 0xed))))) { this._state = TdsParserState.Broken; this._connHandler.BreakConnection(); Bid.Trace("<sc.TdsParser.Run|ERR> Potential multi-threaded misuse of connection, unexpected TDS token found %d#\n", this.ObjectID); throw SQL.ParsingError(); } int tokenLength = this.GetTokenLength(token, stateObj); switch (token) { case 0xa4: if (dataStream == null) { this.SkipBytes(tokenLength, stateObj); } else { dataStream.TableNames = this.ProcessTableName(tokenLength, stateObj); } goto Label_06D5; case 0xa5: if (dataStream == null) { this.SkipBytes(tokenLength, stateObj); } else { _SqlMetaDataSet metaData = this.ProcessColInfo(dataStream.MetaData, dataStream, stateObj); dataStream.SetMetaData(metaData, false); dataStream.BrowseModeInfoConsumed = true; } goto Label_06D5; case 0xa9: this.SkipBytes(tokenLength, stateObj); goto Label_06D5; case 170: case 0xab: { if (token == 170) { stateObj._errorTokenReceived = true; } SqlError error = this.ProcessError(token, stateObj); if (RunBehavior.Clean == (RunBehavior.Clean & runBehavior)) { if (error.Class >= 20) { this.Errors.Add(error); } } else { SqlConnection connection = null; if (this._connHandler != null) { connection = this._connHandler.Connection; } if (((connection != null) && connection.FireInfoMessageEventOnUserErrors) && (error.Class <= 0x10)) { this.FireInfoMessageEvent(connection, stateObj, error); } else if (error.Class < 11) { this.Warnings.Add(error); } else if (error.Class < 20) { this.Errors.Add(error); if ((dataStream != null) && !dataStream.IsInitialized) { runBehavior = RunBehavior.UntilDone; } } else { this.Errors.Add(error); runBehavior = RunBehavior.UntilDone; } } goto Label_06D5; } case 0xac: { SqlReturnValue rec = this.ProcessReturnValue(tokenLength, stateObj); if (cmdHandler != null) { cmdHandler.OnReturnValue(rec); } goto Label_06D5; } case 0xad: { SqlLoginAck ack = this.ProcessLoginAck(stateObj); this._connHandler.OnLoginAck(ack); goto Label_06D5; } case 0x88: { if (stateObj._cleanupAltMetaDataSetArray == null) { stateObj._cleanupAltMetaDataSetArray = new _SqlMetaDataSetCollection(); } _SqlMetaDataSet altMetaDataSet = this.ProcessAltMetaData(tokenLength, stateObj); stateObj._cleanupAltMetaDataSetArray.SetAltMetaData(altMetaDataSet); if (dataStream != null) { dataStream.SetAltMetaDataSet(altMetaDataSet, 0x88 != stateObj.PeekByte()); } goto Label_06D5; } case 0x79: { int status = stateObj.ReadInt32(); if (cmdHandler != null) { cmdHandler.OnReturnStatus(status); } goto Label_06D5; } case 0x81: if (tokenLength != 0xffff) { stateObj._cleanupMetaData = this.ProcessMetaData(tokenLength, stateObj); } else if (cmdHandler != null) { stateObj._cleanupMetaData = cmdHandler.MetaData; } if (dataStream != null) { byte num5 = stateObj.PeekByte(); dataStream.SetMetaData(stateObj._cleanupMetaData, (0xa4 == num5) || (0xa5 == num5)); } else if (bulkCopyHandler != null) { bulkCopyHandler.SetMetaData(stateObj._cleanupMetaData); } goto Label_06D5; case 0xd1: if (bulkCopyHandler == null) { if (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior)) { this.SkipRow(stateObj._cleanupMetaData, stateObj); } break; } this.ProcessRow(stateObj._cleanupMetaData, bulkCopyHandler.CreateRowBuffer(), bulkCopyHandler.CreateIndexMap(), stateObj); break; case 0xd3: if (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior)) { int id = stateObj.ReadUInt16(); this.SkipRow(stateObj._cleanupAltMetaDataSetArray.GetAltMetaData(id), stateObj); } flag = true; goto Label_06D5; case 0xe3: { SqlEnvChange[] changeArray = this.ProcessEnvChange(tokenLength, stateObj); for (int i = 0; i < changeArray.Length; i++) { if ((changeArray[i] == null) || this.Connection.IgnoreEnvChange) { continue; } switch (changeArray[i].type) { case 8: case 11: this._currentTransaction = this._pendingTransaction; this._pendingTransaction = null; if (this._currentTransaction == null) { break; } this._currentTransaction.TransactionId = changeArray[i].newLongValue; goto Label_04B4; case 9: case 12: case 0x11: this._retainedTransactionId = 0L; goto Label_04F7; case 10: goto Label_04F7; default: goto Label_0577; } TransactionType type = (8 == changeArray[i].type) ? TransactionType.LocalFromTSQL : TransactionType.Distributed; this._currentTransaction = new SqlInternalTransaction(this._connHandler, type, null, changeArray[i].newLongValue); Label_04B4: if ((this._statistics != null) && !this._statisticsIsInTransaction) { this._statistics.SafeIncrement(ref this._statistics._transactions); } this._statisticsIsInTransaction = true; this._retainedTransactionId = 0L; continue; Label_04F7: if (this._currentTransaction != null) { if (9 == changeArray[i].type) { this._currentTransaction.Completed(TransactionState.Committed); } else if (10 == changeArray[i].type) { if (this._currentTransaction.IsDistributed && this._currentTransaction.IsActive) { this._retainedTransactionId = changeArray[i].oldLongValue; } this._currentTransaction.Completed(TransactionState.Aborted); } else { this._currentTransaction.Completed(TransactionState.Unknown); } this._currentTransaction = null; } this._statisticsIsInTransaction = false; continue; Label_0577: this._connHandler.OnEnvChange(changeArray[i]); } goto Label_06D5; } case 0xfd: case 0xfe: case 0xff: this.ProcessDone(cmdHandler, dataStream, ref runBehavior, stateObj); if ((token == 0xfe) && (cmdHandler != null)) { cmdHandler.OnDoneProc(); } goto Label_06D5; case 0xed: this.ProcessSSPI(tokenLength); goto Label_06D5; default: goto Label_06D5; } if (this._statistics != null) { this._statistics.WaitForDoneAfterRow = true; } flag = true; Label_06D5: if ((stateObj._pendingData && (RunBehavior.ReturnImmediately != (RunBehavior.ReturnImmediately & runBehavior))) || ((!stateObj._pendingData && stateObj._attentionSent) && !stateObj._attentionReceived)) { goto Label_0016; } Label_0705: if (!stateObj._pendingData && (this.CurrentTransaction != null)) { this.CurrentTransaction.Activate(); } if (stateObj._attentionSent && stateObj._attentionReceived) { stateObj._attentionSent = false; stateObj._attentionReceived = false; if ((RunBehavior.Clean != (RunBehavior.Clean & runBehavior)) && !stateObj._internalTimeout) { this.Errors.Add(new SqlError(0, 0, 11, this._server, SQLMessage.OperationCancelled(), "", 0)); } } if ((this._errors != null) || (this._warnings != null)) { this.ThrowExceptionAndWarning(); } return flag; }
private SqlLoginAck ProcessLoginAck(TdsParserStateObject stateObj) { SqlLoginAck ack = new SqlLoginAck(); this.SkipBytes(1, stateObj); byte[] buff = new byte[4]; stateObj.ReadByteArray(buff, 0, buff.Length); uint num3 = (uint) ((((((buff[0] << 8) | buff[1]) << 8) | buff[2]) << 8) | buff[3]); uint num6 = num3 & 0xff00ffff; uint num2 = (num3 >> 0x10) & 0xff; switch (num6) { case 0x72000002: if (num2 != 9) { throw SQL.InvalidTDSVersion(); } this._isYukon = true; break; case 0x73000003: if (num2 != 10) { throw SQL.InvalidTDSVersion(); } this._isKatmai = true; break; case 0x7000000: switch (num2) { case 1: this._isShiloh = true; goto Label_00DF; } throw SQL.InvalidTDSVersion(); case 0x71000001: if (num2 != 0) { throw SQL.InvalidTDSVersion(); } this._isShilohSP1 = true; break; default: throw SQL.InvalidTDSVersion(); } Label_00DF: this._isYukon |= this._isKatmai; this._isShilohSP1 |= this._isYukon; this._isShiloh |= this._isShilohSP1; ack.isVersion8 = this._isShiloh; stateObj._outBytesUsed = stateObj._outputHeaderLen; byte length = stateObj.ReadByte(); ack.programName = stateObj.ReadString(length); ack.majorVersion = stateObj.ReadByte(); ack.minorVersion = stateObj.ReadByte(); ack.buildNum = (short) ((stateObj.ReadByte() << 8) + stateObj.ReadByte()); this._state = TdsParserState.OpenLoggedIn; if ((this._isYukon && this._fAsync) && this._fMARS) { this._resetConnectionEvent = new AutoResetEvent(true); } if (this._connHandler.ConnectionOptions.UserInstance && ADP.IsEmpty(this._connHandler.InstanceName)) { this.Errors.Add(new SqlError(0, 0, 20, this.Server, SQLMessage.UserInstanceFailure(), "", 0)); this.ThrowExceptionAndWarning(); } return ack; }
private void ProcessAttention(TdsParserStateObject stateObj) { if ((this._state != TdsParserState.Closed) && (this._state != TdsParserState.Broken)) { lock (this._ErrorCollectionLock) { this._attentionErrors = this._errors; this._attentionWarnings = this._warnings; this._errors = null; this._warnings = null; try { this.Run(RunBehavior.Attention, null, null, null, stateObj); } catch (Exception exception) { if (!ADP.IsCatchableExceptionType(exception)) { throw; } ADP.TraceExceptionWithoutRethrow(exception); this._state = TdsParserState.Broken; this._connHandler.BreakConnection(); throw; } this._errors = this._attentionErrors; this._warnings = this._attentionWarnings; this._attentionErrors = null; this._attentionWarnings = null; } } }