Exemple #1
0
        public override void Write(byte[] buffer, int offset, int size)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.HttpListener, this, "Write", "");
            }
            GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Write() buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset);
            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");
            }
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (m_Closed || (size == 0 && m_LeftToWrite != 0))
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.HttpListener, this, "Write", "");
                }
                return;
            }
            if (m_LeftToWrite >= 0 && size > m_LeftToWrite)
            {
                throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig));
            }

            uint          statusCode;
            uint          dataToWrite     = (uint)size;
            SafeLocalFree bufferAsIntPtr  = null;
            IntPtr        pBufferAsIntPtr = IntPtr.Zero;
            bool          sentHeaders     = m_HttpContext.Response.SentHeaders;

            try {
                if (size == 0)
                {
                    statusCode = m_HttpContext.Response.SendHeaders(null, null, flags, false);
                }
                else
                {
                    fixed(byte *pDataBuffer = buffer)
                    {
                        byte *pBuffer = pDataBuffer;

                        if (m_HttpContext.Response.BoundaryType == BoundaryType.Chunked)
                        {
                            //


                            string chunkHeader = size.ToString("x", CultureInfo.InvariantCulture);
                            dataToWrite     = dataToWrite + (uint)(chunkHeader.Length + 4);
                            bufferAsIntPtr  = SafeLocalFree.LocalAlloc((int)dataToWrite);
                            pBufferAsIntPtr = bufferAsIntPtr.DangerousGetHandle();
                            for (int i = 0; i < chunkHeader.Length; i++)
                            {
                                Marshal.WriteByte(pBufferAsIntPtr, i, (byte)chunkHeader[i]);
                            }
                            Marshal.WriteInt16(pBufferAsIntPtr, chunkHeader.Length, 0x0A0D);
                            Marshal.Copy(buffer, offset, IntPtrHelper.Add(pBufferAsIntPtr, chunkHeader.Length + 2), size);
                            Marshal.WriteInt16(pBufferAsIntPtr, (int)(dataToWrite - 2), 0x0A0D);
                            pBuffer = (byte *)pBufferAsIntPtr;
                            offset  = 0;
                        }
                        UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK dataChunk = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK();
                        dataChunk.DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                        dataChunk.pBuffer       = (byte *)(pBuffer + offset);
                        dataChunk.BufferLength  = dataToWrite;

                        flags |= m_LeftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
                        if (!sentHeaders)
                        {
                            statusCode = m_HttpContext.Response.SendHeaders(&dataChunk, null, flags, false);
                        }
                        else
                        {
                            GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Write() calling UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody");

                            statusCode =
                                UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(
                                    m_HttpContext.RequestQueueHandle,
                                    m_HttpContext.RequestId,
                                    (uint)flags,
                                    1,
                                    &dataChunk,
                                    null,
                                    SafeLocalFree.Zero,
                                    0,
                                    null,
                                    null);

                            GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Write() call to UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                            if (m_HttpContext.Listener.IgnoreWriteExceptions)
                            {
                                GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Write() suppressing error");
                                statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS;
                            }
                        }
                    }
                }
            }
            finally {
                if (bufferAsIntPtr != null)
                {
                    // free unmanaged buffer
                    bufferAsIntPtr.Close();
                }
            }

            if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
            {
                Exception exception = new HttpListenerException((int)statusCode);
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "Write", exception);
                }
                m_Closed = true;
                m_HttpContext.Abort();
                throw exception;
            }
            UpdateAfterWrite(dataToWrite);
            if (Logging.On)
            {
                Logging.Dump(Logging.HttpListener, this, "Write", buffer, offset, (int)dataToWrite);
            }
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "Write", "");
            }
        }
