/// <summary>
        /// Read the percent-encoding and try unescape it.
        ///
        /// The operation first peek at the character the <paramref name="scan"/>
        /// iterator points at. If it is % the <paramref name="scan"/> is then
        /// moved on to scan the following to characters. If the two following
        /// characters are hexadecimal literals they will be unescaped and the
        /// value will be returned.
        ///
        /// If the first character is not % the <paramref name="scan"/> iterator
        /// will be removed beyond the location of % and -1 will be returned.
        ///
        /// If the following two characters can't be successfully unescaped the
        /// <paramref name="scan"/> iterator will be move behind the % and -1
        /// will be returned.
        /// </summary>
        /// <param name="scan">The value to read</param>
        /// <param name="end">The end of the sequence</param>
        /// <returns>The unescaped byte if success. Otherwise return -1.</returns>
        private static int UnescapePercentEncoding(ref MemoryPoolIterator2 scan, MemoryPoolIterator2 end)
        {
            if (scan.Take() != '%')
            {
                return(-1);
            }

            var probe = scan;

            int value1 = ReadHex(ref probe, end);

            if (value1 == -1)
            {
                return(-1);
            }

            int value2 = ReadHex(ref probe, end);

            if (value2 == -1)
            {
                return(-1);
            }

            if (SkipUnescape(value1, value2))
            {
                return(-1);
            }

            scan = probe;
            return((value1 << 4) + value2);
        }
Beispiel #2
0
        private void ProducingCompleteNoPreComplete(MemoryPoolIterator2 end)
        {
            MemoryPoolBlock2 blockToReturn = null;

            lock (_returnLock)
            {
                Debug.Assert(!_lastStart.IsDefault);

                // If the socket has been closed, return the produced blocks
                // instead of advancing the now non-existent tail.
                if (_tail != null)
                {
                    _tail     = end.Block;
                    _tail.End = end.Index;
                }
                else
                {
                    blockToReturn = _lastStart.Block;
                }

                _lastStart = default(MemoryPoolIterator2);
            }

            if (blockToReturn != null)
            {
                ThreadPool.QueueUserWorkItem(_returnBlocks, blockToReturn);
            }
        }
 private static void Copy(MemoryPoolIterator2 head, MemoryPoolIterator2 tail, ref MemoryPoolIterator2 writer)
 {
     while (!CompareIterators(ref head, ref tail))
     {
         writer.Put((byte)head.Take());
     }
 }
        /// <summary>
        /// Read the next char and convert it into hexadecimal value.
        ///
        /// The <paramref name="scan"/> iterator will be moved to the next
        /// byte no matter no matter whether the operation successes.
        /// </summary>
        /// <param name="scan">The value to read</param>
        /// <param name="end">The end of the sequence</param>
        /// <returns>The hexadecimal value if successes, otherwise -1.</returns>
        private static int ReadHex(ref MemoryPoolIterator2 scan, MemoryPoolIterator2 end)
        {
            if (CompareIterators(ref scan, ref end))
            {
                return(-1);
            }

            var value  = scan.Take();
            var isHead = (((value >= '0') && (value <= '9')) ||
                          ((value >= 'A') && (value <= 'F')) ||
                          ((value >= 'a') && (value <= 'f')));

            if (!isHead)
            {
                return(-1);
            }

            if (value <= '9')
            {
                return(value - '0');
            }
            else if (value <= 'F')
            {
                return((value - 'A') + 10);
            }
            else // a - f
            {
                return((value - 'a') + 10);
            }
        }
Beispiel #5
0
        public unsafe void Write(
            UvStreamHandle handle,
            MemoryPoolIterator2 start,
            MemoryPoolIterator2 end,
            int nBuffers,
            Action <UvWriteReq, int, Exception, object> callback,
            object state)
        {
            try
            {
                // add GCHandle to keeps this SafeHandle alive while request processing
                _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal));

                var pBuffers = (Libuv.uv_buf_t *)_bufs;
                if (nBuffers > BUFFER_COUNT)
                {
                    // create and pin buffer array when it's larger than the pre-allocated one
                    var bufArray = new Libuv.uv_buf_t[nBuffers];
                    var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned);
                    _pins.Add(gcHandle);
                    pBuffers = (Libuv.uv_buf_t *)gcHandle.AddrOfPinnedObject();
                }

                var block = start.Block;
                for (var index = 0; index < nBuffers; index++)
                {
                    var blockStart = block == start.Block ? start.Index : block.Data.Offset;
                    var blockEnd   = block == end.Block ? end.Index : block.Data.Offset + block.Data.Count;

                    // create and pin each segment being written
                    pBuffers[index] = Libuv.buf_init(
                        block.Pin() + blockStart,
                        blockEnd - blockStart);

                    block = block.Next;
                }

                _callback = callback;
                _state    = state;
                _uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb);
            }
            catch
            {
                _callback = null;
                _state    = null;
                Unpin(this);

                var block = start.Block;
                for (var index = 0; index < nBuffers; index++)
                {
                    block.Unpin();
                    block = block.Next;
                }

                throw;
            }
        }
