Ejemplo n.º 1
0
        public void ByteByByteTest()
        {
            WritableBuffer writableBuffer = default;

            for (int i = 1; i <= 1024 * 1024; i++)
            {
                writableBuffer = _pipe.Writer.Alloc(100);
                writableBuffer.Advance(1);
                writableBuffer.Commit();

                Assert.Equal(i, _pipe.Length);
            }

            writableBuffer.FlushAsync();

            for (int i = 1024 * 1024 - 1; i >= 0; i--)
            {
                var result   = _pipe.Reader.ReadAsync().GetResult();
                var consumed = result.Buffer.Slice(1).Start;

                Assert.Equal(i + 1, result.Buffer.Length);

                _pipe.Reader.Advance(consumed, consumed);

                Assert.Equal(i, _pipe.Length);
            }
        }
Ejemplo n.º 2
0
        private static void WriteAsciiString(ref WritableBuffer buffer, ReadOnlySpan <char> value)
        {
            if (value == null || value.Length == 0)
            {
                return;
            }

            while (value.Length != 0)
            {
                buffer.Ensure();

                var span         = buffer.Buffer.Span;
                int bytesToWrite = Math.Min(value.Length, span.Length);

                // todo: Vector.Narrow

                for (int i = 0; i < bytesToWrite; i++)
                {
                    span[i] = (byte)value[i];
                }

                buffer.Advance(bytesToWrite);
                buffer.Commit();
                value = value.Slice(bytesToWrite);
            }
        }
Ejemplo n.º 3
0
        private void OnRead(UvStreamHandle handle, int status)
        {
            if (status == 0)
            {
                // A zero status does not indicate an error or connection end. It indicates
                // there is no data to be read right now.
                // See the note at http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb.
                _inputBuffer.Commit();
                return;
            }

            var normalRead = status > 0;
            var normalDone = status == EOF;
            var errorDone  = !(normalDone || normalRead);
            var readCount  = normalRead ? status : 0;

            if (!normalRead)
            {
                handle.ReadStop();
            }

            IOException error = null;

            if (errorDone)
            {
                Exception uvError;
                handle.Libuv.Check(status, out uvError);
                error = new IOException(uvError.Message, uvError);

                // REVIEW: Should we treat ECONNRESET as an error?
                // Ignore the error for now
                _input.CompleteWriter();
            }
            else
            {
                _inputBuffer.Advance(readCount);

                var task = _inputBuffer.FlushAsync();

                if (!task.IsCompleted)
                {
                    // If there's back pressure
                    handle.ReadStop();

                    // Resume reading when task continues
                    task.ContinueWith((t, state) => ((UvTcpConnection)state).StartReading(), this);
                }
            }

            if (normalDone || _input.Writing.IsCompleted)
            {
                _input.CompleteWriter();
            }
        }
Ejemplo n.º 4
0
        public void ReceiveBeginComplete(uint bytesTransferred)
        {
            if (bytesTransferred == 0 || _input.Writing.IsCompleted)
            {
                _input.CompleteWriter();
            }
            else
            {
                _buffer.Advance((int)bytesTransferred);
                _buffer.Commit();

                ProcessReceives();
            }
        }
Ejemplo n.º 5
0
        public void ReceiveBeginComplete(uint bytesTransferred)
        {
            if (bytesTransferred == 0 || _input.ReaderCompleted.IsCompleted)
            {
                _input.CompleteWriting();
            }
            else
            {
                _buffer.CommitBytes((int)bytesTransferred);
                _buffer.Commit();

                ProcessReceives();
            }
        }
Ejemplo n.º 6
0
        private static void WriteUtf8String(ref WritableBuffer buffer, ReadOnlySpan <char> value)
        {
            if (value == null || value.Length == 0)
            {
                return;
            }

            var encoder = TextEncoder.Utf8;

            while (value.Length != 0)
            {
                buffer.Ensure(4); // be able to write at least one character (worst case)

                var span = buffer.Buffer.Span;
                encoder.TryEncode(value, span, out int charsConsumed, out int bytesWritten);
                buffer.Advance(bytesWritten);
                buffer.Commit();
                value = value.Slice(charsConsumed);
            }
        }
