_CommandStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Net / System / Net / _CommandStream.cs / 1 / _CommandStream.cs

                            // ------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ----------------------------------------------------------------------------- 
//
 
 
namespace System.Net {
 
    using System.Collections;
    using System.IO;
    using System.Security.Cryptography.X509Certificates ;
    using System.Net.Sockets; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading; 
    using System.Security.Authentication;
 

    /// 
    /// 
    ///     Impliments basic sending and receiving of network commands. 
    ///     Handles generic parsing of server responses and provides
    ///     a Pipeline sequencing mechnism for sending the commands to the 
    ///     server. 
    /// 
    ///  
    internal class CommandStream : PooledStream {

        private static readonly AsyncCallback m_WriteCallbackDelegate = new AsyncCallback(WriteCallback);
        private static readonly AsyncCallback m_ReadCallbackDelegate = new AsyncCallback(ReadCallback); 

        private bool m_RecoverableFailure; 
 
        //
        // Active variables used for the command state machine 
        //

        protected WebRequest        m_Request;
        protected bool              m_Async; 
        private   bool              m_Aborted;
 
        protected PipelineEntry []  m_Commands; 
        protected int               m_Index;
        private bool                m_DoRead; 
        private bool                m_DoSend;
        private ResponseDescription m_CurrentResponseDescription;
        protected string            m_AbortReason;
 
        const int _WaitingForPipeline = 1;
        const int _CompletedPipeline  = 2; 
 

        ///  
        ///    
        ///     Setups and Creates a NetworkStream connection to the server
        ///     perform any initalization if needed
        ///     
        /// 
        internal CommandStream( 
            ConnectionPool connectionPool, 
            TimeSpan lifetime,
            bool checkLifetime 
            ) : base(connectionPool, lifetime, checkLifetime) {
        }

 
        internal virtual void Abort(Exception e) {
            GlobalLog.Print("CommandStream"+ValidationHelper.HashString(this)+"::Abort() - closing control Stream"); 
 
            lock (this) {
                if (m_Aborted) 
                    return;
                m_Aborted = true;
                CanBePooled = false;
            } 

            try { 
                base.Close(0); 
            }
            finally { 
                if (e != null) {
                    InvokeRequestCallback(e);
                } else {
                    InvokeRequestCallback(null); 
                }
            } 
        } 

        ///  
        ///    Used to reset the connection
        /// 
        protected override void Dispose(bool disposing) {
            GlobalLog.Print("CommandStream"+ValidationHelper.HashString(this)+"::Close()"); 
            InvokeRequestCallback(null);
 
            // Do not call base.Dispose(bool), which would close the web request. 
            // This stream effectively should be a wrapper around a web
            // request that does not own the web request. 
        }

        /// 
        ///    A WebRequest can use a different Connection after an Exception is set, or a null is passed 
        ///         to mark completion.  We shouldn't continue calling the Request.RequestCallback after that point
        ///  
        protected void InvokeRequestCallback(object obj) { 
            WebRequest webRequest = m_Request;
            if (webRequest != null) { 
                webRequest.RequestCallback(obj);
            }
        }
 
        /// 
        ///    Indicates that we caught an error that should allow us to resubmit a request 
        ///  
        internal bool RecoverableFailure {
            get { 
                return m_RecoverableFailure;
            }
        }
 
        /// 
        ///    We only offer recovery, if we're at the start of the first command 
        ///  
        protected void MarkAsRecoverableFailure() {
            if (m_Index <= 1) { 
                m_RecoverableFailure = true;
            }
        }
 
        /// 
        ///     
        ///     Setups and Creates a NetworkStream connection to the server 
        ///     perform any initalization if needed
        ///     
        /// 

