| // 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. | 
 |  | 
 | #include "quiche/quic/core/quic_control_frame_manager.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "absl/strings/str_cat.h" | 
 | #include "quiche/quic/core/frames/quic_ack_frequency_frame.h" | 
 | #include "quiche/quic/core/frames/quic_frame.h" | 
 | #include "quiche/quic/core/frames/quic_new_connection_id_frame.h" | 
 | #include "quiche/quic/core/frames/quic_retire_connection_id_frame.h" | 
 | #include "quiche/quic/core/quic_constants.h" | 
 | #include "quiche/quic/core/quic_session.h" | 
 | #include "quiche/quic/core/quic_types.h" | 
 | #include "quiche/quic/core/quic_utils.h" | 
 | #include "quiche/quic/platform/api/quic_bug_tracker.h" | 
 | #include "quiche/quic/platform/api/quic_flag_utils.h" | 
 | #include "quiche/quic/platform/api/quic_flags.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | namespace { | 
 |  | 
 | // The maximum number of buffered control frames which are waiting to be ACKed | 
 | // or sent for the first time. | 
 | const size_t kMaxNumControlFrames = 1000; | 
 |  | 
 | }  // namespace | 
 |  | 
 | QuicControlFrameManager::QuicControlFrameManager(QuicSession* session) | 
 |     : last_control_frame_id_(kInvalidControlFrameId), | 
 |       least_unacked_(1), | 
 |       least_unsent_(1), | 
 |       delegate_(session), | 
 |       num_buffered_max_stream_frames_(0) {} | 
 |  | 
 | QuicControlFrameManager::~QuicControlFrameManager() { | 
 |   while (!control_frames_.empty()) { | 
 |     DeleteFrame(&control_frames_.front()); | 
 |     control_frames_.pop_front(); | 
 |   } | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferQuicFrame(QuicFrame frame) { | 
 |   const bool had_buffered_frames = HasBufferedFrames(); | 
 |   control_frames_.emplace_back(frame); | 
 |   if (control_frames_.size() > kMaxNumControlFrames) { | 
 |     delegate_->OnControlFrameManagerError( | 
 |         QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES, | 
 |         absl::StrCat("More than ", kMaxNumControlFrames, | 
 |                      "buffered control frames, least_unacked: ", least_unacked_, | 
 |                      ", least_unsent_: ", least_unsent_)); | 
 |     return; | 
 |   } | 
 |   if (had_buffered_frames) { | 
 |     return; | 
 |   } | 
 |   WriteBufferedFrames(); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferRstStream( | 
 |     QuicStreamId id, QuicResetStreamError error, | 
 |     QuicStreamOffset bytes_written) { | 
 |   QUIC_DVLOG(1) << "Writing RST_STREAM_FRAME"; | 
 |   WriteOrBufferQuicFrame((QuicFrame(new QuicRstStreamFrame( | 
 |       ++last_control_frame_id_, id, error, bytes_written)))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferGoAway( | 
 |     QuicErrorCode error, QuicStreamId last_good_stream_id, | 
 |     const std::string& reason) { | 
 |   QUIC_DVLOG(1) << "Writing GOAWAY_FRAME"; | 
 |   WriteOrBufferQuicFrame(QuicFrame(new QuicGoAwayFrame( | 
 |       ++last_control_frame_id_, error, last_good_stream_id, reason))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferWindowUpdate( | 
 |     QuicStreamId id, QuicStreamOffset byte_offset) { | 
 |   QUIC_DVLOG(1) << "Writing WINDOW_UPDATE_FRAME"; | 
 |   WriteOrBufferQuicFrame(QuicFrame( | 
 |       QuicWindowUpdateFrame(++last_control_frame_id_, id, byte_offset))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferBlocked( | 
 |     QuicStreamId id, QuicStreamOffset byte_offset) { | 
 |   QUIC_DVLOG(1) << "Writing BLOCKED_FRAME"; | 
 |   WriteOrBufferQuicFrame( | 
 |       QuicFrame(QuicBlockedFrame(++last_control_frame_id_, id, byte_offset))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferStreamsBlocked(QuicStreamCount count, | 
 |                                                           bool unidirectional) { | 
 |   QUIC_DVLOG(1) << "Writing STREAMS_BLOCKED Frame"; | 
 |   QUIC_CODE_COUNT(quic_streams_blocked_transmits); | 
 |   WriteOrBufferQuicFrame(QuicFrame(QuicStreamsBlockedFrame( | 
 |       ++last_control_frame_id_, count, unidirectional))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferMaxStreams(QuicStreamCount count, | 
 |                                                       bool unidirectional) { | 
 |   QUIC_DVLOG(1) << "Writing MAX_STREAMS Frame"; | 
 |   QUIC_CODE_COUNT(quic_max_streams_transmits); | 
 |   WriteOrBufferQuicFrame(QuicFrame( | 
 |       QuicMaxStreamsFrame(++last_control_frame_id_, count, unidirectional))); | 
 |   ++num_buffered_max_stream_frames_; | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferStopSending( | 
 |     QuicResetStreamError error, QuicStreamId stream_id) { | 
 |   QUIC_DVLOG(1) << "Writing STOP_SENDING_FRAME"; | 
 |   WriteOrBufferQuicFrame(QuicFrame( | 
 |       QuicStopSendingFrame(++last_control_frame_id_, stream_id, error))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferHandshakeDone() { | 
 |   QUIC_DVLOG(1) << "Writing HANDSHAKE_DONE"; | 
 |   WriteOrBufferQuicFrame( | 
 |       QuicFrame(QuicHandshakeDoneFrame(++last_control_frame_id_))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferAckFrequency( | 
 |     const QuicAckFrequencyFrame& ack_frequency_frame) { | 
 |   QUIC_DVLOG(1) << "Writing ACK_FREQUENCY frame"; | 
 |   QuicControlFrameId control_frame_id = ++last_control_frame_id_; | 
 |   // Using the control_frame_id for sequence_number here leaves gaps in | 
 |   // sequence_number. | 
 |   WriteOrBufferQuicFrame( | 
 |       QuicFrame(new QuicAckFrequencyFrame(control_frame_id, | 
 |                                           /*sequence_number=*/control_frame_id, | 
 |                                           ack_frequency_frame.packet_tolerance, | 
 |                                           ack_frequency_frame.max_ack_delay))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferNewConnectionId( | 
 |     const QuicConnectionId& connection_id, uint64_t sequence_number, | 
 |     uint64_t retire_prior_to, | 
 |     const StatelessResetToken& stateless_reset_token) { | 
 |   QUIC_DVLOG(1) << "Writing NEW_CONNECTION_ID frame"; | 
 |   WriteOrBufferQuicFrame(QuicFrame(new QuicNewConnectionIdFrame( | 
 |       ++last_control_frame_id_, connection_id, sequence_number, | 
 |       stateless_reset_token, retire_prior_to))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferRetireConnectionId( | 
 |     uint64_t sequence_number) { | 
 |   QUIC_DVLOG(1) << "Writing RETIRE_CONNECTION_ID frame"; | 
 |   WriteOrBufferQuicFrame(QuicFrame(new QuicRetireConnectionIdFrame( | 
 |       ++last_control_frame_id_, sequence_number))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteOrBufferNewToken(absl::string_view token) { | 
 |   QUIC_DVLOG(1) << "Writing NEW_TOKEN frame"; | 
 |   WriteOrBufferQuicFrame( | 
 |       QuicFrame(new QuicNewTokenFrame(++last_control_frame_id_, token))); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::OnControlFrameSent(const QuicFrame& frame) { | 
 |   QuicControlFrameId id = GetControlFrameId(frame); | 
 |   if (id == kInvalidControlFrameId) { | 
 |     QUIC_BUG(quic_bug_12727_1) | 
 |         << "Send or retransmit a control frame with invalid control frame id"; | 
 |     return; | 
 |   } | 
 |   if (frame.type == WINDOW_UPDATE_FRAME) { | 
 |     QuicStreamId stream_id = frame.window_update_frame.stream_id; | 
 |     if (window_update_frames_.contains(stream_id) && | 
 |         id > window_update_frames_[stream_id]) { | 
 |       // Consider the older window update of the same stream as acked. | 
 |       OnControlFrameIdAcked(window_update_frames_[stream_id]); | 
 |     } | 
 |     window_update_frames_[stream_id] = id; | 
 |   } | 
 |   if (pending_retransmissions_.contains(id)) { | 
 |     // This is retransmitted control frame. | 
 |     pending_retransmissions_.erase(id); | 
 |     return; | 
 |   } | 
 |   if (id > least_unsent_) { | 
 |     QUIC_BUG(quic_bug_10517_1) | 
 |         << "Try to send control frames out of order, id: " << id | 
 |         << " least_unsent: " << least_unsent_; | 
 |     delegate_->OnControlFrameManagerError( | 
 |         QUIC_INTERNAL_ERROR, "Try to send control frames out of order"); | 
 |     return; | 
 |   } | 
 |   ++least_unsent_; | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::OnControlFrameAcked(const QuicFrame& frame) { | 
 |   QuicControlFrameId id = GetControlFrameId(frame); | 
 |   if (!OnControlFrameIdAcked(id)) { | 
 |     return false; | 
 |   } | 
 |   if (frame.type == WINDOW_UPDATE_FRAME) { | 
 |     QuicStreamId stream_id = frame.window_update_frame.stream_id; | 
 |     if (window_update_frames_.contains(stream_id) && | 
 |         window_update_frames_[stream_id] == id) { | 
 |       window_update_frames_.erase(stream_id); | 
 |     } | 
 |   } | 
 |   if (frame.type == MAX_STREAMS_FRAME) { | 
 |     if (num_buffered_max_stream_frames_ == 0) { | 
 |       QUIC_BUG(invalid_num_buffered_max_stream_frames); | 
 |     } else { | 
 |       --num_buffered_max_stream_frames_; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void QuicControlFrameManager::OnControlFrameLost(const QuicFrame& frame) { | 
 |   QuicControlFrameId id = GetControlFrameId(frame); | 
 |   if (id == kInvalidControlFrameId) { | 
 |     // Frame does not have a valid control frame ID, ignore it. | 
 |     return; | 
 |   } | 
 |   if (id >= least_unsent_) { | 
 |     QUIC_BUG(quic_bug_10517_2) << "Try to mark unsent control frame as lost"; | 
 |     delegate_->OnControlFrameManagerError( | 
 |         QUIC_INTERNAL_ERROR, "Try to mark unsent control frame as lost"); | 
 |     return; | 
 |   } | 
 |   if (id < least_unacked_ || | 
 |       GetControlFrameId(control_frames_.at(id - least_unacked_)) == | 
 |           kInvalidControlFrameId) { | 
 |     // This frame has already been acked. | 
 |     return; | 
 |   } | 
 |   if (!pending_retransmissions_.contains(id)) { | 
 |     pending_retransmissions_[id] = true; | 
 |     QUIC_BUG_IF(quic_bug_12727_2, | 
 |                 pending_retransmissions_.size() > control_frames_.size()) | 
 |         << "least_unacked_: " << least_unacked_ | 
 |         << ", least_unsent_: " << least_unsent_; | 
 |   } | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::IsControlFrameOutstanding( | 
 |     const QuicFrame& frame) const { | 
 |   QuicControlFrameId id = GetControlFrameId(frame); | 
 |   if (id == kInvalidControlFrameId) { | 
 |     // Frame without a control frame ID should not be retransmitted. | 
 |     return false; | 
 |   } | 
 |   // Consider this frame is outstanding if it does not get acked. | 
 |   return id < least_unacked_ + control_frames_.size() && id >= least_unacked_ && | 
 |          GetControlFrameId(control_frames_.at(id - least_unacked_)) != | 
 |              kInvalidControlFrameId; | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::HasPendingRetransmission() const { | 
 |   return !pending_retransmissions_.empty(); | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::WillingToWrite() const { | 
 |   return HasPendingRetransmission() || HasBufferedFrames(); | 
 | } | 
 |  | 
 | size_t QuicControlFrameManager::NumBufferedMaxStreams() const { | 
 |   return num_buffered_max_stream_frames_; | 
 | } | 
 |  | 
 | QuicFrame QuicControlFrameManager::NextPendingRetransmission() const { | 
 |   QUIC_BUG_IF(quic_bug_12727_3, pending_retransmissions_.empty()) | 
 |       << "Unexpected call to NextPendingRetransmission() with empty pending " | 
 |       << "retransmission list."; | 
 |   QuicControlFrameId id = pending_retransmissions_.begin()->first; | 
 |   return control_frames_.at(id - least_unacked_); | 
 | } | 
 |  | 
 | void QuicControlFrameManager::OnCanWrite() { | 
 |   if (HasPendingRetransmission()) { | 
 |     // Exit early to allow streams to write pending retransmissions if any. | 
 |     WritePendingRetransmission(); | 
 |     return; | 
 |   } | 
 |   WriteBufferedFrames(); | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::RetransmitControlFrame(const QuicFrame& frame, | 
 |                                                      TransmissionType type) { | 
 |   QUICHE_DCHECK(type == PTO_RETRANSMISSION); | 
 |   QuicControlFrameId id = GetControlFrameId(frame); | 
 |   if (id == kInvalidControlFrameId) { | 
 |     // Frame does not have a valid control frame ID, ignore it. Returns true | 
 |     // to allow writing following frames. | 
 |     return true; | 
 |   } | 
 |   if (id >= least_unsent_) { | 
 |     QUIC_BUG(quic_bug_10517_3) << "Try to retransmit unsent control frame"; | 
 |     delegate_->OnControlFrameManagerError( | 
 |         QUIC_INTERNAL_ERROR, "Try to retransmit unsent control frame"); | 
 |     return false; | 
 |   } | 
 |   if (id < least_unacked_ || | 
 |       GetControlFrameId(control_frames_.at(id - least_unacked_)) == | 
 |           kInvalidControlFrameId) { | 
 |     // This frame has already been acked. | 
 |     return true; | 
 |   } | 
 |   QuicFrame copy = CopyRetransmittableControlFrame(frame); | 
 |   QUIC_DVLOG(1) << "control frame manager is forced to retransmit frame: " | 
 |                 << frame; | 
 |   if (delegate_->WriteControlFrame(copy, type)) { | 
 |     return true; | 
 |   } | 
 |   DeleteFrame(©); | 
 |   return false; | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WriteBufferedFrames() { | 
 |   while (HasBufferedFrames()) { | 
 |     QuicFrame frame_to_send = | 
 |         control_frames_.at(least_unsent_ - least_unacked_); | 
 |     QuicFrame copy = CopyRetransmittableControlFrame(frame_to_send); | 
 |     if (!delegate_->WriteControlFrame(copy, NOT_RETRANSMISSION)) { | 
 |       // Connection is write blocked. | 
 |       DeleteFrame(©); | 
 |       break; | 
 |     } | 
 |     OnControlFrameSent(frame_to_send); | 
 |   } | 
 | } | 
 |  | 
 | void QuicControlFrameManager::WritePendingRetransmission() { | 
 |   while (HasPendingRetransmission()) { | 
 |     QuicFrame pending = NextPendingRetransmission(); | 
 |     QuicFrame copy = CopyRetransmittableControlFrame(pending); | 
 |     if (!delegate_->WriteControlFrame(copy, LOSS_RETRANSMISSION)) { | 
 |       // Connection is write blocked. | 
 |       DeleteFrame(©); | 
 |       break; | 
 |     } | 
 |     OnControlFrameSent(pending); | 
 |   } | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::OnControlFrameIdAcked(QuicControlFrameId id) { | 
 |   if (id == kInvalidControlFrameId) { | 
 |     // Frame does not have a valid control frame ID, ignore it. | 
 |     return false; | 
 |   } | 
 |   if (id >= least_unsent_) { | 
 |     QUIC_BUG(quic_bug_10517_4) << "Try to ack unsent control frame"; | 
 |     delegate_->OnControlFrameManagerError(QUIC_INTERNAL_ERROR, | 
 |                                           "Try to ack unsent control frame"); | 
 |     return false; | 
 |   } | 
 |   if (id < least_unacked_ || | 
 |       GetControlFrameId(control_frames_.at(id - least_unacked_)) == | 
 |           kInvalidControlFrameId) { | 
 |     // This frame has already been acked. | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Set control frame ID of acked frames to 0. | 
 |   SetControlFrameId(kInvalidControlFrameId, | 
 |                     &control_frames_.at(id - least_unacked_)); | 
 |   // Remove acked control frames from pending retransmissions. | 
 |   pending_retransmissions_.erase(id); | 
 |   // Clean up control frames queue and increment least_unacked_. | 
 |   while (!control_frames_.empty() && | 
 |          GetControlFrameId(control_frames_.front()) == kInvalidControlFrameId) { | 
 |     DeleteFrame(&control_frames_.front()); | 
 |     control_frames_.pop_front(); | 
 |     ++least_unacked_; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool QuicControlFrameManager::HasBufferedFrames() const { | 
 |   return least_unsent_ < least_unacked_ + control_frames_.size(); | 
 | } | 
 |  | 
 | }  // namespace quic |