Exemple #2
0
        internal static IPHostEntry NativeToHostEntry(IntPtr nativePointer) {
#endif
            //
            // marshal pointer to struct
            //

            hostent Host = (hostent)Marshal.PtrToStructure(nativePointer, typeof(hostent));
            IPHostEntry HostEntry = new IPHostEntry();

            if (Host.h_name != IntPtr.Zero) {
                HostEntry.HostName = Marshal.PtrToStringAnsi(Host.h_name);
                GlobalLog.Print("HostEntry.HostName: " + HostEntry.HostName);
            }

            // decode h_addr_list to ArrayList of IP addresses.
            // The h_addr_list field is really a pointer to an array of pointers
            // to IP addresses. Loop through the array, and while the pointer
            // isn't NULL read the IP address, convert it to an IPAddress class,
            // and add it to the list.

            ArrayList TempList = new ArrayList();
            int IPAddressToAdd;
            string AliasToAdd;
            IntPtr currentArrayElement;

            //
            // get the first pointer in the array
            //
            currentArrayElement = Host.h_addr_list;
            nativePointer = Marshal.ReadIntPtr(currentArrayElement);

            while (nativePointer != IntPtr.Zero) {
                //
                // if it's not null it points to an IPAddress,
                // read it...
                //
                IPAddressToAdd = Marshal.ReadInt32(nativePointer);
#if BIGENDIAN
                // IP addresses from native code are always a byte array
                // converted to int.  We need to convert the address into
                // a uniform integer value.
                IPAddressToAdd = (int)( ((uint)IPAddressToAdd << 24) |
                                        (((uint)IPAddressToAdd & 0x0000FF00) << 8) |
                                        (((uint)IPAddressToAdd >> 8) & 0x0000FF00) |
                                        ((uint)IPAddressToAdd >> 24) );
#endif

                GlobalLog.Print("currentArrayElement: " + currentArrayElement.ToString() + " nativePointer: " + nativePointer.ToString() + " IPAddressToAdd:" + IPAddressToAdd.ToString());

                //
                // ...and add it to the list
                //
                TempList.Add(new IPAddress(IPAddressToAdd));

                //
                // now get the next pointer in the array and start over
                //
                currentArrayElement = IntPtrHelper.Add(currentArrayElement, IntPtr.Size);
                nativePointer = Marshal.ReadIntPtr(currentArrayElement);
            }

            HostEntry.AddressList = new IPAddress[TempList.Count];
            TempList.CopyTo(HostEntry.AddressList, 0);

            //
            // Now do the same thing for the aliases.
            //

            TempList.Clear();

            currentArrayElement = Host.h_aliases;
            nativePointer = Marshal.ReadIntPtr(currentArrayElement);

            while (nativePointer != IntPtr.Zero) {

                GlobalLog.Print("currentArrayElement: " + ((long)currentArrayElement).ToString() + "nativePointer: " + ((long)nativePointer).ToString());

                //
                // if it's not null it points to an Alias,
                // read it...
                //
                AliasToAdd = Marshal.PtrToStringAnsi(nativePointer);

                //
                // ...and add it to the list
                //
                TempList.Add(AliasToAdd);

                //
                // now get the next pointer in the array and start over
                //
                currentArrayElement = IntPtrHelper.Add(currentArrayElement, IntPtr.Size);
                nativePointer = Marshal.ReadIntPtr(currentArrayElement);

            }

            HostEntry.Aliases = new string[TempList.Count];
            TempList.CopyTo(HostEntry.Aliases, 0);

            return HostEntry;

        } // NativeToHostEntry
