System.Net.ConnectStream.CloseInternal C# (CSharp) Method

CloseInternal() private method

private CloseInternal ( bool internalCall, bool aborting ) : void
internalCall bool
aborting bool
return void
        private void CloseInternal(bool internalCall, bool aborting) {
            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal", internalCall.ToString());
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "ConnectStream#" + ValidationHelper.HashString(this) + "::Abort");

            bool normalShutDown = !aborting;
            Exception exceptionOnWrite = null;

            //
            // We have to prevent recursion, because we'll call our parents, close,
            // which might try to flush data. If we're in an error situation, that
            // will cause an error on the write, which will cause Close to be called
            // again, etc.
            //
            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() m_ShutDown:" + m_ShutDown.ToString() + " m_CallNesting:" + m_CallNesting.ToString() + " m_DoneCalled:" + m_DoneCalled.ToString());

            //If this is an abort (aborting == true) of a write stream then we will call request.Abort()
            //that will call us again. To prevent a recursion here, only one abort is allowed.
            //However, Abort must still override previous normal close if any.
            if (aborting) {
                if (Interlocked.Exchange(ref m_ShutDown, AlreadyAborted) >= AlreadyAborted) {
                    GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal", "already has been Aborted");
                    return;
                }
            }
            else {
                //If m_ShutDown != 0, then this method has been already called before,
                //Hence disregard this (presumably normal) extra close
                if (Interlocked.Increment(ref m_ShutDown) > 1) {
                    GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal", "already has been closed");
                    return;
                }
            }

            //
            // Since this should be the last call made, we should be at 0
            //  If not on the read side then it's an error so we should close the socket
            //  If not on the write side then MAY BE we want this write stream to ignore all
            //  further writes and optionally send chunk terminator.
            //
            int nesting = (IsPostStream  && internalCall && !IgnoreSocketErrors && !BufferOnly && normalShutDown && !NclUtilities.HasShutdownStarted)? Nesting.Closed: Nesting.InError;
            if (Interlocked.Exchange(ref m_CallNesting, nesting) == Nesting.IoInProgress)
            {
                if (nesting == Nesting.Closed)
                {
                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() PostStream, Internal call and m_CallNesting==1, defer closing until user write completes");
                    return;
                }
                normalShutDown &= !NclUtilities.HasShutdownStarted;
            }
            GlobalLog.Print("Close m_CallNesting: " + m_CallNesting.ToString());

            // Questionable: Thsi is to avoid throwing on public Close() when IgnoreSocketErrors==true
            if (IgnoreSocketErrors && IsPostStream && !internalCall)
            {
                m_BytesLeftToWrite = 0;
            }

            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() normalShutDown:" + normalShutDown.ToString() + " m_CallNesting:" + m_CallNesting.ToString() + " m_DoneCalled:" + m_DoneCalled.ToString());


            if (IgnoreSocketErrors || !normalShutDown) {
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() don't read/write on this, dead connection stream.");
            }
            else if (!WriteStream) {
                //
                // read stream
                //
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() callNesting: " + m_CallNesting.ToString());
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() read stream, calling DrainSocket()");
#if DEBUG
            using (GlobalLog.SetThreadKind(ThreadKinds.Sync)) {
#endif
                normalShutDown = DrainSocket();
#if DEBUG
            }
#endif
            }
            else {
                //
                // write stream. terminate our chunking if needed.
                //
                try {
                    if (!ErrorInStream) {
                        //
                        // if not error already, then...
                        // first handle chunking case
                        //
                        if (WriteChunked) {
                            //
                            // no need to buffer here:
                            // on resubmit, we won't be chunking anyway this will send 5 bytes on the wire
                            //
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() Chunked, writing ChunkTerminator");
                            try {
                                // The idea behind is that closed stream must not write anything to the wire
                                // Still if we are chunking, the now buffering and future resubmit is possible
                                if (!m_IgnoreSocketErrors) {
                                    m_IgnoreSocketErrors = true;
                                    SafeSetSocketTimeout(SocketShutdown.Send);

#if DEBUG
                                    // Until there is an async version of this, we have to assert Sync privileges here.
                                    using (GlobalLog.SetThreadKind(ThreadKinds.Sync)) {
#endif
                                    m_Connection.Write(NclConstants.ChunkTerminator, 0, NclConstants.ChunkTerminator.Length);
#if DEBUG
                                    }
#endif
                                }
                            }
                            catch {
                                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() IGNORE chunk write fault");
                            }
                            m_BytesLeftToWrite = 0;
                        }
                        else if (BytesLeftToWrite>0) {
                            //
                            // not enough bytes written to client
                            //
                            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() BytesLeftToWrite:" + BytesLeftToWrite.ToString() + " throwing not enough bytes written");
                            throw new IOException(SR.GetString(SR.net_io_notenoughbyteswritten));
                        }
                        else if (BufferOnly) {
                            //
                            // now we need to use the saved reference to the request the client
                            // closed the write stream. we need to wake up the request, so that it
                            // sends the headers and kick off resubmitting of buffered entity body
                            //
                            GlobalLog.Assert(m_Request != null, "ConnectStream#{0}::CloseInternal|m_Request == null", ValidationHelper.HashString(this));
                            m_BytesLeftToWrite = BufferedData.Length;
                            m_Request.SwitchToContentLength();
                            //
                            // writing the headers will kick off the whole request submission process
                            // (including waiting for the 100 Continue and writing the whole entity body)
                            //
                            SafeSetSocketTimeout(SocketShutdown.Send);
                            m_Request.NeedEndSubmitRequest();
                            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal", "Done");
                            return;
                        }
                    }
                    else {
                        normalShutDown = false;
                    }
                }
                catch (Exception exception) {
                    normalShutDown = false;

                    if (NclUtilities.IsFatal(exception))
                    {
                        m_ErrorException = exception;
                        throw;
                    }

                    exceptionOnWrite = new WebException(
                        NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                        exception,
                        WebExceptionStatus.RequestCanceled,
                        null);

                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() exceptionOnWrite:" + exceptionOnWrite.Message);
                }
            }

            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() normalShutDown:" + normalShutDown.ToString() + " m_CallNesting:" + m_CallNesting.ToString() + " m_DoneCalled:" + m_DoneCalled.ToString());

            if (!normalShutDown && m_DoneCalled==0) {
                // If a normal Close (aborting == false) has turned into Abort _inside_ this method,
                // then check if another abort has been charged from other thread
                if (!aborting && Interlocked.Exchange(ref m_ShutDown, AlreadyAborted) >= AlreadyAborted){
                    GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal", "other thread has charged Abort(), canceling that one");
                    return;
                }
                //
                // then abort the connection if we finished in error
                //   note: if m_DoneCalled != 0, then we no longer have
                //   control of the socket, so closing would cause us
                //   to close someone else's socket/connection.
                //
                m_ErrorException =
                    new WebException(
                        NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                        WebExceptionStatus.RequestCanceled);

                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() Aborting the connection");

                m_Connection.AbortSocket(true);
                // For write stream Abort() we depend on either of two, i.e:
                // 1. The connection BeginRead is curently posted (means there are no response headers received yet)
                // 2. The response (read) stream must be closed as well if aborted this (write) stream.
                // Next block takes care of (2) since otherwise, (1) is true.
                if (WriteStream) {
                    HttpWebRequest req = m_Request;
                    if (req != null) {
                        req.Abort();
                    }
                }

                if (exceptionOnWrite != null) {
                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() calling CallDone() on exceptionOnWrite:" + exceptionOnWrite.Message);

                    CallDone();

                    if (!internalCall) {
                        GlobalLog.LeaveException("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() throwing:", exceptionOnWrite);
                        throw exceptionOnWrite;
                    }
                }
            }
            //
            // Let the connection know we're done writing or reading.
            //
            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal() calling CallDone()");

            CallDone();

            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CloseInternal", "Done");
        }