Beispiel #6
0
        private MemoryPoolIterator2 GetIterator(MemoryPoolIterator2 begin, int displacement)
        {
            var result = begin;

            for (int i = 0; i < displacement; ++i)
            {
                result.Take();
            }

            return(result);
        }
Beispiel #7
0
        public void ProducingComplete(MemoryPoolIterator2 end)
        {
            Debug.Assert(!_lastStart.IsDefault);

            int bytesProduced, buffersIncluded;

            BytesBetween(_lastStart, end, out bytesProduced, out buffersIncluded);

            lock (_contextLock)
            {
                _numBytesPreCompleted += bytesProduced;
            }

            ProducingCompleteNoPreComplete(end);
        }
Beispiel #8
0
            public void Reset()
            {
                _lockedStart = default(MemoryPoolIterator2);
                _lockedEnd   = default(MemoryPoolIterator2);
                _bufferCount = 0;
                ByteCount    = 0;

                SocketShutdownSend = false;
                SocketDisconnect   = false;

                WriteStatus = 0;
                WriteError  = null;

                ShutdownSendStatus = 0;
            }
Beispiel #9
0
        public void ProducingComplete(MemoryPoolIterator2 end)
        {
            var block = _producingBlock;

            while (block != end.Block)
            {
                _outputStream.Write(block.Data.Array, block.Data.Offset, block.Data.Count);

                var returnBlock = block;
                block = block.Next;
                returnBlock.Pool?.Return(returnBlock);
            }

            _outputStream.Write(end.Block.Array, end.Block.Data.Offset, end.Index - end.Block.Data.Offset);
            end.Block.Pool?.Return(end.Block);
        }
Beispiel #10
0
        public MemoryPoolIterator2 ProducingStart()
        {
            lock (_returnLock)
            {
                Debug.Assert(_lastStart.IsDefault);

                if (_tail == null)
                {
                    throw new IOException("The socket has been closed.");
                }

                _lastStart = new MemoryPoolIterator2(_tail, _tail.End);

                return(_lastStart);
            }
        }
Beispiel #11
0
        public void ProducingStartAndProducingCompleteCanBeUsedDirectly()
        {
            int nBuffers  = 0;
            var nBufferWh = new ManualResetEventSlim();

            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    nBuffers = buffers;
                    nBufferWh.Set();
                    triggerCompleted(0);
                    return(0);
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                using (var memory = new MemoryPool2())
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue <UvWriteReq>());

                    // block 1
                    var start = socketOutput.ProducingStart();
                    start.Block.End = start.Block.Data.Offset + start.Block.Data.Count;

                    // block 2
                    var block2 = memory.Lease();
                    block2.End       = block2.Data.Offset + block2.Data.Count;
                    start.Block.Next = block2;

                    var end = new MemoryPoolIterator2(block2, block2.End);

                    socketOutput.ProducingComplete(end);

                    // A call to Write is required to ensure a write is scheduled
                    socketOutput.WriteAsync(default(ArraySegment <byte>));

                    Assert.True(nBufferWh.Wait(1000));
                    Assert.Equal(2, nBuffers);
                }
        }
Beispiel #12
0
            private void LockWrite()
            {
                var head = Self._head;
                var tail = Self._tail;

                if (head == null || tail == null)
                {
                    // ReturnAllBlocks has already bee called. Nothing to do here.
                    // Write will no-op since _byteCount will remain 0.
                    return;
                }

                _lockedStart = new MemoryPoolIterator2(head, head.Start);
                _lockedEnd   = new MemoryPoolIterator2(tail, tail.End);

                BytesBetween(_lockedStart, _lockedEnd, out ByteCount, out _bufferCount);
            }
 public void CopyTo(ref MemoryPoolIterator2 output)
 {
     CopyToFast(ref output);
     if (MaybeUnknown != null)
     {
         foreach (var kv in MaybeUnknown)
         {
             foreach (var value in kv.Value)
             {
                 if (value != null)
                 {
                     output.CopyFrom(_CrLf, 0, 2);
                     output.CopyFromAscii(kv.Key);
                     output.CopyFrom(_colonSpace, 0, 2);
                     output.CopyFromAscii(value);
                 }
             }
         }
     }
 }
