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}'"); } } } }