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

InternalWrite() private method

private InternalWrite ( bool async, byte buffer, int offset, int size, AsyncCallback callback, object state ) : IAsyncResult
async bool
buffer byte
offset int
size int
callback AsyncCallback
state object
return IAsyncResult
        private IAsyncResult InternalWrite(bool async, byte[] buffer, int offset, int size, AsyncCallback callback, object state ) {
            //
            // if we have a stream error, or we've already shut down this socket
            //  then we must prevent new BeginRead/BeginWrite's from getting
            //  submited to the socket, since we've already closed the stream.
            //
            if (ErrorInStream) {
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing:" + m_ErrorException.ToString());
                throw m_ErrorException;
            }

            if (IsClosed && !IgnoreSocketErrors) {
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing");
                throw new WebException(
                            NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.ConnectionClosed),
                            WebExceptionStatus.ConnectionClosed);
            }
            
            if (m_Request.Aborted && !IgnoreSocketErrors) {
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing");
                throw new WebException(
                    NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                    WebExceptionStatus.RequestCanceled);
            }             

            int nesting = Interlocked.CompareExchange(ref m_CallNesting, Nesting.IoInProgress, Nesting.Idle);
            GlobalLog.Print((async?"Async ":"") + "InternalWrite() In: callNesting : " + nesting.ToString());
            if (nesting != Nesting.Idle && nesting != Nesting.Closed)
            {
                throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed));
            }

            //
            // buffer data to the ScatterGatherBuffers
            // regardles of chunking, we buffer the data as if we were not chunking
            // and on resubmit, we don't bother chunking.
            //
            if (BufferedData!=null && size != 0 && (m_Request.ContentLength != 0 || !IsPostStream || !m_Request.NtlmKeepAlive)) {
                //
                // if we don't need to, we shouldn't send data on the wire as well
                // but in this case we gave a stream to the user so we have transport
                //
                BufferedData.Write(buffer, offset, size);
            }

            LazyAsyncResult asyncResult = null;
            bool completeSync = false;
            try
            {
                if (size == 0 || BufferOnly || m_SuppressWrite || IgnoreSocketErrors)
                {
                    //
                    // We're not putting this data on the wire, then we're done
                    //
                    if(m_SuppressWrite && m_BytesLeftToWrite > 0 && size > 0)
                    {
                        m_BytesLeftToWrite -= size;
                    }

                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() swallowing: size==0 || BufferOnly || IgnoreSocketErrors= " + (size==0) + BufferOnly + IgnoreSocketErrors);
                    if (async) {
                        asyncResult = new LazyAsyncResult(this, state, callback);
                        completeSync = true;
                    }
                    return asyncResult;
                }
                else if (WriteChunked) {
                    //
                    // We're chunking. Write the chunk header out first,
                    // then the data, then a CRLF.
                    // for this we'll use BeginMultipleSend();
                    //
                    int chunkHeaderOffset = 0;
                    byte[] chunkHeaderBuffer = GetChunkHeader(size, out chunkHeaderOffset);

                    BufferOffsetSize[] buffers;
                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() m_ErrorResponseStatus:" + m_ErrorResponseStatus);

                    if (m_ErrorResponseStatus) {
                        //if we already got a (>200) response, then just terminate chunking and
                        //switch to simple buffering (if any)
                        GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() setting m_IgnoreSocketErrors to True (was:" + m_IgnoreSocketErrors + ") sending chunk terminator");
                        m_IgnoreSocketErrors = true;
                        buffers = new BufferOffsetSize[1];
                        buffers[0] = new BufferOffsetSize(NclConstants.ChunkTerminator, 0, NclConstants.ChunkTerminator.Length, false);
                    }
                    else {
                        buffers = new BufferOffsetSize[3];
                        buffers[0] = new BufferOffsetSize(chunkHeaderBuffer, chunkHeaderOffset, chunkHeaderBuffer.Length - chunkHeaderOffset, false);
                        buffers[1] = new BufferOffsetSize(buffer, offset, size, false);
                        buffers[2] = new BufferOffsetSize(NclConstants.CRLF, 0, NclConstants.CRLF.Length, false);
                    }

                    asyncResult = (async) ? new NestedMultipleAsyncResult(this, state, callback, buffers) : null;

                    //
                    // after setting up the buffers and error checking do the async Write Call
                    //

                    try {
                        if (async) {
                            m_Connection.BeginMultipleWrite(buffers, m_WriteCallbackDelegate, asyncResult);
                        }
                        else {
                            SafeSetSocketTimeout(SocketShutdown.Send);
                            m_Connection.MultipleWrite(buffers);
                        }
                    }

                    catch (Exception exception) {
                        // IgnoreSocketErrors can be set at any time - need to check it again.
                        if (IgnoreSocketErrors && !NclUtilities.IsFatal(exception))
                        {
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() swallowing: IgnoreSocketErrors set after throw.");
                            if (async)
                            {
                                completeSync = true;
                            }
                            return asyncResult;
                        }

                        if (m_Request.Aborted && (exception is IOException || exception is ObjectDisposedException)) {
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing");
                            throw new WebException(
                                NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                                WebExceptionStatus.RequestCanceled);
                        }

                        nesting = Nesting.InError;

                        if (NclUtilities.IsFatal(exception))
                        {
                            m_ErrorResponseStatus = false;
                            IOError(exception);
                            throw;
                        }

                        if (m_ErrorResponseStatus) {
                            // We already got a error response, hence server could drop the connection,
                            // Here we are recovering for future (optional) resubmit ...
                            m_IgnoreSocketErrors = true;
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() IGNORE write fault");
                            if (async)
                            {
                                completeSync = true;
                            }
                        }
                        else {
                            // Note we could swallow this since receive callback is already posted and
                            // should give us similar failure
                            IOError(exception);
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing:" + exception.ToString());
                            throw;
                        }
                    }
                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite chunked");
                    return asyncResult;
                }
                else {
                    //
                    // We're not chunking. See if we're sending too much; if not,
                    // go ahead and write it.
                    //
                    asyncResult = (async) ? new NestedSingleAsyncResult(this, state, callback, buffer, offset, size) : null;

                    if (BytesLeftToWrite != -1) {
                        //
                        // but only check if we aren't writing to an unknown content-length size,
                        // as we can be buffering.
                        //
                        if (BytesLeftToWrite < (long)size) {
                            //
                            // writing too much data.
                            //
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite()");
                            throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig));
                        }

                        if (!async) {
                            //
                            // Otherwise update our bytes left to send and send it.
                            //
                            m_BytesLeftToWrite -= (long)size;
                        }
                    }

                    //
                    // After doing, the m_WriteByte size calculations, and error checking
                    //  here doing the async Write Call
                    //

                    try {
                        if (async) {
                            if(m_Request.ContentLength == 0 && IsPostStream) {
                                m_BytesLeftToWrite -=size;
                                completeSync = true;
                            }
                           else{
                                m_BytesAlreadyTransferred = size;
                                m_Connection.BeginWrite(buffer, offset, size, m_WriteCallbackDelegate, asyncResult);
                           }
                        }
                        else {
                            SafeSetSocketTimeout(SocketShutdown.Send);
                            //If we are doing the ntlm handshake,  contentlength
                            //could be 0 for the first part, even if there is data
                            //to write.
                            if (m_Request.ContentLength != 0 || !IsPostStream || !m_Request.NtlmKeepAlive) {
                                m_Connection.Write(buffer, offset, size);
                            }
                        }
                    }
                    catch (Exception exception) {
                        // IgnoreSocketErrors can be set at any time - need to check it again.
                        if (IgnoreSocketErrors && !NclUtilities.IsFatal(exception))
                        {
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() swallowing: IgnoreSocketErrors set after throw.");
                            if (async)
                            {
                                completeSync = true;
                            }
                            return asyncResult;
                        }

                        if (m_Request.Aborted && (exception is IOException || exception is ObjectDisposedException)) {
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing");
                            throw new WebException(
                                NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                                WebExceptionStatus.RequestCanceled);
                        }

                        nesting = Nesting.InError;

                        if (NclUtilities.IsFatal(exception))
                        {
                            m_ErrorResponseStatus = false;
                            IOError(exception);
                            throw;
                        }

                        if (m_ErrorResponseStatus) {
                            // We already got a error response, hence server could drop the connection,
                            // Here we are recovering for future (optional) resubmit ...
                            m_IgnoreSocketErrors = true;
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternWrite() IGNORE write fault");
                            if (async)
                            {
                                completeSync = true;
                            }
                        }
                        else {
                            // Note we could swallow this since receive callback is already posted and
                            // should give us similar failure
                            IOError(exception);
                            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite() throwing:" + exception.ToString());
                            throw;
                        }
                    }
                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::InternalWrite");
                    return asyncResult;
                }
            }
            finally {
                if (!async || nesting == Nesting.InError || completeSync)
                {
                    nesting = Interlocked.CompareExchange(ref m_CallNesting, (nesting == Nesting.InError? Nesting.InError: Nesting.Idle), Nesting.IoInProgress);
                    GlobalLog.Print("InternalWrite() Out callNesting: " + nesting.ToString());
                    if (nesting == Nesting.Closed)
                    {
                        //send closing bytes
                        ResumeInternalClose(asyncResult);
                    }
                    else if (completeSync && asyncResult != null)
                    {
                        asyncResult.InvokeCallback();
                    }
                }
            }
        }