【BeetleX重构】实现ReadOnlySequence Stream在支持SslSteram出现的狗血问题

         最近在重写BeetleX中需要实现ReadOnlySequence Stream并支持SslStream的功能,其实在旧版本的BeetleX中就实现过这一功能;现在针对支持ReadOnlySequence进行一个重写!测试的时候发现无论我怎传一个byte[]给SslStream的Read方法时,传到自定义的内部Stream总会是byte[0]....翻阅了一堆SslStream的帮助都没办法知道这问题的原因;想提issues吧感觉很难举证毕竟SslStream要基于网络模块才好处理,也正是这自定义Stream模块代码,而其代码功能也不完善不好说具体问题!最后只能调试.net的SDK的源码了。。。。

[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))]
        private async ValueTask<int> EnsureFullTlsFrameAsync<TIOAdapter>(CancellationToken cancellationToken, int estimatedSize)
            where TIOAdapter : IReadWriteAdapter
        {
            if (HaveFullTlsFrame(out int frameSize))
            {
                return frameSize;
            }


            await TIOAdapter.ReadAsync(InnerStream, Memory<byte>.Empty, cancellationToken).ConfigureAwait(false);


            // If we don't have enough data to determine the frame size, use the provided estimate
            // (e.g. a full TLS frame for reads, and a somewhat shorter frame for handshake / renegotiation).
            // If we do know the frame size, ensure we have space for the whole frame.
            _buffer.EnsureAvailableSpace(frameSize == UnknownTlsFrameLength ?
                estimatedSize :
                frameSize - _buffer.EncryptedLength);


            while (_buffer.EncryptedLength < frameSize)
            {
                // there should be space left to read into
                Debug.Assert(_buffer.AvailableLength > 0, "_buffer.AvailableBytes > 0");


                // We either don't have full frame or we don't have enough data to even determine the size.
                int bytesRead = await TIOAdapter.ReadAsync(InnerStream, _buffer.AvailableMemory, cancellationToken).ConfigureAwait(false);
                if (bytesRead == 0)
                {
                    if (_buffer.EncryptedLength != 0)
                    {
                        // we got EOF in middle of TLS frame. Treat that as error.
                        throw new IOException(SR.net_io_eof);
                    }


                    return 0;
                }


                _buffer.Commit(bytesRead);
                if (frameSize == int.MaxValue && _buffer.EncryptedLength > TlsFrameHelper.HeaderSize)
                {
                    // recalculate frame size if needed e.g. we could not get it before.
                    frameSize = GetFrameSize(_buffer.EncryptedReadOnlySpan);
                    _buffer.EnsureAvailableSpace(frameSize - _buffer.EncryptedLength);
                }
            }


            return frameSize;
        }

最后跟踪到以上方法时找到了下面一行代码。。。。

await TIOAdapter.ReadAsync(InnerStream, Memory<byte>.Empty, cancellationToken).ConfigureAwait(false);


 // If we don't have enough data to determine the frame size, use the provided estimate
 // (e.g. a full TLS frame for reads, and a somewhat shorter frame for handshake / renegotiation).
// If we do know the frame size, ensure we have space for the whole frame.

试探性发起一个Read byte[0]8933a1087eccbdb03f7f38f8c55de282.png,虽然注释写了为什么这样做,但我怎么看也看出来这方法执行的代码对后面的逻辑有什么影响。。。。在实现过中只要收到Read byte[0]直接响应读取零长度就好了,之前的实现在当前Stream没有数据时不管传参是什么都返回一个Task awaiter,所以导致功能无法正常使用。。。

public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
    if (!SslCompleted && IsSsl)
    {
        return await base.ReadAsync(buffer, cancellationToken);
    }
    else
    {
        if (buffer.Length == 0)
            return 0;
        if (Length > 0)
        {
            int result = 0;
            readCompletionSource = null;
            if (_ReadBuffer.Length >= buffer.Length)
            {
                result = buffer.Length;
                _ReadBuffer.Slice(0, buffer.Length).CopyTo(buffer.Span);
                ReadAdvance(buffer.Length);


            }
            else
            {
                result = (int)_ReadBuffer.Length;
                _ReadBuffer.Slice(0, _ReadBuffer.Length).CopyTo(buffer.Span);
                ReadAdvance(_ReadBuffer.Length);
            }
            return result;
        }
        else
        {
            readCompletionSource = new ReadTaskCompletionSource();
            readCompletionSource.Buffer = buffer;
            return await readCompletionSource.Task;
        }
    }
}
BeetleX

开源跨平台通讯框架(支持TLS)

提供HTTP,Websocket,MQTT,Redis,RPC和服务网关开源组件

个人微信:henryfan128    QQ:28304340

关注公众号

3b0b99afa133a3f6159bf86caa19c4cb.jpeg

https://github.com/beetlex-io/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值