예제 #1
0
        internal override async ValueTask <(long StreamId, IncomingFrame?Frame, bool Fin)> ReceiveAsync(
            CancellationToken cancel)
        {
            FrameType           type;
            ArraySegment <byte> data;

            while (true)
            {
                // Read Slic frame header
                (type, data) = await ReceiveFrameAsync(CancellationToken.None).ConfigureAwait(false);

                switch (type)
                {
                case FrameType.Ping:
                {
                    ValueTask task = PrepareAndSendFrameAsync(FrameType.Pong, null, CancellationToken.None);
                    HeartbeatCallback !();
                    break;
                }

                case FrameType.Pong:
                {
                    // TODO: setup a timer to expect pong frame response?
                    break;
                }

                case FrameType.Stream:
                case FrameType.StreamLast:
                {
                    (long streamId, int streamIdSize) = data.AsReadOnlySpan().ReadVarLong();
                    data = data.Slice(streamIdSize);
                    IncomingFrame frame = ParseIce2Frame(data);
                    if (Endpoint.Communicator.TraceLevels.Protocol >= 1)
                    {
                        ProtocolTrace.TraceFrame(Endpoint.Communicator, streamId, frame);
                    }
                    return(StreamId : streamId, Frame : frame, Fin : type == FrameType.StreamLast);
                }

                case FrameType.ResetStream:
                {
                    var  istr     = new InputStream(data, Encoding);
                    long streamId = istr.ReadVarLong();
                    long reason   = istr.ReadVarLong();
                    return(StreamId : streamId, Frame : null, Fin : true);
                }

                case FrameType.Close:
                {
                    var    istr   = new InputStream(data, Encoding);
                    long   code   = istr.ReadVarLong(); // TODO: is this really useful?
                    string reason = istr.ReadString();
                    throw new ConnectionClosedByPeerException(reason);
                }

                default:
                {
                    throw new InvalidDataException($"unexpected Slic frame with frame type `{type}'");
                }
                }
            }
        }