Same methods

ConnectStream::CloseInternal ( bool internalCall ) : void

Usage Example

Beispiel #1
0
        /*
            RequestSubmitDone - Handle submit done callback.

            This is our submit done handler, called by the underlying connection
            code when a stream is available for our use. We save the stream for
            later use and signal the wait event.

            We also handle the continuation/termination of a BeginGetRequestStream,
            by saving out the result and calling its callback if needed.

            Input:  SubmitStream        - The stream we may write on.
                    Status              - The status of the submission.

            Returns: Nothing.

        */
        internal void SetRequestSubmitDone(ConnectStream submitStream) {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone", ValidationHelper.HashString(submitStream));

            if (_Abort) {
                try {
                    submitStream.SetAbortState();
                    submitStream.CloseInternal(true);
                }
                catch {
                }

                GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone", "ABORT");
                return;
            }

             //This state should be set before invoking the callback
             //otherwise extra request will be issued without any
             //particular reason.

            _RequestSubmitted = true;
            _SubmitWriteStream = submitStream;

            // Finish the submission of the request. If the asyncResult now
            // isn't null, mark it as completed.

            WebExceptionStatus Error = EndSubmitRequest();

            if (Error != WebExceptionStatus.Pending) {

                // check for failure
                if (Error != WebExceptionStatus.Success) {
                    // OK, something happened on the request, close down stream
                    submitStream.SetAbortState();
                    submitStream.CloseInternal(true);
                }

                // wake up any pending waits to write, since this is an error
                if ( _WriteEvent != null ) {
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone() calling _WriteEvent.Set()");
                    _WriteEvent.Set();
                }
            } // != Pending

            if (_Abort) {
                try {
                    submitStream.SetAbortState();
                    submitStream.CloseInternal(true);
                }
                catch {
                }
            }

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone");
        }