TdsParserStateObject.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Data / System / Data / SqlClient / TdsParserStateObject.cs / 1 / TdsParserStateObject.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.SqlClient {
    using System; 
    using System.Data.Common;
    using System.Data.ProviderBase;
    using System.Data.Sql;
    using System.Data.SqlTypes; 
    using System.Diagnostics;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices; 
    using System.Runtime.ConstrainedExecution;
    using System.Threading; 
    using System.Globalization;

    sealed internal class TdsParserStateObject {
        private static int _objectTypeCount; // Bid counter 
        internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
 
        internal int ObjectID { 
            get {
                return _objectID; 
            }
        }

        // should only be used by TdsParserSessionPool.TdsParserStateObjectListStack.Synchronized(Push|Pop) 
        private TdsParserStateObject _nextPooledObject;
        internal TdsParserStateObject NextPooledObject { 
            get { return _nextPooledObject; } 
            set { _nextPooledObject = value; }
        } 

        private readonly TdsParser      _parser;                            // TdsParser pointer
        private SNIHandle               _sessionHandle = null;              // the SNI handle we're to work on
        private readonly WeakReference  _owner = new WeakReference(null);   // the owner of this session, used to track when it's been orphaned 
        private int                     _activateCount;                     // 0 when we're in the pool, 1 when we're not, all others are an error
 
        // Two buffers exist in tdsparser, an in buffer and an out buffer.  For the out buffer, only 
        // one bookkeeping variable is needed, the number of bytes used in the buffer.  For the in buffer,
        // three variables are actually needed.  First, we need to record from the netlib how many bytes it 
        // read from the netlib, this variable is _inBytesRead.  Then, we need to also keep track of how many
        // bytes we have used as we consume the bytes from the buffer, that variable is _inBytesRead.  Third,
        // we need to keep track of how many bytes are left in the packet, so that we know when we have reached
        // the end of the packet and so we need to consume the next header. 

        // Header length constants 
        internal readonly int           _inputHeaderLen        = TdsEnums.HEADER_LEN; 
        internal readonly int           _outputHeaderLen       = TdsEnums.HEADER_LEN;
 
        // Out buffer variables
        internal byte[]        _outBuff;                                     // internal write buffer - initialize on login
        internal int           _outBytesUsed          = TdsEnums.HEADER_LEN; // number of bytes used in internal write buffer -
                                                                             // - initialize past header 
        // In buffer variables
        private byte[]         _inBuff;                                      // internal read buffer - initialize on login 
        internal int           _inBytesUsed           = 0;                   // number of bytes used in internal read buffer 
        internal int           _inBytesRead           = 0;                   // number of bytes read into internal read buffer
        internal int           _inBytesPacket         = 0;                   // number of bytes left in packet 

        // Packet state variables
        internal byte          _outputMessageType     = 0;                   // tds header type
        internal byte          _messageStatus;                               // tds header status 
        internal byte          _outputPacketNumber    = 1;                   // number of packets sent to server
                                                                             // in message - start at 1 per ramas 
        internal bool          _pendingData           = false; 
        internal volatile bool _fResetEventOwned      = false;               // ResetEvent serializing call to sp_reset_connection
        internal volatile bool _fResetConnectionSent  = false;               // For multiple packet execute 

        internal bool          _errorTokenReceived    = false;               // Keep track of whether an error was received for the result.
                                                                             // This is reset upon each done token - there can be
 
        internal bool          _bulkCopyOpperationInProgress = false;        // Set to true during bulk copy and used to turn toggle write timeouts.
 
        // SNI variables                                                     // multiple resultsets in one batch. 
        internal SNIPacket     _sniPacket             = null;                // Will have to re-vamp this for MARS
        internal SNIPacket     _sniAsyncAttnPacket    = null;                // Packet to use to send Attn 

        // Async variables
        internal DbAsyncResult _asyncResult           = null;                // Use this for current operation
        internal DbAsyncResult _cachedAsyncResult     = null;                // Only for internal use 
        internal DbAsyncResult _asyncAttentionResult  = null;
        private GCHandle       _gcHandle;                                    // keeps this object alive until we're closed. 
        private int            _pendingCallbacks;                            // we increment this before each async read/write call and decrement it in the callback.  We use this to determine when to release the GcHandle... 

        // Timeout variables 
        private  int           _timeoutSeconds;
        private  long          _timeoutTime;                                 // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire
        internal bool          _attentionSent         = false;               // true if we sent an Attention to the server
        internal bool          _attentionReceived     = false; 
        internal bool          _internalTimeout       = false;               // an internal timeout occured
 
        // This variable is used to track whether another thread has requested a cancel.  The 
        // synchronization points are
        //   On the user's execute thread: 
        //     1) the first packet write
        //     2) session close - return this stateObj to the session pool
        //   On cancel thread we only have the cancel call.
        // Currently all access to this variable is inside a lock, though I hope to limit that in the 
        // future.  The state diagram is:
        // 1) pre first packet write, if cancel is requested, set variable so exception is triggered 
        //    on user thread when first packet write is attempted 
        // 2) post first packet write, but before session return - a call to cancel will send an
        //    attention to the server 
        // 3) post session close - no attention is allowed
        private bool _cancelled;

        // This variable is used to prevent sending an attention by another thread that is not the 
        // current owner of the stateObj.  I currently do not know how this can happen.  Mark added
        // the code but does not remember either.  At some point, we need to research killing this 
        // logic. 
        private volatile int _allowObjectID;
 
        internal bool                   _hasOpenResult            = false;
        // Cache the transaction for which this command was executed so upon completion we can
        // decrement the appropriate result count.
        internal SqlInternalTransaction _executedUnderTransaction = null; 

        // TDS stream processing variables 
        internal ulong         _longlen;                                     // plp data length indicator 
        internal ulong         _longlenleft;                                 // Length of data left to read (64 bit lengths)
        internal int[]         _decimalBits           = null;                // scratch buffer for decimal/numeric data 
        internal byte[]        _bTmp                  = new byte[TdsEnums.YUKON_HEADER_LEN];  // Scratch buffer for misc use

        //
        // DO NOT USE THIS BUFFER FOR OTHER THINGS. 
        // ProcessHeader can be called ANYTIME while doing network reads.
        internal byte[]        _bHeaderBuffer =null;   // Scratch buffer for ProcessHeader 
 
        internal SqlError      _error;
 
        //

        internal _SqlMetaDataSet           _cleanupMetaData = null;
        internal _SqlMetaDataSetCollection _cleanupAltMetaDataSetArray = null; 

         // Used for blanking out password in trace. 
        internal int _tracePasswordOffset = 0; 
        internal int _tracePasswordLength = 0;
        internal int _traceChangePasswordOffset = 0; 
        internal int _traceChangePasswordLength = 0;

        internal bool _receivedColMetaData;      // Used to keep track of when to fire StatementCompleted  event.
 
        private SniContext _sniContext=SniContext.Undefined;
#if DEBUG 
        private SniContext _debugOnlyCopyOfSniContext=SniContext.Undefined; 
#endif
 
        private bool _bcpLock = false;

        //////////////////
        // Constructors // 
        //////////////////
 
        internal TdsParserStateObject(TdsParser parser) { 
            // Construct a physical connection
            Debug.Assert(null != parser, "no parser?"); 
            _parser = parser;

            // For physical connection, initialize to default login packet size.
            SetPacketSize(TdsEnums.DEFAULT_LOGIN_PACKET_SIZE); 

            // we post a callback that represents the call to dispose; once the 
            // object is disposed, the next callback will cause the GC Handle to 
            // be released.
            IncrementPendingCallbacks(); 
        }

        internal TdsParserStateObject(TdsParser parser, SNIHandle physicalConnection, bool async) {
            // Construct a MARS session 
            Debug.Assert(null != parser, "no parser?");
            _parser = parser; 
            SniContext=SniContext.Snix_GetMarsSession; 

            Debug.Assert(null != _parser._physicalStateObj, "no physical session?"); 
            Debug.Assert(null != _parser._physicalStateObj._inBuff, "no in buffer?");
            Debug.Assert(null != _parser._physicalStateObj._outBuff, "no out buffer?");
            Debug.Assert(_parser._physicalStateObj._outBuff.Length ==
                         _parser._physicalStateObj._inBuff.Length, "Unexpected unequal buffers."); 

            // Determine packet size based on physical connection buffer lengths. 
            SetPacketSize(_parser._physicalStateObj._outBuff.Length); 

            SNINativeMethodWrapper.ConsumerInfo myInfo = CreateConsumerInfo(async); 
            _sessionHandle = new SNIHandle(myInfo, "session:", physicalConnection);
            if (_sessionHandle.Status != TdsEnums.SNI_SUCCESS) {
                parser.Errors.Add(parser.ProcessSNIError(this));
                parser.ThrowExceptionAndWarning(this); 
            }
 
            // we post a callback that represents the call to dispose; once the 
            // object is disposed, the next callback will cause the GC Handle to
            // be released. 
            IncrementPendingCallbacks();
        }

        //////////////// 
        // Properties //
        //////////////// 
 
        // BcpLock - use to lock this object if there is a potential risk of using this object
        // between tds packets 
        internal bool  BcpLock {
            get {
                return _bcpLock;
            } 
            set {
                _bcpLock = value; 
            } 
        }
 
#if DEBUG
        internal SniContext DebugOnlyCopyOfSniContext {
            get {
                return _debugOnlyCopyOfSniContext; 
            }
        } 
#endif 

        internal SNIHandle Handle { 
            get {
                return _sessionHandle;
            }
        } 

        internal bool HasOpenResult { 
            get { 
                return _hasOpenResult;
            } 
        }

#if DEBUG
        internal void InvalidateDebugOnlyCopyOfSniContext() { 
            _debugOnlyCopyOfSniContext = SniContext.Undefined;
        } 
#endif 

        internal bool IsOrphaned { 
            get {
                Debug.Assert((0 == _activateCount && !_owner.IsAlive) // in pool
                             || (1 == _activateCount && _owner.IsAlive && _owner.Target != null)
                             || (1 == _activateCount && !_owner.IsAlive), "Unknown state on TdsParserStateObject.IsOrphaned!"); 
                return (0 != _activateCount && !_owner.IsAlive);
            } 
        } 

        internal object Owner { 
            set {
                _owner.Target = value;
            }
        } 

        internal TdsParser Parser { 
            get { 
                return _parser;
            } 
        }

        internal SniContext SniContext {
            get { 
                return _sniContext;
            } 
            set { 
                _sniContext = value;
#if DEBUG 
                _debugOnlyCopyOfSniContext = value;
#endif
            }
        } 

        internal UInt32 Status { 
            get { 
                if (_sessionHandle != null) {
                    return _sessionHandle.Status; 
                }
                else { // SQL BU DT 395431.
                    return TdsEnums.SNI_UNINITIALIZED;
                } 
            }
        } 
 
        internal bool TimeoutHasExpired {
            get { 
                Debug.Assert(0 == _timeoutSeconds || 0 == _timeoutTime, "_timeoutTime hasn't been reset");
                return TdsParserStaticMethods.TimeoutHasExpired(_timeoutTime);
            }
        } 

        internal long TimeoutTime { 
            get { 
                if (0 != _timeoutSeconds) {
                    _timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(_timeoutSeconds); 
                    _timeoutSeconds = 0;
                }
                return _timeoutTime;
            } 
            set {
                _timeoutSeconds = 0; 
                _timeoutTime = value; 
            }
        } 

        /////////////////////
        // General methods //
        ///////////////////// 

        internal void Activate(object owner) { 
            Owner = owner; // must assign an owner for reclaimation to work 
            int result = Interlocked.Increment(ref _activateCount);   // must have non-zero activation count for reclaimation to work too.
            Debug.Assert(result == 1, "invalid deactivate count"); 
        }

        // This method is only called by the command or datareader as a result of a user initiated
        // cancel request. 
        internal void Cancel(int objectID) {
            lock(this) { // Lock for the time being - since we need to synchronize the attention send. 
                         // At some point in the future, I hope to remove this. 
                // don't allow objectID -1 since it is reserved for 'not associated with a command'
                // yes, the 2^32-1 comand won't cancel - but it also won't cancel when we don't want it 
                if (!_cancelled && (objectID == _allowObjectID) && (objectID != -1)) {
                    _cancelled = true;

                    if (_pendingData && !_attentionSent) { 
                        SendAttention();
                    } 
                } 
            }
        } 

        // CancelRequest - use to cancel while writing a request to the server
        //
        // o none of the request might have been sent to the server, simply reset the buffer, 
        //   sending attention does not hurt
        // o the request was partially written. Send an ignore header to the server. attention is 
        //   required if the server was waiting for data (e.g. insert bulk rows) 
        // o the request was completely written out and the server started to process the request.
        //   attention is required to have the server stop processing. 
        //
        internal void CancelRequest() {
            ResetBuffer();    // clear out unsent buffer
            SendAttention(); 
            Parser.ProcessPendingAck(this);
        } 
 
        public void CheckSetResetConnectionState(UInt32 error, CallbackType callbackType) {
            // Should only be called for Async AND MARS together - that is the only time we need to take 
            // the ResetConnection lock!

            // SQL BU DT 333026 - it was raised in a security review by [....] questioning whether
            // we need to actually process the resulting packet (sp_reset ack or error) to know if the 
            // reset actually succeeded.  There was a concern that if the reset failed and we proceeded
            // there might be a security issue present.  We have been assured by the server that if 
            // sp_reset fails, they guarantee they will kill the resulting connection.  So - it is 
            // safe for us to simply receive the packet and then consume the pre-login later.
 
            Debug.Assert(_parser.MARSOn,  "Should not be calling CheckSetResetConnectionState on non MARS connection");
            Debug.Assert(_parser.AsyncOn, "Should not be calling CheckSetResetConnectionState on non Async connection");

            if (_fResetEventOwned) { 
                Debug.Assert(_parser._fResetConnection, "Invalid ResetConnection state on WriteAsyncCallback");
                Debug.Assert(_fResetConnectionSent, "Owned event but have not sent reset - on WriteAsyncCallback!"); 
 
                if (callbackType == CallbackType.Read && TdsEnums.SNI_SUCCESS == error) {
                    // RESET SUCCEEDED! 
                    // If we are on read callback and no error occurred (and we own reset event) -
                    // then we sent the sp_reset_connection and so we need to reset sp_reset_connection
                    // flag to false, and then release the ResetEvent.
                    _parser._fResetConnection = false; 
                    _fResetConnectionSent = false;
                    _fResetEventOwned = !_parser._resetConnectionEvent.Set(); 
                    Debug.Assert(!_fResetEventOwned, "Invalid AutoResetEvent state!"); 
                }
 
                if (TdsEnums.SNI_SUCCESS != error) {
                    // RESET FAILED!

                    // 

 
 

 
                    // If write or read failed with reset, we need to clear event but not mark connection
                    // as reset.
                    _fResetConnectionSent = false;
                    _fResetEventOwned = !_parser._resetConnectionEvent.Set(); 
                    Debug.Assert(!_fResetEventOwned, "Invalid AutoResetEvent state!");
                } 
            } 
        }
 
        internal void CloseSession() {
            ResetCancelAndProcessAttention();
#if DEBUG
            InvalidateDebugOnlyCopyOfSniContext(); 
#endif
            Parser.PutSession(this); 
        } 

        private void ResetCancelAndProcessAttention() { 
            // This method is shared by CloseSession initiated by DataReader.Close or completed
            // command execution, as well as the session reclaimation code for cases where the
            // DataReader is opened and then GC'ed.
            lock(this) { 
                // Reset cancel state.
                _cancelled = false; 
                _allowObjectID = -1; 

                if (_attentionSent) { 
                    // Make sure we're cleaning up the AttentionAck if Cancel happened before taking the lock.
                    // We serialize Cancel/CloseSession to prevent a race between these two states.
                    // The problem is that both sending and receiving attentions are time taking
                    // operations. 
                    Parser.ProcessPendingAck(this);
                } 
                _internalTimeout = false; 
            }
        } 

        private SNINativeMethodWrapper.ConsumerInfo CreateConsumerInfo(bool async) {
            SNINativeMethodWrapper.ConsumerInfo myInfo = new SNINativeMethodWrapper.ConsumerInfo();
 
            Debug.Assert(_outBuff.Length == _inBuff.Length, "Unexpected unequal buffers.");
 
            myInfo.defaultBufferSize = _outBuff.Length; // Obtain packet size from outBuff size. 
            myInfo.Prefix            = 	SNINativeMethodWrapper.PrefixNum.UNKNOWN_PREFIX;
 
            if (async) {
                myInfo.readDelegate  = SNILoadHandle.SingletonInstance.ReadAsyncCallbackDispatcher;
                myInfo.writeDelegate = SNILoadHandle.SingletonInstance.WriteAsyncCallbackDispatcher;
                _gcHandle            = GCHandle.Alloc(this, GCHandleType.Normal); 
                myInfo.key           = (IntPtr)_gcHandle;
            } 
            return myInfo; 
        }
 
        internal void CreatePhysicalSNIHandle(string serverName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, bool integratedSecurity, byte[] serverUserName, bool flushCache, bool async) {
            SNINativeMethodWrapper.ConsumerInfo myInfo = CreateConsumerInfo(async);

            // Translate to SNI timeout values (Int32 milliseconds) 
            long timeout;
            if (Int64.MaxValue == timerExpire) { 
                timeout = Int32.MaxValue; 
            }
            else { 
                timeout = ADP.TimerRemainingMilliseconds(timerExpire);
                if (timeout > Int32.MaxValue) {
                    timeout = Int32.MaxValue;
                } 
                else if (0 > timeout) {
                    timeout = 0; 
                } 
            }
 
            _sessionHandle = new SNIHandle(myInfo, serverName, integratedSecurity, serverUserName, ignoreSniOpenTimeout, checked((int)timeout), out instanceName, flushCache, !async);
        }

        internal bool Deactivate() { 
            bool goodForReuse = false;
 
            int result = Interlocked.Decrement(ref _activateCount);   // must have non-zero activation count for reclaimation to work too. 
            Debug.Assert(result == 0, "invalid deactivate count");
            Owner = null; 
            //
            try {
                TdsParserState state = Parser.State;
                if (state != TdsParserState.Broken && state != TdsParserState.Closed) { 
                    if (_pendingData) {
                        CleanWire(); // This may throw - taking us to catch block. 
                    } 

                    if (HasOpenResult) { // SQL BU DT 383773 - need to decrement openResultCount for all pending operations. 
                        DecrementOpenResultCount();
                    }

                    ResetCancelAndProcessAttention(); 
                    goodForReuse = true;
                } 
            } 
            catch (Exception e) {
                if (!ADP.IsCatchableExceptionType(e)) { 
                    throw;
                }
                ADP.TraceExceptionWithoutRethrow(e);
            } 
            return goodForReuse;
        } 
 
        internal void DecrementOpenResultCount() {
            if (_executedUnderTransaction == null) { 
                // If we were not executed under a transaction - decrement the global count
                // on the parser.
                _parser.DecrementNonTransactedOpenResultCount();
            } 
            else {
                // If we were executed under a transaction - decrement the count on the transaction. 
                _executedUnderTransaction.DecrementAndObtainOpenResultCount(); 
                _executedUnderTransaction = null;
            } 
            _hasOpenResult = false;
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        internal void DecrementPendingCallbacks(bool release) {
            int remaining = Interlocked.Decrement(ref _pendingCallbacks); 
            if (Bid.AdvancedOn) { 
                Bid.Trace(" %d#, after decrementing _pendingCallbacks: %d\n", ObjectID, _pendingCallbacks);
            } 

            if ((0 == remaining || release) && _gcHandle.IsAllocated) {
                if (Bid.AdvancedOn) {
                    Bid.Trace(" %d#, FREEING HANDLE!\n", ObjectID); 
                }
                _gcHandle.Free(); 
            } 
        }
 
        internal void Dispose() {
            SafeHandle packetHandle  = _sniPacket;
            SafeHandle sessionHandle = _sessionHandle;
            SafeHandle asyncAttnPacket = _sniAsyncAttnPacket; 
            _sniPacket     = null;
            _sessionHandle = null; 
            _sniAsyncAttnPacket = null; 

            if (null != sessionHandle || null != packetHandle) { 
                // Comment CloseMARSSession
                //

 

                // 
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try {} finally {
                    if (packetHandle != null) { 
                        packetHandle.Dispose();
                    }
                    if (asyncAttnPacket != null) {
                        asyncAttnPacket.Dispose (); 
                    }
                    if (sessionHandle != null) { 
                        sessionHandle.Dispose(); 
                        DecrementPendingCallbacks(true); // Will dispose of GC handle.
                    } 
                }
            }
        }
 
        internal Int32 IncrementAndObtainOpenResultCount(SqlInternalTransaction transaction) {
            _hasOpenResult = true; 
 
            if (transaction == null) {
                // If we are not passed a transaction, we are not executing under a transaction 
                // and thus we should increment the global connection result count.
                return _parser.IncrementNonTransactedOpenResultCount();
            }
            else { 
                // If we are passed a transaction, we are executing under a transaction
                // and thus we should increment the transaction's result count. 
                _executedUnderTransaction = transaction; 
                return transaction.IncrementAndObtainOpenResultCount();
            } 
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal void IncrementPendingCallbacks() { 
            Interlocked.Increment(ref _pendingCallbacks);
            if (Bid.AdvancedOn) { 
                Bid.Trace(" %d#, after incrementing _pendingCallbacks: %d\n", ObjectID, _pendingCallbacks); 
            }
        } 

        internal void SetTimeoutSeconds(int timeout) {
            _timeoutSeconds = timeout;
            if (timeout == 0) { 
                _timeoutTime = Int64.MaxValue;
            } 
        } 

        internal void StartSession(int objectID) { 
            _allowObjectID = objectID;
        }

        private void ThrowExceptionAndWarning() { 
            Parser.ThrowExceptionAndWarning(this);
        } 
 
        ////////////////////////////////////////////
        // TDS Packet/buffer manipulation methods // 
        ////////////////////////////////////////////

        internal void CleanWire() {
            if (TdsParserState.Broken == Parser.State || TdsParserState.Closed == Parser.State ) { 
                return;
            } 
            if (Bid.AdvancedOn) { 
                Bid.Trace(" %d#\n", ObjectID);
            } 

            // Loop until found packet with EOM AND that packet has been fully read from the wire!
            while (_messageStatus != TdsEnums.ST_EOM ||
                   (_messageStatus == TdsEnums.ST_EOM && _inBytesPacket != 0)) { 

                // jump to the next header 
                int cb = _inBytesRead - _inBytesUsed; 

                if (_inBytesPacket >= cb) { 
                    // consume the bytes in our buffer and
                    // decrement the bytes left in the packet
                    _inBytesPacket -= cb;
                    _inBytesUsed = _inBytesRead; 
                    if (_messageStatus != TdsEnums.ST_EOM ||
                        _inBytesPacket > 0) { 
                        // If we have not reached EOM packet, or if we have not consumed all bytes in 
                        // packet then call ReadBuffer.
                        ReadBuffer(); 
                    }

                    AssertValidState();
                } 
                else {
                    _inBytesUsed += _inBytesPacket; 
                    _inBytesPacket = 0; 
                    ProcessHeader();
 
                    AssertValidState();
                }
            }
 
            // cleaned the network, now fixup our buffers
            _inBytesUsed = _inBytesPacket = _inBytesRead = 0; 
            _pendingData = false; 

            AssertValidState(); 
        }

        internal void ExecuteFlush() {
            lock (this) { 
                if (_cancelled && 1 == _outputPacketNumber) {
                    ResetBuffer(); 
                    _cancelled = false; 
                    throw SQL.OperationCancelled();
                } 
                else {
                    WritePacket(TdsEnums.HARDFLUSH);
                    _pendingData = true;
                } 
            }
        } 
 
        // Processes the tds header that is present in the buffer
        internal void ProcessHeader() { 
            Debug.Assert(_inBytesPacket == 0, "there should not be any bytes left in packet when ReadHeader is called");
            // if the header splits buffer reads - special case!
            if (_inBytesUsed + _inputHeaderLen > _inBytesRead) {
                int bytesRemaining = _inBytesRead - _inBytesUsed; 
                int bytesMissing = _inputHeaderLen - bytesRemaining;
 
                Debug.Assert(bytesRemaining > 0 && bytesRemaining < _inputHeaderLen && 
                             bytesMissing > 0 && bytesMissing < _inputHeaderLen, "ProcessHeader error, bytesRemaining: " + Convert.ToString(bytesRemaining, (IFormatProvider)null) + ", bytesMissing: " + Convert.ToString(bytesMissing, (IFormatProvider)null) + ".");
                if (_bHeaderBuffer == null) 
                    _bHeaderBuffer = new byte[_inputHeaderLen];
                Buffer.BlockCopy(_inBuff, _inBytesUsed, _bHeaderBuffer, 0, bytesRemaining);

                _inBytesUsed = _inBytesRead; 

                // VSTS 219884: when some kind of MITM (man-in-the-middle) tool splits the network packets, the message header can be split over 
                // several network packets. 
                // Note: cannot use ReadByteArray here since it uses _inBytesPacket which is not set yet.
                int bytesCopied = bytesRemaining; 
                do {
                    if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
                        // NOTE: ReadNetworkPacket does nothing if the parser state is closed or broken
                        // to avoid infinite loop, we raise an exception 
                        ThrowExceptionAndWarning();
                        // 
                        return; 
                    }
 
                    ReadNetworkPacket();

                    if (_internalTimeout) {
                        ThrowExceptionAndWarning(); 
                        //
                        return; 
                    } 

                    int copy = Math.Min(_inBytesRead - _inBytesUsed, bytesMissing); 
                    Debug.Assert(copy > 0, "ReadNetworkPacket read empty buffer");

                    Buffer.BlockCopy(_inBuff, _inBytesUsed, _bHeaderBuffer, bytesCopied, copy);
                    bytesCopied += copy; 
                    bytesMissing -= copy;
                    _inBytesUsed += copy; 
                } while (bytesMissing > 0); 

                _inBytesPacket = ((int)_bHeaderBuffer[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8 | 
                                  (int)_bHeaderBuffer[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen;

                _messageStatus = _bHeaderBuffer[1];
 
                AssertValidState();
            } 
            else { 
                // normal header processing...
                _messageStatus = _inBuff[_inBytesUsed + 1]; 
                _inBytesPacket = ((int)_inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8 |
                                              (int)_inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen;
                _inBytesUsed += _inputHeaderLen;
 
                AssertValidState();
            } 
        } 

        // Wrapper function that calls the function that reads as much as possible from the netlib 
        // and inserts it into the in buffer.
        internal void ReadBuffer() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadBuffer");  // you need to setup for a thread abort somewhere before you call this method
            Debug.Assert(_inBytesUsed == _inBytesRead, "buffer should be exhaused!"); 
            Debug.Assert(_inBuff != null, "packet buffer should not be null!");
 
            // If the _inBytesPacket is not zero, then we have data left in the packet, but the data in the packet 
            // spans the buffer, so we can read any amount of data possible, and we do not need to call ProcessHeader
            // because there isn't a header at the beginning of the data that we are reading. 
            if (_inBytesPacket > 0) {
                ReadNetworkPacket();

                AssertValidState(); 
            }
            else if (_inBytesPacket == 0) { 
                // Else we have finished the packet and so we must read the next header and then as much data as 
                // posssible.
                ReadNetworkPacket(); 

                ProcessHeader();

                Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!"); 
                if (_inBytesUsed == _inBytesRead)
                { 
                    // we read a header but didn't get anything else except it 
                    // VSTS 219884: it can happen that the TDS packet header and its data are split across two network packets.
                    // Read at least one more byte to get/cache the first data portion of this TDS packet 
                    ReadNetworkPacket();
                }

                AssertValidState(); 
            }
            else { 
                Debug.Assert(false, "entered negative _inBytesPacket loop"); 
            }
        } 

        internal void ResetBuffer() {
            _outBytesUsed = _outputHeaderLen;
        } 

        internal bool SetPacketSize(int size) { 
            if (size > TdsEnums.MAX_PACKET_SIZE) { 
                throw SQL.InvalidPacketSize();
            } 
            Debug.Assert(size >= 1, "Cannot set packet size to less than 1.");
            Debug.Assert( (_outBuff == null && _inBuff == null) ||
                          (_outBuff.Length == _inBuff.Length),
                          "Buffers are not in consistent state"); 
            Debug.Assert( (_outBuff == null && _inBuff == null) ||
                          this == _parser._physicalStateObj, 
                          "SetPacketSize should only be called on a stateObj with null buffers on the physicalStateObj!"); 
            Debug.Assert( _inBuff == null
                          || 
                          (_parser.IsYukonOrNewer &&
                           _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen)) &&
                           _outputPacketNumber == 1)
                          || 
                          (_outBytesUsed == _outputHeaderLen && _outputPacketNumber == 1),
                          "SetPacketSize called with data in the buffer!"); 
 
            if (_inBuff == null || _inBuff.Length != size) { // We only check _inBuff, since two buffers should be consistent.
                // Allocate or re-allocate _inBuff. 
                if (_inBuff == null) {
                    _inBuff = new byte[size];
                    _inBytesRead = 0;
                    _inBytesUsed = 0; 
                }
                else if (size != _inBuff.Length) { 
                    // If new size is other than existing... 
                    if (_inBytesRead > _inBytesUsed) {
                        // if we still have data left in the buffer we must keep that array reference and then copy into new one 
                        byte[] temp = _inBuff;

                        _inBuff = new byte[size];
 
                        // copy remainder of unused data
                        int remainingData = _inBytesRead - _inBytesUsed; 
                        if ((temp.Length < _inBytesUsed + remainingData) || (_inBuff.Length < remainingData)) { 
                          string errormessage = Res.GetString(Res.SQL_InvalidInternalPacketSize) + ' ' + temp.Length + ", " + _inBytesUsed + ", " + remainingData + ", " + _inBuff.Length;
                          throw SQL.InvalidInternalPacketSize (errormessage); 
                        }
                        Buffer.BlockCopy(temp, _inBytesUsed, _inBuff, 0, remainingData);

                        _inBytesRead = _inBytesRead - _inBytesUsed; 
                        _inBytesUsed = 0;
 
                        AssertValidState(); 
                    }
                    else { 
                        // buffer is empty - just create the new one that is double the size of the old one
                        _inBuff = new byte[size];
                        _inBytesRead = 0;
                        _inBytesUsed = 0; 
                    }
                } 
 
                // Always re-allocate _outBuff - assert is above to verify state.
                _outBuff      = new byte[size]; 
                _outBytesUsed = _outputHeaderLen;

                AssertValidState();
                return true; 
            }
 
            return false; 
        }
 
        ///////////////////////////////////////
        // Buffer read methods - data values //
        ///////////////////////////////////////
 
        // look at the next byte without pulling it off the wire, don't just returun _inBytesUsed since we may
        // have to go to the network to get the next byte. 
        internal byte PeekByte() { 
            byte peek = ReadByte();
 
            // now do fixup
            _inBytesPacket++;
            _inBytesUsed--;
 
            AssertValidState();
            return peek; 
        } 

        // Takes a byte array, an offset, and a len and fills the array from the offset to len number of 
        // bytes from the in buffer.
        public void ReadByteArray(byte[] buff, int offset, int len) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadByteArray");  // you need to setup for a thread abort somewhere before you call this method
 
#if DEBUG
            if (buff != null) { 
                Debug.Assert(buff.Length >= len, "Invalid length sent to ReadByteArray()!"); 
            }
#endif 

            // loop through and read up to array length
            while (len > 0) {
                if ((len <= _inBytesPacket) && ((_inBytesUsed + len) <= _inBytesRead)) { 
                    // NO STRING PACKET SPAN AND NO STRING SPAN OF BUFFER
                    // If all of string is in the packet and all of the string is in the buffer 
                    // then we have the full string available for copying - then take care of counters 
                    // and break out of loop
 
                    if (buff != null) {
                        Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset, len);
                    }
 
                    _inBytesUsed += len;
                    _inBytesPacket -= len; 
 
                    AssertValidState();
                    break; 
                }
                else if (((len <= _inBytesPacket) && ((_inBytesUsed + len) > _inBytesRead)) ||
                          ((len > _inBytesPacket) && ((_inBytesUsed + _inBytesPacket) > _inBytesRead))) {
                    // NO PACKET SPAN AND STRING SPANS BUFFER        OR 
                    // STRING SPANS PACKET AND PACKET SPANS BUFFER
                    // If all of the string is in the packet and the string spans buffer OR 
                    // if the string spans packets and packet spans buffer 
                    // then we only have a partial string available to us, with the length being
                    // the rest of the bytes in the buffer.  So, there is no header in the rest of 
                    // the buffer.  The remainder of bytes left in the buffer is given by the number
                    // read minus the number used.  Copy that and then take care of the proper counters and
                    // then get the next byte from the new buffer by using the appropriate ReadByte function
                    // which will make a proper read and then take care of the header and all of that business. 

                    int remainder = _inBytesRead - _inBytesUsed; 
 
                    // read the remainder
                    if (buff != null) { 
                        Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset, remainder);
                    }

                    offset += remainder; 
                    _inBytesUsed += remainder;
                    _inBytesPacket -= remainder; 
                    len -= remainder; 

                    AssertValidState(); 

                    // and get more data from the wire
                    ReadBuffer();
                } 
                else if ((len > _inBytesPacket) && ((_inBytesUsed + _inBytesPacket) <= _inBytesRead)) {
                    // STRING SPANS PACKET AND NO PACKET SPAN OF BUFFER 
                    // If the string spans packets and all of packet is in buffer 
                    // then, all of the packet is in the buffer, but there may be more.  So,
                    // read the rest of the packet, take care of the counters, and reset the number 
                    // of bytes in the packet to zero.

                    if (buff != null) {
                        Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset, _inBytesPacket); 
                    }
 
                    _inBytesUsed += _inBytesPacket; 
                    offset += _inBytesPacket;
                    len -= _inBytesPacket; 

                    _inBytesPacket = 0;

                    AssertValidState(); 

                    // Now, check to see if we still have data in the buffer.  If we do, then we must have a 
                    // header at the beginning of the data, since we are on a new packet.  So, since we have a 
                    // header call ProcessHeader to take care of the header.  If we don't have data in the buffer
                    // then call ReadBuffer to refill the header.  ReadBuffer will take care of the header at the 
                    // beginning of the new buffer, so don't worry about that here.
                    if (_inBytesUsed == _inBytesRead)
                        ReadBuffer();
                    else { 
                        ProcessHeader();
 
                        Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!"); 

                        if (_inBytesUsed == _inBytesRead) 
                            ReadBuffer();
                    }
                }
                else { 
                    Debug.Assert(false, "Failed to catch condition in ReadByteArray");
                } 
            } 

            AssertValidState(); 
        }

        // Takes no arguments and returns a byte from the buffer.  If the buffer is empty, it is filled
        // before the byte is returned. 
        internal byte ReadByte() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadByte");  // you need to setup for a thread abort somewhere before you call this method 
            Debug.Assert(_inBytesUsed >= 0 && _inBytesUsed <= _inBytesRead, "ERROR - TDSParser: _inBytesUsed < 0 or _inBytesUsed > _inBytesRead"); 

            // if we have exhausted the read buffer, we need to call ReadBuffer to get more data 
            if (_inBytesUsed == _inBytesRead) {
                ReadBuffer();
            }
            else if (_inBytesPacket == 0) { 
                ProcessHeader();
                Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!"); 
 
                if (_inBytesUsed == _inBytesRead) {
                    ReadBuffer(); 
                }
            }

            // decrement the number of bytes left in the packet 
            _inBytesPacket--;
 
            Debug.Assert(_inBytesPacket >= 0, "ERROR - TDSParser: _inBytesPacket < 0"); 

            // return the byte from the buffer and increment the counter for number of bytes used in the in buffer 
            byte b = (_inBuff[_inBytesUsed++]);

            AssertValidState();
            return b; 
        }
 
        internal char ReadChar() { 
            byte b1 = ReadByte();
            byte b2 = ReadByte(); 

            AssertValidState();
            return (char)(((b2 & 0xff) << 8) + (b1 & 0xff));
        } 

        internal short ReadInt16() { 
            // appears to be more performant this way than like ReadUnsignedInt 
            byte b1 = ReadByte();
            byte b2 = ReadByte(); 

            AssertValidState();
            return (Int16)((b2 << 8) + b1);
        } 

        internal int ReadInt32() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadInt32");  // you need to setup for a thread abort somewhere before you call this method 
            if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) {
                // If the int isn't fully in the buffer, or if it isn't fully in the packet, 
                // then use ReadByteArray since the logic is there to take care of that.

                ReadByteArray(_bTmp, 0, 4);
 
                AssertValidState();
                return BitConverter.ToInt32(_bTmp, 0); 
            } 
            else {
                // The entire int is in the packet and in the buffer, so just return it 
                // and take care of the counters.

                int i = BitConverter.ToInt32(_inBuff, _inBytesUsed);
 
                _inBytesUsed += 4;
                _inBytesPacket -= 4; 
 
                AssertValidState();
                return i; 
            }
        }

        internal long ReadInt64() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadInt64");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)) { 
                // If the long isn't fully in the buffer, or if it isn't fully in the packet, 
                // then use ReadByteArray since the logic is there to take care of that.
 
                ReadByteArray(_bTmp, 0, 8);

                AssertValidState();
                return BitConverter.ToInt64(_bTmp, 0); 
            }
            else { 
                // The entire long is in the packet and in the buffer, so just return it 
                // and take care of the counters.
 
                long l = BitConverter.ToInt64(_inBuff, _inBytesUsed);

                _inBytesUsed += 8;
                _inBytesPacket -= 8; 

                AssertValidState(); 
                return l; 
            }
        } 

        internal ushort ReadUInt16() {
            // appears to be more performant this way than like ReadUnsignedInt
            byte b1 = ReadByte(); 
            byte b2 = ReadByte();
 
            AssertValidState(); 
            return (UInt16)((b2 << 8) + b1);
        } 

        internal uint ReadUInt32() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadUInt32");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) { 
                // If the int isn't fully in the buffer, or if it isn't fully in the packet,
                // then use ReadByteArray since the logic is there to take care of that. 
 
                ReadByteArray(_bTmp, 0, 4);
 
                AssertValidState();
                return BitConverter.ToUInt32(_bTmp, 0);
            }
            else { 
                // The entire int is in the packet and in the buffer, so just return it
                // and take care of the counters. 
 
                uint i = BitConverter.ToUInt32(_inBuff, _inBytesUsed);
 
                _inBytesUsed += 4;
                _inBytesPacket -= 4;

                AssertValidState(); 
                return i;
            } 
        } 

        internal float ReadSingle() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadSingle");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) {
                // If the float isn't fully in the buffer, or if it isn't fully in the packet,
                // then use ReadByteArray since the logic is there to take care of that. 

                ReadByteArray(_bTmp, 0, 4); 
 
                AssertValidState();
                return BitConverter.ToSingle(_bTmp, 0); 
            }
            else {
                // The entire float is in the packet and in the buffer, so just return it
                // and take care of the counters. 

                float f = BitConverter.ToSingle(_inBuff, _inBytesUsed); 
 
                _inBytesUsed += 4;
                _inBytesPacket -= 4; 

                AssertValidState();
                return f;
            } 
        }
 
        internal double ReadDouble() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadDouble");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)) { 
                // If the double isn't fully in the buffer, or if it isn't fully in the packet,
                // then use ReadByteArray since the logic is there to take care of that.

                ReadByteArray(_bTmp, 0, 8); 

                AssertValidState(); 
                return BitConverter.ToDouble(_bTmp, 0); 
            }
            else { 
                // The entire double is in the packet and in the buffer, so just return it
                // and take care of the counters.

                double d = BitConverter.ToDouble(_inBuff, _inBytesUsed); 

                _inBytesUsed += 8; 
                _inBytesPacket -= 8; 

                AssertValidState(); 
                return d;
            }
        }
 
        internal string ReadString(int length) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadString");  // you need to setup for a thread abort somewhere before you call this method 
            int cBytes = length << 1; 
            byte[] buf;
            int offset = 0; 

            if (((_inBytesUsed + cBytes) > _inBytesRead) || (_inBytesPacket < cBytes)) {
                if (_bTmp == null || _bTmp.Length < cBytes) {
                    _bTmp = new byte[cBytes]; 
                }
 
                ReadByteArray(_bTmp, 0, cBytes); 

                // assign local to point to parser scratch buffer 
                buf = _bTmp;

                AssertValidState();
            } 
            else {
                // assign local to point to _inBuff 
                buf = _inBuff; 
                offset = _inBytesUsed;
                _inBytesUsed += cBytes; 
                _inBytesPacket -= cBytes;

                AssertValidState();
            } 
            return System.Text.Encoding.Unicode.GetString(buf, offset, cBytes);
        } 
 
        internal string ReadStringWithEncoding(int length, System.Text.Encoding encoding, bool isPlp) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadStringWithEncoding");  // you need to setup for a thread abort somewhere before you call this method 

            if (null == encoding) {
                _parser.ThrowUnsupportedCollationEncountered(this);
            } 
            byte[] buf = null;
            int offset = 0; 
 
            if (isPlp) {
                length = ReadPlpBytes(ref buf, 0, Int32.MaxValue); 

                AssertValidState();
            }
            else { 
                if (((_inBytesUsed + length) > _inBytesRead) || (_inBytesPacket < length)) {
                    if (_bTmp == null || _bTmp.Length < length) { 
                        _bTmp = new byte[length]; 
                    }
 
                    ReadByteArray(_bTmp, 0, length);

                    // assign local to point to parser scratch buffer
                    buf = _bTmp; 

                    AssertValidState(); 
                } 
                else {
                    // assign local to point to _inBuff 
                    buf = _inBuff;
                    offset = _inBytesUsed;
                    _inBytesUsed += length;
                    _inBytesPacket -= length; 

                    AssertValidState(); 
                } 
            }
 
            // BCL optimizes to not use char[] underneath
            return encoding.GetString(buf, offset, length);
        }
 
        // Reads the length of either the entire data or the length of the next chunk in a
        //   partially length prefixed data 
        // After this call, call  ReadPlpBytes/ReadPlpUnicodeChars untill the specified length of data 
        // is consumed. Repeat this until ReadPlpLength returns 0 in order to read the
        // entire stream. 
        // When this function returns 0, it means the data stream is read completely and the
        // plp state in the tdsparser is cleaned.
        internal ulong ReadPlpLength(bool returnPlpNullIfNull) {
            uint chunklen; 
           // bool firstchunk = false;
            bool isNull = false; 
 
            Debug.Assert(_longlenleft == 0, "Out of synch length read request");
            if (_longlen == 0) { 
                // First chunk is being read. Find out what type of chunk it is
                _longlen = (ulong)ReadInt64();
                // firstchunk = true;
            } 

            if (_longlen == TdsEnums.SQL_PLP_NULL) { 
                _longlen = 0; 
                _longlenleft = 0;
                isNull = true; 
            }
            else {
                // Data is coming in uint chunks, read length of next chunk
                chunklen = ReadUInt32(); 
                if (chunklen == TdsEnums.SQL_PLP_CHUNK_TERMINATOR) {
                    _longlenleft = 0; 
                    _longlen = 0; 
                }
                else { 
                    _longlenleft = (ulong)chunklen;
                }
            }
 
            AssertValidState();
 
            if (isNull && returnPlpNullIfNull) 
                return TdsEnums.SQL_PLP_NULL;
 
            return _longlenleft;
        }

        // Reads the current chunk in a bigvarbinary(max) data stream. 
        // Will not start reading into the next chunk if bytes requested is larger than
        // the current chunk length. Use ReadPlpBytes in that case. 
        // Returns the actual bytes read 
        internal int ReadPlpBytesChunk(byte[] buff, int offset, int len) {
            int bytesRead = 0; 

            if (_longlenleft == 0) {
                Debug.Assert(false, "Out of [....] read request");
                return 0; 
            }
 
            bytesRead = len; 

            if (_longlenleft < (ulong)len) 
                bytesRead = (int)_longlenleft;

            // ReadByteArray does the appropriate checks for buffer length, etc...
            ReadByteArray(buff, offset, bytesRead); 
            _longlenleft -= (ulong)bytesRead;
 
            AssertValidState(); 
            return bytesRead;
        } 

        // Reads the requested number of bytes from a plp data stream, or the entire data if
        // requested length is -1 or larger than the actual length of data. First call to this method
        //  should be preceeded by a call to ReadPlpLength or ReadDataLength. 
        // Returns the actual bytes read.
        internal int ReadPlpBytes(ref byte[] buff, int offst, int len) { 
            int bytesRead = 0; 
            int totalbytesRead = 0;
            int bytesLeft; 
            byte[] newbuf;

            if (_longlen == 0) {
                Debug.Assert(_longlenleft == 0); 
                if (buff == null) {
                    buff = new byte[0]; 
                } 

                AssertValidState(); 
                return 0;       // No data
            }

            Debug.Assert((_longlen != TdsEnums.SQL_PLP_NULL), 
                    "Out of [....] plp read request");
 
            Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpBytes()!"); 
            bytesLeft = len;
 
            // If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time
            if (buff == null && _longlen != TdsEnums.SQL_PLP_UNKNOWNLEN) {
                buff = new byte[(int)Math.Min((int)_longlen, len)];
            } 

            if (_longlenleft == 0) { 
                ReadPlpLength( false); 
                if (_longlenleft == 0)  // Data read complete
                    return 0; 
            }

            if (buff == null) {
                buff = new byte[_longlenleft]; 
            }
 
            while (bytesLeft > 0) { 
                bytesRead = (int)Math.Min(_longlenleft, (ulong)bytesLeft);
                if (buff.Length < (offst + bytesRead)) { 
                    // Grow the array
                    newbuf = new byte[offst + bytesRead];
                    Buffer.BlockCopy(buff, 0, newbuf, 0, offst);
                    buff = newbuf; 
                }
 
                bytesRead = ReadPlpBytesChunk(buff, offst, bytesRead); 
                bytesLeft -= bytesRead;
                offst += bytesRead; 
                totalbytesRead += bytesRead;
                if (_longlenleft == 0)  // Read the next chunk or cleanup state if hit the end
                    ReadPlpLength( false);
 
                AssertValidState();
 
                // Catch the point where we read the entire plp data stream and clean up state 
                if (_longlenleft == 0)   // Data read complete
                    break; 
            }
            return (totalbytesRead);
        }
 
        /////////////////////////////////////////
        // Network/Packet Reading & Processing // 
        ///////////////////////////////////////// 

        // Should only be called for [....], or [....] over async.  This should never be called for a non-blocking async read. 
        internal void ReadNetworkPacket() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadBuffer");  // you need to setup for a thread abort somewhere before you call this method
            _inBytesUsed = 0; // Reset _inBytesUsed, we have data in the buffer but none of it has been used.
 