Exemple #3
0
        /*++
         *
         * Routine Description:
         *
         *  Takes a native pointer (expressed as an int) to a hostent structure,
         *  and converts the information in their to an IPHostEntry class. This
         *  involves walking through an array of native pointers, and a temporary
         *  ArrayList object is used in doing this.
         *
         * Arguments:
         *
         *  nativePointer   - Native pointer to hostent structure.
         *
         *
         *
         * Return Value:
         *
         *  An IPHostEntry structure.
         *
         * --*/
        private static IPHostEntry NativeToHostEntry(IntPtr nativePointer)
        {
            //
            // marshal pointer to struct
            //

            hostent     Host      = Marshal.PtrToStructure <hostent>(nativePointer);
            IPHostEntry HostEntry = new IPHostEntry();

            if (Host.h_name != IntPtr.Zero)
            {
                HostEntry.HostName = Marshal.PtrToStringAnsi(Host.h_name);
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(null, $"HostEntry.HostName: {HostEntry.HostName}");
                }
            }

            // decode h_addr_list to ArrayList of IP addresses.
            // The h_addr_list field is really a pointer to an array of pointers
            // to IP addresses. Loop through the array, and while the pointer
            // isn't NULL read the IP address, convert it to an IPAddress class,
            // and add it to the list.

            var    TempIPAddressList = new List <IPAddress>();
            int    IPAddressToAdd;
            string AliasToAdd;
            IntPtr currentArrayElement;

            //
            // get the first pointer in the array
            //
            currentArrayElement = Host.h_addr_list;
            nativePointer       = Marshal.ReadIntPtr(currentArrayElement);

            while (nativePointer != IntPtr.Zero)
            {
                //
                // if it's not null it points to an IPAddress,
                // read it...
                //
                IPAddressToAdd = Marshal.ReadInt32(nativePointer);
#if BIGENDIAN
                // IP addresses from native code are always a byte array
                // converted to int.  We need to convert the address into
                // a uniform integer value.
                IPAddressToAdd = (int)(((uint)IPAddressToAdd << 24) |
                                       (((uint)IPAddressToAdd & 0x0000FF00) << 8) |
                                       (((uint)IPAddressToAdd >> 8) & 0x0000FF00) |
                                       ((uint)IPAddressToAdd >> 24));
#endif

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(null, $"currentArrayElement:{currentArrayElement} nativePointer:{nativePointer} IPAddressToAdd:{IPAddressToAdd}");
                }

                //
                // ...and add it to the list
                //
                TempIPAddressList.Add(new IPAddress((long)IPAddressToAdd & 0x0FFFFFFFF));

                //
                // now get the next pointer in the array and start over
                //
                currentArrayElement = IntPtrHelper.Add(currentArrayElement, IntPtr.Size);
                nativePointer       = Marshal.ReadIntPtr(currentArrayElement);
            }

            HostEntry.AddressList = TempIPAddressList.ToArray();

            //
            // Now do the same thing for the aliases.
            //

            var TempAliasList = new List <string>();

            currentArrayElement = Host.h_aliases;
            nativePointer       = Marshal.ReadIntPtr(currentArrayElement);

            while (nativePointer != IntPtr.Zero)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(null, $"currentArrayElement:{currentArrayElement} nativePointer:{nativePointer}");
                }

                //
                // if it's not null it points to an Alias,
                // read it...
                //
                AliasToAdd = Marshal.PtrToStringAnsi(nativePointer);

                //
                // ...and add it to the list
                //
                TempAliasList.Add(AliasToAdd);

                //
                // now get the next pointer in the array and start over
                //
                currentArrayElement = IntPtrHelper.Add(currentArrayElement, IntPtr.Size);
                nativePointer       = Marshal.ReadIntPtr(currentArrayElement);
            }

            HostEntry.Aliases = TempAliasList.ToArray();

            return(HostEntry);
        } // NativeToHostEntry
