| // Copyright (c) 2017 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef QUICHE_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_ | |
| #define QUICHE_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_ | |
| #include <cstdint> | |
| #include <string> | |
| #include "absl/container/flat_hash_map.h" | |
| #include "quiche/quic/core/frames/quic_frame.h" | |
| #include "quiche/quic/core/quic_connection_id.h" | |
| #include "quiche/quic/core/quic_error_codes.h" | |
| #include "quiche/quic/core/quic_types.h" | |
| #include "quiche/common/quiche_circular_deque.h" | |
| #include "quiche/common/quiche_linked_hash_map.h" | |
| namespace quic { | |
| class QuicSession; | |
| namespace test { | |
| class QuicControlFrameManagerPeer; | |
| } // namespace test | |
| // Control frame manager contains a list of sent control frames with valid | |
| // control frame IDs. Control frames without valid control frame IDs include: | |
| // (1) non-retransmittable frames (e.g., ACK_FRAME, PADDING_FRAME, | |
| // STOP_WAITING_FRAME, etc.), (2) CONNECTION_CLOSE and IETF Quic | |
| // APPLICATION_CLOSE frames. | |
| // New control frames are added to the tail of the list when they are added to | |
| // the generator. Control frames are removed from the head of the list when they | |
| // get acked. Control frame manager also keeps track of lost control frames | |
| // which need to be retransmitted. | |
| class QUIC_EXPORT_PRIVATE QuicControlFrameManager { | |
| public: | |
| class QUIC_EXPORT_PRIVATE DelegateInterface { | |
| public: | |
| virtual ~DelegateInterface() = default; | |
| // Notifies the delegate of errors. | |
| virtual void OnControlFrameManagerError(QuicErrorCode error_code, | |
| std::string error_details) = 0; | |
| virtual bool WriteControlFrame(const QuicFrame& frame, | |
| TransmissionType type) = 0; | |
| }; | |
| explicit QuicControlFrameManager(QuicSession* session); | |
| QuicControlFrameManager(const QuicControlFrameManager& other) = delete; | |
| QuicControlFrameManager(QuicControlFrameManager&& other) = delete; | |
| ~QuicControlFrameManager(); | |
| // Tries to send a WINDOW_UPDATE_FRAME. Buffers the frame if it cannot be sent | |
| // immediately. | |
| void WriteOrBufferRstStream(QuicControlFrameId id, QuicResetStreamError error, | |
| QuicStreamOffset bytes_written); | |
| // Tries to send a GOAWAY_FRAME. Buffers the frame if it cannot be sent | |
| // immediately. | |
| void WriteOrBufferGoAway(QuicErrorCode error, | |
| QuicStreamId last_good_stream_id, | |
| const std::string& reason); | |
| // Tries to send a WINDOW_UPDATE_FRAME. Buffers the frame if it cannot be sent | |
| // immediately. | |
| void WriteOrBufferWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset); | |
| // Tries to send a BLOCKED_FRAME. Buffers the frame if it cannot be sent | |
| // immediately. | |
| void WriteOrBufferBlocked(QuicStreamId id, QuicStreamOffset byte_offset); | |
| // Tries to send a STREAMS_BLOCKED Frame. Buffers the frame if it cannot be | |
| // sent immediately. | |
| void WriteOrBufferStreamsBlocked(QuicStreamCount count, bool unidirectional); | |
| // Tries to send a MAX_STREAMS Frame. Buffers the frame if it cannot be sent | |
| // immediately. | |
| void WriteOrBufferMaxStreams(QuicStreamCount count, bool unidirectional); | |
| // Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it | |
| // can not be sent immediately. | |
| void WriteOrBufferStopSending(QuicResetStreamError error, | |
| QuicStreamId stream_id); | |
| // Tries to send an HANDSHAKE_DONE frame. The frame is buffered if it can not | |
| // be sent immediately. | |
| void WriteOrBufferHandshakeDone(); | |
| // Tries to send an AckFrequencyFrame. The frame is buffered if it cannot be | |
| // sent immediately. | |
| void WriteOrBufferAckFrequency( | |
| const QuicAckFrequencyFrame& ack_frequency_frame); | |
| // Tries to send a NEW_CONNECTION_ID frame. The frame is buffered if it cannot | |
| // be sent immediately. | |
| void WriteOrBufferNewConnectionId( | |
| const QuicConnectionId& connection_id, uint64_t sequence_number, | |
| uint64_t retire_prior_to, | |
| const StatelessResetToken& stateless_reset_token); | |
| // Tries to send a RETIRE_CONNNECTION_ID frame. The frame is buffered if it | |
| // cannot be sent immediately. | |
| void WriteOrBufferRetireConnectionId(uint64_t sequence_number); | |
| // Tries to send a NEW_TOKEN frame. Buffers the frame if it cannot be sent | |
| // immediately. | |
| void WriteOrBufferNewToken(absl::string_view token); | |
| // Called when |frame| gets acked. Returns true if |frame| gets acked for the | |
| // first time, return false otherwise. | |
| bool OnControlFrameAcked(const QuicFrame& frame); | |
| // Called when |frame| is considered as lost. | |
| void OnControlFrameLost(const QuicFrame& frame); | |
| // Called by the session when the connection becomes writable. | |
| void OnCanWrite(); | |
| // Retransmit |frame| if it is still outstanding. Returns false if the frame | |
| // does not get retransmitted because the connection is blocked. Otherwise, | |
| // returns true. | |
| bool RetransmitControlFrame(const QuicFrame& frame, TransmissionType type); | |
| // Returns true if |frame| is outstanding and waiting to be acked. Returns | |
| // false otherwise. | |
| bool IsControlFrameOutstanding(const QuicFrame& frame) const; | |
| // Returns true if there is any lost control frames waiting to be | |
| // retransmitted. | |
| bool HasPendingRetransmission() const; | |
| // Returns true if there are any lost or new control frames waiting to be | |
| // sent. | |
| bool WillingToWrite() const; | |
| private: | |
| friend class test::QuicControlFrameManagerPeer; | |
| // Tries to write buffered control frames to the peer. | |
| void WriteBufferedFrames(); | |
| // Called when |frame| is sent for the first time or gets retransmitted. | |
| void OnControlFrameSent(const QuicFrame& frame); | |
| // Writes pending retransmissions if any. | |
| void WritePendingRetransmission(); | |
| // Called when frame with |id| gets acked. Returns true if |id| gets acked for | |
| // the first time, return false otherwise. | |
| bool OnControlFrameIdAcked(QuicControlFrameId id); | |
| // Retrieves the next pending retransmission. This must only be called when | |
| // there are pending retransmissions. | |
| QuicFrame NextPendingRetransmission() const; | |
| // Returns true if there are buffered frames waiting to be sent for the first | |
| // time. | |
| bool HasBufferedFrames() const; | |
| // Writes or buffers a control frame. Frame is buffered if there already | |
| // are frames waiting to be sent. If no others waiting, will try to send the | |
| // frame. | |
| void WriteOrBufferQuicFrame(QuicFrame frame); | |
| quiche::QuicheCircularDeque<QuicFrame> control_frames_; | |
| // Id of latest saved control frame. 0 if no control frame has been saved. | |
| QuicControlFrameId last_control_frame_id_; | |
| // The control frame at the 0th index of control_frames_. | |
| QuicControlFrameId least_unacked_; | |
| // ID of the least unsent control frame. | |
| QuicControlFrameId least_unsent_; | |
| // TODO(fayang): switch to linked_hash_set when chromium supports it. The bool | |
| // is not used here. | |
| // Lost control frames waiting to be retransmitted. | |
| quiche::QuicheLinkedHashMap<QuicControlFrameId, bool> | |
| pending_retransmissions_; | |
| DelegateInterface* delegate_; | |
| // Last sent window update frame for each stream. | |
| absl::flat_hash_map<QuicStreamId, QuicControlFrameId> window_update_frames_; | |
| }; | |
| } // namespace quic | |
| #endif // QUICHE_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_ |