#if NONETWORK
            NoNetworkProcessing(); 
#else // !NONETWORK 
            if (Parser.AsyncOn && _cachedAsyncResult == null) { // Alloc DbAsyncResult used for [....] over async
                _cachedAsyncResult = new DbAsyncResult(this, String.Empty, null, null, null); 
            }
            Debug.Assert(!Parser.AsyncOn || (Parser.AsyncOn && _cachedAsyncResult != null), "Unexpected state for _cachedAsyncResult!");

            ReadSni(_cachedAsyncResult, this); // _cachedAsyncResult null if !Parser.AsyncOn 

            // ReadSni will not block for async, so if ReadNetworkPacket is called with async we are [....]/async and need to block. 
            if (Parser.AsyncOn) { 
                ReadSniSyncOverAsync();
            } 
#endif // !NONETWORK

#if BUILDHARDCODEDPACKETCODE
            BuildHardCodedPacketCodeRead(); 
#endif //BUILDHARDCODEDPACKETCODE
 
            SniReadStatisticsAndTracing(); 

            if (Bid.AdvancedOn) { 
                Bid.TraceBin(" Packet read", _inBuff, (UInt16)_inBytesRead);
            }

            AssertValidState(); 
        }
 
        internal void ReadSniSyncOverAsync() { // Will block until posted Async read returns. 
            Debug.Assert(Parser.AsyncOn, "TdsParserStateObject.ReadSniSyncOverAsync should never be called on [....] connection");
            Debug.Assert(_parser.State != TdsParserState.Broken && _parser.State != TdsParserState.Closed, "Must not call ReadSniSync if connection is broken or closed"); 
            if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
                return;
            }
 
            try {
                // Block for callback to occur, since we are [....] over async. 
                if (!(((IAsyncResult)_cachedAsyncResult).AsyncWaitHandle.WaitOne(TdsParserStaticMethods.GetTimeoutMilliseconds(TimeoutTime), false))) { 
                    // WaitOne did not return in timeout period, so we have now timed out.
                    bool fail = false; 

                    if (_internalTimeout) { // This is now our second timeout - time to give up and break connection.
                        fail = true;
                    } 
                    else {
                        _internalTimeout = true; 
                        _parser.Errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, SQLMessage.Timeout(), "", 0)); 

                        if (!_attentionSent) { 
                            if (_parser.State == TdsParserState.OpenLoggedIn) {
                                SendAttention();
                            }
                            else { 
                                fail = true; // We aren't open yet - do not send attention!
                            } 
 
                            // Now wait another 5 seconds for the callback to occur.
                            if (!(((IAsyncResult)_cachedAsyncResult).AsyncWaitHandle.WaitOne(TdsParserStaticMethods.GetTimeoutMilliseconds(TimeoutTime), false))) { 
                                fail = true; // We timed out on secondary 5 second time out - time to give up and break connection.
                            }
                        }
                    } 

                    if (fail) { // ABORT, ABORT, ABORT! 
                        _parser.State = TdsParserState.Broken; 
                        _parser.Connection.BreakConnection();
                        _parser.ThrowExceptionAndWarning(this); 
                    }
                }

                if (_error != null) { // In case ReadCallback returned error, we need to fail and throw! 
                    // We don't need to check fAwaitingPreLogin before throwing, because in that case we do not cache error.
                    Parser.Errors.Add(_error); 
                    _error = null; 
                    _parser.ThrowExceptionAndWarning(this);
                } 
            }
            finally {
                if (_cachedAsyncResult != null) {
                    _cachedAsyncResult.Reset(); 
                }
 
                AssertValidState(); 
            }
        } 

        internal void ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) {
            Debug.Assert(_parser.State != TdsParserState.Broken && _parser.State != TdsParserState.Closed, "Must not call ReadSniSync if connection is broken or closed");
            if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) { 
                return;
            } 
 
            IntPtr readPacket = IntPtr.Zero;
            UInt32 error; 

            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                if (!_parser.AsyncOn) { 
                    Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadSniSync");  // you need to setup for a thread abort somewhere before you call this method
 
                    error = SNINativeMethodWrapper.SNIReadSync(stateObj.Handle, ref readPacket, TdsParserStaticMethods.GetTimeoutMilliseconds(stateObj.TimeoutTime)); 

                    if (TdsEnums.SNI_SUCCESS == error) { // Success - process results! 
                        Debug.Assert(ADP.PtrZero != readPacket, "ReadNetworkPacket cannot be null in syncronous operation!");
                        stateObj.ProcessSniPacket(readPacket, 0);
                    }
                    else { // Failure! 
                        Debug.Assert(IntPtr.Zero == readPacket, "unexpected readPacket without corresponding SNIPacketRelease");
                        ReadSniError(stateObj, error); 
                    } 
                }
                else { 
                    Debug.Assert(asyncResult != null, "Async on but null asyncResult passed");
                    stateObj._asyncResult = asyncResult;

                    RuntimeHelpers.PrepareConstrainedRegions(); 
                    try {} finally {
                        stateObj.IncrementPendingCallbacks(); 
                        error = SNINativeMethodWrapper.SNIReadAsync(stateObj.Handle, ref readPacket); 

                        if (!(TdsEnums.SNI_SUCCESS == error || TdsEnums.SNI_SUCCESS_IO_PENDING == error)) { 
                            stateObj.DecrementPendingCallbacks(false); // Failure - we won't receive callback!
                        }
                    }
 
                    if (TdsEnums.SNI_SUCCESS == error) { // Success - process results!
                        Debug.Assert(ADP.PtrZero != readPacket, "ReadNetworkPacket should not have been null on this async operation!"); 
                        stateObj._asyncResult.SetCompletedSynchronously(); 
                        stateObj.ReadAsyncCallback(ADP.PtrZero, readPacket, 0);
                    } 
                    else if (TdsEnums.SNI_SUCCESS_IO_PENDING != error) { // FAILURE!
                        Debug.Assert(IntPtr.Zero == readPacket, "unexpected readPacket without corresponding SNIPacketRelease");
                        ReadSniError(stateObj, error);
                    } 
                    // DO NOT HANDLE PENDING READ HERE - which is TdsEnums.SNI_SUCCESS_IO_PENDING state.
                    // That is handled by user who initiated async read, or by ReadNetworkPacket which is [....] over async. 
                } 
            }
            finally { 
                if (readPacket != IntPtr.Zero) {
                    // Be sure to release packet, otherwise it will be leaked by native.
                    SNINativeMethodWrapper.SNIPacketRelease(readPacket);
                } 

                AssertValidState(); 
            } 
        }
 
        // This method should only be called by ReadSni!  If not - it may have problems with timeouts!
        private void ReadSniError(TdsParserStateObject stateObj, UInt32 error) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadSniSyncError");  // you need to setup for a thread abort somewhere before you call this method
            // Due to the fact 7.0 kills connections on which pre-login packets are sent, we 
            // are required to eat non-timeout failures on Read() after the connection was
            // successfully established.  SQL BU DT 229929. 
            if (_parser._fAwaitingPreLogin && error != TdsEnums.SNI_WAIT_TIMEOUT) { 
                _parser._fPreLoginErrorOccurred = true;
            } 
            else {
                if (TdsEnums.SNI_WAIT_TIMEOUT == error) {
                    Debug.Assert(!_parser.AsyncOn, "Should never reach here with async on!");
                    bool fail = false; 

                    if (_internalTimeout) { // This is now our second timeout - time to give up. 
                        fail = true; 
                    }
                    else { 
                        stateObj._internalTimeout = true;
                        _parser.Errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, SQLMessage.Timeout(), "", 0));

                        if (!stateObj._attentionSent) { 
                            if (stateObj.Parser.State == TdsParserState.OpenLoggedIn) {
                                stateObj.SendAttention(); 
                                IntPtr syncReadPacket = IntPtr.Zero; 

                                RuntimeHelpers.PrepareConstrainedRegions(); 
                                try {
                                    error = SNINativeMethodWrapper.SNIReadSync(stateObj.Handle, ref syncReadPacket, TdsParserStaticMethods.GetTimeoutMilliseconds(stateObj.TimeoutTime));
                                    if (TdsEnums.SNI_SUCCESS == error) {
                                        // We will end up letting the run method deal with the expected done:done_attn token stream. 
                                        stateObj.ProcessSniPacket(syncReadPacket, 0);
                                        return; 
                                    } 
                                    else {
                                        Debug.Assert(IntPtr.Zero == syncReadPacket, "unexpected syncReadPacket without corresponding SNIPacketRelease"); 
                                        fail = true; // Subsequent read failed, time to give up.
                                    }
                                }
                                finally { 
                                    if (syncReadPacket != IntPtr.Zero) {
                                        // Be sure to release packet, otherwise it will be leaked by native. 
                                        SNINativeMethodWrapper.SNIPacketRelease(syncReadPacket); 
                                    }
                                } 
                            }
                            else {
                                fail = true; // We aren't yet logged in - just fail.
                            } 
                        }
                    } 
 
                    if (fail) {
                        _parser.State = TdsParserState.Broken; // We failed subsequent read, we have to quit! 
                        _parser.Connection.BreakConnection();
                    }
                }
                else { 
                    // Caution: ProcessSNIError  always  returns a fatal error!
                    _parser.Errors.Add(_parser.ProcessSNIError(stateObj)); 
                } 
                _parser.ThrowExceptionAndWarning(stateObj);
            } 

            AssertValidState();
        }
 
        //
        public void ProcessSniPacket(IntPtr packet, UInt32 error) { 
            // Do nothing with with callback if closed or broken and error not 0 - callback can occur 
            // after connection has been closed.  PROBLEM IN NETLIB - DESIGN FLAW.
            if ( (_parser.State == TdsParserState.Closed || _parser.State == TdsParserState.Broken) 
                 && error != 0) {
                return; // Packet will still get released in finally block.
            }
 
            if (error != 0) {
                // Due to the fact 7.0 kills connections on which pre-login packets are sent, we 
                // are required to eat non-timeout failures on Read() after the connection was 
                // successfully established.  SQL BU DT 229929.
                if (_parser._fAwaitingPreLogin && error != TdsEnums.SNI_WAIT_TIMEOUT) { 
                    _parser._fPreLoginErrorOccurred = true;
                }
                else {
                    Debug.Assert(_error == null, "Unexpectedly already have a cached error!"); 
                    _error = _parser.ProcessSNIError(this);
                } 
 
                AssertValidState();
            } 
            else {
                IntPtr pConn = SNINativeMethodWrapper.SNIPacketGetConnection(packet);

                UInt32 dataSize = 0; 
                IntPtr pointer = ADP.PtrZero;
                SNINativeMethodWrapper.SNIPacketGetData(packet,  ref pointer, ref dataSize); 
 
                if (_inBuff.Length < dataSize) {
                    Debug.Assert(true, "Unexpected dataSize on Read"); 
                    throw SQL.InvalidInternalPacketSize (Res.GetString(Res.SqlMisc_InvalidArraySizeMessage));
                }
                Marshal.Copy(pointer, _inBuff, 0, (Int32) dataSize);
 
                _inBytesRead = (int) dataSize;
                _inBytesUsed = 0; 
 
                AssertValidState();
            } 
        }

        public void ReadAsyncCallback(IntPtr key, IntPtr packet, UInt32 error) { // Key never used.
            // Note - it's possible that when native calls managed that an asynchronous exception 
            // could occur in the native->managed transition, which would
            // have two impacts: 
            // 1) user event not called 
            // 2) DecrementPendingCallbacks not called, which would mean this object would be leaked due
            //    to the outstanding GCRoot until AppDomain.Unload. 
            // We live with the above for the time being due to the constraints of the current
            // reliability infrastructure provided by the CLR.
            RuntimeHelpers.PrepareConstrainedRegions();
            bool processFinallyBlock = true; 
            try {
                Debug.Assert(IntPtr.Zero == packet || IntPtr.Zero != packet && _asyncResult != null, "AsyncResult null on callback"); 
                if (_parser.MARSOn) { // Only take reset lock on MARS and Async. 
                    CheckSetResetConnectionState(error, CallbackType.Read);
                } 
                ProcessSniPacket(packet, error);
            }
            catch (Exception e) {
                processFinallyBlock = ADP.IsCatchableExceptionType(e); 
                throw;
            } 
            finally { 
                DecrementPendingCallbacks(false); // may dispose of GC handle.
                if (processFinallyBlock) { 
                    _asyncResult.SetCompleted();
                }

                AssertValidState(); 
            }
        } 
 
        /////////////////////////////////////////
        // Network/Packet Writing & Processing // 
        /////////////////////////////////////////

        // Dumps contents of buffer to SNI for network write.
        internal void WritePacket(byte flushMode) { 
            Debug.Assert(_parser.State == TdsParserState.OpenNotLoggedIn || _parser.State == TdsParserState.OpenLoggedIn,
                         "Cannot flush buffer when connection is closed!"); 
 
            if  (   _parser.State == TdsParserState.Closed
                ||  _parser.State == TdsParserState.Broken 
                ||  _parser.IsYukonOrNewer && !_bulkCopyOpperationInProgress // ignore the condition checking for bulk copy (SQL BU 414551)
                    && _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen))
                    && _outputPacketNumber == 1
                ||  _outBytesUsed == _outputHeaderLen 
                    && _outputPacketNumber == 1) {
                return; 
            } 

            byte status = TdsEnums.ST_EOM; 
            byte packetNumber = _outputPacketNumber;

            // Set Status byte based whether this is end of message or not
            if (TdsEnums.HARDFLUSH == flushMode) { 
                status = TdsEnums.ST_EOM;
                _outputPacketNumber = 1;              // end of message - reset to 1 - per ramas 
            } 
            else if (TdsEnums.SOFTFLUSH==flushMode) {
                status = TdsEnums.ST_BATCH; 
                _outputPacketNumber++;
            }
            else {
                Debug.Assert (false, String.Format((IFormatProvider)null, "Unexpected argument {0,-2:x2} to WritePacket", flushMode)); 
            }
 
            _outBuff[0] = _outputMessageType;         // Message Type 
            _outBuff[1] = status;
            _outBuff[2] = (byte)(_outBytesUsed >> 8); // length - upper byte 
            _outBuff[3] = (byte)(_outBytesUsed&0xff); // length - lower byte
            _outBuff[4] = 0;                          // channel
            _outBuff[5] = 0;
            _outBuff[6] = packetNumber;               // packet 
            _outBuff[7] = 0;                          // window
 
            _parser.CheckResetConnection(this);       // HAS SIDE EFFECTS - re-org at a later time if possible 

            WriteSni(); 

            AssertValidState();
        }
 

        private UInt32 SNIWriteAsync(SNIHandle handle,SNIPacket packet, DbAsyncResult asyncResult) { 
            UInt32 sniError; 
            // Async operation completion may be delayed (success pending).
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
            }
            finally {
                IncrementPendingCallbacks(); 
                sniError = SNINativeMethodWrapper.SNIWriteAsync(handle, packet);
 
                if (sniError == TdsEnums.SNI_SUCCESS || sniError != TdsEnums.SNI_SUCCESS_IO_PENDING) { 
                    // If read completed synchronously, or if error occurred, decrement _pendingCallbacks.
                    DecrementPendingCallbacks(false); 
                }
            }

            if (sniError != TdsEnums.SNI_SUCCESS) { 
                if (sniError != TdsEnums.SNI_SUCCESS_IO_PENDING) { // Error occurred.
                    Bid.Trace(" write async returned error code %d\n", (int)sniError); 
                    _parser.Errors.Add(_parser.ProcessSNIError(this)); 
                    ThrowExceptionAndWarning();
                } 
                else if (sniError == TdsEnums.SNI_SUCCESS_IO_PENDING) { // Write result is pending.
                    try {
                        // Write callback expected - wait for it - block indefinitely. :(
                        ((IAsyncResult)asyncResult).AsyncWaitHandle.WaitOne(); 
                        // After unblocked by background thread, check to see if error occurred.
                        if (_error != null) { // Add to collection if occurred. 
                            _parser.Errors.Add(_error); 
                            _error = null;
                            Bid.Trace(" write async returned error code %d\n", (int)sniError); 
                            ThrowExceptionAndWarning();
                        }
                    }
                    finally { 
                        asyncResult.Reset();
                    } 
                } 
            }
 
            AssertValidState();
            return sniError;
        }
 
        // Sends an attention signal - executing thread will consume attn.
        internal void SendAttention() { 
            if (!_attentionSent) { 
                // Dumps contents of buffer to OOB write (currently only used for
                // attentions.  There is no body for this message 
                // Doesn't touch this._outBytesUsed
                Debug.Assert((_parser.State == TdsParserState.OpenNotLoggedIn ||
                             _parser.State == TdsParserState.OpenLoggedIn),
                             "Cannot flush bufferOOB when connection is closed!"); 

                if (_parser.State == TdsParserState.Closed || _parser.State == TdsParserState.Broken) { 
                    return; 
                }
 
                SNIPacket attnPacket = new SNIPacket(Handle);
                if (_parser.AsyncOn) {
                    _sniAsyncAttnPacket = attnPacket;
                    if (_asyncAttentionResult == null) { 
                        _asyncAttentionResult = new DbAsyncResult(_parser, String.Empty, null, null, null);
                    } 
                } 
                else {
                    _sniAsyncAttnPacket = null; 
                }

                SNINativeMethodWrapper.SNIPacketSetData(attnPacket, SQL.AttentionHeader, TdsEnums.HEADER_LEN);
 
                UInt32 sniError;
                if (_parser.AsyncOn) { 
                    sniError = SNIWriteAsync (Handle, attnPacket, _asyncAttentionResult); 
                    Bid.Trace(" Send Attention ASync .\n");
                } 
                else {
                    sniError = SNINativeMethodWrapper.SNIWriteSync(Handle, attnPacket);
                    Bid.Trace(" Send Attention [....].\n");
 
                    if (sniError != TdsEnums.SNI_SUCCESS) {
                        Bid.Trace(" SNIWriteSync returned error code %d\n", (int)sniError); 
 
                        //
                        _parser.Errors.Add(_parser.ProcessSNIError(this)); 
                        _parser.ThrowExceptionAndWarning(this);
                    }
                }
 
                SetTimeoutSeconds(5); // Initialize new attention timeout of 5 seconds.
                _attentionSent = true; 
 
                if (Bid.AdvancedOn)  {
                    Bid.TraceBin("  Packet sent", _outBuff, (UInt16)_outBytesUsed); 
                }
                Bid.Trace(" Attention sent to the server.\n");

                AssertValidState(); 
            }
        } 
 
        private void WriteSni() {
#if NONETWORK 
            ResetBuffer(); // DO NOT REMOVE THIS CODE UNLESS YOU TALK WITH [....] FIRST. WE USE THIS CODE TO CREATE HARD CODED PACKETS FOR PEFORMANCE TESTING!
#else //!NONETWORK

#if BUILDHARDCODEDPACKETCODE 
            BuildHardCodedPacketCodeWrite(_outBytesUsed);
#endif //BUILDHARDCODEDPACKETCODE 
 
            // Prepare packet, and write to packet.
            if (_sniPacket == null) { 
                _sniPacket = new SNIPacket(Handle);
            }
            else {
                SNINativeMethodWrapper.SNIPacketReset(Handle, SNINativeMethodWrapper.IOType.WRITE, _sniPacket); 
            }
            SNINativeMethodWrapper.SNIPacketSetData(_sniPacket, _outBuff, _outBytesUsed); 
 
            UInt32 sniError;
            // Prepare for async, if present. 
            if (_parser.AsyncOn) {
                if (_cachedAsyncResult == null) {
                    _cachedAsyncResult = new DbAsyncResult(_parser, String.Empty, null, null, null);
                } 
                _asyncResult = _cachedAsyncResult;
                sniError = SNIWriteAsync(Handle, _sniPacket, _cachedAsyncResult); 
            } 
            else {
                // Synchronous operation - operation completes immediately. 
                sniError = SNINativeMethodWrapper.SNIWriteSync(Handle, _sniPacket);

                if (sniError != TdsEnums.SNI_SUCCESS) {
                    Bid.Trace(" write [....] returned error code %d\n", (int)sniError); 
                    _parser.Errors.Add(_parser.ProcessSNIError(this));
                    ThrowExceptionAndWarning(); 
                } 

                // Check to see if the timeout has occured.  This time out code is special case code to allow BCP writes to timeout to fix bug 350558, eventually we should make all writes timeout. 
                if (_bulkCopyOpperationInProgress && 0 == TdsParserStaticMethods.GetTimeoutMilliseconds(TimeoutTime)) {
                     _parser.Errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, SQLMessage.Timeout(), "", 0));
                     SendAttention();
                     _parser.ProcessPendingAck(this); 
                     _parser.ThrowExceptionAndWarning(this);
                } 
            } 

            // Special case logic for encryption removal. 
            //
            if (_parser.State == TdsParserState.OpenNotLoggedIn &&
                _parser.EncryptionOptions == EncryptionOptions.LOGIN) {
                // If no error occurred, and we are Open but not logged in, and 
                // our encryptionOption state is login, remove the SSL Provider.
                // We only need encrypt the very first packet of the login message to the server. 
 
                // SQL BU DT 332481 - we wanted to encrypt entire login channel, but there is
                // currently no mechanism to communicate this.  Removing encryption post 1st packet 
                // is a hard-coded agreement between client and server.  We need some mechanism or
                // common change to be able to make this change in a non-breaking fasion.
                _parser.RemoveEncryption();                        // Remove the SSL Provider.
                _parser.EncryptionOptions = EncryptionOptions.OFF; // Turn encryption off. 

                // Since this packet was associated with encryption, dispose and re-create. 
                _sniPacket.Dispose(); 
                _sniPacket = new SNIPacket(Handle);
            } 

            SniWriteStatisticsAndTracing();

            ResetBuffer(); 