        internal Stream SubmitRequest(WebRequest request, bool async, bool readInitalResponseOnConnect) {
            ClearState(); 
            UpdateLifetime();
            PipelineEntry [] commands = BuildCommandsList(request); 
            InitCommandPipeline(request, commands, async); 
            if(readInitalResponseOnConnect && JustConnected){
                m_DoSend = false; 
                m_Index = -1;
            }
            return ContinueCommandPipeline();
        } 

        protected virtual void ClearState() { 
            InitCommandPipeline(null, null, false); 
        }
 
        protected virtual PipelineEntry [] BuildCommandsList(WebRequest request) {
            return null;
        }
 
        protected Exception GenerateException(WebExceptionStatus status, Exception innerException) {
            return new WebException( 
                            NetRes.GetWebStatusString("net_connclosed", status), 
                            innerException,
                            status, 
                            null /* no response */ );
        }

 
        protected Exception GenerateException(FtpStatusCode code, string statusDescription, Exception innerException) {
 
            return new WebException(SR.GetString(SR.net_servererror,NetRes.GetWebStatusCodeString(code, statusDescription)), 
                                    innerException,WebExceptionStatus.ProtocolError,null );
        } 


        protected void InitCommandPipeline(WebRequest request, PipelineEntry [] commands, bool async) {
            m_Commands = commands; 
            m_Index = 0;
            m_Request = request; 
            m_Aborted = false; 
            m_DoRead = true;
            m_DoSend = true; 
            m_CurrentResponseDescription = null;
            m_Async = async;
            m_RecoverableFailure = false;
            m_AbortReason = string.Empty; 
        }
 
        internal void CheckContinuePipeline() 
        {
            if (m_Async) 
                return;
            try {
                ContinueCommandPipeline();
            } catch (Exception e) { 
                Abort(e);
            } catch  { 
                Abort(new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
            }
        } 

        ///     Pipelined command resoluton, how this works:
        ///     a list of commands that need to be sent to the FTP server are spliced together into a array,
        ///     each command such STOR, PORT, etc, is sent to the server, then the response is parsed into a string, 
        ///     with the response, the delegate is called, which returns an instruction (either continue, stop, or read additional
        ///     responses from server). 
        /// 
        /// When done calling Close() to Notify ConnectionGroup that we are free
        protected Stream ContinueCommandPipeline() 
        {
            // In async case, The BeginWrite can actually result in a
            // series of synchronous completions that eventually close
            // the connection. So we need to save the members that 
            // we need to access, since they may not be valid after
            // BeginWrite returns 
            bool async = m_Async; 
            while (m_Index < m_Commands.Length)
            { 
                if (m_DoSend)
                {
                    if (m_Index < 0)
                        throw new InternalException(); 

                    byte[] sendBuffer = Encoding.GetBytes(m_Commands[m_Index].Command); 
                    if (Logging.On) 
                    {
                        string sendCommand = m_Commands[m_Index].Command.Substring(0, m_Commands[m_Index].Command.Length-2); 
                        if (m_Commands[m_Index].HasFlag(PipelineEntryFlags.DontLogParameter))
                        {
                            int index = sendCommand.IndexOf(' ');
                            if (index != -1) 
                            sendCommand = sendCommand.Substring(0, index) + " ********";
                        } 
                        Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_sending_command, sendCommand)); 
                    }
                    try { 
                        if (async) {
                            BeginWrite(sendBuffer, 0, sendBuffer.Length, m_WriteCallbackDelegate, this);
                        } else {
                            Write(sendBuffer, 0, sendBuffer.Length); 
                        }
                    } catch (IOException) { 
                        MarkAsRecoverableFailure(); 
                        throw;
                    } catch { 
                        throw;
                    }

                    if (async) { 
                        return null;
                    } 
                } 

                Stream stream = null; 
                bool isReturn = PostSendCommandProcessing(ref stream);
                if (isReturn)
                {
                    return stream; 
                }
            } 
 
            lock (this)
            { 
                Close();
            }