Exemple #4
0
        public override unsafe void Write(byte[] buffer, int offset, int size)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.HttpListener, this, "Write", "");
            }
            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");
            }
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = this.ComputeLeftToWrite();
            if (this.m_Closed || ((size == 0) && (this.m_LeftToWrite != 0L)))
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.HttpListener, this, "Write", "");
                }
            }
            else
            {
                uint num;
                if ((this.m_LeftToWrite >= 0L) && (size > this.m_LeftToWrite))
                {
                    throw new ProtocolViolationException(SR.GetString("net_entitytoobig"));
                }
                uint          dataWritten = (uint)size;
                SafeLocalFree free        = null;
                IntPtr        zero        = IntPtr.Zero;
                bool          sentHeaders = this.m_HttpContext.Response.SentHeaders;
                try
                {
                    if (size == 0)
                    {
                        num = this.m_HttpContext.Response.SendHeaders(null, null, flags);
                    }
                    else
                    {
                        try
                        {
                            byte[] buffer2;
                            if (((buffer2 = buffer) == null) || (buffer2.Length == 0))
                            {
                                numRef = null;
                                goto Label_0109;
                            }
                            fixed(byte *numRef = buffer2)
                            {
                                byte *numPtr;

Label_0109:
                                numPtr = numRef;
                                if (this.m_HttpContext.Response.BoundaryType == BoundaryType.Chunked)
                                {
                                    string str = size.ToString("x", CultureInfo.InvariantCulture);
                                    dataWritten += (uint)(str.Length + 4);
                                    free         = SafeLocalFree.LocalAlloc((int)dataWritten);
                                    zero         = free.DangerousGetHandle();
                                    for (int i = 0; i < str.Length; i++)
                                    {
                                        Marshal.WriteByte(zero, i, (byte)str[i]);
                                    }
                                    Marshal.WriteInt16(zero, str.Length, (short)0xa0d);
                                    Marshal.Copy(buffer, offset, IntPtrHelper.Add(zero, str.Length + 2), size);
                                    Marshal.WriteInt16(zero, ((int)dataWritten) - 2, (short)0xa0d);
                                    numPtr = (byte *)zero;
                                    offset = 0;
                                }
                                UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK pDataChunk = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK {
                                    DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory,
                                    pBuffer       = numPtr + offset,
                                    BufferLength  = dataWritten
                                };
                                flags |= (this.m_LeftToWrite == size) ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
                                if (!sentHeaders)
                                {
                                    num = this.m_HttpContext.Response.SendHeaders(&pDataChunk, null, flags);
                                }
                                else
                                {
                                    num = UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(this.m_HttpContext.RequestQueueHandle, this.m_HttpContext.RequestId, (uint)flags, 1, &pDataChunk, null, SafeLocalFree.Zero, 0, null, null);
                                    if (this.m_HttpContext.Listener.IgnoreWriteExceptions)
                                    {
                                        num = 0;
                                    }
                                }
                            }
                        }
                        finally
                        {
                            numRef = null;
                        }
                    }
                }
                finally
                {
                    if (free != null)
                    {
                        free.Close();
                    }
                }
                switch (num)
                {
                case 0:
                case 0x26:
                    this.UpdateAfterWrite(dataWritten);
                    if (Logging.On)
                    {
                        Logging.Dump(Logging.HttpListener, this, "Write", buffer, offset, (int)dataWritten);
                    }
                    if (Logging.On)
                    {
                        Logging.Exit(Logging.HttpListener, this, "Write", "");
                    }
                    return;
                }
                Exception e = new HttpListenerException((int)num);
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "Write", e);
                }
                this.m_HttpContext.Abort();
                throw e;
            }
        }
        } // Position


        //
        // write a chunk of data to ul
        //

        public override void Write(
            byte[] buffer,
            int offset,
            int count)
        {
            GlobalLog.Print("ListenerResponseStream.WriteCore() offset: " + Convert.ToString(offset) + " count:" + Convert.ToString(count));

            if (m_ContentLength != -1 && m_ContentLength < count)
            {
                //
                // user can't send more data than specified in the ContentLength
                //

                throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig));
            }

            int DataToWrite = count;

            GCHandle PinnedBuffer       = new GCHandle();
            IntPtr   AddrOfPinnedBuffer = IntPtr.Zero;

            if (m_SendChunked)
            {
                string ChunkHeader = "0x" + Convert.ToString(count, 16);

                DataToWrite += ChunkHeader.Length + 4;

                AddrOfPinnedBuffer = Marshal.AllocHGlobal(DataToWrite);

                Marshal.Copy(ChunkHeader.ToCharArray(), 0, AddrOfPinnedBuffer, ChunkHeader.Length);
                Marshal.WriteInt16(AddrOfPinnedBuffer, ChunkHeader.Length, 0x0A0D);
                Marshal.Copy((byte[])buffer, offset, IntPtrHelper.Add(AddrOfPinnedBuffer, ChunkHeader.Length + 2), count);
                Marshal.WriteInt16(AddrOfPinnedBuffer, DataToWrite - 2, 0x0A0D);
            }
            else
            {
                //
                // pin the buffer and make an unmanaged call to the driver to
                // write more entity body
                //

                PinnedBuffer       = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject();
            }


            //
            // set up a UL_DATA_CHUNK structure to pass down to UL with pointers
            // to data to be written
            //

            IntPtr AddrOfPinnedEntityChunks = Marshal.AllocHGlobal(32);

            //
            // AddrOfPinnedBuffer and count go into a pEntityChunks structure
            //

            Marshal.WriteInt64(AddrOfPinnedEntityChunks, 0, 0);
            Marshal.WriteIntPtr(AddrOfPinnedEntityChunks, 8, AddrOfPinnedBuffer);
            Marshal.WriteInt32(AddrOfPinnedEntityChunks, 12, DataToWrite);
            Marshal.WriteInt64(AddrOfPinnedEntityChunks, 16, 0);
            Marshal.WriteInt64(AddrOfPinnedEntityChunks, 24, 0);

            GlobalLog.Print("Calling UlSendHttpResponseEntityBody: AddrOfPinnedEntityChunks:" + Convert.ToString(AddrOfPinnedEntityChunks)
                            + " AddrOfPinnedBuffer:" + Convert.ToString(AddrOfPinnedBuffer)
                            + " DataToWrite:" + Convert.ToString(DataToWrite));

            //
            // issue unmanaged blocking call
            //

            int DataWritten = 0;

            int result =
                ComNetOS.IsWinNt ?

                UlSysApi.UlSendEntityBody(
                    m_AppPoolHandle,
                    m_RequestId,
                    UlConstants.UL_SEND_RESPONSE_FLAG_MORE_DATA,
                    1,
                    AddrOfPinnedEntityChunks,
                    ref DataWritten,
                    IntPtr.Zero)

            :

                UlVxdApi.UlSendHttpResponseEntityBody(
                    m_AppPoolHandle,
                    m_RequestId,
                    0,
                    1,
                    AddrOfPinnedEntityChunks,
                    ref DataWritten,
                    IntPtr.Zero);

            if (m_SendChunked)
            {
                //
                // data was copied into an unmanaged buffer, free it
                //

                Marshal.FreeHGlobal(AddrOfPinnedBuffer);
            }
            else
            {
                //
                // data wasn't copied unpin the pinned buffer
                //

                PinnedBuffer.Free();
            }

            Marshal.FreeHGlobal(AddrOfPinnedEntityChunks);

            GlobalLog.Print("UlSendHttpResponseEntityBody() DataWritten:" + Convert.ToString(DataWritten) + " DataToWrite:" + Convert.ToString(DataToWrite));

            if (result != NativeMethods.ERROR_SUCCESS)   //Win32.ERROR_CANCELLED || Win32.ERROR_BAD_COMMAND || NativeMethods.ERROR_INVALID_PARAMETER
            {
                throw new ProtocolViolationException(SR.GetString(SR.net_connclosed) + Convert.ToString(result));
            }

            //
            // double check the number of bytes written
            //

            if (DataWritten != DataToWrite)
            {
                throw new InvalidOperationException("sync UlSendHttpResponseEntityBody() failed to write all the data" +
                                                    " count:" + Convert.ToString(count) +
                                                    " DataWritten:" + Convert.ToString(DataWritten) +
                                                    " DataToWrite:" + Convert.ToString(DataToWrite) +
                                                    " m_AppPoolHandle:" + Convert.ToString(m_AppPoolHandle) +
                                                    " m_RequestId:" + Convert.ToString(m_RequestId) +
                                                    " err#" + Convert.ToString(result));
            }

            if (result != NativeMethods.ERROR_SUCCESS && result != NativeMethods.ERROR_HANDLE_EOF)
            {
                //
                // Consider: move all Exception string to system.txt for localization
                //
                throw new InvalidOperationException("sync UlSendHttpResponseEntityBody() failed, err#" + Convert.ToString(result));
            }

            if (m_ContentLength != -1)
            {
                //
                // keep track of the data transferred
                //

                m_ContentLength -= count;

                if (m_ContentLength == 0)
                {
                    //
                    // I should be able to call Close() at this point
                    //
                }
            }

            return; // DataToWrite;
        } // Write()
        BeginGetRequest(
            AsyncCallback requestCallback,
            Object stateObject)
        {
            //
            // Validation
            //

            if (m_AppPoolHandle == NativeMethods.INVALID_HANDLE_VALUE)
            {
                throw new InvalidOperationException("The AppPool handle is invalid");
            }

            //
            // prepare the ListenerAsyncResult object ( this will have it's own
            // event that the user can wait on for IO completion - which means we
            // need to signal it when IO completes )
            //

            GlobalLog.Print("BeginGetRequest() creating ListenerAsyncResult");

            ListenerAsyncResult AResult = new ListenerAsyncResult(
                stateObject,
                requestCallback);

            AutoResetEvent m_Event = new AutoResetEvent(false);

            Marshal.WriteIntPtr(
                AResult.m_Overlapped,
                Win32.OverlappedhEventOffset,
                m_Event.Handle);

            //
            // issue unmanaged 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
            //

            int result;

            for (;;)
            {
                //
                // check if we're in a healthy state
                //
                if (AResult.m_Retries++ > m_MaxRetries)
                {
                    throw new InvalidOperationException("UlReceiveHttpRequest() Too many retries");
                }

                result =
                    ComNetOS.IsWinNt ?

                    UlSysApi.UlReceiveHttpRequest(
                        m_AppPoolHandle,
                        AResult.m_RequestId,
                        UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY,
                        AResult.m_Buffer,
                        AResult.m_BufferSize,
                        ref AResult.m_BytesReturned,
                        AResult.m_Overlapped)

                :

                    UlVxdApi.UlReceiveHttpRequestHeaders(
                        m_AppPoolHandle,
                        AResult.m_RequestId,
                        0,
                        AResult.m_Buffer,
                        AResult.m_BufferSize,
                        ref AResult.m_BytesReturned,
                        AResult.m_Overlapped);

                GlobalLog.Print("UlReceiveHttpRequest() returns:"
                                + Convert.ToString(result));

                if (result == NativeMethods.ERROR_SUCCESS || result == NativeMethods.ERROR_IO_PENDING)
                {
                    //
                    // synchronous success or successfull pending: we are done
                    //

                    break;
                }

                if (result == NativeMethods.ERROR_INVALID_PARAMETER)
                {
                    //
                    // we might get this if somebody stole our RequestId,
                    // set RequestId to null
                    //

                    AResult.m_RequestId = 0;

                    //
                    // and start all over again with the buffer we
                    // just allocated
                    //

                    continue;
                }

                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
                    //

                    AResult.m_RequestId = Marshal.ReadInt64(IntPtrHelper.Add(AResult.m_Buffer, m_RequestIdOffset));

                    //
                    // allocate a new buffer of the required size
                    //

                    IntPtr NewBuffer = Marshal.AllocHGlobal(AResult.m_BytesReturned);

                    //
                    // copy the data already read from the old buffer into the
                    // new one
                    //

                    NativeMethods.CopyMemory(NewBuffer, AResult.m_Buffer, AResult.m_BufferSize);


                    //
                    // free the old buffer
                    //

                    Marshal.FreeHGlobal(AResult.m_Buffer);

                    //
                    // update buffer pointer and size
                    //

                    AResult.m_Buffer        = NewBuffer;
                    AResult.m_BufferSize    = AResult.m_BytesReturned;
                    AResult.m_BytesReturned = 0;

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

            //
            // we get here only if a break happens, i.e.
            // 1) syncronous completion
            // 2) the IO pended
            //

            if (result == NativeMethods.ERROR_SUCCESS)
            {
                //
                // set syncronous completion to true
                //

                AResult.Complete(true);

                //
                // and call the internal callback
                //

                WaitCallback(AResult, false);
            }
            else
            {
                //
                // create a new delegate
                // and spin a new thread from the thread pool to wake up when the
                // event is signaled and call the delegate
                //

                ThreadPool.RegisterWaitForSingleObject(
                    m_Event,
                    new WaitOrTimerCallback(WaitCallback),
                    AResult,
                    -1,
                    true);
            }

            GlobalLog.Print("returning AResult");

            return(AResult);
        } // StartListen()
        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()