#endif // !NONETWORK
 
            AssertValidState(); 
        }
 
        public void WriteAsyncCallback(IntPtr key, IntPtr packet, UInt32 error) {
            DbAsyncResult dbAsyncResult = _asyncResult;
            // SQL BU DT 346588 - this call to DangerousGetHandle is safe since we only use the
            // resulting pointer for a comparison only.  We do not cache the pointer or use it for 
            // any further operations or PInvokes.
            if (_sniAsyncAttnPacket != null && _sniAsyncAttnPacket.DangerousGetHandle () == packet) { 
                dbAsyncResult = _asyncAttentionResult; 
            }
 
            bool processFinallyBlock = true;
            try {
                if (_parser.MARSOn) { // Only take reset lock on MARS and Async.
                    CheckSetResetConnectionState(error, CallbackType.Read); 
                }
 
                if (error != 0) { 
                    Debug.Assert(_error == null, "Unexpectedly already have a cached error!");
                    _error = _parser.ProcessSNIError(this); // Cache error for WriteSni to use. 
                }
            }
            catch (Exception e) {
                processFinallyBlock = ADP.IsCatchableExceptionType(e); 
                throw;
            } 
            finally { 
                DecrementPendingCallbacks(false); // may dispose of GC handle.
                if (processFinallyBlock) { 
                    dbAsyncResult.SetCompleted();
                }

                AssertValidState(); 
            }
        } 
 
        //////////////////////////////////////////////
        // Statistics, Tracing, and related methods // 
        //////////////////////////////////////////////

