/// <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); }
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); } }
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; } }
private MemoryPoolIterator2 GetIterator(MemoryPoolIterator2 begin, int displacement) { var result = begin; for (int i = 0; i < displacement; ++i) { result.Take(); } return(result); }
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); }
public void Reset() { _lockedStart = default(MemoryPoolIterator2); _lockedEnd = default(MemoryPoolIterator2); _bufferCount = 0; ByteCount = 0; SocketShutdownSend = false; SocketDisconnect = false; WriteStatus = 0; WriteError = null; ShutdownSendStatus = 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); }
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); } }
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); } }
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); } } } } }
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); } }
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)); }