} // 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()