#if BUILDHARDCODEDPACKETCODE
        private void BuildHardCodedPacketCodeWrite(int bytesWritten) { 
            // DO NOT REMOVE THIS CODE UNLESS YOU TALK WITH [....] FIRST
            // WE USE THIS CODE TO CREATE HARD CODED PACKETS FOR PEFORMANCE 
            // TESTING!!!! 
            Console.WriteLine (String.Format((IFormatProvider)null, "static private byte[] send_packet_{0} = {1}", _outputPacketNumber, '{'));
            for (int i=0; i < _outBytesUsed; i++) { 
                if (i % 16 == 0) {
                    if (i > 0) {
                        Console.WriteLine();
                    } 
                    Console.Write("        ");
                } 
                Console.Write(String.Format((IFormatProvider)null, "0x{0,-2:x2},", _outBuff[i])); 
            }
            Console.WriteLine (String.Format((IFormatProvider)null, "}}; // {0} bytes", _outBytesUsed)); 
        }

        private void BuildHardCodedPacketCodeRead() {
            Console.WriteLine (String.Format((IFormatProvider)null, "static private byte[] recv_packet_n = {0}", '{')); 
            for (int i=0; i < _inBytesRead; i++) {
                if (i % 16 == 0) { 
                    if (i > 0) { 
                        Console.WriteLine();
                    } 
                    Console.Write("        ");
                }
                Console.Write(String.Format((IFormatProvider)null, "0x{0,-2:x2},", _inBuff[i]));
            } 
            Console.WriteLine (String.Format((IFormatProvider)null, "}}; // {0} bytes", _inBytesRead));
        } 
#endif //BUILDHARDCODEDPACKETCODE 

#if NONETWORK 
        private void NoNetworkProcessing() {
            // DO NOT REMOVE THIS CODE UNLESS YOU TALK WITH [....] FIRST
            // WE USE THIS CODE TO CREATE HARD CODED PACKETS FOR PEFORMANCE
            // TESTING!!!! 
            recv_packet[recv_packet_number].CopyTo(_inBuff, 0);
            _inBytesRead = recv_packet[recv_packet_number].Length; 
            if (++recv_packet_number >= recv_packet.Length) { 
                recv_packet_number = 1;
            } 
        }
#endif // !NONETWORK

        private void SniReadStatisticsAndTracing() { 
            SqlStatistics statistics = Parser.Statistics;
            if (null != statistics) { 
                if (statistics.WaitForReply) { 
                    statistics.SafeIncrement(ref statistics._serverRoundtrips);
                    statistics.ReleaseAndUpdateNetworkServerTimer(); 
                }

                statistics.SafeAdd(ref statistics._bytesReceived, _inBytesRead);
                statistics.SafeIncrement(ref statistics._buffersReceived); 
            }
        } 
 
        private void SniWriteStatisticsAndTracing() {
            SqlStatistics statistics = _parser.Statistics; 
            if (null != statistics) {
                statistics.SafeIncrement(ref statistics._buffersSent);
                statistics.SafeAdd(ref statistics._bytesSent, _outBytesUsed);
                statistics.RequestNetworkServerTimer(); 
            }
 
            if (Bid.AdvancedOn) { 
                // If we have tracePassword variables set, we are flushing TDSLogin and so we need to
                // blank out password in buffer.  Buffer has already been sent to netlib, so no danger 
                // of losing info.
                if (_tracePasswordOffset != 0) {
                    for (int i = _tracePasswordOffset; i < _tracePasswordOffset +
                        _tracePasswordLength; i++) { 
                        _outBuff[i] = 0;
                    } 
 
                    // Reset state.
                    _tracePasswordOffset = 0; 
                    _tracePasswordLength = 0;
                }
                if (_traceChangePasswordOffset != 0) {
                    for (int i = _traceChangePasswordOffset; i < _traceChangePasswordOffset + 
                        _traceChangePasswordLength; i++) {
                        _outBuff[i] = 0; 
                    } 

                    // Reset state. 
                    _traceChangePasswordOffset = 0;
                    _traceChangePasswordLength = 0;
                }
                Bid.TraceBin("  Packet sent", _outBuff, (UInt16)_outBytesUsed); 
            }
        } 
 
        [Conditional("DEBUG")]
        void AssertValidState() { 
            string assertMessage = null;

            if (_inBytesUsed < 0 || _inBytesRead < 0) {
                assertMessage = string.Format( 
                    CultureInfo.InvariantCulture,
                    "either _inBytesUsed or _inBytesRead is negative: {0}, {1}", 
                    _inBytesUsed, _inBytesRead); 
            }
            else if (_inBytesUsed > _inBytesRead) { 
                assertMessage = string.Format(
                    CultureInfo.InvariantCulture,
                    "_inBytesUsed > _inBytesRead: {0} > {1}",
                    _inBytesUsed, _inBytesRead); 
            }
 
            // 

            if (assertMessage != null) { 
                Debug.Assert(false, "Invalid TDS Parser State: " + assertMessage);
            }
        }
 
