protected internal override ReadOnlySequence <byte> _GetSequence(int index, int count)
        {
            if (0u >= (uint)count)
            {
                return(ReadOnlySequence <byte> .Empty);
            }

            var buffers = ThreadLocalList <ReadOnlyMemory <byte> > .NewInstance(_componentCount);

            try
            {
                int i = ToComponentIndex0(index);
                while (count > 0)
                {
                    ComponentEntry c           = _components[i];
                    IByteBuffer    s           = c.Buffer;
                    int            localLength = Math.Min(count, c.EndOffset - index);
                    switch (s.IoBufferCount)
                    {
                    case 0:
                        ThrowHelper.ThrowNotSupportedException();
                        break;

                    case 1:
                        if (s.IsSingleIoBuffer)
                        {
                            buffers.Add(s.GetReadableMemory(c.Idx(index), localLength));
                        }
                        else
                        {
                            var sequence0 = s.GetSequence(c.Idx(index), localLength);
                            foreach (var memory in sequence0)
                            {
                                buffers.Add(memory);
                            }
                        }
                        break;

                    default:
                        var sequence = s.GetSequence(c.Idx(index), localLength);
                        foreach (var memory in sequence)
                        {
                            buffers.Add(memory);
                        }
                        break;
                    }

                    index += localLength;
                    count -= localLength;
                    i++;
                }

                return(ReadOnlyBufferSegment.Create(buffers));
            }
            finally
            {
                buffers.Return();
            }
        }
        protected internal override ReadOnlyMemory <byte> _GetReadableMemory(int index, int count)
        {
            if (0u >= (uint)count)
            {
                return(ReadOnlyMemory <byte> .Empty);
            }

            switch (_componentCount)
            {
            case 0:
                return(ReadOnlyMemory <byte> .Empty);

            case 1:
                ComponentEntry c   = _components[0];
                IByteBuffer    buf = c.Buffer;
                if (buf.IsSingleIoBuffer)
                {
                    return(buf.GetReadableMemory(c.Idx(index), count));
                }
                break;
            }

            var merged  = new Memory <byte>(new byte[count]);
            var buffers = GetSequence(index, count);

            int offset = 0;

            foreach (var buf in buffers)
            {
                Debug.Assert(merged.Length - offset >= buf.Length);

                buf.CopyTo(merged.Slice(offset));
                offset += buf.Length;
            }

            return(merged);
        }
        /// <summary>Unwraps inbound SSL records.</summary>
        private void Unwrap(IChannelHandlerContext ctx, IByteBuffer packet, int offset, int length)
        {
            bool pending = false;

            IByteBuffer outputBuffer = null;

            try
            {
#if NETCOREAPP || NETSTANDARD_2_0_GREATER
                ReadOnlyMemory <byte> inputIoBuffer = packet.GetReadableMemory(offset, length);
                _mediationStream.SetSource(inputIoBuffer, ctx.Allocator);
#else
                ArraySegment <byte> inputIoBuffer = packet.GetIoBuffer(offset, length);
                _mediationStream.SetSource(inputIoBuffer.Array, inputIoBuffer.Offset, ctx.Allocator);
#endif
                if (!EnsureAuthenticationCompleted(ctx))
                {
                    _mediationStream.ExpandSource(length);
                    return;
                }

                _mediationStream.ExpandSource(length);

                var currentReadFuture = _pendingSslStreamReadFuture;

                if (currentReadFuture is object)
                {
                    // restoring context from previous read
                    Debug.Assert(_pendingSslStreamReadBuffer is object);

                    outputBuffer = _pendingSslStreamReadBuffer;
                    var outputBufferLength = outputBuffer.WritableBytes;

                    _pendingSslStreamReadFuture = null;
                    _pendingSslStreamReadBuffer = null;

                    // there was a read pending already, so we make sure we completed that first
                    if (currentReadFuture.IsCompleted)
                    {
                        if (currentReadFuture.IsFailure())
                        {
                            // The decryption operation failed
                            ExceptionDispatchInfo.Capture(currentReadFuture.Exception.InnerException).Throw();
                        }
                        int read = currentReadFuture.Result;
                        if (0u >= (uint)read)
                        {
                            // Stream closed
                            NotifyClosePromise(null);
                            return;
                        }

                        // Now output the result of previous read and decide whether to do an extra read on the same source or move forward
                        outputBuffer.Advance(read);
                        _firedChannelRead = true;
                        ctx.FireChannelRead(outputBuffer);

                        currentReadFuture = null;
                        outputBuffer      = null;

                        if (0u >= (uint)_mediationStream.SourceReadableBytes)
                        {
                            // we just made a frame available for reading but there was already pending read so SslStream read it out to make further progress there

                            if (read < outputBufferLength)
                            {
                                // SslStream returned non-full buffer and there's no more input to go through ->
                                // typically it means SslStream is done reading current frame so we skip
                                return;
                            }

                            // we've read out `read` bytes out of current packet to fulfil previously outstanding read
                            outputBufferLength = length - read;
                            if ((uint)(outputBufferLength - 1) > SharedConstants.TooBigOrNegative) // <= 0
                            {
                                // after feeding to SslStream current frame it read out more bytes than current packet size
                                outputBufferLength = c_fallbackReadBufferSize;
                            }
                        }
                        outputBuffer      = ctx.Allocator.Buffer(outputBufferLength);
                        currentReadFuture = ReadFromSslStreamAsync(outputBuffer, outputBufferLength);
                    }
                }
                else
                {
                    // there was no pending read before so we estimate buffer of `length` bytes to be sufficient
                    outputBuffer      = ctx.Allocator.Buffer(length);
                    currentReadFuture = ReadFromSslStreamAsync(outputBuffer, length);
                }

                // read out the rest of SslStream's output (if any) at risk of going async
                // using FallbackReadBufferSize - buffer size we're ok to have pinned with the SslStream until it's done reading
                while (true)
                {
                    if (currentReadFuture is object)
                    {
                        if (!currentReadFuture.IsCompleted)
                        {
                            break;
                        }
                        if (currentReadFuture.IsFailure())
                        {
                            // The decryption operation failed
                            ExceptionDispatchInfo.Capture(currentReadFuture.Exception.InnerException).Throw();
                        }
                        int read = currentReadFuture.Result;

                        if (0u >= (uint)read)
                        {
                            // Stream closed
                            NotifyClosePromise(null);
                            return;
                        }

                        outputBuffer.Advance(read);
                        _firedChannelRead = true;
                        ctx.FireChannelRead(outputBuffer);

                        currentReadFuture = null;
                        outputBuffer      = null;
                        if (0u >= (uint)_mediationStream.SourceReadableBytes)
                        {
                            return;
                        }
                    }
                    outputBuffer      = ctx.Allocator.Buffer(c_fallbackReadBufferSize);
                    currentReadFuture = ReadFromSslStreamAsync(outputBuffer, c_fallbackReadBufferSize);
                }

                pending = true;
                _pendingSslStreamReadBuffer = outputBuffer;
                _pendingSslStreamReadFuture = currentReadFuture;
            }
            finally
            {
                _mediationStream.ResetSource(ctx.Allocator);
                if (!pending && outputBuffer is object)
                {
                    if (outputBuffer.IsReadable())
                    {
                        _firedChannelRead = true;
                        ctx.FireChannelRead(outputBuffer);
                    }
                    else
                    {
                        outputBuffer.SafeRelease();
                    }
                }
            }
        }