Beispiel #14
0
        private static void BytesBetween(MemoryPoolIterator2 start, MemoryPoolIterator2 end, out int bytes, out int buffers)
        {
            if (start.Block == end.Block)
            {
                bytes   = end.Index - start.Index;
                buffers = 1;
                return;
            }

            bytes   = start.Block.Data.Offset + start.Block.Data.Count - start.Index;
            buffers = 1;

            for (var block = start.Block.Next; block != end.Block; block = block.Next)
            {
                bytes += block.Data.Count;
                buffers++;
            }

            bytes += end.Index - end.Block.Data.Offset;
            buffers++;
        }
        /// <summary>
        /// Unescapes the string between given memory iterators in place.
        /// </summary>
        /// <param name="start">The iterator points to the beginning of the sequence.</param>
        /// <param name="end">The iterator points to the byte behind the end of the sequence.</param>
        /// <returns>The iterator points to the byte behind the end of the processed sequence.</returns>
        public static MemoryPoolIterator2 Unescape(MemoryPoolIterator2 start, MemoryPoolIterator2 end)
        {
            // the slot to read the input
            var reader = start;

            // the slot to write the unescaped byte
            var writer = reader;

            while (true)
            {
                if (CompareIterators(ref reader, ref end))
                {
                    return(writer);
                }

                if (reader.Peek() == '%')
                {
                    var decodeReader = reader;

                    // If decoding process succeeds, the writer iterator will be moved
                    // to the next write-ready location. On the other hand if the scanned
                    // percent-encodings cannot be interpreted as sequence of UTF-8 octets,
                    // these bytes should be copied to output as is.
                    // The decodeReader iterator is always moved to the first byte not yet
                    // be scanned after the process. A failed decoding means the chars
                    // between the reader and decodeReader can be copied to output untouched.
                    if (!DecodeCore(ref decodeReader, ref writer, end))
                    {
                        Copy(reader, decodeReader, ref writer);
                    }

                    reader = decodeReader;
                }
                else
                {
                    writer.Put((byte)reader.Take());
                }
            }
        }
        public void ConsumingComplete(
            MemoryPoolIterator2 consumed,
            MemoryPoolIterator2 examined)
        {
            MemoryPoolBlock2 returnStart = null;
            MemoryPoolBlock2 returnEnd   = null;

            lock (_sync)
            {
                if (!consumed.IsDefault)
                {
                    returnStart = _head;
                    returnEnd   = consumed.Block;
                    _head       = consumed.Block;
                    _head.Start = consumed.Index;
                }
                if (!examined.IsDefault &&
                    examined.IsEnd &&
                    RemoteIntakeFin == false &&
                    _awaitableError == null)
                {
                    _manualResetEvent.Reset();

                    var awaitableState = Interlocked.CompareExchange(
                        ref _awaitableState,
                        _awaitableIsNotCompleted,
                        _awaitableIsCompleted);
                }
            }
            while (returnStart != returnEnd)
            {
                var returnBlock = returnStart;
                returnStart = returnStart.Next;
                returnBlock.Pool?.Return(returnBlock);
            }
        }