/*
 
// leave this in. comes handy if you have to do Console.WriteLine style debugging ;) 
        private void DumpBuffer() {
            Console.WriteLine("dumping buffer"); 
            Console.WriteLine("_inBytesRead = {0}", _inBytesRead);
            Console.WriteLine("_inBytesUsed = {0}", _inBytesUsed);
            int cc = 0; // character counter
            int i; 
            Console.WriteLine("used buffer:");
            for (i=0; i< _inBytesUsed; i++) { 
                if (cc==16) { 
                    Console.WriteLine();
                    cc = 0; 
                }
                Console.Write("{0,-2:X2} ", _inBuff[i]);
                cc++;
            } 
            if (cc>0) {
                Console.WriteLine(); 
            } 

            cc = 0; 
            Console.WriteLine("unused buffer:");
            for (i=_inBytesUsed; i<_inBytesRead; i++) {
                if (cc==16) {
                    Console.WriteLine(); 
                    cc = 0;
                } 
                Console.Write("{0,-2:X2} ", _inBuff[i]); 
                cc++;
            } 
            if (cc>0) {
                Console.WriteLine();
            }
        } 
*/
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.SqlClient {
    using System; 
    using System.Data.Common;
    using System.Data.ProviderBase;
    using System.Data.Sql;
    using System.Data.SqlTypes; 
    using System.Diagnostics;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices; 
    using System.Runtime.ConstrainedExecution;
    using System.Threading; 
    using System.Globalization;

    sealed internal class TdsParserStateObject {
        private static int _objectTypeCount; // Bid counter 
        internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
 
        internal int ObjectID { 
            get {
                return _objectID; 
            }
        }

        // should only be used by TdsParserSessionPool.TdsParserStateObjectListStack.Synchronized(Push|Pop) 
        private TdsParserStateObject _nextPooledObject;
        internal TdsParserStateObject NextPooledObject { 
            get { return _nextPooledObject; } 
            set { _nextPooledObject = value; }
        } 

        private readonly TdsParser      _parser;                            // TdsParser pointer
        private SNIHandle               _sessionHandle = null;              // the SNI handle we're to work on
        private readonly WeakReference  _owner = new WeakReference(null);   // the owner of this session, used to track when it's been orphaned 
        private int                     _activateCount;                     // 0 when we're in the pool, 1 when we're not, all others are an error
 
        // Two buffers exist in tdsparser, an in buffer and an out buffer.  For the out buffer, only 
        // one bookkeeping variable is needed, the number of bytes used in the buffer.  For the in buffer,
        // three variables are actually needed.  First, we need to record from the netlib how many bytes it 
        // read from the netlib, this variable is _inBytesRead.  Then, we need to also keep track of how many
        // bytes we have used as we consume the bytes from the buffer, that variable is _inBytesRead.  Third,
        // we need to keep track of how many bytes are left in the packet, so that we know when we have reached
        // the end of the packet and so we need to consume the next header. 

        // Header length constants 
        internal readonly int           _inputHeaderLen        = TdsEnums.HEADER_LEN; 
        internal readonly int           _outputHeaderLen       = TdsEnums.HEADER_LEN;
 
        // Out buffer variables
        internal byte[]        _outBuff;                                     // internal write buffer - initialize on login
        internal int           _outBytesUsed          = TdsEnums.HEADER_LEN; // number of bytes used in internal write buffer -
                                                                             // - initialize past header 
        // In buffer variables
        private byte[]         _inBuff;                                      // internal read buffer - initialize on login 
        internal int           _inBytesUsed           = 0;                   // number of bytes used in internal read buffer 
        internal int           _inBytesRead           = 0;                   // number of bytes read into internal read buffer
        internal int           _inBytesPacket         = 0;                   // number of bytes left in packet 

        // Packet state variables
        internal byte          _outputMessageType     = 0;                   // tds header type
        internal byte          _messageStatus;                               // tds header status 
        internal byte          _outputPacketNumber    = 1;                   // number of packets sent to server
                                                                             // in message - start at 1 per ramas 
        internal bool          _pendingData           = false; 
        internal volatile bool _fResetEventOwned      = false;               // ResetEvent serializing call to sp_reset_connection
        internal volatile bool _fResetConnectionSent  = false;               // For multiple packet execute 

        internal bool          _errorTokenReceived    = false;               // Keep track of whether an error was received for the result.
                                                                             // This is reset upon each done token - there can be
 
        internal bool          _bulkCopyOpperationInProgress = false;        // Set to true during bulk copy and used to turn toggle write timeouts.
 
        // SNI variables                                                     // multiple resultsets in one batch. 
        internal SNIPacket     _sniPacket             = null;                // Will have to re-vamp this for MARS
        internal SNIPacket     _sniAsyncAttnPacket    = null;                // Packet to use to send Attn 

        // Async variables
        internal DbAsyncResult _asyncResult           = null;                // Use this for current operation
        internal DbAsyncResult _cachedAsyncResult     = null;                // Only for internal use 
        internal DbAsyncResult _asyncAttentionResult  = null;
        private GCHandle       _gcHandle;                                    // keeps this object alive until we're closed. 
        private int            _pendingCallbacks;                            // we increment this before each async read/write call and decrement it in the callback.  We use this to determine when to release the GcHandle... 

        // Timeout variables 
        private  int           _timeoutSeconds;
        private  long          _timeoutTime;                                 // variable used for timeout computations, holds the value of the hi-res performance counter at which this request should expire
        internal bool          _attentionSent         = false;               // true if we sent an Attention to the server
        internal bool          _attentionReceived     = false; 
        internal bool          _internalTimeout       = false;               // an internal timeout occured
 
        // This variable is used to track whether another thread has requested a cancel.  The 
        // synchronization points are
        //   On the user's execute thread: 
        //     1) the first packet write
        //     2) session close - return this stateObj to the session pool
        //   On cancel thread we only have the cancel call.
        // Currently all access to this variable is inside a lock, though I hope to limit that in the 
        // future.  The state diagram is:
        // 1) pre first packet write, if cancel is requested, set variable so exception is triggered 
        //    on user thread when first packet write is attempted 
        // 2) post first packet write, but before session return - a call to cancel will send an
        //    attention to the server 
        // 3) post session close - no attention is allowed
        private bool _cancelled;

        // This variable is used to prevent sending an attention by another thread that is not the 
        // current owner of the stateObj.  I currently do not know how this can happen.  Mark added
        // the code but does not remember either.  At some point, we need to research killing this 
        // logic. 
        private volatile int _allowObjectID;
 
        internal bool                   _hasOpenResult            = false;
        // Cache the transaction for which this command was executed so upon completion we can
        // decrement the appropriate result count.
        internal SqlInternalTransaction _executedUnderTransaction = null; 

        // TDS stream processing variables 
        internal ulong         _longlen;                                     // plp data length indicator 
        internal ulong         _longlenleft;                                 // Length of data left to read (64 bit lengths)
        internal int[]         _decimalBits           = null;                // scratch buffer for decimal/numeric data 
        internal byte[]        _bTmp                  = new byte[TdsEnums.YUKON_HEADER_LEN];  // Scratch buffer for misc use

        //
        // DO NOT USE THIS BUFFER FOR OTHER THINGS. 
        // ProcessHeader can be called ANYTIME while doing network reads.
        internal byte[]        _bHeaderBuffer =null;   // Scratch buffer for ProcessHeader 
 
        internal SqlError      _error;
 
        //

        internal _SqlMetaDataSet           _cleanupMetaData = null;
        internal _SqlMetaDataSetCollection _cleanupAltMetaDataSetArray = null; 

         // Used for blanking out password in trace. 
        internal int _tracePasswordOffset = 0; 
        internal int _tracePasswordLength = 0;
        internal int _traceChangePasswordOffset = 0; 
        internal int _traceChangePasswordLength = 0;

        internal bool _receivedColMetaData;      // Used to keep track of when to fire StatementCompleted  event.
 
        private SniContext _sniContext=SniContext.Undefined;
#if DEBUG 
        private SniContext _debugOnlyCopyOfSniContext=SniContext.Undefined; 
#endif
 
        private bool _bcpLock = false;

        //////////////////
        // Constructors // 
        //////////////////
 
        internal TdsParserStateObject(TdsParser parser) { 
            // Construct a physical connection
            Debug.Assert(null != parser, "no parser?"); 
            _parser = parser;

            // For physical connection, initialize to default login packet size.
            SetPacketSize(TdsEnums.DEFAULT_LOGIN_PACKET_SIZE); 

            // we post a callback that represents the call to dispose; once the 
            // object is disposed, the next callback will cause the GC Handle to 
            // be released.
            IncrementPendingCallbacks(); 
        }

        internal TdsParserStateObject(TdsParser parser, SNIHandle physicalConnection, bool async) {
            // Construct a MARS session 
            Debug.Assert(null != parser, "no parser?");
            _parser = parser; 
            SniContext=SniContext.Snix_GetMarsSession; 

            Debug.Assert(null != _parser._physicalStateObj, "no physical session?"); 
            Debug.Assert(null != _parser._physicalStateObj._inBuff, "no in buffer?");
            Debug.Assert(null != _parser._physicalStateObj._outBuff, "no out buffer?");
            Debug.Assert(_parser._physicalStateObj._outBuff.Length ==
                         _parser._physicalStateObj._inBuff.Length, "Unexpected unequal buffers."); 

            // Determine packet size based on physical connection buffer lengths. 
            SetPacketSize(_parser._physicalStateObj._outBuff.Length); 

            SNINativeMethodWrapper.ConsumerInfo myInfo = CreateConsumerInfo(async); 
            _sessionHandle = new SNIHandle(myInfo, "session:", physicalConnection);
            if (_sessionHandle.Status != TdsEnums.SNI_SUCCESS) {
                parser.Errors.Add(parser.ProcessSNIError(this));
                parser.ThrowExceptionAndWarning(this); 
            }
 
            // we post a callback that represents the call to dispose; once the 
            // object is disposed, the next callback will cause the GC Handle to
            // be released. 
            IncrementPendingCallbacks();
        }

        //////////////// 
        // Properties //
        //////////////// 
 
        // BcpLock - use to lock this object if there is a potential risk of using this object
        // between tds packets 
        internal bool  BcpLock {
            get {
                return _bcpLock;
            } 
            set {
                _bcpLock = value; 
            } 
        }
 
#if DEBUG
        internal SniContext DebugOnlyCopyOfSniContext {
            get {
                return _debugOnlyCopyOfSniContext; 
            }
        } 
#endif 

        internal SNIHandle Handle { 
            get {
                return _sessionHandle;
            }
        } 

        internal bool HasOpenResult { 
            get { 
                return _hasOpenResult;
            } 
        }

#if DEBUG
        internal void InvalidateDebugOnlyCopyOfSniContext() { 
            _debugOnlyCopyOfSniContext = SniContext.Undefined;
        } 
#endif 

        internal bool IsOrphaned { 
            get {
                Debug.Assert((0 == _activateCount && !_owner.IsAlive) // in pool
                             || (1 == _activateCount && _owner.IsAlive && _owner.Target != null)
                             || (1 == _activateCount && !_owner.IsAlive), "Unknown state on TdsParserStateObject.IsOrphaned!"); 
                return (0 != _activateCount && !_owner.IsAlive);
            } 
        } 

        internal object Owner { 
            set {
                _owner.Target = value;
            }
        } 

        internal TdsParser Parser { 
            get { 
                return _parser;
            } 
        }

        internal SniContext SniContext {
            get { 
                return _sniContext;
            } 
            set { 
                _sniContext = value;
#if DEBUG 
                _debugOnlyCopyOfSniContext = value;
#endif
            }
        } 

        internal UInt32 Status { 
            get { 
                if (_sessionHandle != null) {
                    return _sessionHandle.Status; 
                }
                else { // SQL BU DT 395431.
                    return TdsEnums.SNI_UNINITIALIZED;
                } 
            }
        } 
 
        internal bool TimeoutHasExpired {
            get { 
                Debug.Assert(0 == _timeoutSeconds || 0 == _timeoutTime, "_timeoutTime hasn't been reset");
                return TdsParserStaticMethods.TimeoutHasExpired(_timeoutTime);
            }
        } 

        internal long TimeoutTime { 
            get { 
                if (0 != _timeoutSeconds) {
                    _timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(_timeoutSeconds); 
                    _timeoutSeconds = 0;
                }
                return _timeoutTime;
            } 
            set {
                _timeoutSeconds = 0; 
                _timeoutTime = value; 
            }
        } 

        /////////////////////
        // General methods //
        ///////////////////// 

        internal void Activate(object owner) { 
            Owner = owner; // must assign an owner for reclaimation to work 
            int result = Interlocked.Increment(ref _activateCount);   // must have non-zero activation count for reclaimation to work too.
            Debug.Assert(result == 1, "invalid deactivate count"); 
        }

        // This method is only called by the command or datareader as a result of a user initiated
        // cancel request. 
        internal void Cancel(int objectID) {
            lock(this) { // Lock for the time being - since we need to synchronize the attention send. 
                         // At some point in the future, I hope to remove this. 
                // don't allow objectID -1 since it is reserved for 'not associated with a command'
                // yes, the 2^32-1 comand won't cancel - but it also won't cancel when we don't want it 
                if (!_cancelled && (objectID == _allowObjectID) && (objectID != -1)) {
                    _cancelled = true;

                    if (_pendingData && !_attentionSent) { 
                        SendAttention();
                    } 
                } 
            }
        } 

        // CancelRequest - use to cancel while writing a request to the server
        //
        // o none of the request might have been sent to the server, simply reset the buffer, 
        //   sending attention does not hurt
        // o the request was partially written. Send an ignore header to the server. attention is 
        //   required if the server was waiting for data (e.g. insert bulk rows) 
        // o the request was completely written out and the server started to process the request.
        //   attention is required to have the server stop processing. 
        //
        internal void CancelRequest() {
            ResetBuffer();    // clear out unsent buffer
            SendAttention(); 
            Parser.ProcessPendingAck(this);
        } 
 
        public void CheckSetResetConnectionState(UInt32 error, CallbackType callbackType) {
            // Should only be called for Async AND MARS together - that is the only time we need to take 
            // the ResetConnection lock!

            // SQL BU DT 333026 - it was raised in a security review by [....] questioning whether
            // we need to actually process the resulting packet (sp_reset ack or error) to know if the 
            // reset actually succeeded.  There was a concern that if the reset failed and we proceeded
            // there might be a security issue present.  We have been assured by the server that if 
            // sp_reset fails, they guarantee they will kill the resulting connection.  So - it is 
            // safe for us to simply receive the packet and then consume the pre-login later.
 
            Debug.Assert(_parser.MARSOn,  "Should not be calling CheckSetResetConnectionState on non MARS connection");
            Debug.Assert(_parser.AsyncOn, "Should not be calling CheckSetResetConnectionState on non Async connection");

            if (_fResetEventOwned) { 
                Debug.Assert(_parser._fResetConnection, "Invalid ResetConnection state on WriteAsyncCallback");
                Debug.Assert(_fResetConnectionSent, "Owned event but have not sent reset - on WriteAsyncCallback!"); 
 
                if (callbackType == CallbackType.Read && TdsEnums.SNI_SUCCESS == error) {
                    // RESET SUCCEEDED! 
                    // If we are on read callback and no error occurred (and we own reset event) -
                    // then we sent the sp_reset_connection and so we need to reset sp_reset_connection
                    // flag to false, and then release the ResetEvent.
                    _parser._fResetConnection = false; 
                    _fResetConnectionSent = false;
                    _fResetEventOwned = !_parser._resetConnectionEvent.Set(); 
                    Debug.Assert(!_fResetEventOwned, "Invalid AutoResetEvent state!"); 
                }
 
                if (TdsEnums.SNI_SUCCESS != error) {
                    // RESET FAILED!

                    // 

 
 

 
                    // If write or read failed with reset, we need to clear event but not mark connection
                    // as reset.
                    _fResetConnectionSent = false;
                    _fResetEventOwned = !_parser._resetConnectionEvent.Set(); 
                    Debug.Assert(!_fResetEventOwned, "Invalid AutoResetEvent state!");
                } 
            } 
        }
 
        internal void CloseSession() {
            ResetCancelAndProcessAttention();
#if DEBUG
            InvalidateDebugOnlyCopyOfSniContext(); 
#endif
            Parser.PutSession(this); 
        } 

        private void ResetCancelAndProcessAttention() { 
            // This method is shared by CloseSession initiated by DataReader.Close or completed
            // command execution, as well as the session reclaimation code for cases where the
            // DataReader is opened and then GC'ed.
            lock(this) { 
                // Reset cancel state.
                _cancelled = false; 
                _allowObjectID = -1; 

                if (_attentionSent) { 
                    // Make sure we're cleaning up the AttentionAck if Cancel happened before taking the lock.
                    // We serialize Cancel/CloseSession to prevent a race between these two states.
                    // The problem is that both sending and receiving attentions are time taking
                    // operations. 
                    Parser.ProcessPendingAck(this);
                } 
                _internalTimeout = false; 
            }
        } 

        private SNINativeMethodWrapper.ConsumerInfo CreateConsumerInfo(bool async) {
            SNINativeMethodWrapper.ConsumerInfo myInfo = new SNINativeMethodWrapper.ConsumerInfo();
 
            Debug.Assert(_outBuff.Length == _inBuff.Length, "Unexpected unequal buffers.");
 
            myInfo.defaultBufferSize = _outBuff.Length; // Obtain packet size from outBuff size. 
            myInfo.Prefix            = 	SNINativeMethodWrapper.PrefixNum.UNKNOWN_PREFIX;
 
            if (async) {
                myInfo.readDelegate  = SNILoadHandle.SingletonInstance.ReadAsyncCallbackDispatcher;
                myInfo.writeDelegate = SNILoadHandle.SingletonInstance.WriteAsyncCallbackDispatcher;
                _gcHandle            = GCHandle.Alloc(this, GCHandleType.Normal); 
                myInfo.key           = (IntPtr)_gcHandle;
            } 
            return myInfo; 
        }
 
        internal void CreatePhysicalSNIHandle(string serverName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, bool integratedSecurity, byte[] serverUserName, bool flushCache, bool async) {
            SNINativeMethodWrapper.ConsumerInfo myInfo = CreateConsumerInfo(async);

            // Translate to SNI timeout values (Int32 milliseconds) 
            long timeout;
            if (Int64.MaxValue == timerExpire) { 
                timeout = Int32.MaxValue; 
            }
            else { 
                timeout = ADP.TimerRemainingMilliseconds(timerExpire);
                if (timeout > Int32.MaxValue) {
                    timeout = Int32.MaxValue;
                } 
                else if (0 > timeout) {
                    timeout = 0; 
                } 
            }
 
            _sessionHandle = new SNIHandle(myInfo, serverName, integratedSecurity, serverUserName, ignoreSniOpenTimeout, checked((int)timeout), out instanceName, flushCache, !async);
        }

        internal bool Deactivate() { 
            bool goodForReuse = false;
 
            int result = Interlocked.Decrement(ref _activateCount);   // must have non-zero activation count for reclaimation to work too. 
            Debug.Assert(result == 0, "invalid deactivate count");
            Owner = null; 
            //
            try {
                TdsParserState state = Parser.State;
                if (state != TdsParserState.Broken && state != TdsParserState.Closed) { 
                    if (_pendingData) {
                        CleanWire(); // This may throw - taking us to catch block. 
                    } 

                    if (HasOpenResult) { // SQL BU DT 383773 - need to decrement openResultCount for all pending operations. 
                        DecrementOpenResultCount();
                    }

                    ResetCancelAndProcessAttention(); 
                    goodForReuse = true;
                } 
            } 
            catch (Exception e) {
                if (!ADP.IsCatchableExceptionType(e)) { 
                    throw;
                }
                ADP.TraceExceptionWithoutRethrow(e);
            } 
            return goodForReuse;
        } 
 
        internal void DecrementOpenResultCount() {
            if (_executedUnderTransaction == null) { 
                // If we were not executed under a transaction - decrement the global count
                // on the parser.
                _parser.DecrementNonTransactedOpenResultCount();
            } 
            else {
                // If we were executed under a transaction - decrement the count on the transaction. 
                _executedUnderTransaction.DecrementAndObtainOpenResultCount(); 
                _executedUnderTransaction = null;
            } 
            _hasOpenResult = false;
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        internal void DecrementPendingCallbacks(bool release) {
            int remaining = Interlocked.Decrement(ref _pendingCallbacks); 
            if (Bid.AdvancedOn) { 
                Bid.Trace(" %d#, after decrementing _pendingCallbacks: %d\n", ObjectID, _pendingCallbacks);
            } 

            if ((0 == remaining || release) && _gcHandle.IsAllocated) {
                if (Bid.AdvancedOn) {
                    Bid.Trace(" %d#, FREEING HANDLE!\n", ObjectID); 
                }
                _gcHandle.Free(); 
            } 
        }
 
        internal void Dispose() {
            SafeHandle packetHandle  = _sniPacket;
            SafeHandle sessionHandle = _sessionHandle;
            SafeHandle asyncAttnPacket = _sniAsyncAttnPacket; 
            _sniPacket     = null;
            _sessionHandle = null; 
            _sniAsyncAttnPacket = null; 

            if (null != sessionHandle || null != packetHandle) { 
                // Comment CloseMARSSession
                //

 

                // 
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try {} finally {
                    if (packetHandle != null) { 
                        packetHandle.Dispose();
                    }
                    if (asyncAttnPacket != null) {
                        asyncAttnPacket.Dispose (); 
                    }
                    if (sessionHandle != null) { 
                        sessionHandle.Dispose(); 
                        DecrementPendingCallbacks(true); // Will dispose of GC handle.
                    } 
                }
            }
        }
 
        internal Int32 IncrementAndObtainOpenResultCount(SqlInternalTransaction transaction) {
            _hasOpenResult = true; 
 
            if (transaction == null) {
                // If we are not passed a transaction, we are not executing under a transaction 
                // and thus we should increment the global connection result count.
                return _parser.IncrementNonTransactedOpenResultCount();
            }
            else { 
                // If we are passed a transaction, we are executing under a transaction
                // and thus we should increment the transaction's result count. 
                _executedUnderTransaction = transaction; 
                return transaction.IncrementAndObtainOpenResultCount();
            } 
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal void IncrementPendingCallbacks() { 
            Interlocked.Increment(ref _pendingCallbacks);
            if (Bid.AdvancedOn) { 
                Bid.Trace(" %d#, after incrementing _pendingCallbacks: %d\n", ObjectID, _pendingCallbacks); 
            }
        } 

        internal void SetTimeoutSeconds(int timeout) {
            _timeoutSeconds = timeout;
            if (timeout == 0) { 
                _timeoutTime = Int64.MaxValue;
            } 
        } 

        internal void StartSession(int objectID) { 
            _allowObjectID = objectID;
        }

        private void ThrowExceptionAndWarning() { 
            Parser.ThrowExceptionAndWarning(this);
        } 
 
        ////////////////////////////////////////////
        // TDS Packet/buffer manipulation methods // 
        ////////////////////////////////////////////

        internal void CleanWire() {
            if (TdsParserState.Broken == Parser.State || TdsParserState.Closed == Parser.State ) { 
                return;
            } 
            if (Bid.AdvancedOn) { 
                Bid.Trace(" %d#\n", ObjectID);
            } 

            // Loop until found packet with EOM AND that packet has been fully read from the wire!
            while (_messageStatus != TdsEnums.ST_EOM ||
                   (_messageStatus == TdsEnums.ST_EOM && _inBytesPacket != 0)) { 

                // jump to the next header 
                int cb = _inBytesRead - _inBytesUsed; 

                if (_inBytesPacket >= cb) { 
                    // consume the bytes in our buffer and
                    // decrement the bytes left in the packet
                    _inBytesPacket -= cb;
                    _inBytesUsed = _inBytesRead; 
                    if (_messageStatus != TdsEnums.ST_EOM ||
                        _inBytesPacket > 0) { 
                        // If we have not reached EOM packet, or if we have not consumed all bytes in 
                        // packet then call ReadBuffer.
                        ReadBuffer(); 
                    }

                    AssertValidState();
                } 
                else {
                    _inBytesUsed += _inBytesPacket; 
                    _inBytesPacket = 0; 
                    ProcessHeader();
 
                    AssertValidState();
                }
            }
 
            // cleaned the network, now fixup our buffers
            _inBytesUsed = _inBytesPacket = _inBytesRead = 0; 
            _pendingData = false; 

            AssertValidState(); 
        }

        internal void ExecuteFlush() {
            lock (this) { 
                if (_cancelled && 1 == _outputPacketNumber) {
                    ResetBuffer(); 
                    _cancelled = false; 
                    throw SQL.OperationCancelled();
                } 
                else {
                    WritePacket(TdsEnums.HARDFLUSH);
                    _pendingData = true;
                } 
            }
        } 
 
        // Processes the tds header that is present in the buffer
        internal void ProcessHeader() { 
            Debug.Assert(_inBytesPacket == 0, "there should not be any bytes left in packet when ReadHeader is called");
            // if the header splits buffer reads - special case!
            if (_inBytesUsed + _inputHeaderLen > _inBytesRead) {
                int bytesRemaining = _inBytesRead - _inBytesUsed; 
                int bytesMissing = _inputHeaderLen - bytesRemaining;
 
                Debug.Assert(bytesRemaining > 0 && bytesRemaining < _inputHeaderLen && 
                             bytesMissing > 0 && bytesMissing < _inputHeaderLen, "ProcessHeader error, bytesRemaining: " + Convert.ToString(bytesRemaining, (IFormatProvider)null) + ", bytesMissing: " + Convert.ToString(bytesMissing, (IFormatProvider)null) + ".");
                if (_bHeaderBuffer == null) 
                    _bHeaderBuffer = new byte[_inputHeaderLen];
                Buffer.BlockCopy(_inBuff, _inBytesUsed, _bHeaderBuffer, 0, bytesRemaining);

                _inBytesUsed = _inBytesRead; 

                // VSTS 219884: when some kind of MITM (man-in-the-middle) tool splits the network packets, the message header can be split over 
                // several network packets. 
                // Note: cannot use ReadByteArray here since it uses _inBytesPacket which is not set yet.
                int bytesCopied = bytesRemaining; 
                do {
                    if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
                        // NOTE: ReadNetworkPacket does nothing if the parser state is closed or broken
                        // to avoid infinite loop, we raise an exception 
                        ThrowExceptionAndWarning();
                        // 
                        return; 
                    }
 
                    ReadNetworkPacket();

                    if (_internalTimeout) {
                        ThrowExceptionAndWarning(); 
                        //
                        return; 
                    } 

                    int copy = Math.Min(_inBytesRead - _inBytesUsed, bytesMissing); 
                    Debug.Assert(copy > 0, "ReadNetworkPacket read empty buffer");

                    Buffer.BlockCopy(_inBuff, _inBytesUsed, _bHeaderBuffer, bytesCopied, copy);
                    bytesCopied += copy; 
                    bytesMissing -= copy;
                    _inBytesUsed += copy; 
                } while (bytesMissing > 0); 

                _inBytesPacket = ((int)_bHeaderBuffer[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8 | 
                                  (int)_bHeaderBuffer[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen;

                _messageStatus = _bHeaderBuffer[1];
 
                AssertValidState();
            } 
            else { 
                // normal header processing...
                _messageStatus = _inBuff[_inBytesUsed + 1]; 
                _inBytesPacket = ((int)_inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8 |
                                              (int)_inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen;
                _inBytesUsed += _inputHeaderLen;
 
                AssertValidState();
            } 
        } 

        // Wrapper function that calls the function that reads as much as possible from the netlib 
        // and inserts it into the in buffer.
        internal void ReadBuffer() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadBuffer");  // you need to setup for a thread abort somewhere before you call this method
            Debug.Assert(_inBytesUsed == _inBytesRead, "buffer should be exhaused!"); 
            Debug.Assert(_inBuff != null, "packet buffer should not be null!");
 
            // If the _inBytesPacket is not zero, then we have data left in the packet, but the data in the packet 
            // spans the buffer, so we can read any amount of data possible, and we do not need to call ProcessHeader
            // because there isn't a header at the beginning of the data that we are reading. 
            if (_inBytesPacket > 0) {
                ReadNetworkPacket();

                AssertValidState(); 
            }
            else if (_inBytesPacket == 0) { 
                // Else we have finished the packet and so we must read the next header and then as much data as 
                // posssible.
                ReadNetworkPacket(); 

                ProcessHeader();

                Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!"); 
                if (_inBytesUsed == _inBytesRead)
                { 
                    // we read a header but didn't get anything else except it 
                    // VSTS 219884: it can happen that the TDS packet header and its data are split across two network packets.
                    // Read at least one more byte to get/cache the first data portion of this TDS packet 
                    ReadNetworkPacket();
                }

                AssertValidState(); 
            }
            else { 
                Debug.Assert(false, "entered negative _inBytesPacket loop"); 
            }
        } 

        internal void ResetBuffer() {
            _outBytesUsed = _outputHeaderLen;
        } 

        internal bool SetPacketSize(int size) { 
            if (size > TdsEnums.MAX_PACKET_SIZE) { 
                throw SQL.InvalidPacketSize();
            } 
            Debug.Assert(size >= 1, "Cannot set packet size to less than 1.");
            Debug.Assert( (_outBuff == null && _inBuff == null) ||
                          (_outBuff.Length == _inBuff.Length),
                          "Buffers are not in consistent state"); 
            Debug.Assert( (_outBuff == null && _inBuff == null) ||
                          this == _parser._physicalStateObj, 
                          "SetPacketSize should only be called on a stateObj with null buffers on the physicalStateObj!"); 
            Debug.Assert( _inBuff == null
                          || 
                          (_parser.IsYukonOrNewer &&
                           _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen)) &&
                           _outputPacketNumber == 1)
                          || 
                          (_outBytesUsed == _outputHeaderLen && _outputPacketNumber == 1),
                          "SetPacketSize called with data in the buffer!"); 
 
            if (_inBuff == null || _inBuff.Length != size) { // We only check _inBuff, since two buffers should be consistent.
                // Allocate or re-allocate _inBuff. 
                if (_inBuff == null) {
                    _inBuff = new byte[size];
                    _inBytesRead = 0;
                    _inBytesUsed = 0; 
                }
                else if (size != _inBuff.Length) { 
                    // If new size is other than existing... 
                    if (_inBytesRead > _inBytesUsed) {
                        // if we still have data left in the buffer we must keep that array reference and then copy into new one 
                        byte[] temp = _inBuff;

                        _inBuff = new byte[size];
 
                        // copy remainder of unused data
                        int remainingData = _inBytesRead - _inBytesUsed; 
                        if ((temp.Length < _inBytesUsed + remainingData) || (_inBuff.Length < remainingData)) { 
                          string errormessage = Res.GetString(Res.SQL_InvalidInternalPacketSize) + ' ' + temp.Length + ", " + _inBytesUsed + ", " + remainingData + ", " + _inBuff.Length;
                          throw SQL.InvalidInternalPacketSize (errormessage); 
                        }
                        Buffer.BlockCopy(temp, _inBytesUsed, _inBuff, 0, remainingData);

                        _inBytesRead = _inBytesRead - _inBytesUsed; 
                        _inBytesUsed = 0;
 
                        AssertValidState(); 
                    }
                    else { 
                        // buffer is empty - just create the new one that is double the size of the old one
                        _inBuff = new byte[size];
                        _inBytesRead = 0;
                        _inBytesUsed = 0; 
                    }
                } 
 
                // Always re-allocate _outBuff - assert is above to verify state.
                _outBuff      = new byte[size]; 
                _outBytesUsed = _outputHeaderLen;

                AssertValidState();
                return true; 
            }
 
            return false; 
        }
 
        ///////////////////////////////////////
        // Buffer read methods - data values //
        ///////////////////////////////////////
 
        // look at the next byte without pulling it off the wire, don't just returun _inBytesUsed since we may
        // have to go to the network to get the next byte. 
        internal byte PeekByte() { 
            byte peek = ReadByte();
 
            // now do fixup
            _inBytesPacket++;
            _inBytesUsed--;
 
            AssertValidState();
            return peek; 
        } 

        // Takes a byte array, an offset, and a len and fills the array from the offset to len number of 
        // bytes from the in buffer.
        public void ReadByteArray(byte[] buff, int offset, int len) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadByteArray");  // you need to setup for a thread abort somewhere before you call this method
 
#if DEBUG
            if (buff != null) { 
                Debug.Assert(buff.Length >= len, "Invalid length sent to ReadByteArray()!"); 
            }
#endif 

            // loop through and read up to array length
            while (len > 0) {
                if ((len <= _inBytesPacket) && ((_inBytesUsed + len) <= _inBytesRead)) { 
                    // NO STRING PACKET SPAN AND NO STRING SPAN OF BUFFER
                    // If all of string is in the packet and all of the string is in the buffer 
                    // then we have the full string available for copying - then take care of counters 
                    // and break out of loop
 
                    if (buff != null) {
                        Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset, len);
                    }
 
                    _inBytesUsed += len;
                    _inBytesPacket -= len; 
 
                    AssertValidState();
                    break; 
                }
                else if (((len <= _inBytesPacket) && ((_inBytesUsed + len) > _inBytesRead)) ||
                          ((len > _inBytesPacket) && ((_inBytesUsed + _inBytesPacket) > _inBytesRead))) {
                    // NO PACKET SPAN AND STRING SPANS BUFFER        OR 
                    // STRING SPANS PACKET AND PACKET SPANS BUFFER
                    // If all of the string is in the packet and the string spans buffer OR 
                    // if the string spans packets and packet spans buffer 
                    // then we only have a partial string available to us, with the length being
                    // the rest of the bytes in the buffer.  So, there is no header in the rest of 
                    // the buffer.  The remainder of bytes left in the buffer is given by the number
                    // read minus the number used.  Copy that and then take care of the proper counters and
                    // then get the next byte from the new buffer by using the appropriate ReadByte function
                    // which will make a proper read and then take care of the header and all of that business. 

                    int remainder = _inBytesRead - _inBytesUsed; 
 
                    // read the remainder
                    if (buff != null) { 
                        Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset, remainder);
                    }

                    offset += remainder; 
                    _inBytesUsed += remainder;
                    _inBytesPacket -= remainder; 
                    len -= remainder; 

                    AssertValidState(); 

                    // and get more data from the wire
                    ReadBuffer();
                } 
                else if ((len > _inBytesPacket) && ((_inBytesUsed + _inBytesPacket) <= _inBytesRead)) {
                    // STRING SPANS PACKET AND NO PACKET SPAN OF BUFFER 
                    // If the string spans packets and all of packet is in buffer 
                    // then, all of the packet is in the buffer, but there may be more.  So,
                    // read the rest of the packet, take care of the counters, and reset the number 
                    // of bytes in the packet to zero.

                    if (buff != null) {
                        Buffer.BlockCopy(_inBuff, _inBytesUsed, buff, offset, _inBytesPacket); 
                    }
 
                    _inBytesUsed += _inBytesPacket; 
                    offset += _inBytesPacket;
                    len -= _inBytesPacket; 

                    _inBytesPacket = 0;

                    AssertValidState(); 

                    // Now, check to see if we still have data in the buffer.  If we do, then we must have a 
                    // header at the beginning of the data, since we are on a new packet.  So, since we have a 
                    // header call ProcessHeader to take care of the header.  If we don't have data in the buffer
                    // then call ReadBuffer to refill the header.  ReadBuffer will take care of the header at the 
                    // beginning of the new buffer, so don't worry about that here.
                    if (_inBytesUsed == _inBytesRead)
                        ReadBuffer();
                    else { 
                        ProcessHeader();
 
                        Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!"); 

                        if (_inBytesUsed == _inBytesRead) 
                            ReadBuffer();
                    }
                }
                else { 
                    Debug.Assert(false, "Failed to catch condition in ReadByteArray");
                } 
            } 

            AssertValidState(); 
        }

        // Takes no arguments and returns a byte from the buffer.  If the buffer is empty, it is filled
        // before the byte is returned. 
        internal byte ReadByte() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadByte");  // you need to setup for a thread abort somewhere before you call this method 
            Debug.Assert(_inBytesUsed >= 0 && _inBytesUsed <= _inBytesRead, "ERROR - TDSParser: _inBytesUsed < 0 or _inBytesUsed > _inBytesRead"); 

            // if we have exhausted the read buffer, we need to call ReadBuffer to get more data 
            if (_inBytesUsed == _inBytesRead) {
                ReadBuffer();
            }
            else if (_inBytesPacket == 0) { 
                ProcessHeader();
                Debug.Assert(_inBytesPacket != 0, "_inBytesPacket cannot be 0 after processing header!"); 
 
                if (_inBytesUsed == _inBytesRead) {
                    ReadBuffer(); 
                }
            }

            // decrement the number of bytes left in the packet 
            _inBytesPacket--;
 
            Debug.Assert(_inBytesPacket >= 0, "ERROR - TDSParser: _inBytesPacket < 0"); 

            // return the byte from the buffer and increment the counter for number of bytes used in the in buffer 
            byte b = (_inBuff[_inBytesUsed++]);

            AssertValidState();
            return b; 
        }
 
        internal char ReadChar() { 
            byte b1 = ReadByte();
            byte b2 = ReadByte(); 

            AssertValidState();
            return (char)(((b2 & 0xff) << 8) + (b1 & 0xff));
        } 

        internal short ReadInt16() { 
            // appears to be more performant this way than like ReadUnsignedInt 
            byte b1 = ReadByte();
            byte b2 = ReadByte(); 

            AssertValidState();
            return (Int16)((b2 << 8) + b1);
        } 

        internal int ReadInt32() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadInt32");  // you need to setup for a thread abort somewhere before you call this method 
            if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) {
                // If the int isn't fully in the buffer, or if it isn't fully in the packet, 
                // then use ReadByteArray since the logic is there to take care of that.

                ReadByteArray(_bTmp, 0, 4);
 
                AssertValidState();
                return BitConverter.ToInt32(_bTmp, 0); 
            } 
            else {
                // The entire int is in the packet and in the buffer, so just return it 
                // and take care of the counters.

                int i = BitConverter.ToInt32(_inBuff, _inBytesUsed);
 
                _inBytesUsed += 4;
                _inBytesPacket -= 4; 
 
                AssertValidState();
                return i; 
            }
        }

        internal long ReadInt64() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadInt64");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)) { 
                // If the long isn't fully in the buffer, or if it isn't fully in the packet, 
                // then use ReadByteArray since the logic is there to take care of that.
 
                ReadByteArray(_bTmp, 0, 8);

                AssertValidState();
                return BitConverter.ToInt64(_bTmp, 0); 
            }
            else { 
                // The entire long is in the packet and in the buffer, so just return it 
                // and take care of the counters.
 
                long l = BitConverter.ToInt64(_inBuff, _inBytesUsed);

                _inBytesUsed += 8;
                _inBytesPacket -= 8; 

                AssertValidState(); 
                return l; 
            }
        } 

        internal ushort ReadUInt16() {
            // appears to be more performant this way than like ReadUnsignedInt
            byte b1 = ReadByte(); 
            byte b2 = ReadByte();
 
            AssertValidState(); 
            return (UInt16)((b2 << 8) + b1);
        } 

        internal uint ReadUInt32() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadUInt32");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) { 
                // If the int isn't fully in the buffer, or if it isn't fully in the packet,
                // then use ReadByteArray since the logic is there to take care of that. 
 
                ReadByteArray(_bTmp, 0, 4);
 
                AssertValidState();
                return BitConverter.ToUInt32(_bTmp, 0);
            }
            else { 
                // The entire int is in the packet and in the buffer, so just return it
                // and take care of the counters. 
 
                uint i = BitConverter.ToUInt32(_inBuff, _inBytesUsed);
 
                _inBytesUsed += 4;
                _inBytesPacket -= 4;

                AssertValidState(); 
                return i;
            } 
        } 

        internal float ReadSingle() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadSingle");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 4) > _inBytesRead) || (_inBytesPacket < 4)) {
                // If the float isn't fully in the buffer, or if it isn't fully in the packet,
                // then use ReadByteArray since the logic is there to take care of that. 

                ReadByteArray(_bTmp, 0, 4); 
 
                AssertValidState();
                return BitConverter.ToSingle(_bTmp, 0); 
            }
            else {
                // The entire float is in the packet and in the buffer, so just return it
                // and take care of the counters. 

                float f = BitConverter.ToSingle(_inBuff, _inBytesUsed); 
 
                _inBytesUsed += 4;
                _inBytesPacket -= 4; 

                AssertValidState();
                return f;
            } 
        }
 
        internal double ReadDouble() { 
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadDouble");  // you need to setup for a thread abort somewhere before you call this method
            if (((_inBytesUsed + 8) > _inBytesRead) || (_inBytesPacket < 8)) { 
                // If the double isn't fully in the buffer, or if it isn't fully in the packet,
                // then use ReadByteArray since the logic is there to take care of that.

                ReadByteArray(_bTmp, 0, 8); 

                AssertValidState(); 
                return BitConverter.ToDouble(_bTmp, 0); 
            }
            else { 
                // The entire double is in the packet and in the buffer, so just return it
                // and take care of the counters.

                double d = BitConverter.ToDouble(_inBuff, _inBytesUsed); 

                _inBytesUsed += 8; 
                _inBytesPacket -= 8; 

                AssertValidState(); 
                return d;
            }
        }
 
        internal string ReadString(int length) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadString");  // you need to setup for a thread abort somewhere before you call this method 
            int cBytes = length << 1; 
            byte[] buf;
            int offset = 0; 

            if (((_inBytesUsed + cBytes) > _inBytesRead) || (_inBytesPacket < cBytes)) {
                if (_bTmp == null || _bTmp.Length < cBytes) {
                    _bTmp = new byte[cBytes]; 
                }
 
                ReadByteArray(_bTmp, 0, cBytes); 

                // assign local to point to parser scratch buffer 
                buf = _bTmp;

                AssertValidState();
            } 
            else {
                // assign local to point to _inBuff 
                buf = _inBuff; 
                offset = _inBytesUsed;
                _inBytesUsed += cBytes; 
                _inBytesPacket -= cBytes;

                AssertValidState();
            } 
            return System.Text.Encoding.Unicode.GetString(buf, offset, cBytes);
        } 
 
        internal string ReadStringWithEncoding(int length, System.Text.Encoding encoding, bool isPlp) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadStringWithEncoding");  // you need to setup for a thread abort somewhere before you call this method 

            if (null == encoding) {
                _parser.ThrowUnsupportedCollationEncountered(this);
            } 
            byte[] buf = null;
            int offset = 0; 
 
            if (isPlp) {
                length = ReadPlpBytes(ref buf, 0, Int32.MaxValue); 

                AssertValidState();
            }
            else { 
                if (((_inBytesUsed + length) > _inBytesRead) || (_inBytesPacket < length)) {
                    if (_bTmp == null || _bTmp.Length < length) { 
                        _bTmp = new byte[length]; 
                    }
 
                    ReadByteArray(_bTmp, 0, length);

                    // assign local to point to parser scratch buffer
                    buf = _bTmp; 

                    AssertValidState(); 
                } 
                else {
                    // assign local to point to _inBuff 
                    buf = _inBuff;
                    offset = _inBytesUsed;
                    _inBytesUsed += length;
                    _inBytesPacket -= length; 

                    AssertValidState(); 
                } 
            }
 
            // BCL optimizes to not use char[] underneath
            return encoding.GetString(buf, offset, length);
        }
 
        // Reads the length of either the entire data or the length of the next chunk in a
        //   partially length prefixed data 
        // After this call, call  ReadPlpBytes/ReadPlpUnicodeChars untill the specified length of data 
        // is consumed. Repeat this until ReadPlpLength returns 0 in order to read the
        // entire stream. 
        // When this function returns 0, it means the data stream is read completely and the
        // plp state in the tdsparser is cleaned.
        internal ulong ReadPlpLength(bool returnPlpNullIfNull) {
            uint chunklen; 
           // bool firstchunk = false;
            bool isNull = false; 
 
            Debug.Assert(_longlenleft == 0, "Out of synch length read request");
            if (_longlen == 0) { 
                // First chunk is being read. Find out what type of chunk it is
                _longlen = (ulong)ReadInt64();
                // firstchunk = true;
            } 

            if (_longlen == TdsEnums.SQL_PLP_NULL) { 
                _longlen = 0; 
                _longlenleft = 0;
                isNull = true; 
            }
            else {
                // Data is coming in uint chunks, read length of next chunk
                chunklen = ReadUInt32(); 
                if (chunklen == TdsEnums.SQL_PLP_CHUNK_TERMINATOR) {
                    _longlenleft = 0; 
                    _longlen = 0; 
                }
                else { 
                    _longlenleft = (ulong)chunklen;
                }
            }
 
            AssertValidState();
 
            if (isNull && returnPlpNullIfNull) 
                return TdsEnums.SQL_PLP_NULL;
 
            return _longlenleft;
        }

        // Reads the current chunk in a bigvarbinary(max) data stream. 
        // Will not start reading into the next chunk if bytes requested is larger than
        // the current chunk length. Use ReadPlpBytes in that case. 
        // Returns the actual bytes read 
        internal int ReadPlpBytesChunk(byte[] buff, int offset, int len) {
            int bytesRead = 0; 

            if (_longlenleft == 0) {
                Debug.Assert(false, "Out of [....] read request");
                return 0; 
            }
 
            bytesRead = len; 

            if (_longlenleft < (ulong)len) 
                bytesRead = (int)_longlenleft;

            // ReadByteArray does the appropriate checks for buffer length, etc...
            ReadByteArray(buff, offset, bytesRead); 
            _longlenleft -= (ulong)bytesRead;
 
            AssertValidState(); 
            return bytesRead;
        } 

        // Reads the requested number of bytes from a plp data stream, or the entire data if
        // requested length is -1 or larger than the actual length of data. First call to this method
        //  should be preceeded by a call to ReadPlpLength or ReadDataLength. 
        // Returns the actual bytes read.
        internal int ReadPlpBytes(ref byte[] buff, int offst, int len) { 
            int bytesRead = 0; 
            int totalbytesRead = 0;
            int bytesLeft; 
            byte[] newbuf;

            if (_longlen == 0) {
                Debug.Assert(_longlenleft == 0); 
                if (buff == null) {
                    buff = new byte[0]; 
                } 

                AssertValidState(); 
                return 0;       // No data
            }

            Debug.Assert((_longlen != TdsEnums.SQL_PLP_NULL), 
                    "Out of [....] plp read request");
 
            Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpBytes()!"); 
            bytesLeft = len;
 
            // If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time
            if (buff == null && _longlen != TdsEnums.SQL_PLP_UNKNOWNLEN) {
                buff = new byte[(int)Math.Min((int)_longlen, len)];
            } 

            if (_longlenleft == 0) { 
                ReadPlpLength( false); 
                if (_longlenleft == 0)  // Data read complete
                    return 0; 
            }

            if (buff == null) {
                buff = new byte[_longlenleft]; 
            }
 
            while (bytesLeft > 0) { 
                bytesRead = (int)Math.Min(_longlenleft, (ulong)bytesLeft);
                if (buff.Length < (offst + bytesRead)) { 
                    // Grow the array
                    newbuf = new byte[offst + bytesRead];
                    Buffer.BlockCopy(buff, 0, newbuf, 0, offst);
                    buff = newbuf; 
                }
 
                bytesRead = ReadPlpBytesChunk(buff, offst, bytesRead); 
                bytesLeft -= bytesRead;
                offst += bytesRead; 
                totalbytesRead += bytesRead;
                if (_longlenleft == 0)  // Read the next chunk or cleanup state if hit the end
                    ReadPlpLength( false);
 
                AssertValidState();
 
                // Catch the point where we read the entire plp data stream and clean up state 
                if (_longlenleft == 0)   // Data read complete
                    break; 
            }
            return (totalbytesRead);
        }
 
        /////////////////////////////////////////
        // Network/Packet Reading & Processing // 
        ///////////////////////////////////////// 

        // Should only be called for [....], or [....] over async.  This should never be called for a non-blocking async read. 
        internal void ReadNetworkPacket() {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadBuffer");  // you need to setup for a thread abort somewhere before you call this method
            _inBytesUsed = 0; // Reset _inBytesUsed, we have data in the buffer but none of it has been used.
 
#if NONETWORK
            NoNetworkProcessing(); 
#else // !NONETWORK 
            if (Parser.AsyncOn && _cachedAsyncResult == null) { // Alloc DbAsyncResult used for [....] over async
                _cachedAsyncResult = new DbAsyncResult(this, String.Empty, null, null, null); 
            }
            Debug.Assert(!Parser.AsyncOn || (Parser.AsyncOn && _cachedAsyncResult != null), "Unexpected state for _cachedAsyncResult!");

            ReadSni(_cachedAsyncResult, this); // _cachedAsyncResult null if !Parser.AsyncOn 

            // ReadSni will not block for async, so if ReadNetworkPacket is called with async we are [....]/async and need to block. 
            if (Parser.AsyncOn) { 
                ReadSniSyncOverAsync();
            } 
#endif // !NONETWORK

#if BUILDHARDCODEDPACKETCODE
            BuildHardCodedPacketCodeRead(); 
#endif //BUILDHARDCODEDPACKETCODE
 
            SniReadStatisticsAndTracing(); 

            if (Bid.AdvancedOn) { 
                Bid.TraceBin(" Packet read", _inBuff, (UInt16)_inBytesRead);
            }

            AssertValidState(); 
        }
 
        internal void ReadSniSyncOverAsync() { // Will block until posted Async read returns. 
            Debug.Assert(Parser.AsyncOn, "TdsParserStateObject.ReadSniSyncOverAsync should never be called on [....] connection");
            Debug.Assert(_parser.State != TdsParserState.Broken && _parser.State != TdsParserState.Closed, "Must not call ReadSniSync if connection is broken or closed"); 
            if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) {
                return;
            }
 
            try {
                // Block for callback to occur, since we are [....] over async. 
                if (!(((IAsyncResult)_cachedAsyncResult).AsyncWaitHandle.WaitOne(TdsParserStaticMethods.GetTimeoutMilliseconds(TimeoutTime), false))) { 
                    // WaitOne did not return in timeout period, so we have now timed out.
                    bool fail = false; 

                    if (_internalTimeout) { // This is now our second timeout - time to give up and break connection.
                        fail = true;
                    } 
                    else {
                        _internalTimeout = true; 
                        _parser.Errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, SQLMessage.Timeout(), "", 0)); 

                        if (!_attentionSent) { 
                            if (_parser.State == TdsParserState.OpenLoggedIn) {
                                SendAttention();
                            }
                            else { 
                                fail = true; // We aren't open yet - do not send attention!
                            } 
 
                            // Now wait another 5 seconds for the callback to occur.
                            if (!(((IAsyncResult)_cachedAsyncResult).AsyncWaitHandle.WaitOne(TdsParserStaticMethods.GetTimeoutMilliseconds(TimeoutTime), false))) { 
                                fail = true; // We timed out on secondary 5 second time out - time to give up and break connection.
                            }
                        }
                    } 

                    if (fail) { // ABORT, ABORT, ABORT! 
                        _parser.State = TdsParserState.Broken; 
                        _parser.Connection.BreakConnection();
                        _parser.ThrowExceptionAndWarning(this); 
                    }
                }

                if (_error != null) { // In case ReadCallback returned error, we need to fail and throw! 
                    // We don't need to check fAwaitingPreLogin before throwing, because in that case we do not cache error.
                    Parser.Errors.Add(_error); 
                    _error = null; 
                    _parser.ThrowExceptionAndWarning(this);
                } 
            }
            finally {
                if (_cachedAsyncResult != null) {
                    _cachedAsyncResult.Reset(); 
                }
 
                AssertValidState(); 
            }
        } 

        internal void ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) {
            Debug.Assert(_parser.State != TdsParserState.Broken && _parser.State != TdsParserState.Closed, "Must not call ReadSniSync if connection is broken or closed");
            if (_parser.State == TdsParserState.Broken || _parser.State == TdsParserState.Closed) { 
                return;
            } 
 
            IntPtr readPacket = IntPtr.Zero;
            UInt32 error; 

            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                if (!_parser.AsyncOn) { 
                    Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadSniSync");  // you need to setup for a thread abort somewhere before you call this method
 
                    error = SNINativeMethodWrapper.SNIReadSync(stateObj.Handle, ref readPacket, TdsParserStaticMethods.GetTimeoutMilliseconds(stateObj.TimeoutTime)); 

                    if (TdsEnums.SNI_SUCCESS == error) { // Success - process results! 
                        Debug.Assert(ADP.PtrZero != readPacket, "ReadNetworkPacket cannot be null in syncronous operation!");
                        stateObj.ProcessSniPacket(readPacket, 0);
                    }
                    else { // Failure! 
                        Debug.Assert(IntPtr.Zero == readPacket, "unexpected readPacket without corresponding SNIPacketRelease");
                        ReadSniError(stateObj, error); 
                    } 
                }
                else { 
                    Debug.Assert(asyncResult != null, "Async on but null asyncResult passed");
                    stateObj._asyncResult = asyncResult;

                    RuntimeHelpers.PrepareConstrainedRegions(); 
                    try {} finally {
                        stateObj.IncrementPendingCallbacks(); 
                        error = SNINativeMethodWrapper.SNIReadAsync(stateObj.Handle, ref readPacket); 

                        if (!(TdsEnums.SNI_SUCCESS == error || TdsEnums.SNI_SUCCESS_IO_PENDING == error)) { 
                            stateObj.DecrementPendingCallbacks(false); // Failure - we won't receive callback!
                        }
                    }
 
                    if (TdsEnums.SNI_SUCCESS == error) { // Success - process results!
                        Debug.Assert(ADP.PtrZero != readPacket, "ReadNetworkPacket should not have been null on this async operation!"); 
                        stateObj._asyncResult.SetCompletedSynchronously(); 
                        stateObj.ReadAsyncCallback(ADP.PtrZero, readPacket, 0);
                    } 
                    else if (TdsEnums.SNI_SUCCESS_IO_PENDING != error) { // FAILURE!
                        Debug.Assert(IntPtr.Zero == readPacket, "unexpected readPacket without corresponding SNIPacketRelease");
                        ReadSniError(stateObj, error);
                    } 
                    // DO NOT HANDLE PENDING READ HERE - which is TdsEnums.SNI_SUCCESS_IO_PENDING state.
                    // That is handled by user who initiated async read, or by ReadNetworkPacket which is [....] over async. 
                } 
            }
            finally { 
                if (readPacket != IntPtr.Zero) {
                    // Be sure to release packet, otherwise it will be leaked by native.
                    SNINativeMethodWrapper.SNIPacketRelease(readPacket);
                } 

                AssertValidState(); 
            } 
        }
 
        // This method should only be called by ReadSni!  If not - it may have problems with timeouts!
        private void ReadSniError(TdsParserStateObject stateObj, UInt32 error) {
            Debug.Assert(null != Thread.GetData(TdsParser.ReliabilitySlot), "unreliable call to ReadSniSyncError");  // you need to setup for a thread abort somewhere before you call this method
            // Due to the fact 7.0 kills connections on which pre-login packets are sent, we 
            // are required to eat non-timeout failures on Read() after the connection was
            // successfully established.  SQL BU DT 229929. 
            if (_parser._fAwaitingPreLogin && error != TdsEnums.SNI_WAIT_TIMEOUT) { 
                _parser._fPreLoginErrorOccurred = true;
            } 
            else {
                if (TdsEnums.SNI_WAIT_TIMEOUT == error) {
                    Debug.Assert(!_parser.AsyncOn, "Should never reach here with async on!");
                    bool fail = false; 

                    if (_internalTimeout) { // This is now our second timeout - time to give up. 
                        fail = true; 
                    }
                    else { 
                        stateObj._internalTimeout = true;
                        _parser.Errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, SQLMessage.Timeout(), "", 0));

                        if (!stateObj._attentionSent) { 
                            if (stateObj.Parser.State == TdsParserState.OpenLoggedIn) {
                                stateObj.SendAttention(); 
                                IntPtr syncReadPacket = IntPtr.Zero; 

                                RuntimeHelpers.PrepareConstrainedRegions(); 
                                try {
                                    error = SNINativeMethodWrapper.SNIReadSync(stateObj.Handle, ref syncReadPacket, TdsParserStaticMethods.GetTimeoutMilliseconds(stateObj.TimeoutTime));
                                    if (TdsEnums.SNI_SUCCESS == error) {
                                        // We will end up letting the run method deal with the expected done:done_attn token stream. 
                                        stateObj.ProcessSniPacket(syncReadPacket, 0);
                                        return; 
                                    } 
                                    else {
                                        Debug.Assert(IntPtr.Zero == syncReadPacket, "unexpected syncReadPacket without corresponding SNIPacketRelease"); 
                                        fail = true; // Subsequent read failed, time to give up.
                                    }
                                }
                                finally { 
                                    if (syncReadPacket != IntPtr.Zero) {
                                        // Be sure to release packet, otherwise it will be leaked by native. 
                                        SNINativeMethodWrapper.SNIPacketRelease(syncReadPacket); 
                                    }
                                } 
                            }
                            else {
                                fail = true; // We aren't yet logged in - just fail.
                            } 
                        }
                    } 
 
                    if (fail) {
                        _parser.State = TdsParserState.Broken; // We failed subsequent read, we have to quit! 
                        _parser.Connection.BreakConnection();
                    }
                }
                else { 
                    // Caution: ProcessSNIError  always  returns a fatal error!
                    _parser.Errors.Add(_parser.ProcessSNIError(stateObj)); 
                } 
                _parser.ThrowExceptionAndWarning(stateObj);
            } 

            AssertValidState();
        }
 
        //
        public void ProcessSniPacket(IntPtr packet, UInt32 error) { 
            // Do nothing with with callback if closed or broken and error not 0 - callback can occur 
            // after connection has been closed.  PROBLEM IN NETLIB - DESIGN FLAW.
            if ( (_parser.State == TdsParserState.Closed || _parser.State == TdsParserState.Broken) 
                 && error != 0) {
                return; // Packet will still get released in finally block.
            }
 
            if (error != 0) {
                // Due to the fact 7.0 kills connections on which pre-login packets are sent, we 
                // are required to eat non-timeout failures on Read() after the connection was 
                // successfully established.  SQL BU DT 229929.
                if (_parser._fAwaitingPreLogin && error != TdsEnums.SNI_WAIT_TIMEOUT) { 
                    _parser._fPreLoginErrorOccurred = true;
                }
                else {
                    Debug.Assert(_error == null, "Unexpectedly already have a cached error!"); 
                    _error = _parser.ProcessSNIError(this);
                } 
 
                AssertValidState();
            } 
            else {
                IntPtr pConn = SNINativeMethodWrapper.SNIPacketGetConnection(packet);

                UInt32 dataSize = 0; 
                IntPtr pointer = ADP.PtrZero;
                SNINativeMethodWrapper.SNIPacketGetData(packet,  ref pointer, ref dataSize); 
 
                if (_inBuff.Length < dataSize) {
                    Debug.Assert(true, "Unexpected dataSize on Read"); 
                    throw SQL.InvalidInternalPacketSize (Res.GetString(Res.SqlMisc_InvalidArraySizeMessage));
                }
                Marshal.Copy(pointer, _inBuff, 0, (Int32) dataSize);
 
                _inBytesRead = (int) dataSize;
                _inBytesUsed = 0; 
 
                AssertValidState();
            } 
        }

        public void ReadAsyncCallback(IntPtr key, IntPtr packet, UInt32 error) { // Key never used.
            // Note - it's possible that when native calls managed that an asynchronous exception 
            // could occur in the native->managed transition, which would
            // have two impacts: 
            // 1) user event not called 
            // 2) DecrementPendingCallbacks not called, which would mean this object would be leaked due
            //    to the outstanding GCRoot until AppDomain.Unload. 
            // We live with the above for the time being due to the constraints of the current
            // reliability infrastructure provided by the CLR.
            RuntimeHelpers.PrepareConstrainedRegions();
            bool processFinallyBlock = true; 
            try {
                Debug.Assert(IntPtr.Zero == packet || IntPtr.Zero != packet && _asyncResult != null, "AsyncResult null on callback"); 
                if (_parser.MARSOn) { // Only take reset lock on MARS and Async. 
                    CheckSetResetConnectionState(error, CallbackType.Read);
                } 
                ProcessSniPacket(packet, error);
            }
            catch (Exception e) {
                processFinallyBlock = ADP.IsCatchableExceptionType(e); 
                throw;
            } 
            finally { 
                DecrementPendingCallbacks(false); // may dispose of GC handle.
                if (processFinallyBlock) { 
                    _asyncResult.SetCompleted();
                }

                AssertValidState(); 
            }
        } 
 
        /////////////////////////////////////////
        // Network/Packet Writing & Processing // 
        /////////////////////////////////////////

        // Dumps contents of buffer to SNI for network write.
        internal void WritePacket(byte flushMode) { 
            Debug.Assert(_parser.State == TdsParserState.OpenNotLoggedIn || _parser.State == TdsParserState.OpenLoggedIn,
                         "Cannot flush buffer when connection is closed!"); 
 
            if  (   _parser.State == TdsParserState.Closed
                ||  _parser.State == TdsParserState.Broken 
                ||  _parser.IsYukonOrNewer && !_bulkCopyOpperationInProgress // ignore the condition checking for bulk copy (SQL BU 414551)
                    && _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen))
                    && _outputPacketNumber == 1
                ||  _outBytesUsed == _outputHeaderLen 
                    && _outputPacketNumber == 1) {
                return; 
            } 

            byte status = TdsEnums.ST_EOM; 
            byte packetNumber = _outputPacketNumber;

            // Set Status byte based whether this is end of message or not
            if (TdsEnums.HARDFLUSH == flushMode) { 
                status = TdsEnums.ST_EOM;
                _outputPacketNumber = 1;              // end of message - reset to 1 - per ramas 
            } 
            else if (TdsEnums.SOFTFLUSH==flushMode) {
                status = TdsEnums.ST_BATCH; 
                _outputPacketNumber++;
            }
            else {
                Debug.Assert (false, String.Format((IFormatProvider)null, "Unexpected argument {0,-2:x2} to WritePacket", flushMode)); 
            }
 
            _outBuff[0] = _outputMessageType;         // Message Type 
            _outBuff[1] = status;
            _outBuff[2] = (byte)(_outBytesUsed >> 8); // length - upper byte 
            _outBuff[3] = (byte)(_outBytesUsed&0xff); // length - lower byte
            _outBuff[4] = 0;                          // channel
            _outBuff[5] = 0;
            _outBuff[6] = packetNumber;               // packet 
            _outBuff[7] = 0;                          // window
 
            _parser.CheckResetConnection(this);       // HAS SIDE EFFECTS - re-org at a later time if possible 

            WriteSni(); 

            AssertValidState();
        }
 

        private UInt32 SNIWriteAsync(SNIHandle handle,SNIPacket packet, DbAsyncResult asyncResult) { 
            UInt32 sniError; 
            // Async operation completion may be delayed (success pending).
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
            }
            finally {
                IncrementPendingCallbacks(); 
                sniError = SNINativeMethodWrapper.SNIWriteAsync(handle, packet);
 
                if (sniError == TdsEnums.SNI_SUCCESS || sniError != TdsEnums.SNI_SUCCESS_IO_PENDING) { 
                    // If read completed synchronously, or if error occurred, decrement _pendingCallbacks.
                    DecrementPendingCallbacks(false); 
                }
            }

            if (sniError != TdsEnums.SNI_SUCCESS) { 
                if (sniError != TdsEnums.SNI_SUCCESS_IO_PENDING) { // Error occurred.
                    Bid.Trace(" write async returned error code %d\n", (int)sniError); 
                    _parser.Errors.Add(_parser.ProcessSNIError(this)); 
                    ThrowExceptionAndWarning();
                } 
                else if (sniError == TdsEnums.SNI_SUCCESS_IO_PENDING) { // Write result is pending.
                    try {
                        // Write callback expected - wait for it - block indefinitely. :(
                        ((IAsyncResult)asyncResult).AsyncWaitHandle.WaitOne(); 
                        // After unblocked by background thread, check to see if error occurred.
                        if (_error != null) { // Add to collection if occurred. 
                            _parser.Errors.Add(_error); 
                            _error = null;
                            Bid.Trace(" write async returned error code %d\n", (int)sniError); 
                            ThrowExceptionAndWarning();
                        }
                    }
                    finally { 
                        asyncResult.Reset();
                    } 
                } 
            }
 
            AssertValidState();
            return sniError;
        }
 
        // Sends an attention signal - executing thread will consume attn.
        internal void SendAttention() { 
            if (!_attentionSent) { 
                // Dumps contents of buffer to OOB write (currently only used for
                // attentions.  There is no body for this message 
                // Doesn't touch this._outBytesUsed
                Debug.Assert((_parser.State == TdsParserState.OpenNotLoggedIn ||
                             _parser.State == TdsParserState.OpenLoggedIn),
                             "Cannot flush bufferOOB when connection is closed!"); 

                if (_parser.State == TdsParserState.Closed || _parser.State == TdsParserState.Broken) { 
                    return; 
                }
 
                SNIPacket attnPacket = new SNIPacket(Handle);
                if (_parser.AsyncOn) {
                    _sniAsyncAttnPacket = attnPacket;
                    if (_asyncAttentionResult == null) { 
                        _asyncAttentionResult = new DbAsyncResult(_parser, String.Empty, null, null, null);
                    } 
                } 
                else {
                    _sniAsyncAttnPacket = null; 
                }

                SNINativeMethodWrapper.SNIPacketSetData(attnPacket, SQL.AttentionHeader, TdsEnums.HEADER_LEN);
 
                UInt32 sniError;
                if (_parser.AsyncOn) { 
                    sniError = SNIWriteAsync (Handle, attnPacket, _asyncAttentionResult); 
                    Bid.Trace(" Send Attention ASync .\n");
                } 
                else {
                    sniError = SNINativeMethodWrapper.SNIWriteSync(Handle, attnPacket);
                    Bid.Trace(" Send Attention [....].\n");
 
                    if (sniError != TdsEnums.SNI_SUCCESS) {
                        Bid.Trace(" SNIWriteSync returned error code %d\n", (int)sniError); 
 
                        //
                        _parser.Errors.Add(_parser.ProcessSNIError(this)); 
                        _parser.ThrowExceptionAndWarning(this);
                    }
                }
 
                SetTimeoutSeconds(5); // Initialize new attention timeout of 5 seconds.
                _attentionSent = true; 
 
                if (Bid.AdvancedOn)  {
                    Bid.TraceBin("  Packet sent", _outBuff, (UInt16)_outBytesUsed); 
                }
                Bid.Trace(" Attention sent to the server.\n");

                AssertValidState(); 
            }
        } 
 
        private void WriteSni() {
#if NONETWORK 
            ResetBuffer(); // DO NOT REMOVE THIS CODE UNLESS YOU TALK WITH [....] FIRST. WE USE THIS CODE TO CREATE HARD CODED PACKETS FOR PEFORMANCE TESTING!
#else //!NONETWORK

#if BUILDHARDCODEDPACKETCODE 
            BuildHardCodedPacketCodeWrite(_outBytesUsed);
#endif //BUILDHARDCODEDPACKETCODE 
 
            // Prepare packet, and write to packet.
            if (_sniPacket == null) { 
                _sniPacket = new SNIPacket(Handle);
            }
            else {
                SNINativeMethodWrapper.SNIPacketReset(Handle, SNINativeMethodWrapper.IOType.WRITE, _sniPacket); 
            }
            SNINativeMethodWrapper.SNIPacketSetData(_sniPacket, _outBuff, _outBytesUsed); 
 
            UInt32 sniError;
            // Prepare for async, if present. 
            if (_parser.AsyncOn) {
                if (_cachedAsyncResult == null) {
                    _cachedAsyncResult = new DbAsyncResult(_parser, String.Empty, null, null, null);
                } 
                _asyncResult = _cachedAsyncResult;
                sniError = SNIWriteAsync(Handle, _sniPacket, _cachedAsyncResult); 
            } 
            else {
                // Synchronous operation - operation completes immediately. 
                sniError = SNINativeMethodWrapper.SNIWriteSync(Handle, _sniPacket);

                if (sniError != TdsEnums.SNI_SUCCESS) {
                    Bid.Trace(" write [....] returned error code %d\n", (int)sniError); 
                    _parser.Errors.Add(_parser.ProcessSNIError(this));
                    ThrowExceptionAndWarning(); 
                } 

                // Check to see if the timeout has occured.  This time out code is special case code to allow BCP writes to timeout to fix bug 350558, eventually we should make all writes timeout. 
                if (_bulkCopyOpperationInProgress && 0 == TdsParserStaticMethods.GetTimeoutMilliseconds(TimeoutTime)) {
                     _parser.Errors.Add(new SqlError(TdsEnums.TIMEOUT_EXPIRED, (byte)0x00, TdsEnums.MIN_ERROR_CLASS, _parser.Server, SQLMessage.Timeout(), "", 0));
                     SendAttention();
                     _parser.ProcessPendingAck(this); 
                     _parser.ThrowExceptionAndWarning(this);
                } 
            } 

            // Special case logic for encryption removal. 
            //
            if (_parser.State == TdsParserState.OpenNotLoggedIn &&
                _parser.EncryptionOptions == EncryptionOptions.LOGIN) {
                // If no error occurred, and we are Open but not logged in, and 
                // our encryptionOption state is login, remove the SSL Provider.
                // We only need encrypt the very first packet of the login message to the server. 
 
                // SQL BU DT 332481 - we wanted to encrypt entire login channel, but there is
                // currently no mechanism to communicate this.  Removing encryption post 1st packet 
                // is a hard-coded agreement between client and server.  We need some mechanism or
                // common change to be able to make this change in a non-breaking fasion.
                _parser.RemoveEncryption();                        // Remove the SSL Provider.
                _parser.EncryptionOptions = EncryptionOptions.OFF; // Turn encryption off. 

                // Since this packet was associated with encryption, dispose and re-create. 
                _sniPacket.Dispose(); 
                _sniPacket = new SNIPacket(Handle);
            } 

            SniWriteStatisticsAndTracing();

            ResetBuffer(); 
#endif // !NONETWORK
 
            AssertValidState(); 
        }
 
        public void WriteAsyncCallback(IntPtr key, IntPtr packet, UInt32 error) {
            DbAsyncResult dbAsyncResult = _asyncResult;
            // SQL BU DT 346588 - this call to DangerousGetHandle is safe since we only use the
            // resulting pointer for a comparison only.  We do not cache the pointer or use it for 
            // any further operations or PInvokes.
            if (_sniAsyncAttnPacket != null && _sniAsyncAttnPacket.DangerousGetHandle () == packet) { 
                dbAsyncResult = _asyncAttentionResult; 
            }
 
            bool processFinallyBlock = true;
            try {
                if (_parser.MARSOn) { // Only take reset lock on MARS and Async.
                    CheckSetResetConnectionState(error, CallbackType.Read); 
                }
 
                if (error != 0) { 
                    Debug.Assert(_error == null, "Unexpectedly already have a cached error!");
                    _error = _parser.ProcessSNIError(this); // Cache error for WriteSni to use. 
                }
            }
            catch (Exception e) {
                processFinallyBlock = ADP.IsCatchableExceptionType(e); 
                throw;
            } 
            finally { 
                DecrementPendingCallbacks(false); // may dispose of GC handle.
                if (processFinallyBlock) { 
                    dbAsyncResult.SetCompleted();
                }

                AssertValidState(); 
            }
        } 
 
        //////////////////////////////////////////////
        // Statistics, Tracing, and related methods // 
        //////////////////////////////////////////////