Пример #4
0
        /// <summary>Unwraps inbound SSL records.</summary>
        private void Unwrap(IChannelHandlerContext ctx, IByteBuffer packet, int offset, int length, List <int> packetLengths, List <object> output)
        {
            if (0u >= (uint)packetLengths.Count)
            {
                ThrowHelper.ThrowArgumentException();
            }

            //bool notifyClosure = false; // todo: netty/issues/137
            bool pending = false;

            IByteBuffer outputBuffer = null;

            try
            {
#if NETCOREAPP || NETSTANDARD_2_0_GREATER
                ReadOnlyMemory <byte> inputIoBuffer = packet.GetReadableMemory(offset, length);
                _mediationStream.SetSource(inputIoBuffer);
#else
                ArraySegment <byte> inputIoBuffer = packet.GetIoBuffer(offset, length);
                _mediationStream.SetSource(inputIoBuffer.Array, inputIoBuffer.Offset);
#endif

                int packetIndex = 0;

                while (!EnsureAuthenticated(ctx))
                {
                    _mediationStream.ExpandSource(packetLengths[packetIndex]);
                    if ((uint)(++packetIndex) >= (uint)packetLengths.Count)
                    {
                        return;
                    }
                }

                var currentReadFuture = _pendingSslStreamReadFuture;

                int outputBufferLength;

                if (currentReadFuture is object)
                {
                    // restoring context from previous read
                    Debug.Assert(_pendingSslStreamReadBuffer is object);

                    outputBuffer       = _pendingSslStreamReadBuffer;
                    outputBufferLength = outputBuffer.WritableBytes;

                    _pendingSslStreamReadFuture = null;
                    _pendingSslStreamReadBuffer = null;
                }
                else
                {
                    outputBufferLength = 0;
                }

                // go through packets one by one (because SslStream does not consume more than 1 packet at a time)
                for (; packetIndex < packetLengths.Count; packetIndex++)
                {
                    int currentPacketLength = packetLengths[packetIndex];
                    _mediationStream.ExpandSource(currentPacketLength);

                    if (currentReadFuture is object)
                    {
                        // there was a read pending already, so we make sure we completed that first

                        if (!currentReadFuture.IsCompleted)
                        {
                            // we did feed the whole current packet to SslStream yet it did not produce any result -> move to the next packet in input

                            continue;
                        }

                        int read = currentReadFuture.Result;

                        if (0u >= (uint)read)
                        {
                            //Stream closed
                            return;
                        }

                        // Now output the result of previous read and decide whether to do an extra read on the same source or move forward
                        AddBufferToOutput(outputBuffer, read, output);

                        currentReadFuture = null;
                        outputBuffer      = null;
                        if (0u >= (uint)_mediationStream.SourceReadableBytes)
                        {
                            // we just made a frame available for reading but there was already pending read so SslStream read it out to make further progress there

                            if (read < outputBufferLength)
                            {
                                // SslStream returned non-full buffer and there's no more input to go through ->
                                // typically it means SslStream is done reading current frame so we skip
                                continue;
                            }

                            // we've read out `read` bytes out of current packet to fulfil previously outstanding read
                            outputBufferLength = currentPacketLength - read;
                            if ((uint)(outputBufferLength - 1) > SharedConstants.TooBigOrNegative) // <= 0
                            {
                                // after feeding to SslStream current frame it read out more bytes than current packet size
                                outputBufferLength = c_fallbackReadBufferSize;
                            }
                        }
                        else
                        {
                            // SslStream did not get to reading current frame so it completed previous read sync
                            // and the next read will likely read out the new frame
                            outputBufferLength = currentPacketLength;
                        }
                    }
                    else
                    {
                        // there was no pending read before so we estimate buffer of `currentPacketLength` bytes to be sufficient
                        outputBufferLength = currentPacketLength;
                    }

                    outputBuffer      = ctx.Allocator.Buffer(outputBufferLength);
                    currentReadFuture = ReadFromSslStreamAsync(outputBuffer, outputBufferLength);
                }

                // read out the rest of SslStream's output (if any) at risk of going async
                // using FallbackReadBufferSize - buffer size we're ok to have pinned with the SslStream until it's done reading
                while (true)
                {
                    if (currentReadFuture is object)
                    {
                        if (!currentReadFuture.IsCompleted)
                        {
                            break;
                        }
                        int read = currentReadFuture.Result;
                        AddBufferToOutput(outputBuffer, read, output);
                    }
                    outputBuffer      = ctx.Allocator.Buffer(c_fallbackReadBufferSize);
                    currentReadFuture = ReadFromSslStreamAsync(outputBuffer, c_fallbackReadBufferSize);
                }

                pending = true;
                _pendingSslStreamReadBuffer = outputBuffer;
                _pendingSslStreamReadFuture = currentReadFuture;
            }
            finally
            {
                _mediationStream.ResetSource();
                if (!pending && outputBuffer is object)
                {
                    if (outputBuffer.IsReadable())
                    {
                        output.Add(outputBuffer);
                    }
                    else
                    {
                        outputBuffer.SafeRelease();
                    }
                }
            }
        }
Пример #5
0
 public ReadOnlyMemory <byte> GetReadableMemory(int index, int count)
 {
     return(_buffer.GetReadableMemory(index, count));
 }