Beispiel #17
0
        public void ServerPipeListenForConnections()
        {
            var loop             = new UvLoopHandle(_logger);
            var serverListenPipe = new UvPipeHandle(_logger);

            loop.Init(_uv);
            serverListenPipe.Init(loop, false);
            serverListenPipe.Bind(@"\\.\pipe\ServerPipeListenForConnections");
            serverListenPipe.Listen(128, (_1, status, error, _2) =>
            {
                var serverConnectionPipe = new UvPipeHandle(_logger);
                serverConnectionPipe.Init(loop, true);
                try
                {
                    serverListenPipe.Accept(serverConnectionPipe);
                }
                catch (Exception)
                {
                    serverConnectionPipe.Dispose();
                    return;
                }

                var writeRequest = new UvWriteReq(new KestrelTrace(new TestKestrelTrace()));
                writeRequest.Init(loop);
                var block = MemoryPoolBlock2.Create(
                    new ArraySegment <byte>(new byte[] { 1, 2, 3, 4 }),
                    dataPtr: IntPtr.Zero,
                    pool: null,
                    slab: null);
                var start = new MemoryPoolIterator2(block, 0);
                var end   = new MemoryPoolIterator2(block, block.Data.Count);
                writeRequest.Write(
                    serverConnectionPipe,
                    start,
                    end,
                    1,
                    (_3, status2, error2, _4) =>
                {
                    writeRequest.Dispose();
                    serverConnectionPipe.Dispose();
                    serverListenPipe.Dispose();
                    block.Unpin();
                },
                    null);
            }, null);

            var worker = new Thread(() =>
            {
                var loop2 = new UvLoopHandle(_logger);
                var clientConnectionPipe = new UvPipeHandle(_logger);
                var connect = new UvConnectRequest(new KestrelTrace(new TestKestrelTrace()));

                loop2.Init(_uv);
                clientConnectionPipe.Init(loop2, true);
                connect.Init(loop2);
                connect.Connect(clientConnectionPipe, @"\\.\pipe\ServerPipeListenForConnections", (_1, status, error, _2) =>
                {
                    var buf = loop2.Libuv.buf_init(Marshal.AllocHGlobal(8192), 8192);

                    connect.Dispose();
                    clientConnectionPipe.ReadStart(
                        (_3, cb, _4) => buf,
                        (_3, status2, _4) =>
                    {
                        if (status2 == 0)
                        {
                            clientConnectionPipe.Dispose();
                        }
                    },
                        null);
                }, null);
                loop2.Run();
                loop2.Dispose();
            });

            worker.Start();
            loop.Run();
            loop.Dispose();
            worker.Join();
        }
        public async Task SocketCanReadAndWrite()
        {
            var loop = new UvLoopHandle(_logger);

            loop.Init(_uv);
            var tcp = new UvTcpHandle(_logger);

            tcp.Init(loop);
            var address = ServerAddress.FromUrl("http://localhost:54321/");

            tcp.Bind(address);
            tcp.Listen(10, (_, status, error, state) =>
            {
                Console.WriteLine("Connected");
                var tcp2 = new UvTcpHandle(_logger);
                tcp2.Init(loop);
                tcp.Accept(tcp2);
                var data = Marshal.AllocCoTaskMem(500);
                tcp2.ReadStart(
                    (a, b, c) => tcp2.Libuv.buf_init(data, 500),
                    (__, nread, state2) =>
                {
                    if (nread <= 0)
                    {
                        tcp2.Dispose();
                    }
                    else
                    {
                        for (var x = 0; x < 2; x++)
                        {
                            var req = new UvWriteReq(new KestrelTrace(new TestKestrelTrace()));
                            req.Init(loop);
                            var block = MemoryPoolBlock2.Create(
                                new ArraySegment <byte>(new byte[] { 65, 66, 67, 68, 69 }),
                                dataPtr: IntPtr.Zero,
                                pool: null,
                                slab: null);
                            var start = new MemoryPoolIterator2(block, 0);
                            var end   = new MemoryPoolIterator2(block, block.Data.Count);
                            req.Write(
                                tcp2,
                                start,
                                end,
                                1,
                                (_1, _2, _3, _4) =>
                            {
                                block.Unpin();
                            },
                                null);
                        }
                    }
                },
                    null);
                tcp.Dispose();
            }, null);
            Console.WriteLine("Task.Run");
            var t = Task.Run(async() =>
            {
                var socket = new Socket(
                    AddressFamily.InterNetwork,
                    SocketType.Stream,
                    ProtocolType.Tcp);
#if DNX451
                await Task.Factory.FromAsync(
                    socket.BeginConnect,
                    socket.EndConnect,
                    new IPEndPoint(IPAddress.Loopback, 54321),
                    null,
                    TaskCreationOptions.None);
                await Task.Factory.FromAsync(
                    socket.BeginSend,
                    socket.EndSend,
                    new[] { new ArraySegment <byte>(new byte[] { 1, 2, 3, 4, 5 }) },
                    SocketFlags.None,
                    null,
                    TaskCreationOptions.None);
#else
                await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 54321));
                await socket.SendAsync(new[] { new ArraySegment <byte>(new byte[] { 1, 2, 3, 4, 5 }) },
                                       SocketFlags.None);
#endif
                socket.Shutdown(SocketShutdown.Send);
                var buffer = new ArraySegment <byte>(new byte[2048]);
                while (true)
                {
#if DNX451
                    var count = await Task.Factory.FromAsync(
                        socket.BeginReceive,
                        socket.EndReceive,
                        new[] { buffer },
                        SocketFlags.None,
                        null,
                        TaskCreationOptions.None);
#else
                    var count = await socket.ReceiveAsync(new[] { buffer }, SocketFlags.None);
#endif
                    Console.WriteLine("count {0} {1}",
                                      count,
                                      System.Text.Encoding.ASCII.GetString(buffer.Array, 0, count));
                    if (count <= 0)
                    {
                        break;
                    }
                }
                socket.Dispose();
            });

            loop.Run();
            loop.Dispose();
            await t;
        }
 private void AssertIterator(MemoryPoolIterator2 iter, MemoryPoolBlock2 block, int index)
 {
     Assert.Same(block, iter.Block);
     Assert.Equal(index, iter.Index);
 }
        public static MemoryPoolIterator2 Add(this MemoryPoolIterator2 iterator, int count)
        {
            int actual;

            return(iterator.CopyTo(new byte[count], 0, count, out actual));
        }
        /// <summary>
        /// Unescape the percent-encodings
        /// </summary>
        /// <param name="reader">The iterator point to the first % char</param>
        /// <param name="writer">The place to write to</param>
        /// <param name="end">The end of the sequence</param>
        private static bool DecodeCore(ref MemoryPoolIterator2 reader, ref MemoryPoolIterator2 writer, MemoryPoolIterator2 end)
        {
            // preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets,
            // bytes from this till the last scanned one will be copied to the memory pointed by writer.
            var byte1 = UnescapePercentEncoding(ref reader, end);

            if (byte1 == -1)
            {
                return(false);
            }

            if (byte1 <= 0x7F)
            {
                // first byte < U+007f, it is a single byte ASCII
                writer.Put((byte)byte1);
                return(true);
            }

            int byte2 = 0, byte3 = 0, byte4 = 0;

            // anticipate more bytes
            var currentDecodeBits = 0;
            var byteCount         = 1;
            var expectValueMin    = 0;

            if ((byte1 & 0xE0) == 0xC0)
            {
                // 110x xxxx, expect one more byte
                currentDecodeBits = byte1 & 0x1F;
                byteCount         = 2;
                expectValueMin    = 0x80;
            }
            else if ((byte1 & 0xF0) == 0xE0)
            {
                // 1110 xxxx, expect two more bytes
                currentDecodeBits = byte1 & 0x0F;
                byteCount         = 3;
                expectValueMin    = 0x800;
            }
            else if ((byte1 & 0xF8) == 0xF0)
            {
                // 1111 0xxx, expect three more bytes
                currentDecodeBits = byte1 & 0x07;
                byteCount         = 4;
                expectValueMin    = 0x10000;
            }
            else
            {
                // invalid first byte
                return(false);
            }

            var remainingBytes = byteCount - 1;

            while (remainingBytes > 0)
            {
                // read following three chars
                if (CompareIterators(ref reader, ref end))
                {
                    return(false);
                }

                var nextItr  = reader;
                var nextByte = UnescapePercentEncoding(ref nextItr, end);
                if (nextByte == -1)
                {
                    return(false);
                }

                if ((nextByte & 0xC0) != 0x80)
                {
                    // the follow up byte is not in form of 10xx xxxx
                    return(false);
                }

                currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F);
                remainingBytes--;

                if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F)
                {
                    // this is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that
                    // are not allowed in UTF-8;
                    return(false);
                }

                if (remainingBytes == 2 && currentDecodeBits >= 0x110)
                {
                    // this is going to be out of the upper Unicode bound 0x10FFFF.
                    return(false);
                }

                reader = nextItr;
                if (byteCount - remainingBytes == 2)
                {
                    byte2 = nextByte;
                }
                else if (byteCount - remainingBytes == 3)
                {
                    byte3 = nextByte;
                }
                else if (byteCount - remainingBytes == 4)
                {
                    byte4 = nextByte;
                }
            }

            if (currentDecodeBits < expectValueMin)
            {
                // overlong encoding (e.g. using 2 bytes to encode something that only needed 1).
                return(false);
            }

            // all bytes are verified, write to the output
            if (byteCount > 0)
            {
                writer.Put((byte)byte1);
            }
            if (byteCount > 1)
            {
                writer.Put((byte)byte2);
            }
            if (byteCount > 2)
            {
                writer.Put((byte)byte3);
            }
            if (byteCount > 3)
            {
                writer.Put((byte)byte4);
            }

            return(true);
        }
 private static bool CompareIterators(ref MemoryPoolIterator2 lhs, ref MemoryPoolIterator2 rhs)
 {
     // uses ref parameter to save cost of copying
     return((lhs.Block == rhs.Block) && (lhs.Index == rhs.Index));
 }