internal SplitWritesState(BufferOffsetSize[] buffers) { this._UserBuffers = buffers; this._LastBufferConsumed = 0; this._Index = 0; this._RealBuffers = null; }
internal IAsyncResult BeginWrite(BufferOffsetSize[] buffers, AsyncCallback asyncCallback, object asyncState) { LazyAsyncResult userAsyncResult = new LazyAsyncResult(this, asyncState, asyncCallback); SplitWriteAsyncProtocolRequest asyncRequest = new SplitWriteAsyncProtocolRequest(userAsyncResult); this.ProcessWrite(buffers, asyncRequest); return userAsyncResult; }
internal override IAsyncResult BeginMultipleWrite(BufferOffsetSize[] buffers, AsyncCallback callback, object state) { IAsyncResult result2; if (!this.m_Worker.IsAuthenticated) { BufferAsyncResult result = new BufferAsyncResult(this, buffers, state, callback); if (this.ProcessAuthentication(result)) { return result; } } try { result2 = this.m_Worker.SecureStream.BeginWrite(buffers, callback, state); } catch { if (this.m_Worker.IsCertValidationFailed) { this.m_ExceptionStatus = WebExceptionStatus.TrustFailure; } else if (this.m_Worker.LastSecurityStatus != SecurityStatus.OK) { this.m_ExceptionStatus = WebExceptionStatus.SecureChannelFailure; } else { this.m_ExceptionStatus = WebExceptionStatus.SendFailure; } throw; } return result2; }
// // // // public void WriteMessage(byte[] message) { if (message == null) { throw new ArgumentNullException("message"); } m_WriteHeader.PayloadSize = message.Length; m_WriteHeader.CopyTo(m_WriteHeaderBuffer, 0); if (m_NetworkStream != null && message.Length != 0) { BufferOffsetSize[] buffers = new BufferOffsetSize[2]; buffers[0] = new BufferOffsetSize(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, false); buffers[1] = new BufferOffsetSize(message, 0, message.Length, false); m_NetworkStream.MultipleWrite(buffers); } else { Transport.Write(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length); if (message.Length == 0) { return; } Transport.Write(message, 0, message.Length); } }
public IAsyncResult BeginWriteMessage(byte[] message, AsyncCallback asyncCallback, object stateObject) { if (message == null) { throw new ArgumentNullException("message"); } this.m_WriteHeader.PayloadSize = message.Length; this.m_WriteHeader.CopyTo(this.m_WriteHeaderBuffer, 0); if ((this.m_NetworkStream != null) && (message.Length != 0)) { BufferOffsetSize[] buffers = new BufferOffsetSize[] { new BufferOffsetSize(this.m_WriteHeaderBuffer, 0, this.m_WriteHeaderBuffer.Length, false), new BufferOffsetSize(message, 0, message.Length, false) }; return(this.m_NetworkStream.BeginMultipleWrite(buffers, asyncCallback, stateObject)); } if (message.Length == 0) { return(this.Transport.BeginWrite(this.m_WriteHeaderBuffer, 0, this.m_WriteHeaderBuffer.Length, asyncCallback, stateObject)); } WorkerAsyncResult state = new WorkerAsyncResult(this, stateObject, asyncCallback, message, 0, message.Length); IAsyncResult transportResult = this.Transport.BeginWrite(this.m_WriteHeaderBuffer, 0, this.m_WriteHeaderBuffer.Length, this.m_BeginWriteCallback, state); if (transportResult.CompletedSynchronously) { this.BeginWriteComplete(transportResult); } return(state); }
Stream CreateStreamWrapper(BufferOffsetSize buffer) { if (buffer == null || buffer.Size == 0) { return(InnerStream); } return(new BufferedReadStream(Operation, InnerStream, buffer)); }
internal NestedMultipleAsyncResult(object asyncObject, object asyncState, AsyncCallback asyncCallback, BufferOffsetSize[] buffers) : base(asyncObject, asyncState, asyncCallback) { this.Buffers = buffers; this.Size = 0; for (int i = 0; i < this.Buffers.Length; i++) { this.Size += this.Buffers[i].Size; } }
public WebOperation(HttpWebRequest request, BufferOffsetSize writeBuffer, bool isNtlmChallenge, CancellationToken cancellationToken) { Request = request; WriteBuffer = writeBuffer; IsNtlmChallenge = isNtlmChallenge; cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); requestTask = new WebCompletionSource <WebRequestStream> (); requestWrittenTask = new WebCompletionSource <WebRequestStream> (); responseTask = new WebCompletionSource <WebResponseStream> (); finishedTask = new WebCompletionSource <(bool, WebOperation)> (); }
internal BufferOffsetSize[] GetBuffers() { if (this.Empty) { return null; } BufferOffsetSize[] sizeArray = new BufferOffsetSize[this.chunkCount]; int index = 0; for (MemoryChunk chunk = this.headChunk; chunk != null; chunk = chunk.Next) { sizeArray[index] = new BufferOffsetSize(chunk.Buffer, 0, chunk.FreeOffset, false); index++; } return sizeArray; }
internal void SetUnmanagedStructures(BufferOffsetSize[] buffers) { this.m_WSABuffers = new WSABuffer[buffers.Length]; object[] objectsToPin = new object[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { objectsToPin[i] = buffers[i].Buffer; } base.SetUnmanagedStructures(objectsToPin); for (int j = 0; j < buffers.Length; j++) { this.m_WSABuffers[j].Length = buffers[j].Size; this.m_WSABuffers[j].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[j].Buffer, buffers[j].Offset); } }
internal BufferOffsetSize[] GetBuffers() { if (this.Empty) { return(null); } BufferOffsetSize[] sizeArray = new BufferOffsetSize[this.chunkCount]; int index = 0; for (MemoryChunk chunk = this.headChunk; chunk != null; chunk = chunk.Next) { sizeArray[index] = new BufferOffsetSize(chunk.Buffer, 0, chunk.FreeOffset, false); index++; } return(sizeArray); }
public BufferOffsetSize[] GetBuffers() { if (Empty) { return null; } GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::ToArray() chunkCount:" + chunkCount.ToString()); BufferOffsetSize[] array = new BufferOffsetSize[chunkCount]; int index = 0; MemoryChunk thisMemoryChunk = headChunk; while (thisMemoryChunk!=null) { GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::ToArray() index:" + index.ToString() + " size:" + thisMemoryChunk.FreeOffset); // // buffer itself is referenced by the BufferOffsetSize struct, data is not copied // array[index] = new BufferOffsetSize(thisMemoryChunk.Buffer, 0, thisMemoryChunk.FreeOffset, false); index++; thisMemoryChunk = thisMemoryChunk.Next; } return array; }
internal void SetUnmanagedStructures(BufferOffsetSize[] buffers) { // Fill in Buffer Array structure that will be used for our send/recv Buffer _wsaBuffers = new WSABuffer[buffers.Length]; object[] objectsToPin = new object[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { objectsToPin[i] = buffers[i].Buffer; } // has to be called now to pin memory base.SetUnmanagedStructures(objectsToPin); for (int i = 0; i < buffers.Length; i++) { _wsaBuffers[i].Length = buffers[i].Size; _wsaBuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[i].Buffer, buffers[i].Offset); } }
internal async Task WriteRequestAsync(CancellationToken cancellationToken) { Operation.ThrowIfClosedOrDisposed(cancellationToken); WebConnection.Debug($"{ME} WRITE REQUEST: {requestWritten} {sendChunked} {allowBuffering} {HasWriteBuffer}"); if (requestWritten) { return; } requestWritten = true; if (sendChunked || !HasWriteBuffer) { return; } BufferOffsetSize buffer = GetWriteBuffer(); if (buffer != null && !Operation.IsNtlmChallenge && Request.ContentLength != -1 && Request.ContentLength < buffer.Size) { closed = true; var throwMe = new WebException("Specified Content-Length is less than the number of bytes to write", null, WebExceptionStatus.ServerProtocolViolation, null); Operation.CompleteRequestWritten(this, throwMe); throw throwMe; } await SetHeadersAsync(true, cancellationToken).ConfigureAwait(false); WebConnection.Debug($"{ME} WRITE REQUEST #1: {buffer != null}"); Operation.ThrowIfClosedOrDisposed(cancellationToken); if (buffer != null && buffer.Size > 0) { await InnerStream.WriteAsync(buffer.Buffer, 0, buffer.Size, cancellationToken); } await FinishWriting(cancellationToken); }
public void WriteMessage(byte[] message) { if (message == null) { throw new ArgumentNullException("message"); } this.m_WriteHeader.PayloadSize = message.Length; this.m_WriteHeader.CopyTo(this.m_WriteHeaderBuffer, 0); if ((this.m_NetworkStream != null) && (message.Length != 0)) { BufferOffsetSize[] buffers = new BufferOffsetSize[] { new BufferOffsetSize(this.m_WriteHeaderBuffer, 0, this.m_WriteHeaderBuffer.Length, false), new BufferOffsetSize(message, 0, message.Length, false) }; this.m_NetworkStream.MultipleWrite(buffers); } else { this.Transport.Write(this.m_WriteHeaderBuffer, 0, this.m_WriteHeaderBuffer.Length); if (message.Length != 0) { this.Transport.Write(message, 0, message.Length); } } }
// // // // public IAsyncResult BeginWriteMessage(byte[] message, AsyncCallback asyncCallback, object stateObject) { if (message == null) { throw new ArgumentNullException("message"); } m_WriteHeader.PayloadSize = message.Length; m_WriteHeader.CopyTo(m_WriteHeaderBuffer, 0); if (m_NetworkStream != null && message.Length != 0) { BufferOffsetSize[] buffers = new BufferOffsetSize[2]; buffers[0] = new BufferOffsetSize(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, false); buffers[1] = new BufferOffsetSize(message, 0, message.Length, false); return(m_NetworkStream.BeginMultipleWrite(buffers, asyncCallback, stateObject)); } if (message.Length == 0) { return(Transport.BeginWrite(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, asyncCallback, stateObject)); } //Will need two async writes // Prepare the second WorkerAsyncResult workerResult = new WorkerAsyncResult(this, stateObject, asyncCallback, message, 0, message.Length); // Charge the first IAsyncResult result = Transport.BeginWrite(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, m_BeginWriteCallback, workerResult); if (result.CompletedSynchronously) { BeginWriteComplete(result); } return(workerResult); }
internal BufferOffsetSize[] GetBuffers() { if (Empty) { return(null); } GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::ToArray() chunkCount:" + chunkCount.ToString()); BufferOffsetSize[] array = new BufferOffsetSize[chunkCount]; int index = 0; MemoryChunk thisMemoryChunk = headChunk; while (thisMemoryChunk != null) { GlobalLog.Print("ScatterGatherBuffers#" + ValidationHelper.HashString(this) + "::ToArray() index:" + index.ToString() + " size:" + thisMemoryChunk.FreeOffset); // // buffer itself is referenced by the BufferOffsetSize struct, data is not copied // array[index] = new BufferOffsetSize(thisMemoryChunk.Buffer, 0, thisMemoryChunk.FreeOffset, false); index++; thisMemoryChunk = thisMemoryChunk.Next; } return(array); }
private IAsyncResult InnerWrite(bool async, byte[] buffer, int offset, int size, AsyncCallback asyncCallback, object asyncState) { // after shutdown/Close throw an exception if (m_ShutDown > 0) { throw new ObjectDisposedException(this.GetType().FullName); } // on earlier error throw an exception if (InnerException != null) { throw InnerException; } // // parameter validation // if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (size < 0 || size > buffer.Length - offset) { throw new ArgumentOutOfRangeException("size"); } // // Lock the Write: this is inefficent, but we need to prevent // writing data while the Stream is doing a handshake with the server. // writing other data during the handshake would cause the server to // fail and close the connection. // lock (this) { // // encrypt the data // byte[] ciphertext = null; GlobalLog.Print("Encrypt[" + Encoding.ASCII.GetString(buffer, 0, Math.Min(buffer.Length, 512)) + "]"); SecureChannel chkSecureChannel = SecureChannel; if (chkSecureChannel == null) { InnerException = new IOException(SR.GetString(SR.net_io_writefailure)); throw InnerException; } if (size > chkSecureChannel.MaxDataSize) { BufferOffsetSize [] buffers = new BufferOffsetSize[1]; buffers[0] = new BufferOffsetSize(buffer, offset, size, false); if (async) { return(BeginMultipleWrite(buffers, asyncCallback, asyncState)); } else { MultipleWrite(buffers); return(null); } } int errorCode = chkSecureChannel.Encrypt(buffer, offset, size, ref ciphertext); if (errorCode != (int)SecurityStatus.OK) { ProtocolToken message = new ProtocolToken(null, errorCode); InnerException = message.GetException(); throw InnerException; } try { if (async) { IAsyncResult asyncResult = base.BeginWrite( ciphertext, 0, ciphertext.Length, asyncCallback, asyncState); return(asyncResult); } else { base.Write(ciphertext, 0, ciphertext.Length); return(null); } } catch (Exception exception) { // // some sort of error occured Writing to the Trasport, // set the Exception as InnerException and throw // InnerException = new IOException(SR.GetString(SR.net_io_writefailure), exception); throw InnerException; } } }
// Encryption takes CPU and if the input is large (like 10 mb) then a delay may // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks // up to c_SplitEncryptedBuffersSize total. // Note that upon return from here EncryptBuffers() may additonally split the input // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO. // // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done) // // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method // internal BufferOffsetSize[] GetNextBuffers() { int curIndex = _Index; int currentTotalSize = 0; int lastChunkSize = 0; int firstBufferConsumed = _LastBufferConsumed; for ( ;_Index < _UserBuffers.Length; ++_Index) { lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed; currentTotalSize += lastChunkSize; if (currentTotalSize > c_SplitEncryptedBuffersSize) { lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize); currentTotalSize = c_SplitEncryptedBuffersSize; break; } lastChunkSize = 0; _LastBufferConsumed = 0; } // Are we done done? if (currentTotalSize == 0) return null; // Do all buffers fit the limit? if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length) return _UserBuffers; // We do have something to split and send out int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1; if (_RealBuffers == null || _RealBuffers.Length != buffersCount) _RealBuffers = new BufferOffsetSize[buffersCount]; int j = 0; for (; curIndex < _Index; ++curIndex) { _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false); firstBufferConsumed = 0; } if (lastChunkSize != 0) { _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false); if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size) { ++_Index; _LastBufferConsumed = 0; } } return _RealBuffers; }
// // Handles either async or sync Writing for *public* stream API // 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() ----ing: 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() ----ing: 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 ---- 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() ----ing: 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 ---- 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(); } } } }
internal IAsyncResult UnsafeBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state) { // Unsafe - don't flow. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback); DoBeginMultipleSend(buffers, socketFlags, asyncResult); return asyncResult; }
public static SocketError Send(SafeCloseSocket handle, BufferOffsetSize[] buffers, SocketFlags socketFlags, out int bytesTransferred) { var bufferList = new BufferList(buffers); int platformFlags = GetPlatformSocketFlags(socketFlags); if (!handle.IsNonBlocking) { return handle.AsyncContext.Send(bufferList, platformFlags, handle.SendTimeout, out bytesTransferred); } bytesTransferred = 0; int bufferIndex = 0; int offset = 0; SocketError errorCode; bool completed = TryCompleteSendTo(handle.FileDescriptor, bufferList, ref bufferIndex, ref offset, platformFlags, null, 0, ref bytesTransferred, out errorCode); return completed ? errorCode : SocketError.WouldBlock; }
// // // // public void WriteMessage(byte[] message) { if (message == null) { throw new ArgumentNullException("message"); } m_WriteHeader.PayloadSize = message.Length; m_WriteHeader.CopyTo(m_WriteHeaderBuffer, 0); if (m_NetworkStream != null && message.Length != 0) { BufferOffsetSize[] buffers = new BufferOffsetSize[2]; buffers[0] = new BufferOffsetSize(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, false); buffers[1] = new BufferOffsetSize(message, 0, message.Length, false); m_NetworkStream.MultipleWrite(buffers); } else { Transport.Write(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length); if (message.Length==0) { return; } Transport.Write(message, 0, message.Length); } }
internal void MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags) { if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "MultipleSend", ""); if (CleanedUp) { throw new ObjectDisposedException(this.GetType().FullName); } // // parameter validation // GlobalLog.Assert(buffers != null, "Socket#{0}::MultipleSend()|buffers == null", ValidationHelper.HashString(this)); GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() buffers.Length:" + buffers.Length.ToString()); WSABuffer[] WSABuffers = new WSABuffer[buffers.Length]; GCHandle[] objectsToPin = null; int bytesTransferred; SocketError errorCode; try { objectsToPin = new GCHandle[buffers.Length]; for (int i = 0; i < buffers.Length; ++i) { objectsToPin[i] = GCHandle.Alloc(buffers[i].Buffer, GCHandleType.Pinned); WSABuffers[i].Length = buffers[i].Size; WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[i].Buffer, buffers[i].Offset); } // This can throw ObjectDisposedException. errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking( m_Handle.DangerousGetHandle(), WSABuffers, WSABuffers.Length, out bytesTransferred, socketFlags, SafeNativeOverlapped.Zero, IntPtr.Zero); GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::MultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString()); } finally { if (objectsToPin != null) for (int i = 0; i < objectsToPin.Length; ++i) if (objectsToPin[i].IsAllocated) objectsToPin[i].Free(); } if (errorCode!=SocketError.Success) { SocketException socketException = new SocketException(); UpdateStatusAfterSocketError(socketException); if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "MultipleSend", socketException); throw socketException; } if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "MultipleSend", ""); }
private void DoBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult) { if (Socket.s_LoggingEnabled) Logging.Enter(Logging.Sockets, (object) this, "BeginMultipleSend", ""); if (this.CleanedUp) throw new ObjectDisposedException(this.GetType().FullName); SocketError socketError = SocketError.SocketError; try { asyncResult.SetUnmanagedStructures(buffers, ref this.Caches.SendOverlappedCache); int bytesTransferred; socketError = UnsafeNclNativeMethods.OSSOCK.WSASend(this.m_Handle, asyncResult.m_WSABuffers, asyncResult.m_WSABuffers.Length, out bytesTransferred, socketFlags, asyncResult.OverlappedHandle, IntPtr.Zero); if (socketError != SocketError.Success) socketError = (SocketError) Marshal.GetLastWin32Error(); } finally { socketError = asyncResult.CheckAsyncCallOverlappedResult(socketError); } if (socketError != SocketError.Success) { asyncResult.ExtractCache(ref this.Caches.SendOverlappedCache); SocketException socketException = new SocketException(socketError); this.UpdateStatusAfterSocketError(socketException); if (Socket.s_LoggingEnabled) Logging.Exception(Logging.Sockets, (object) this, "BeginMultipleSend", (Exception) socketException); throw socketException; } else { if (!Socket.s_LoggingEnabled) return; Logging.Exit(Logging.Sockets, (object) this, "BeginMultipleSend", (object) asyncResult); } }
internal void MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags) { if (Socket.s_LoggingEnabled) Logging.Enter(Logging.Sockets, (object) this, "MultipleSend", ""); if (this.CleanedUp) throw new ObjectDisposedException(this.GetType().FullName); WSABuffer[] buffersArray = new WSABuffer[buffers.Length]; GCHandle[] gcHandleArray = (GCHandle[]) null; SocketError socketError; try { gcHandleArray = new GCHandle[buffers.Length]; for (int index = 0; index < buffers.Length; ++index) { gcHandleArray[index] = GCHandle.Alloc((object) buffers[index].Buffer, GCHandleType.Pinned); buffersArray[index].Length = buffers[index].Size; buffersArray[index].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement((Array) buffers[index].Buffer, buffers[index].Offset); } int bytesTransferred; socketError = UnsafeNclNativeMethods.OSSOCK.WSASend_Blocking(this.m_Handle.DangerousGetHandle(), buffersArray, buffersArray.Length, out bytesTransferred, socketFlags, (SafeHandle) SafeNativeOverlapped.Zero, IntPtr.Zero); } finally { if (gcHandleArray != null) { for (int index = 0; index < gcHandleArray.Length; ++index) { if (gcHandleArray[index].IsAllocated) gcHandleArray[index].Free(); } } } if (socketError != SocketError.Success) { SocketException socketException = new SocketException(); this.UpdateStatusAfterSocketError(socketException); if (Socket.s_LoggingEnabled) Logging.Exception(Logging.Sockets, (object) this, "MultipleSend", (Exception) socketException); throw socketException; } else { if (!Socket.s_LoggingEnabled) return; Logging.Exit(Logging.Sockets, (object) this, "MultipleSend", ""); } }
internal IAsyncResult BeginMultipleSend( BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, Object state) { // // parameter validation // GlobalLog.Assert(buffers!=null, "Socket:BeginMultipleSend(): buffers==null", ""); GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginMultipleSend() buffers.Length:" + buffers.Length.ToString()); // // Allocate the async result and the event we'll pass to the // thread pool. // OverlappedAsyncResult asyncResult = new OverlappedAsyncResult( this, state, callback ); // // Set up asyncResult for overlapped WSASend. // This call will use // completion ports on WinNT and Overlapped IO on Win9x. // asyncResult.SetUnmanagedStructures( buffers, socketFlags); // // Get the Send going. // int errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend( m_Handle, asyncResult.m_WSABuffers, asyncResult.m_WSABuffers.Length, OverlappedAsyncResult.m_BytesTransferred, asyncResult.m_Flags, asyncResult.IntOverlapped, IntPtr.Zero ); if (errorCode!=SocketErrors.Success) { errorCode = Marshal.GetLastWin32Error(); } asyncResult.CheckAsyncCallOverlappedResult(errorCode); GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginMultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult)); // // if the asynchronous native call fails synchronously // we'll throw a SocketException // if (asyncResult.ErrorCode!=SocketErrors.Success) { // // update our internal state after this socket error and throw // UpdateStatusAfterSocketError(); throw new SocketException(asyncResult.ErrorCode); } return asyncResult; }
internal void MultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags) { if (s_loggingEnabled) { Logging.Enter(Logging.Sockets, this, "MultipleSend", ""); } if (CleanedUp) { throw new ObjectDisposedException(this.GetType().FullName); } // Validate input parameters. GlobalLog.Assert(buffers != null, "Socket#{0}::MultipleSend()|buffers == null", Logging.HashString(this)); GlobalLog.Print("Socket#" + Logging.HashString(this) + "::MultipleSend() buffers.Length:" + buffers.Length.ToString()); int bytesTransferred; SocketError errorCode = SocketPal.Send(_handle, buffers, socketFlags, out bytesTransferred); GlobalLog.Print("Socket#" + Logging.HashString(this) + "::MultipleSend() Interop.Winsock.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString()); if (errorCode != SocketError.Success) { SocketException socketException = new SocketException((int)SocketPal.GetLastSocketError()); UpdateStatusAfterSocketError(socketException); if (s_loggingEnabled) { Logging.Exception(Logging.Sockets, this, "MultipleSend", socketException); } throw socketException; } if (s_loggingEnabled) { Logging.Exit(Logging.Sockets, this, "MultipleSend", ""); } }
internal async Task ReadAllAsync(bool resending, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} READ ALL ASYNC: resending={resending} eof={read_eof} total={totalRead} " + "length={contentLength} nextReadCalled={nextReadCalled}"); if (read_eof || totalRead >= contentLength || nextReadCalled) { if (!nextReadCalled) { nextReadCalled = true; Operation.Finish(true); } return; } var completion = new WebCompletionSource(); var timeoutCts = new CancellationTokenSource(); try { var timeoutTask = Task.Delay(ReadTimeout, timeoutCts.Token); while (true) { /* * 'currentRead' is set by ReadAsync(). */ cancellationToken.ThrowIfCancellationRequested(); var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null); if (oldCompletion == null) { break; } // ReadAsync() is in progress. var oldReadTask = oldCompletion.WaitForCompletion(); var anyTask = await Task.WhenAny(oldReadTask, timeoutTask).ConfigureAwait(false); if (anyTask == timeoutTask) { throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout); } } } finally { timeoutCts.Cancel(); timeoutCts.Dispose(); } WebConnection.Debug($"{ME} READ ALL ASYNC #1"); cancellationToken.ThrowIfCancellationRequested(); try { if (totalRead >= contentLength) { return; } byte[] b = null; int new_size; if (contentLength == Int64.MaxValue && !ChunkedRead) { WebConnection.Debug($"{ME} READ ALL ASYNC - NEITHER LENGTH NOR CHUNKED"); /* * This is a violation of the HTTP Spec - the server neither send a * "Content-Length:" nor a "Transfer-Encoding: chunked" header. * * When we're redirecting or resending for NTLM, then we can simply close * the connection here. * * However, if it's the final reply, then we need to try our best to read it. */ if (resending) { Close(); return; } KeepAlive = false; } if (contentLength == Int64.MaxValue) { MemoryStream ms = new MemoryStream(); BufferOffsetSize buffer = null; if (readBuffer != null && readBuffer.Size > 0) { ms.Write(readBuffer.Buffer, readBuffer.Offset, readBuffer.Size); readBuffer.Offset = 0; readBuffer.Size = readBuffer.Buffer.Length; if (readBuffer.Buffer.Length >= 8192) { buffer = readBuffer; } } if (buffer == null) { buffer = new BufferOffsetSize(new byte[8192], false); } int read; while ((read = await InnerReadAsync(buffer.Buffer, buffer.Offset, buffer.Size, cancellationToken)) != 0) { ms.Write(buffer.Buffer, buffer.Offset, read); } new_size = (int)ms.Length; contentLength = new_size; readBuffer = new BufferOffsetSize(ms.GetBuffer(), 0, new_size, false); } else { new_size = (int)(contentLength - totalRead); b = new byte[new_size]; int readSize = 0; if (readBuffer != null && readBuffer.Size > 0) { readSize = readBuffer.Size; if (readSize > new_size) { readSize = new_size; } Buffer.BlockCopy(readBuffer.Buffer, readBuffer.Offset, b, 0, readSize); } int remaining = new_size - readSize; int r = -1; while (remaining > 0 && r != 0) { r = await InnerReadAsync(b, readSize, remaining, cancellationToken); remaining -= r; readSize += r; } } readBuffer = new BufferOffsetSize(b, 0, new_size, false); totalRead = 0; nextReadCalled = true; completion.TrySetCompleted(); } catch (Exception ex) { WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}"); completion.TrySetException(ex); throw; } finally { WebConnection.Debug($"{ME} READ ALL ASYNC #2"); pendingRead = null; } Operation.Finish(true); }
async Task Initialize(BufferOffsetSize buffer, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}"); string contentType = Headers["Transfer-Encoding"]; bool chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1); string clength = Headers["Content-Length"]; if (!chunkedRead && !string.IsNullOrEmpty(clength)) { if (!long.TryParse(clength, out contentLength)) { contentLength = Int64.MaxValue; } } else { contentLength = Int64.MaxValue; } if (Version == HttpVersion.Version11 && RequestStream.KeepAlive) { KeepAlive = true; var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"]; if (cncHeader != null) { cncHeader = cncHeader.ToLower(); KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1; if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1) { KeepAlive = false; } } } // Negative numbers? if (!Int32.TryParse(clength, out stream_length)) { stream_length = -1; } string me = "WebResponseStream.Initialize()"; string tencoding = null; if (ExpectContent) { tencoding = Headers["Transfer-Encoding"]; } ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1); if (!ChunkedRead) { readBuffer = buffer; try { if (contentLength > 0 && readBuffer.Size >= contentLength) { if (!IsNtlmAuth()) { await ReadAllAsync(false, cancellationToken).ConfigureAwait(false); } } } catch (Exception e) { throw GetReadException(WebExceptionStatus.ReceiveFailure, e, me); } } else if (ChunkStream == null) { try { ChunkStream = new MonoChunkStream(buffer.Buffer, buffer.Offset, buffer.Offset + buffer.Size, Headers); } catch (Exception e) { throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, me); } } else { ChunkStream.ResetBuffer(); try { ChunkStream.Write(buffer.Buffer, buffer.Offset, buffer.Size); } catch (Exception e) { throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, me); } } WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}"); if (!ExpectContent) { if (!closed && !nextReadCalled) { if (contentLength == Int64.MaxValue) { contentLength = 0; } nextReadCalled = true; } Operation.Finish(true); } }
public BufferedReadStream(WebOperation operation, Stream innerStream, BufferOffsetSize readBuffer) : base(operation, innerStream) { this.readBuffer = readBuffer; }
// MultipleWriteOnly // public BufferAsyncResult(object asyncObject, BufferOffsetSize[] buffers, object asyncState, AsyncCallback asyncCallback) :base (asyncObject, asyncState, asyncCallback) { Buffers = buffers; IsWrite = true; }
internal void SetUnmanagedStructures(BufferOffsetSize[] buffers, ref OverlappedCache overlappedCache) { SetupCache(ref overlappedCache); SetUnmanagedStructures(buffers); }
bool GetResponse(BufferOffsetSize buffer, ref int pos, ref ReadState state) { string line = null; bool lineok = false; bool isContinue = false; bool emptyFirstLine = false; do { if (state == ReadState.Aborted) { throw GetReadException(WebExceptionStatus.RequestCanceled, null, "GetResponse"); } if (state == ReadState.None) { lineok = WebConnection.ReadLine(buffer.Buffer, ref pos, buffer.Offset, ref line); if (!lineok) { return(false); } if (line == null) { emptyFirstLine = true; continue; } emptyFirstLine = false; state = ReadState.Status; string[] parts = line.Split(' '); if (parts.Length < 2) { throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "GetResponse"); } if (String.Compare(parts[0], "HTTP/1.1", true) == 0) { Version = HttpVersion.Version11; ServicePoint.SetVersion(HttpVersion.Version11); } else { Version = HttpVersion.Version10; ServicePoint.SetVersion(HttpVersion.Version10); } StatusCode = (HttpStatusCode)UInt32.Parse(parts[1]); if (parts.Length >= 3) { StatusDescription = String.Join(" ", parts, 2, parts.Length - 2); } else { StatusDescription = string.Empty; } if (pos >= buffer.Offset) { return(true); } } emptyFirstLine = false; if (state == ReadState.Status) { state = ReadState.Headers; Headers = new WebHeaderCollection(); var headerList = new List <string> (); bool finished = false; while (!finished) { if (WebConnection.ReadLine(buffer.Buffer, ref pos, buffer.Offset, ref line) == false) { break; } if (line == null) { // Empty line: end of headers finished = true; continue; } if (line.Length > 0 && (line[0] == ' ' || line[0] == '\t')) { int count = headerList.Count - 1; if (count < 0) { break; } string prev = headerList[count] + line; headerList[count] = prev; } else { headerList.Add(line); } } if (!finished) { return(false); } // .NET uses ParseHeaders or ParseHeadersStrict which is much better foreach (string s in headerList) { int pos_s = s.IndexOf(':'); if (pos_s == -1) { throw new ArgumentException("no colon found", "header"); } var header = s.Substring(0, pos_s); var value = s.Substring(pos_s + 1).Trim(); if (WebHeaderCollection.AllowMultiValues(header)) { Headers.AddInternal(header, value); } else { Headers.SetInternal(header, value); } } if (StatusCode == HttpStatusCode.Continue) { ServicePoint.SendContinue = true; if (pos >= buffer.Offset) { return(true); } if (Request.ExpectContinue) { Request.DoContinueDelegate((int)StatusCode, Headers); // Prevent double calls when getting the // headers in several packets. Request.ExpectContinue = false; } state = ReadState.None; isContinue = true; } else { state = ReadState.Content; return(true); } } } while (emptyFirstLine || isContinue); throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "GetResponse"); }
internal IAsyncResult BeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state) { OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback); asyncResult.StartPostingAsyncOp(false); this.DoBeginMultipleSend(buffers, socketFlags, asyncResult); asyncResult.FinishPostingAsyncOp(ref this.Caches.SendClosureCache); return (IAsyncResult) asyncResult; }
// // // // public IAsyncResult BeginWriteMessage(byte[] message, AsyncCallback asyncCallback, object stateObject) { if (message == null) { throw new ArgumentNullException("message"); } m_WriteHeader.PayloadSize = message.Length; m_WriteHeader.CopyTo(m_WriteHeaderBuffer, 0); if (m_NetworkStream != null && message.Length != 0) { BufferOffsetSize[] buffers = new BufferOffsetSize[2]; buffers[0] = new BufferOffsetSize(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, false); buffers[1] = new BufferOffsetSize(message, 0, message.Length, false); return m_NetworkStream.BeginMultipleWrite(buffers, asyncCallback, stateObject); } if (message.Length == 0) { return Transport.BeginWrite(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, asyncCallback, stateObject); } //Will need two async writes // Prepare the second WorkerAsyncResult workerResult = new WorkerAsyncResult(this, stateObject, asyncCallback, message, 0, message.Length); // Charge the first IAsyncResult result = Transport.BeginWrite(m_WriteHeaderBuffer, 0, m_WriteHeaderBuffer.Length, m_BeginWriteCallback, workerResult); if (result.CompletedSynchronously) { BeginWriteComplete(result); } return workerResult; }
internal override void MultipleWrite(BufferOffsetSize[] buffers) { GlobalLog.Print("TlsStream#" + ValidationHelper.HashString(this) + "::MultipleWrite() SecureWorker#" + ValidationHelper.HashString(m_Worker) + " buffers.Length:" + buffers.Length.ToString()); if (!m_Worker.IsAuthenticated) ProcessAuthentication(null); try { m_Worker.SecureStream.Write(buffers); } catch { //HttpWbeRequest depends on the physical stream to be dropped on a write error. Socket chkSocket = this.Socket; if(chkSocket != null) { chkSocket.InternalShutdown(SocketShutdown.Both); } // We preserve the original status of a failure because the read // side will now fail with object dispose error. if (m_Worker.IsCertValidationFailed) { m_ExceptionStatus = WebExceptionStatus.TrustFailure; } else if (m_Worker.LastSecurityStatus != SecurityStatus.OK) { m_ExceptionStatus = WebExceptionStatus.SecureChannelFailure; } else { m_ExceptionStatus = WebExceptionStatus.SendFailure; } throw; } }
internal IAsyncResult BeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state) { // Set up the async result and start the flow. OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback); asyncResult.StartPostingAsyncOp(false); // Start the send. DoBeginMultipleSend(buffers, socketFlags, asyncResult); // Finish it up (capture, complete). asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache); return asyncResult; }
internal override IAsyncResult BeginMultipleWrite(BufferOffsetSize[] buffers, AsyncCallback callback, object state) { GlobalLog.Print("TlsStream#" + ValidationHelper.HashString(this) + "::BeginMultipleWrite() SecureWorker#" + ValidationHelper.HashString(m_Worker) + " buffers.Length:" + buffers.Length.ToString()); if (!m_Worker.IsAuthenticated) { BufferAsyncResult result = new BufferAsyncResult(this, buffers, state, callback); if (ProcessAuthentication(result)) return result; } try { return m_Worker.SecureStream.BeginWrite(buffers, callback, state); } catch { if (m_Worker.IsCertValidationFailed) { m_ExceptionStatus = WebExceptionStatus.TrustFailure; } else if (m_Worker.LastSecurityStatus != SecurityStatus.OK) { m_ExceptionStatus = WebExceptionStatus.SecureChannelFailure; } else { m_ExceptionStatus = WebExceptionStatus.SendFailure; } throw; } }
private void DoBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult) { if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "BeginMultipleSend", ""); if (CleanedUp) { throw new ObjectDisposedException(this.GetType().FullName); } // // parameter validation // GlobalLog.Assert(buffers != null, "Socket#{0}::DoBeginMultipleSend()|buffers == null", ValidationHelper.HashString(this)); GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::DoBeginMultipleSend() buffers.Length:" + buffers.Length.ToString()); // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to // avoid a Socket leak in case of error. SocketError errorCode = SocketError.SocketError; try { // Set up asyncResult for overlapped WSASend. // This call will use completion ports on WinNT and Overlapped IO on Win9x. asyncResult.SetUnmanagedStructures(buffers, ref Caches.SendOverlappedCache); // This can throw ObjectDisposedException. int bytesTransferred; errorCode = UnsafeNclNativeMethods.OSSOCK.WSASend( m_Handle, asyncResult.m_WSABuffers, asyncResult.m_WSABuffers.Length, out bytesTransferred, socketFlags, asyncResult.OverlappedHandle, IntPtr.Zero); if (errorCode!=SocketError.Success) { errorCode = (SocketError)Marshal.GetLastWin32Error(); } GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginMultipleSend() UnsafeNclNativeMethods.OSSOCK.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult)); } finally { errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode); } // // if the asynchronous native call fails synchronously // we'll throw a SocketException // if (errorCode!=SocketError.Success) { // // update our internal state after this socket error and throw // asyncResult.ExtractCache(ref Caches.SendOverlappedCache); SocketException socketException = new SocketException(errorCode); UpdateStatusAfterSocketError(socketException); if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginMultipleSend", socketException); throw socketException; } if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginMultipleSend", asyncResult); }
internal override IAsyncResult UnsafeBeginMultipleWrite(BufferOffsetSize[] buffers, AsyncCallback callback, object state) { return BeginMultipleWrite(buffers,callback,state); }
public static SocketError SendAsync(SafeCloseSocket handle, BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult) { return handle.AsyncContext.SendAsync(new BufferList(buffers), GetPlatformSocketFlags(socketFlags), asyncResult.CompletionCallback); }
void Initialize(BufferOffsetSize buffer) { WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}"); long contentLength; string contentType = Headers["Transfer-Encoding"]; bool chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1); string clength = Headers["Content-Length"]; if (!chunkedRead && !string.IsNullOrEmpty(clength)) { if (!long.TryParse(clength, out contentLength)) { contentLength = Int64.MaxValue; } } else { contentLength = Int64.MaxValue; } string tencoding = null; if (ExpectContent) { tencoding = Headers["Transfer-Encoding"]; } ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1); if (Version == HttpVersion.Version11 && RequestStream.KeepAlive) { KeepAlive = true; var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"]; if (cncHeader != null) { cncHeader = cncHeader.ToLower(); KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1; if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1) { KeepAlive = false; } } if (!ChunkedRead && contentLength == Int64.MaxValue) { /* * This is a violation of the HTTP Spec - the server neither send a * "Content-Length:" nor a "Transfer-Encoding: chunked" header. * The only way to recover from this is to keep reading until the * remote closes the connection, so we can't reuse it. */ KeepAlive = false; } } /* * Inner layer: * We may have read a few extra bytes while parsing the headers, these will be * passed to us in the @buffer parameter and we need to read these before * reading from the `InnerStream`. */ Stream networkStream; if (!ExpectContent || (!ChunkedRead && buffer.Size >= contentLength)) { bufferedEntireContent = true; innerStream = new BufferedReadStream(Operation, null, buffer); networkStream = innerStream; } else if (buffer.Size > 0) { networkStream = new BufferedReadStream(Operation, RequestStream.InnerStream, buffer); } else { networkStream = RequestStream.InnerStream; } /* * Intermediate layer: * - Wrap with MonoChunkStream when using chunked encoding. * - Otherwise, we should have a Content-Length, wrap with * FixedSizeReadStream to read exactly that many bytes. */ if (ChunkedRead) { innerStream = new MonoChunkStream(Operation, networkStream, Headers); } else if (bufferedEntireContent) { // 'innerStream' has already been set above. } else if (contentLength != Int64.MaxValue) { innerStream = new FixedSizeReadStream(Operation, networkStream, contentLength); } else { // Violation of the HTTP Spec - neither chunked nor length. innerStream = new BufferedReadStream(Operation, networkStream, null); } /* * Outer layer: * - Decode gzip/deflate if requested. */ string content_encoding = Headers["Content-Encoding"]; if (content_encoding == "gzip" && (Request.AutomaticDecompression & DecompressionMethods.GZip) != 0) { innerStream = ContentDecodeStream.Create(Operation, innerStream, ContentDecodeStream.Mode.GZip); Headers.Remove(HttpRequestHeader.ContentEncoding); } else if (content_encoding == "deflate" && (Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0) { innerStream = ContentDecodeStream.Create(Operation, innerStream, ContentDecodeStream.Mode.Deflate); Headers.Remove(HttpRequestHeader.ContentEncoding); } WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}"); if (!ExpectContent) { nextReadCalled = true; Operation.Finish(true); } }
/*++ Uses an old Stream to resubmit buffered data using the current stream, this is used in cases of POST, or authentication, where we need to buffer upload data so that it can be resubmitted Input: OldStream - Old Stream that was previously used Returns: Nothing. --*/ // internal void ResubmitWrite(ConnectStream oldStream, bool suppressWrite) { GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite", ValidationHelper.HashString(oldStream)); GlobalLog.ThreadContract(ThreadKinds.Sync, "ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite"); // // // // we're going to resubmit // try { Interlocked.CompareExchange(ref m_CallNesting, Nesting.InternalIO, Nesting.Idle); GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite() Inc: " + m_CallNesting.ToString()); GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite(), callNesting : " + m_CallNesting.ToString() + " IsClosed = " + IsClosed); // // no need to buffer here: // we're already resubmitting buffered data give it to the connection to put it on the wire again // we set BytesLeftToWrite to 0 'cause even on failure there can be no recovery, // so just leave it to IOError() to clean up and don't call ResubmitWrite() // ScatterGatherBuffers bufferedData = oldStream.BufferedData; SafeSetSocketTimeout(SocketShutdown.Send); if (!WriteChunked) { if (!suppressWrite) m_Connection.Write(bufferedData); } else { // we have the data buffered, but we still want to chunk. // first set this to disable Close() from sending a chunk terminator. GlobalLog.Assert(m_HttpWriteMode != HttpWriteMode.None, "ConnectStream#{0}::ResubmitWrite()|m_HttpWriteMode == HttpWriteMode.None", ValidationHelper.HashString(this)); m_HttpWriteMode = HttpWriteMode.ContentLength; if (bufferedData.Length==0) { m_Connection.Write(NclConstants.ChunkTerminator, 0, NclConstants.ChunkTerminator.Length); } else { int chunkHeaderOffset = 0; byte[] chunkHeaderBuffer = GetChunkHeader(bufferedData.Length, out chunkHeaderOffset); BufferOffsetSize[] dataBuffers = bufferedData.GetBuffers(); BufferOffsetSize[] buffers = new BufferOffsetSize[dataBuffers.Length + 3]; buffers[0] = new BufferOffsetSize(chunkHeaderBuffer, chunkHeaderOffset, chunkHeaderBuffer.Length - chunkHeaderOffset, false); int index = 0; foreach (BufferOffsetSize buffer in dataBuffers) { buffers[++index] = buffer; } buffers[++index] = new BufferOffsetSize(NclConstants.CRLF, 0, NclConstants.CRLF.Length, false); buffers[++index] = new BufferOffsetSize(NclConstants.ChunkTerminator, 0, NclConstants.ChunkTerminator.Length, false); SplitWritesState splitState = new SplitWritesState(buffers); BufferOffsetSize[] sendBuffers = splitState.GetNextBuffers(); while(sendBuffers != null){ m_Connection.MultipleWrite(sendBuffers); sendBuffers = splitState.GetNextBuffers(); } } } if(Logging.On && bufferedData.GetBuffers() != null) { foreach (BufferOffsetSize bufferOffsetSize in bufferedData.GetBuffers()) { if (bufferOffsetSize == null) { Logging.Dump(Logging.Web, this, "ResubmitWrite", null, 0, 0); } else { Logging.Dump(Logging.Web, this, "ResubmitWrite", bufferOffsetSize.Buffer, bufferOffsetSize.Offset, bufferOffsetSize.Size); } } } GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite() sent:" + bufferedData.Length.ToString() ); } catch (Exception exception) { if (NclUtilities.IsFatal(exception)) throw; // A Fatal error WebException we = new WebException(NetRes.GetWebStatusString("net_connclosed", WebExceptionStatus.SendFailure), WebExceptionStatus.SendFailure, WebExceptionInternalStatus.RequestFatal, exception); IOError(we, false); } finally { Interlocked.CompareExchange(ref m_CallNesting, Nesting.Idle, Nesting.InternalIO); GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite(), callNesting : " + m_CallNesting.ToString() + " IsClosed = " + IsClosed); } m_BytesLeftToWrite = 0; CallDone(); GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::ResubmitWrite", BytesLeftToWrite.ToString()); }
internal async Task ReadAllAsync(bool resending, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} READ ALL ASYNC: resending={resending} eof={read_eof} " + "nextReadCalled={nextReadCalled}"); if (read_eof || bufferedEntireContent || nextReadCalled) { if (!nextReadCalled) { nextReadCalled = true; Operation.Finish(true); } return; } var completion = new WebCompletionSource(); var timeoutCts = new CancellationTokenSource(); try { var timeoutTask = Task.Delay(ReadTimeout, timeoutCts.Token); while (true) { /* * 'currentRead' is set by ReadAsync(). */ cancellationToken.ThrowIfCancellationRequested(); var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null); if (oldCompletion == null) { break; } // ReadAsync() is in progress. var oldReadTask = oldCompletion.WaitForCompletion(); var anyTask = await Task.WhenAny(oldReadTask, timeoutTask).ConfigureAwait(false); if (anyTask == timeoutTask) { throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout); } } } finally { timeoutCts.Cancel(); timeoutCts.Dispose(); } WebConnection.Debug($"{ME} READ ALL ASYNC #1"); try { cancellationToken.ThrowIfCancellationRequested(); /* * We may have awaited on the 'readTcs', so check * for eof again as ReadAsync() may have set it. */ if (read_eof || bufferedEntireContent) { return; } /* * Simplify: if we're resending on a new connection, * then we can simply close the connection here. */ if (resending && !KeepAlive) { Close(); return; } var buffer = await ReadAllAsyncInner(cancellationToken).ConfigureAwait(false); var bos = new BufferOffsetSize(buffer, 0, buffer.Length, false); innerStream = new BufferedReadStream(Operation, null, bos); nextReadCalled = true; completion.TrySetCompleted(); } catch (Exception ex) { WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}"); completion.TrySetException(ex); throw; } finally { WebConnection.Debug($"{ME} READ ALL ASYNC #2"); pendingRead = null; } Operation.Finish(true); }
// Encryption takes CPU and if the input is large (like 10 mb) then a delay may // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks // up to c_SplitEncryptedBuffersSize total. // Note that upon return from here EncryptBuffers() may additonally split the input // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO. // // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done) // // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method // internal BufferOffsetSize[] GetNextBuffers() { int curIndex = _Index; int currentTotalSize = 0; int lastChunkSize = 0; int firstBufferConsumed = _LastBufferConsumed; for ( ; _Index < _UserBuffers.Length; ++_Index) { lastChunkSize = _UserBuffers[_Index].Size - _LastBufferConsumed; currentTotalSize += lastChunkSize; if (currentTotalSize > c_SplitEncryptedBuffersSize) { lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize); currentTotalSize = c_SplitEncryptedBuffersSize; break; } lastChunkSize = 0; _LastBufferConsumed = 0; } // Are we done done? if (currentTotalSize == 0) { return(null); } // Do all buffers fit the limit? if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length) { return(_UserBuffers); } // We do have something to split and send out int buffersCount = lastChunkSize == 0? _Index - curIndex: _Index - curIndex + 1; if (_RealBuffers == null || _RealBuffers.Length != buffersCount) { _RealBuffers = new BufferOffsetSize[buffersCount]; } int j = 0; for (; curIndex < _Index; ++curIndex) { _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size - firstBufferConsumed, false); firstBufferConsumed = 0; } if (lastChunkSize != 0) { _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false); if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size) { ++_Index; _LastBufferConsumed = 0; } } return(_RealBuffers); }
internal async Task InitReadAsync(CancellationToken cancellationToken) { WebConnection.Debug($"{ME} INIT READ ASYNC"); var buffer = new BufferOffsetSize(new byte[4096], false); var state = ReadState.None; int position = 0; while (true) { Operation.ThrowIfClosedOrDisposed(cancellationToken); WebConnection.Debug($"{ME} INIT READ ASYNC LOOP: {state} {position} - {buffer.Offset}/{buffer.Size}"); var nread = await RequestStream.InnerStream.ReadAsync( buffer.Buffer, buffer.Offset, buffer.Size, cancellationToken).ConfigureAwait(false); WebConnection.Debug($"{ME} INIT READ ASYNC LOOP #1: {state} {position} - {buffer.Offset}/{buffer.Size} - {nread}"); if (nread == 0) { throw GetReadException(WebExceptionStatus.ReceiveFailure, null, "ReadDoneAsync2"); } if (nread < 0) { throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "ReadDoneAsync3"); } buffer.Offset += nread; buffer.Size -= nread; if (state == ReadState.None) { try { var oldPos = position; if (!GetResponse(buffer, ref position, ref state)) { position = oldPos; } } catch (Exception e) { WebConnection.Debug($"{ME} INIT READ ASYNC FAILED: {e.Message}\n{e}"); throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, "ReadDoneAsync4"); } } if (state == ReadState.Aborted) { throw GetReadException(WebExceptionStatus.RequestCanceled, null, "ReadDoneAsync5"); } if (state == ReadState.Content) { buffer.Size = buffer.Offset - position; buffer.Offset = position; break; } int est = nread * 2; if (est > buffer.Size) { var newBuffer = new byte [buffer.Buffer.Length + est]; Buffer.BlockCopy(buffer.Buffer, 0, newBuffer, 0, buffer.Offset); buffer = new BufferOffsetSize(newBuffer, buffer.Offset, newBuffer.Length - buffer.Offset, false); } state = ReadState.None; position = 0; } WebConnection.Debug($"{ME} INIT READ ASYNC LOOP DONE: {buffer.Offset} {buffer.Size}"); try { Initialize(buffer); } catch (Exception e) { throw GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadDoneAsync6"); } }
private void DoBeginMultipleSend(BufferOffsetSize[] buffers, SocketFlags socketFlags, OverlappedAsyncResult asyncResult) { if (s_loggingEnabled) { Logging.Enter(Logging.Sockets, this, "BeginMultipleSend", ""); } if (CleanedUp) { throw new ObjectDisposedException(this.GetType().FullName); } // Validate input parameters. GlobalLog.Assert(buffers != null, "Socket#{0}::DoBeginMultipleSend()|buffers == null", Logging.HashString(this)); GlobalLog.Print("Socket#" + Logging.HashString(this) + "::DoBeginMultipleSend() buffers.Length:" + buffers.Length.ToString()); // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to // avoid a Socket leak in case of error. SocketError errorCode = SocketError.SocketError; try { errorCode = SocketPal.SendAsync(_handle, buffers, socketFlags, asyncResult); GlobalLog.Print("Socket#" + Logging.HashString(this) + "::BeginMultipleSend() Interop.Winsock.WSASend returns:" + errorCode.ToString() + " size:" + buffers.Length.ToString() + " returning AsyncResult:" + Logging.HashString(asyncResult)); } finally { errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode); } // Throw an appropriate SocketException if the native call fails synchronously. if (errorCode != SocketError.Success) { // Update the internal state of this socket according to the error before throwing. SocketException socketException = new SocketException((int)errorCode); UpdateStatusAfterSocketError(socketException); if (s_loggingEnabled) { Logging.Exception(Logging.Sockets, this, "BeginMultipleSend", socketException); } throw socketException; } if (s_loggingEnabled) { Logging.Exit(Logging.Sockets, this, "BeginMultipleSend", asyncResult); } }
void Initialize(BufferOffsetSize buffer) { WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}"); string contentType = Headers["Transfer-Encoding"]; bool chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1); string clength = Headers["Content-Length"]; if (!chunkedRead && !string.IsNullOrEmpty(clength)) { if (!long.TryParse(clength, out contentLength)) { contentLength = Int64.MaxValue; } } else { contentLength = Int64.MaxValue; } if (Version == HttpVersion.Version11 && RequestStream.KeepAlive) { KeepAlive = true; var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"]; if (cncHeader != null) { cncHeader = cncHeader.ToLower(); KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1; if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1) { KeepAlive = false; } } } // Negative numbers? if (!Int32.TryParse(clength, out stream_length)) { stream_length = -1; } string tencoding = null; if (ExpectContent) { tencoding = Headers["Transfer-Encoding"]; } ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1); if (ChunkedRead) { innerStreamWrapper = innerChunkStream = new MonoChunkStream( Operation, CreateStreamWrapper(buffer), Headers); } else if (!IsNtlmAuth() && contentLength > 0 && buffer.Size >= contentLength) { innerStreamWrapper = new BufferedReadStream(Operation, null, buffer); } else { innerStreamWrapper = CreateStreamWrapper(buffer); } string content_encoding = Headers["Content-Encoding"]; if (content_encoding == "gzip" && (Request.AutomaticDecompression & DecompressionMethods.GZip) != 0) { innerStreamWrapper = new GZipStream(innerStreamWrapper, CompressionMode.Decompress); Headers.Remove(HttpRequestHeader.ContentEncoding); } else if (content_encoding == "deflate" && (Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0) { innerStreamWrapper = new DeflateStream(innerStreamWrapper, CompressionMode.Decompress); Headers.Remove(HttpRequestHeader.ContentEncoding); } WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}"); if (!ExpectContent) { if (!closed && !nextReadCalled) { if (contentLength == Int64.MaxValue) { contentLength = 0; } nextReadCalled = true; } Operation.CompleteResponseRead(true); } }