} // Position public override int Read( [In, Out] byte[] buffer, int offset, int count) { GlobalLog.Print("ListenerRequestStream.ReadCore() offset: " + Convert.ToString(offset) + " count:" + Convert.ToString(count)); int DataCopiedFromBuffer = 0; int DataCopiedFromDriver = 0; // // see if we still have some data in the buffer // if (m_BufferedDataExists) { // // start sending data in the buffer // DataCopiedFromBuffer = Math.Min( m_DataBuffer.Length - m_DataBufferOffset, count); Buffer.BlockCopy( m_DataBuffer, m_DataBufferOffset, buffer, offset, DataCopiedFromBuffer); // // update the offset for the buffered data for subsequent calls // m_DataBufferOffset += DataCopiedFromBuffer; m_BufferedDataExists = m_DataBuffer.Length > m_DataBufferOffset; // // update offset and count in the buffer for subsequent calls // offset += DataCopiedFromBuffer; count -= DataCopiedFromBuffer; } // // if all the data requested was handled by the buffered data we don't // need to call the driver for more, so we just return here // if (count <= 0 || !m_MoreToRead) { return(DataCopiedFromBuffer); } // // otherwise pin the buffer and make an unmanaged call to the driver to // read more entity body // GCHandle PinnedBuffer; IntPtr AddrOfPinnedBuffer = IntPtr.Zero; PinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject(); // // issue unmanaged blocking call // int result = ComNetOS.IsWinNt ? UlSysApi.UlReceiveEntityBody( m_AppPoolHandle, m_RequestId, UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY, AddrOfPinnedBuffer, count, ref DataCopiedFromDriver, IntPtr.Zero) : UlVxdApi.UlReceiveHttpRequestEntityBody( m_AppPoolHandle, m_RequestId, 0, AddrOfPinnedBuffer, count, ref DataCopiedFromDriver, IntPtr.Zero); PinnedBuffer.Free(); if (result != NativeMethods.ERROR_SUCCESS && result != NativeMethods.ERROR_HANDLE_EOF) { // // Consider: move all Exception string to system.txt for localization // throw new InvalidOperationException("UlReceiveEntityBody() failed, err#" + Convert.ToString(result)); } return(DataCopiedFromBuffer + DataCopiedFromDriver); } // Read()
GetRequest() { // // Validation // if (m_AppPoolHandle == NativeMethods.INVALID_HANDLE_VALUE) { throw new InvalidOperationException("The AppPool handle is invalid"); } int result; int retries = 0; // // defined in ulcommonapi.cs // int RcvHeadersBufferSize = UlConstants.InitialBufferSize; // // prepare ( allocate/pin ) buffers and data for the first unmanaged call // GCHandle PinnedBuffer; GCHandle NewPinnedBuffer; IntPtr AddrOfPinnedBuffer = IntPtr.Zero; IntPtr NewAddrOfPinnedBuffer = IntPtr.Zero; int BytesReturned = 0; long RequestId = 0; byte[] RcvHeadersBuffer = new byte[RcvHeadersBufferSize]; // // pin buffers and data for the unmanaged call // PinnedBuffer = GCHandle.Alloc(RcvHeadersBuffer, GCHandleType.Pinned); AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject(); // // issue unmanaged blocking call until we read enough data: // usually starting with a InitialBufferSize==4096 bytes we should be // able to get all the headers ( and part of the entity body, if any // is present ), if we don't, if the call didn't fail for othe reasons, // we get indication in BytesReturned, on how big the buffer should be // to receive the data available, so usually the second call will // succeed, but we have to consider the case of two competing calls // for the same RequestId, and that's why we need a loop and not just // a try/retry-expecting-success fashion // for (;;) { // // check if we're in a healthy state // if (retries++ > m_MaxRetries) { throw new InvalidOperationException("UlReceiveHttpRequest() Too many retries"); } result = ComNetOS.IsWinNt ? UlSysApi.UlReceiveHttpRequest( m_AppPoolHandle, RequestId, UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY, AddrOfPinnedBuffer, RcvHeadersBufferSize, ref BytesReturned, IntPtr.Zero) : UlVxdApi.UlReceiveHttpRequestHeaders( m_AppPoolHandle, RequestId, 0, AddrOfPinnedBuffer, RcvHeadersBufferSize, ref BytesReturned, IntPtr.Zero); if (result == NativeMethods.ERROR_SUCCESS) { // // success, we are done. // break; } if (result == NativeMethods.ERROR_INVALID_PARAMETER) { // // we might get this if somebody stole our RequestId, // set RequestId to null // RequestId = 0; // // and start all over again with the buffer we // just allocated // continue; } // // let's check if ul is in good shape: // if (BytesReturned < RcvHeadersBufferSize) { throw new InvalidOperationException("UlReceiveHttpRequest() sent bogus BytesReturned: " + Convert.ToString(BytesReturned)); } if (result == NativeMethods.ERROR_MORE_DATA) { // // the buffer was not big enough to fit the headers, we need // to read the RequestId returned, grow the buffer, keeping // the data already transferred // RequestId = Marshal.ReadInt64(IntPtrHelper.Add(AddrOfPinnedBuffer, m_RequestIdOffset)); // // CODEWORK: wait for the answer from LarrySu // // // if the buffer size was too small, grow the buffer // this reallocation dereferences the old buffer, but since // this was previously pinned, it won't be garbage collected // until we unpin it ( which we do below ) // RcvHeadersBuffer = new byte[BytesReturned]; // // pin the new one // NewPinnedBuffer = GCHandle.Alloc(RcvHeadersBuffer, GCHandleType.Pinned); NewAddrOfPinnedBuffer = NewPinnedBuffer.AddrOfPinnedObject(); // // copy the valid data // Marshal.Copy(AddrOfPinnedBuffer, RcvHeadersBuffer, 0, RcvHeadersBufferSize); RcvHeadersBufferSize = BytesReturned; // // unpin the old buffer, reset pinned/unmanaged pointers // PinnedBuffer.Free(); PinnedBuffer = NewPinnedBuffer; AddrOfPinnedBuffer = NewAddrOfPinnedBuffer; // // and start all over again with the new buffer // continue; } // // someother bad error, possible( ? ) return values are: // // ERROR_INVALID_HANDLE // ERROR_INSUFFICIENT_BUFFER // ERROR_OPERATION_ABORTED // ERROR_IO_PENDING // throw new InvalidOperationException("UlReceiveHttpRequest() failed, err#" + Convert.ToString(result)); } GlobalLog.Print("GetRequest RequestId:" + Convert.ToString(RequestId)); // // translate unmanaged results into a new managed object // HttpListenerWebRequest myWebRequest = new HttpListenerWebRequest(AddrOfPinnedBuffer, RcvHeadersBufferSize, m_AppPoolHandle); // // free the unmanaged buffer ( deallocate/unpin ) after unmanaged call // PinnedBuffer.Free(); return(myWebRequest); } // GetRequest()