#if BUILDHARDCODEDPACKETCODE
        private void BuildHardCodedPacketCodeWrite(int bytesWritten) { 
            // DO NOT REMOVE THIS CODE UNLESS YOU TALK WITH [....] FIRST
            // WE USE THIS CODE TO CREATE HARD CODED PACKETS FOR PEFORMANCE 
            // TESTING!!!! 
            Console.WriteLine (String.Format((IFormatProvider)null, "static private byte[] send_packet_{0} = {1}", _outputPacketNumber, '{'));
            for (int i=0; i < _outBytesUsed; i++) { 
                if (i % 16 == 0) {
                    if (i > 0) {
                        Console.WriteLine();
                    } 
                    Console.Write("        ");
                } 
                Console.Write(String.Format((IFormatProvider)null, "0x{0,-2:x2},", _outBuff[i])); 
            }
            Console.WriteLine (String.Format((IFormatProvider)null, "}}; // {0} bytes", _outBytesUsed)); 
        }

        private void BuildHardCodedPacketCodeRead() {
            Console.WriteLine (String.Format((IFormatProvider)null, "static private byte[] recv_packet_n = {0}", '{')); 
            for (int i=0; i < _inBytesRead; i++) {
                if (i % 16 == 0) { 
                    if (i > 0) { 
                        Console.WriteLine();
                    } 
                    Console.Write("        ");
                }
                Console.Write(String.Format((IFormatProvider)null, "0x{0,-2:x2},", _inBuff[i]));
            } 
            Console.WriteLine (String.Format((IFormatProvider)null, "}}; // {0} bytes", _inBytesRead));
        } 
