public ValueTask <WriteResult> WriteWindowUpdate( FrameHeader header, WindowUpdateData data) { return(PerformWriteRequestAsync( header.StreamId, wr => { wr.Header = header; wr.WindowUpdateData = data; }, false)); }
public static async Task AssertWindowUpdate( this IReadableByteStream stream, uint expectedStreamId, int increment) { var header = await stream.ReadFrameHeaderWithTimeout(); Assert.Equal(FrameType.WindowUpdate, header.Type); Assert.Equal(WindowUpdateData.Size, header.Length); Assert.Equal(0, header.Flags); Assert.Equal(expectedStreamId, header.StreamId); var buf = new byte[WindowUpdateData.Size]; await stream.ReadAllWithTimeout(new ArraySegment <byte>(buf)); var wu = WindowUpdateData.DecodeFrom(new ArraySegment <byte>(buf)); Assert.Equal(increment, wu.WindowSizeIncrement); }
public static async Task WriteWindowUpdate( this IWriteAndCloseableByteStream stream, uint streamId, int amount) { var windowUpdateHeader = new FrameHeader { Type = FrameType.WindowUpdate, Flags = 0, Length = WindowUpdateData.Size, StreamId = streamId, }; var data = new WindowUpdateData { WindowSizeIncrement = amount, }; var dataBytes = new byte[WindowUpdateData.Size]; data.EncodeInto(new ArraySegment <byte>(dataBytes)); await stream.WriteFrameHeader(windowUpdateHeader); await stream.WriteAsync(new ArraySegment <byte>(dataBytes)); }
private async ValueTask <Http2Error?> HandleWindowUpdateFrame(FrameHeader fh) { if (fh.Length != WindowUpdateData.Size) { return(new Http2Error { StreamId = 0, Code = ErrorCode.FrameSizeError, Message = "收到无效的窗口更新帧头", }); } await inputStream.ReadAll( new ArraySegment <byte>(receiveBuffer, 0, WindowUpdateData.Size)); var windowUpdateData = WindowUpdateData.DecodeFrom( new ArraySegment <byte>(receiveBuffer, 0, WindowUpdateData.Size)); bool isIdleStream = false; lock (shared.Mutex) { isIdleStream = IsIdleStreamId( fh.StreamId, shared.LastOutgoingStreamId, shared.LastIncomingStreamId); } if (isIdleStream) { return(new Http2Error { StreamId = 0u, Code = ErrorCode.ProtocolError, Message = "接收到空闲流的窗口更新", }); } return(writer.UpdateFlowControlWindow( fh.StreamId, windowUpdateData.WindowSizeIncrement)); }
private async ValueTask <object> SendWindowUpdate(int amount) { var fh = new FrameHeader { StreamId = this.Id, Type = FrameType.WindowUpdate, Flags = 0, }; var updateData = new WindowUpdateData { WindowSizeIncrement = amount, }; try { await this.connection.writer.WriteWindowUpdate(fh, updateData); } catch (Exception) { } return(null); }
private async ValueTask <Http2Error?> HandleDataFrame(FrameHeader fh) { if (fh.StreamId == 0) { return(new Http2Error { StreamId = 0, Code = ErrorCode.ProtocolError, Message = "接收到无效的数据帧头", }); } if ((fh.Flags & (byte)DataFrameFlags.Padded) != 0 && fh.Length < 1) { return(new Http2Error { StreamId = 0, Code = ErrorCode.ProtocolError, Message = "帧太小,无法包含填充", }); } if (fh.Length > localSettings.MaxFrameSize) { return(new Http2Error { StreamId = 0, Code = ErrorCode.FrameSizeError, Message = "超过最大帧大小", }); } var dataBuffer = config.BufferPool.Rent(fh.Length); try { await inputStream.ReadAll( new ArraySegment <byte>(dataBuffer, 0, fh.Length)); } catch (Exception) { config.BufferPool.Return(dataBuffer); throw; } var isPadded = (fh.Flags & (byte)DataFrameFlags.Padded) != 0; var padLen = 0; var offset = isPadded ? 1 : 0; var dataSize = fh.Length; if (isPadded) { padLen = dataBuffer[0]; dataSize = fh.Length - 1 - padLen; if (dataSize < 0) { config.BufferPool.Return(dataBuffer); return(new Http2Error { StreamId = 0, Code = ErrorCode.ProtocolError, Message = "减法填充后帧太小", }); } } if (dataSize != 0) { if (dataSize > connReceiveFlowWindow) { config.BufferPool.Return(dataBuffer); return(new Http2Error { StreamId = 0, Code = ErrorCode.FlowControlError, Message = "超过接收窗口", }); } connReceiveFlowWindow -= dataSize; } StreamImpl stream = null; uint lastIncomingStreamId; uint lastOutgoingStreamId; lock (shared.Mutex) { lastIncomingStreamId = shared.LastIncomingStreamId; lastOutgoingStreamId = shared.LastOutgoingStreamId; shared.streamMap.TryGetValue(fh.StreamId, out stream); } Http2Error?processError = null; bool streamTookBufferOwnership = false; if (stream != null) { processError = stream.PushBuffer( new ArraySegment <byte>(dataBuffer, offset, dataSize), (fh.Flags & (byte)DataFrameFlags.EndOfStream) != 0, out streamTookBufferOwnership); } else { var isIdleStreamId = IsIdleStreamId( fh.StreamId, lastOutgoingStreamId, lastIncomingStreamId); processError = new Http2Error { StreamId = isIdleStreamId ? 0u : fh.StreamId, Code = ErrorCode.StreamClosed, Message = "接收到未知帧的数据", }; } if (!streamTookBufferOwnership) { config.BufferPool.Return(dataBuffer); } dataBuffer = null; if (processError.HasValue && processError.Value.StreamId == 0) { return(processError); } var maxWindow = Constants.InitialConnectionWindowSize; var possibleWindowUpdate = maxWindow - connReceiveFlowWindow; var windowUpdateAmount = 0; if (possibleWindowUpdate >= (maxWindow / 2)) { windowUpdateAmount = possibleWindowUpdate; connReceiveFlowWindow += windowUpdateAmount; } if (windowUpdateAmount > 0) { var wfh = new FrameHeader { StreamId = 0, Type = FrameType.WindowUpdate, Flags = 0, }; var updateData = new WindowUpdateData { WindowSizeIncrement = windowUpdateAmount, }; try { await writer.WriteWindowUpdate(wfh, updateData); } catch (Exception) { } } return(processError); }