            return null; 
        }
        // 
        private bool PostSendCommandProcessing(ref Stream stream) 
        {
/* 
            ** I don;t see how this code can be still relevant, remove it of no problems observed **

            //
            // This is a general race condition in Sync mode, if the server returns an error 
            // after we open the data connection, we will be off reading the data connection,
            // and not the control connection. The best we can do is try to poll, and in the 
            // the worst case, we will timeout on establishing the data connection. 
            //
            if (!m_DoRead && !m_Async) { 
                m_DoRead = Poll(100 * 1000, SelectMode.SelectRead);   // Poll is in Microseconds.
            }
*/
            if (m_DoRead) 
            {
                // In async case, The next call can actually result in a 
                // series of synchronous completions that eventually close 
                // the connection. So we need to save the members that
                // we need to access, since they may not be valid after the 
                // next call returns
                bool async               = m_Async;
                int index                = m_Index;
                PipelineEntry[] commands = m_Commands; 

                try { 
                    ResponseDescription response = ReceiveCommandResponse(); 
                    if (async) {
                        return true; 
                    }
                    m_CurrentResponseDescription = response;
                } catch {
                    // If we get an exception on the QUIT command (which is 
                    // always the last command), ignore the final exception
                    // and continue with the pipeline regardlss of sync/async 
                    if (index < 0 || index >= commands.Length || 
                        commands[index].Command != "QUIT\r\n")
                        throw; 
                }
            }
            return PostReadCommandProcessing(ref stream);
        } 
        //
        private bool PostReadCommandProcessing(ref Stream stream) 
        { 
            if (m_Index >= m_Commands.Length)
                return false; 

            // Set up front to prevent a race condition on result == PipelineInstruction.Pause
            m_DoSend = false;
            m_DoRead = false; 

            PipelineInstruction result; 
            PipelineEntry entry; 
            if(m_Index == -1)
                entry = null; 
            else
                entry = m_Commands[m_Index];

            // Final QUIT command may get exceptions since the connectin 
            // may be already closed by the server. So there is no response
            // to process, just advance the pipeline to continue 
            if (m_CurrentResponseDescription == null && entry.Command == "QUIT\r\n") 
                result = PipelineInstruction.Advance;
            else 
                result = PipelineCallback(entry, m_CurrentResponseDescription, false, ref stream);

            if (result == PipelineInstruction.Abort)
            { 
                Exception exception;
                if (m_AbortReason != string.Empty) 
                    exception = new WebException(m_AbortReason); 
                else
                    exception = GenerateException(WebExceptionStatus.ServerProtocolViolation, null); 
                Abort(exception);
                throw exception;
            }
            else if (result == PipelineInstruction.Advance) 
            {
                m_CurrentResponseDescription = null; 
                m_DoSend = true; 
                m_DoRead = true;
                m_Index++; 

            }
            else if (result == PipelineInstruction.Pause)
            { 
                //
                // PipelineCallback did an async operation and will have to re-enter again 
                // Hold on for now 
                //
                return true; 
            }
            else if (result == PipelineInstruction.GiveStream)
            {
                // 
                // We will have another response coming, don't send
                // 
                m_CurrentResponseDescription = null; 
                m_DoRead = true;
                if (m_Async) 
                {
                    // If they block in the requestcallback we should still continue the pipeline
                    ContinueCommandPipeline();
                    InvokeRequestCallback(stream); 
                }
                return true; 
            } 
            else if (result == PipelineInstruction.Reread)
            { 
                // Another response is expected after this one
                m_CurrentResponseDescription = null;
                m_DoRead = true;
            } 
            return false;
        } 
 
        internal enum PipelineInstruction {
            Abort,          // aborts the pipeline 
            Advance,        // advances to the next pipelined command
            Pause,          // Let async callback to continue the pipeline
            Reread,         // rereads from the command socket
            GiveStream,     // returns with open data stream, let stream close to continue 
        }
 
        [Flags] 
        internal enum PipelineEntryFlags {
            UserCommand           = 0x1, 
            GiveDataStream        = 0x2,
            CreateDataConnection  = 0x4,
            DontLogParameter      = 0x8
        } 

        internal class PipelineEntry { 
            internal PipelineEntry(string command) { 
                Command = command;
            } 
            internal PipelineEntry(string command, PipelineEntryFlags flags) {
                Command = command;
                Flags = flags;
            } 
            internal bool HasFlag(PipelineEntryFlags flags) {
                return (Flags & flags) != 0; 
            } 
            internal string Command;
            internal PipelineEntryFlags Flags; 
        }

        protected virtual PipelineInstruction PipelineCallback(PipelineEntry entry, ResponseDescription response, bool timeout, ref Stream stream) {
            return PipelineInstruction.Abort; 
        }
 
        // 
        // I/O callback methods
        // 

        /// 
        ///    Provides a wrapper for the async operations, so that the code can be shared with sync
        ///  
        private static void ReadCallback(IAsyncResult asyncResult) {
            ReceiveState state = (ReceiveState)asyncResult.AsyncState; 
            try { 
                Stream stream = (Stream)state.Connection;
                int bytesRead = 0; 
                try {
                    bytesRead = stream.EndRead(asyncResult);
                    if (bytesRead == 0)
                        state.Connection.CloseSocket(); 
                }
                catch (IOException) { 
                    state.Connection.MarkAsRecoverableFailure(); 
                    throw;
                } 
                catch {
                    throw;
                }
 
                state.Connection.ReceiveCommandResponseCallback(state, bytesRead);
            } catch (Exception e) { 
                state.Connection.Abort(e); 
            }
        } 


        /// 
        ///    Provides a wrapper for the async write operations 
        /// 
        private static void WriteCallback(IAsyncResult asyncResult) { 
            CommandStream connection = (CommandStream)asyncResult.AsyncState; 
            try {
                try { 
                    connection.EndWrite(asyncResult);
                }
                catch (IOException) {
                    connection.MarkAsRecoverableFailure(); 
                    throw;
                } 
                catch { 
                    throw;
                } 
                Stream stream = null;
                if (connection.PostSendCommandProcessing(ref stream))
                    return;
                connection.ContinueCommandPipeline(); 
            } catch (Exception e) {
                connection.Abort(e); 
            } 
        }
 
        //
        // Read parsing methods and privates
        //
 
        private byte[]  m_Buffer = new byte[256];
        private int     m_BufferOffset; 
        private int     m_BufferCount; 
        private Encoding m_Encoding = Encoding.UTF8;
 

        protected Encoding Encoding {
            get {
                return m_Encoding; 
            }
            set { 
                m_Encoding = value; 
            }
        } 

        /// 
        ///  Sets Buffer = buffer, BufferOffset = offset, and BufferCount = count.
        ///  CAUTION!  The buffer is not copied.  The buffer reference is used. 
        /// 
        protected void SetBuffer(byte[] buffer, int offset, int count) 
        { 
            if(buffer == null) throw new ArgumentNullException("buffer");
            if(offset < 0) throw new ArgumentException(SR.GetString(SR.net_value_cannot_be_negative), "offset"); 
            if(count < 0) throw new ArgumentException(SR.GetString(SR.net_value_cannot_be_negative), "count");
            if(offset + count > buffer.Length) throw new ArgumentException(SR.GetString(SR.net_offset_plus_count));
            m_Buffer = buffer;
            m_BufferOffset = offset; 
            m_BufferCount = count;
        } 
 

        ///  
        /// This function is called a derived class to determine whether a response is valid, and when it is complete.
        /// 
        protected virtual bool CheckValid(ResponseDescription response, ref int validThrough, ref int completeLength) {
            return false; 
        }
 
        ///  
        /// Kicks off an asynchronous or sync request to receive a response from the server.
        /// Uses the Encoding encoding to transform the bytes received into a string to be 
        /// returned in the GeneralResponseDescription's StatusDescription field.
        /// 
        private ResponseDescription ReceiveCommandResponse()
        { 
            // These are the things that will be needed to maintain state
            ReceiveState state = new ReceiveState(this); 
 
            // If there are any bytes left over in the buffer, then attempt to form a string out of the bytes remaining, decoding it
            // into a string using the implementor's encoding. 
            if(m_BufferCount > 0) {
                state.StringFromBuffer = Encoding.GetString(m_Buffer, m_BufferOffset, m_BufferCount);
            }
            try 
            {
                // If a string of nonzero length was decoded from the buffered bytes, then we 
                // will use this string as our first string to append to the response StatusBuffer, and we will 
                // forego a Connection.Receive here.
 
                // Note that we get the number of bytes in the byte encoding of the decoded string, in order to determine
                // how many bytes were used in the string.  The number of bytes left in the buffer is decremented by this
                // amount (this will usually mean buffer count goes to zero) and increment the buffer offset to indicate
                // that there are a few buffer bytes left over. 
                if(state.StringFromBuffer.Length > 0)
                { 
                    int bytesUsed = Encoding.GetByteCount(state.StringFromBuffer); 
                    m_BufferCount -= bytesUsed;
                    m_BufferOffset += bytesUsed; 
                    ReceiveCommandResponseCallback(state, -1);
                }
                else
                { 
                    int bytesRead;
                    int readOffset = 0; 
                    int readLength = state.Buffer.Length; 

                    // we didn't get anything out of the buffer - 
                    // this means that either the only contents of the buffer were less than a complete character in the encoding,
                    // or that there was nothing in the buffer at all.
                    if(m_BufferCount > 0)
                    { 
                        // if there was anything in the buffer, then the buffer contents represent a partial character in the encoding used.
                        // This means that in order to get anything productive done, we need to perform a Receive on the connection in order 
                        // to finish at least one character to send to CheckValid. 
                        // So copy the remaining contents of the buffer into the beginning of the receive buffer (state.Buffer).
                        // Then try to fill the rest of the buffer with a receive. 

                        Buffer.BlockCopy(m_Buffer, m_BufferOffset, state.Buffer, 0, m_BufferCount);
                        state.BytesInBuffer = m_BufferCount;
 
                        readOffset = m_BufferCount;
                        readLength = state.Buffer.Length - readOffset; 
 
                        m_BufferCount = 0; // buffer is flushed.
 
                    }


                    try { 
                        if (m_Async) {
                            BeginRead(state.Buffer, readOffset, readLength, m_ReadCallbackDelegate, state); 
                            return null; 
                        } else {
                            bytesRead = Read(state.Buffer, readOffset, readLength); 
                            if (bytesRead == 0)
                                CloseSocket();
                            ReceiveCommandResponseCallback(state, bytesRead);
                        } 
                    }
                    catch (IOException) { 
                        MarkAsRecoverableFailure(); 
                        throw;
                    } 
                    catch {
                        throw;
                    }
                } 
            }
            catch(Exception e) { 
                if (e is WebException) 
                    throw;
                throw GenerateException(WebExceptionStatus.ReceiveFailure, e); 
            }
            return state.Resp;
        }
 

        ///  
        /// ReceiveCommandResponseCallback is the main "while loop" of the ReceiveCommandResponse function family. 
        /// In general, what is does is perform an EndReceive() to complete the previous retrieval of bytes from the
        /// server (unless it is using a buffered response)  It then processes what is received by using the 
        /// implementing class's CheckValid() function, as described above. If the response is complete, it returns the single complete
        /// response in the GeneralResponseDescription created in BeginReceiveComamndResponse, and buffers the rest as described above.
        ///
        /// If the resposne is not complete, it issues another Connection.BeginReceive, with callback ReceiveCommandResponse2, 
        /// so the action will continue at the next invocation of ReceiveCommandResponse2.
        ///  
        ///  
        ///
        private void ReceiveCommandResponseCallback(ReceiveState state, int bytesRead) 
        {
            // completeLength will be set to a nonnegative number by CheckValid if the response is complete:
            // it will set completeLength to the length of a complete response.
            int completeLength = -1; 

            while (true) 
            { 
                int validThrough = state.ValidThrough; // passed to checkvalid
 

                // If we got a string from decoding the contents of the Buffered response, then we didn't call BeginReceive, so don't
                // call end receive...
                if(state.StringFromBuffer.Length > 0) 
                {
                    // Append the string we got from the buffer, and flush it out. 
                    state.Resp.StatusBuffer.Append(state.StringFromBuffer); 
                    state.StringFromBuffer = "";
 
                    // invoke checkvalid.
                    if(!CheckValid(state.Resp, ref validThrough, ref completeLength)) {
                        throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null);
                    } 

                    // if the response is NOT complete, then we'll have to do a Receive.  However, there may be 
                    // bytes left over in the buffer that were not decoded into the string. 
                    // Copy these bytes into the receive buffer so that they will not be lost in the next Receive().
                    if(completeLength < 0) 
                    {
                        Buffer.BlockCopy(m_Buffer, m_BufferOffset, state.Buffer, 0, m_BufferCount);
                        state.BytesInBuffer = m_BufferCount;
                        m_BufferCount = 0; 
                    }
                    // else if the response is complete, then we can leave the buffer, possibly with leftover bytes, as is, and all is accurate. 
 
                    // Update the "last length of the statusBuffer" info.
                    state.LastResponseLength += state.StringFromBuffer.Length; 
                }
                else // we did a Connection.BeginReceive.  Note that in this case, all bytes received are in the receive buffer (because bytes from
                    // the buffer were transferred there if necessary
                { 
                    // this indicates the connection was closed.
                    if(bytesRead <= 0)  { 
                        throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); 
                    }
 
                    // There may have been bytes in the receive buffer before, so increase the count of bytes by the number read from (receive).
                    state.BytesInBuffer += bytesRead;

                    // decode the bytes in the receive buffer into a string, append it to the statusbuffer, and invoke checkvalid. 
                    string szResponse = Encoding.GetString(state.Buffer, 0, state.BytesInBuffer);
                    state.Resp.StatusBuffer.Append(szResponse); 
                    if(!CheckValid(state.Resp, ref validThrough, ref completeLength)) 
                    {
                        throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); 
                    }

                    // If the response is complete, then determine how many bytes are left over...these bytes need to be set into Buffer.
                    // To do this we see how many characters from the last appended string are used up in the complete response. 
                    // This number is completeLength - state.LastResponseLength.  Note at every execution of ReceiveCommandresponse2,
                    // the invariant is that the bytes in the receive buffer are exactly those bytes beyond the end of the last status buffer 
                    // string, so the encoding in bytes of the status buffer from (state.LastResponseLength) to (completeLength) are those 
                    // bytes used from the last string appended, and the rest are to be buffered.
                    if(completeLength >= 0) 
                    {
                        if(completeLength < state.LastResponseLength) {
                            throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); // CompleteLength Too Low
                        } 

                        int bytesFromThisReceive = Encoding.GetByteCount(szResponse.Substring(0, completeLength - state.LastResponseLength)); 
                        // bytes to buffer 
                        if(state.BytesInBuffer > bytesFromThisReceive) {
                            SetBuffer(state.Buffer, bytesFromThisReceive, state.BytesInBuffer - bytesFromThisReceive); 
                        }
                    }
                    else // not complete.  Any bytes that were not in the string that was appended (szResponse)
                        //  are moved to the beginning of the receive buffer so they can be considered in the next Receive(). 
                        // this prevents loss of any bytes.
                    { 
                        state.LastResponseLength = state.Resp.StatusBuffer.Length;  // update the last length of the statusbuffer. 
                        int bytesUsed = Encoding.GetByteCount(szResponse);
                        state.BytesInBuffer -= bytesUsed; 

                        Buffer.BlockCopy(state.Buffer, bytesUsed, state.Buffer, 0, state.BytesInBuffer);
                    }
                } 

                // Now, in general, if the response is not complete, update the "valid through" length for the efficiency of checkValid. 
                // and perform the next receive. 
                // Note that there may be bytes in the beginning of the receive buffer (if there were partial characters left over after the
                // last encoding), so start the receive at state.BytesInBuffer. 
                if(completeLength < 0)
                {
                    state.ValidThrough = validThrough;
                    try { 
                        if (m_Async) {
                            BeginRead(state.Buffer, state.BytesInBuffer, state.Buffer.Length - state.BytesInBuffer, m_ReadCallbackDelegate, state); 
                            return; 
                        } else {
                            bytesRead = Read(state.Buffer, state.BytesInBuffer, state.Buffer.Length - state.BytesInBuffer); 
                            if (bytesRead == 0)
                                CloseSocket();
                            continue;
                        } 
                    }
                    catch (IOException) { 
                        MarkAsRecoverableFailure(); 
                        throw;
                    } 
                    catch {
                        throw;
                    }
                } 
                // the response is completed
                break; 
            } 

 
            // Otherwise, we have a complete response.
            string responseString = state.Resp.StatusBuffer.ToString();
            state.Resp.StatusDescription = responseString.Substring(0, completeLength);
            // set the StatusDescription to the complete part of the response.  Note that the Buffer has already been taken care of above. 

            if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_received_response, responseString.Substring(0, completeLength-2))); 
 
            if (m_Async) {
                // Tell who is listening what was received. 
                if (state.Resp != null) {
                    m_CurrentResponseDescription = state.Resp;
                }
                Stream stream = null; 
                if (PostReadCommandProcessing(ref stream))
                    return; 
                ContinueCommandPipeline(); 
            }
        } 

    } // class CommandStream

 
    /// 
    /// Contains the parsed status line from the server 
    ///  
    internal class ResponseDescription {
        internal const int NoStatus = -1; 
        internal bool Multiline = false;

        internal int           Status = NoStatus;
        internal string        StatusDescription; 
        internal StringBuilder StatusBuffer = new StringBuilder();
 
        internal string        StatusCodeString; 

        internal bool PositiveIntermediate   { get { return (Status >= 100 && Status <= 199); } } 
        internal bool PositiveCompletion     { get { return (Status >= 200 && Status <= 299); } }
        //internal bool PositiveAuthRelated { get { return (Status >= 300 && Status <= 399); } }
        internal bool TransientFailure { get { return (Status >= 400 && Status <= 499); }     }
        internal bool PermanentFailure { get { return (Status >= 500 && Status <= 599); }    } 
        internal bool InvalidStatusCode { get { return (Status < 100 || Status > 599); }    }
    } 
 

    ///  
    /// State information that is used during ReceiveCommandResponse()'s async operations
    /// 
    internal class ReceiveState
    { 
        private const int bufferSize = 1024;
 
        internal Decoder Decoder; 
        internal ResponseDescription Resp;
        internal int ValidThrough; 
        internal byte[] Buffer;
        internal int BytesInBuffer;
        internal string StringFromBuffer;
        internal CommandStream Connection; 

        internal int LastResponseLength; 
 
        internal ReceiveState(CommandStream connection)
        { 
            Connection = connection;
            Resp = new ResponseDescription();
            Buffer = new byte[bufferSize];  //1024
            LastResponseLength = 0; 
            StringFromBuffer = String.Empty;
            ValidThrough = 0; 
        } 
    }
 


} // namespace System.Net
                        

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