#endif //BUILDHARDCODEDPACKETCODE 

#if NONETWORK 
        private void NoNetworkProcessing() {
            // DO NOT REMOVE THIS CODE UNLESS YOU TALK WITH [....] FIRST
            // WE USE THIS CODE TO CREATE HARD CODED PACKETS FOR PEFORMANCE
            // TESTING!!!! 
            recv_packet[recv_packet_number].CopyTo(_inBuff, 0);
            _inBytesRead = recv_packet[recv_packet_number].Length; 
            if (++recv_packet_number >= recv_packet.Length) { 
                recv_packet_number = 1;
            } 
        }
#endif // !NONETWORK

        private void SniReadStatisticsAndTracing() { 
            SqlStatistics statistics = Parser.Statistics;
            if (null != statistics) { 
                if (statistics.WaitForReply) { 
                    statistics.SafeIncrement(ref statistics._serverRoundtrips);
                    statistics.ReleaseAndUpdateNetworkServerTimer(); 
                }

                statistics.SafeAdd(ref statistics._bytesReceived, _inBytesRead);
                statistics.SafeIncrement(ref statistics._buffersReceived); 
            }
        } 
 
        private void SniWriteStatisticsAndTracing() {
            SqlStatistics statistics = _parser.Statistics; 
            if (null != statistics) {
                statistics.SafeIncrement(ref statistics._buffersSent);
                statistics.SafeAdd(ref statistics._bytesSent, _outBytesUsed);
                statistics.RequestNetworkServerTimer(); 
            }
 
            if (Bid.AdvancedOn) { 
                // If we have tracePassword variables set, we are flushing TDSLogin and so we need to
                // blank out password in buffer.  Buffer has already been sent to netlib, so no danger 
                // of losing info.
                if (_tracePasswordOffset != 0) {
                    for (int i = _tracePasswordOffset; i < _tracePasswordOffset +
                        _tracePasswordLength; i++) { 
                        _outBuff[i] = 0;
                    } 
 
                    // Reset state.
                    _tracePasswordOffset = 0; 
                    _tracePasswordLength = 0;
                }
                if (_traceChangePasswordOffset != 0) {
                    for (int i = _traceChangePasswordOffset; i < _traceChangePasswordOffset + 
                        _traceChangePasswordLength; i++) {
                        _outBuff[i] = 0; 
                    } 

                    // Reset state. 
                    _traceChangePasswordOffset = 0;
                    _traceChangePasswordLength = 0;
                }
                Bid.TraceBin("  Packet sent", _outBuff, (UInt16)_outBytesUsed); 
            }
        } 
 
        [Conditional("DEBUG")]
        void AssertValidState() { 
            string assertMessage = null;

            if (_inBytesUsed < 0 || _inBytesRead < 0) {
                assertMessage = string.Format( 
                    CultureInfo.InvariantCulture,
                    "either _inBytesUsed or _inBytesRead is negative: {0}, {1}", 
                    _inBytesUsed, _inBytesRead); 
            }
            else if (_inBytesUsed > _inBytesRead) { 
                assertMessage = string.Format(
                    CultureInfo.InvariantCulture,
                    "_inBytesUsed > _inBytesRead: {0} > {1}",
                    _inBytesUsed, _inBytesRead); 
            }
 
            // 

            if (assertMessage != null) { 
                Debug.Assert(false, "Invalid TDS Parser State: " + assertMessage);
            }
        }
 
/*
 
// leave this in. comes handy if you have to do Console.WriteLine style debugging ;) 
        private void DumpBuffer() {
            Console.WriteLine("dumping buffer"); 
            Console.WriteLine("_inBytesRead = {0}", _inBytesRead);
            Console.WriteLine("_inBytesUsed = {0}", _inBytesUsed);
            int cc = 0; // character counter
            int i; 
            Console.WriteLine("used buffer:");
            for (i=0; i< _inBytesUsed; i++) { 
                if (cc==16) { 
                    Console.WriteLine();
                    cc = 0; 
                }
                Console.Write("{0,-2:X2} ", _inBuff[i]);
                cc++;
            } 
            if (cc>0) {
                Console.WriteLine(); 
            } 

            cc = 0; 
            Console.WriteLine("unused buffer:");
            for (i=_inBytesUsed; i<_inBytesRead; i++) {
                if (cc==16) {
                    Console.WriteLine(); 
                    cc = 0;
                } 
                Console.Write("{0,-2:X2} ", _inBuff[i]); 
                cc++;
            } 
            if (cc>0) {
                Console.WriteLine();
            }
        } 
*/
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK