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(); } } } }
/// <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(); } } } }
public ReadOnlyMemory <byte> GetReadableMemory(int index, int count) { return(_buffer.GetReadableMemory(index, count)); }