Ejemplo n.º 7
0
        private void OnRead(UvStreamHandle handle, int status)
        {
            if (status == 0)
            {
                // EAGAIN/EWOULDBLOCK so just return the buffer.
                // http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb
                Debug.Assert(_currentWritableBuffer != null);
                _currentWritableBuffer.Value.Commit();
            }
            else if (status > 0)
            {
                Log.ConnectionRead(ConnectionId, status);

                Debug.Assert(_currentWritableBuffer != null);
                var currentWritableBuffer = _currentWritableBuffer.Value;
                currentWritableBuffer.Advance(status);
                var flushTask = currentWritableBuffer.FlushAsync();

                if (!flushTask.IsCompleted)
                {
                    // We wrote too many bytes to the reader, so pause reading and resume when
                    // we hit the low water mark.
                    _ = ApplyBackpressureAsync(flushTask);
                }
            }
            else
            {
                // Given a negative status, it's possible that OnAlloc wasn't called.
                _currentWritableBuffer?.Commit();
                _socket.ReadStop();

                IOException error = null;

                if (status == LibuvConstants.EOF)
                {
                    Log.ConnectionReadFin(ConnectionId);
                }
                else
                {
                    handle.Libuv.Check(status, out var uvError);

                    // Log connection resets at a lower (Debug) level.
                    if (LibuvConstants.IsConnectionReset(status))
                    {
                        Log.ConnectionReset(ConnectionId);
                        error = new ConnectionResetException(uvError.Message, uvError);
                    }
                    else
                    {
                        Log.ConnectionError(ConnectionId, uvError);
                        error = new IOException(uvError.Message, uvError);
                    }
                }

                // Complete after aborting the connection
                Input.Complete(error);
            }

            // Cleanup state from last OnAlloc. This is safe even if OnAlloc wasn't called.
            _currentWritableBuffer = null;
            _bufferHandle.Dispose();
        }
Ejemplo n.º 8
0
        private async void OnRead(UvStreamHandle handle, int status)
        {
            if (status == 0)
            {
                // A zero status does not indicate an error or connection end. It indicates
                // there is no data to be read right now.
                // See the note at http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb.
                _inputBuffer?.Commit();
                _inputBuffer = null;
                return;
            }

            var normalRead = status > 0;
            var normalDone = status == EOF;
            var errorDone  = !(normalDone || normalRead);
            var readCount  = normalRead ? status : 0;

            if (!normalRead)
            {
                handle.ReadStop();
            }

            IOException error = null;

            if (errorDone)
            {
                Exception uvError;
                handle.Libuv.Check(status, out uvError);
                error = new IOException(uvError.Message, uvError);

                _inputBuffer?.Commit();

                // REVIEW: Should we treat ECONNRESET as an error?
                // Ignore the error for now
                _input.Writer.Complete();
            }
            else
            {
                var inputBuffer = _inputBuffer.Value;
                _inputBuffer = null;

                inputBuffer.Advance(readCount);
                inputBuffer.Commit();

                // Flush if there was data
                if (readCount > 0)
                {
                    var awaitable = inputBuffer.FlushAsync();

                    if (!awaitable.IsCompleted)
                    {
                        // If there's back pressure
                        handle.ReadStop();

                        // Resume reading when the awaitable completes
                        if (await awaitable)
                        {
                            StartReading();
                        }
                        else
                        {
                            // We're done writing, the reading is gone
                            _input.Writer.Complete();
                        }
                    }
                }
            }

            if (normalDone)
            {
                _input.Writer.Complete();
            }
        }
Ejemplo n.º 9
0
 public void Commit() => _innerBuffer.Commit();