Commit e8220f00 authored by Fan Yang's avatar Fan Yang Committed by Commit Bot

Add QuicControlFrameManager which is not used yet.

Merge internal change: 176702384

Bug: 
Change-Id: I93b5cf6c8bfa92c4a700d16fef79d691f9ba2071
Reviewed-on: https://chromium-review.googlesource.com/791030Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Commit-Queue: Fan Yang <fayang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#519408}
parent 8d71ca83
...@@ -1296,6 +1296,8 @@ component("net") { ...@@ -1296,6 +1296,8 @@ component("net") {
"quic/core/quic_connection_stats.h", "quic/core/quic_connection_stats.h",
"quic/core/quic_constants.cc", "quic/core/quic_constants.cc",
"quic/core/quic_constants.h", "quic/core/quic_constants.h",
"quic/core/quic_control_frame_manager.cc",
"quic/core/quic_control_frame_manager.h",
"quic/core/quic_crypto_client_handshaker.cc", "quic/core/quic_crypto_client_handshaker.cc",
"quic/core/quic_crypto_client_handshaker.h", "quic/core/quic_crypto_client_handshaker.h",
"quic/core/quic_crypto_client_stream.cc", "quic/core/quic_crypto_client_stream.cc",
...@@ -5050,6 +5052,7 @@ test("net_unittests") { ...@@ -5050,6 +5052,7 @@ test("net_unittests") {
"quic/core/quic_client_push_promise_index_test.cc", "quic/core/quic_client_push_promise_index_test.cc",
"quic/core/quic_config_test.cc", "quic/core/quic_config_test.cc",
"quic/core/quic_connection_test.cc", "quic/core/quic_connection_test.cc",
"quic/core/quic_control_frame_manager_test.cc",
"quic/core/quic_crypto_client_stream_test.cc", "quic/core/quic_crypto_client_stream_test.cc",
"quic/core/quic_crypto_server_stream_test.cc", "quic/core/quic_crypto_server_stream_test.cc",
"quic/core/quic_crypto_stream_test.cc", "quic/core/quic_crypto_stream_test.cc",
......
// 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 "net/quic/core/quic_control_frame_manager.h"
#include "net/quic/core/quic_constants.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
#include "net/quic/platform/api/quic_map_util.h"
namespace net {
QuicControlFrameManager::QuicControlFrameManager() : least_unacked_(1) {}
QuicControlFrameManager::~QuicControlFrameManager() {
while (!control_frames_.empty()) {
DeleteFrame(&control_frames_.front());
control_frames_.pop_front();
}
}
void QuicControlFrameManager::OnControlFrameSent(const QuicFrame& frame) {
QuicControlFrameId id = GetControlFrameId(frame);
if (id == kInvalidControlFrameId) {
QUIC_BUG
<< "Send or retransmit a control frame with invalid control frame id";
return;
}
if (id == least_unacked_ + control_frames_.size()) {
// This is a newly sent control frame. Save a copy of this frame.
switch (frame.type) {
case RST_STREAM_FRAME:
control_frames_.emplace_back(
QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame)));
return;
case GOAWAY_FRAME:
control_frames_.emplace_back(
QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame)));
return;
case WINDOW_UPDATE_FRAME:
control_frames_.emplace_back(
QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame)));
return;
case BLOCKED_FRAME:
control_frames_.emplace_back(
QuicFrame(new QuicBlockedFrame(*frame.blocked_frame)));
return;
case PING_FRAME:
control_frames_.emplace_back(
QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id)));
return;
default:
DCHECK(false);
return;
}
}
if (QuicContainsKey(pending_retransmissions_, id)) {
// This is retransmitted control frame.
pending_retransmissions_.erase(id);
return;
}
QUIC_BUG << frame << " is neither a new or retransmitted control frame.";
}
void QuicControlFrameManager::OnControlFrameAcked(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_unacked_) {
// This frame has already been acked.
return;
}
if (id >= least_unacked_ + control_frames_.size()) {
QUIC_BUG << "Try to ack unsent control frame";
return;
}
// 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_;
}
}
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_unacked_ ||
GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
kInvalidControlFrameId) {
// This frame has already been acked.
return;
}
if (id >= least_unacked_ + control_frames_.size()) {
QUIC_BUG << "Try to mark unsent control frame as lost";
return;
}
if (!QuicContainsKey(pending_retransmissions_, id)) {
pending_retransmissions_[id] = true;
}
}
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;
}
if (id >= least_unacked_ + control_frames_.size()) {
QUIC_BUG << "Try to check retransmittability of an unsent frame.";
return false;
}
return id >= least_unacked_ &&
GetControlFrameId(control_frames_.at(id - least_unacked_)) !=
kInvalidControlFrameId;
}
bool QuicControlFrameManager::HasPendingRetransmission() const {
return !pending_retransmissions_.empty();
}
QuicFrame QuicControlFrameManager::NextPendingRetransmission() const {
QUIC_BUG_IF(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_);
}
size_t QuicControlFrameManager::size() const {
return control_frames_.size();
}
} // namespace net
// 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 NET_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_
#define NET_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_
#include "net/quic/core/frames/quic_frame.h"
#include "net/quic/platform/api/quic_containers.h"
namespace net {
// 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 frame.
// 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:
QuicControlFrameManager();
QuicControlFrameManager(const QuicControlFrameManager& other) = delete;
QuicControlFrameManager(QuicControlFrameManager&& other) = delete;
~QuicControlFrameManager();
// Called when |frame| is sent for the first time or gets retransmitted.
// Please note, this function should be called when |frame| is added to the
// generator.
void OnControlFrameSent(const QuicFrame& frame);
// Called when |frame| gets acked.
void OnControlFrameAcked(const QuicFrame& frame);
// Called when |frame| is considered as lost.
void OnControlFrameLost(const QuicFrame& frame);
// 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;
// Retrieves the next pending retransmission. This must only be called when
// there are pending retransmissions.
QuicFrame NextPendingRetransmission() const;
size_t size() const;
private:
QuicDeque<QuicFrame> control_frames_;
// The control frame at the 0th index of control_frames_.
QuicControlFrameId least_unacked_;
// TODO(fayang): switch to linked_hash_set when chromium supports it. The bool
// is not used here.
// Lost control frames waiting to be retransmitted.
QuicLinkedHashMap<QuicControlFrameId, bool> pending_retransmissions_;
};
} // namespace net
#endif // NET_QUIC_CORE_QUIC_CONTROL_FRAME_MANAGER_H_
// 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 "net/quic/core/quic_control_frame_manager.h"
#include "net/quic/platform/api/quic_test.h"
namespace net {
namespace test {
namespace {
const QuicStreamId kTestStreamId = 5;
class QuicControlFrameManagerTest : public QuicTest {
public:
QuicControlFrameManagerTest()
: rst_stream_(1, kTestStreamId, QUIC_STREAM_CANCELLED, 0),
goaway_(2, QUIC_PEER_GOING_AWAY, kTestStreamId, "Going away."),
window_update_(3, kTestStreamId, 100),
blocked_(4, kTestStreamId) {}
QuicControlFrameManager manager_;
QuicRstStreamFrame rst_stream_;
QuicGoAwayFrame goaway_;
QuicWindowUpdateFrame window_update_;
QuicBlockedFrame blocked_;
};
TEST_F(QuicControlFrameManagerTest, OnControlFrameAcked) {
EXPECT_EQ(0u, manager_.size());
manager_.OnControlFrameSent(QuicFrame(&rst_stream_));
manager_.OnControlFrameSent(QuicFrame(&goaway_));
manager_.OnControlFrameSent(QuicFrame(&window_update_));
manager_.OnControlFrameSent(QuicFrame(&blocked_));
manager_.OnControlFrameSent(QuicFrame(QuicPingFrame(5)));
EXPECT_EQ(5u, manager_.size());
EXPECT_TRUE(manager_.IsControlFrameOutstanding(QuicFrame(&window_update_)));
manager_.OnControlFrameAcked(QuicFrame(&window_update_));
EXPECT_FALSE(manager_.IsControlFrameOutstanding(QuicFrame(&window_update_)));
EXPECT_EQ(5u, manager_.size());
manager_.OnControlFrameAcked(QuicFrame(&goaway_));
EXPECT_EQ(5u, manager_.size());
manager_.OnControlFrameAcked(QuicFrame(&rst_stream_));
EXPECT_EQ(2u, manager_.size());
}
TEST_F(QuicControlFrameManagerTest, OnControlFrameLost) {
EXPECT_FALSE(manager_.HasPendingRetransmission());
EXPECT_EQ(0u, manager_.size());
manager_.OnControlFrameSent(QuicFrame(&rst_stream_));
manager_.OnControlFrameSent(QuicFrame(&goaway_));
manager_.OnControlFrameSent(QuicFrame(&window_update_));
manager_.OnControlFrameSent(QuicFrame(&blocked_));
manager_.OnControlFrameSent(QuicFrame(QuicPingFrame(5)));
EXPECT_EQ(5u, manager_.size());
manager_.OnControlFrameLost(QuicFrame(&window_update_));
manager_.OnControlFrameLost(QuicFrame(&rst_stream_));
EXPECT_TRUE(manager_.HasPendingRetransmission());
EXPECT_EQ(window_update_.control_frame_id,
manager_.NextPendingRetransmission()
.window_update_frame->control_frame_id);
manager_.OnControlFrameSent(QuicFrame(&window_update_));
EXPECT_TRUE(manager_.IsControlFrameOutstanding(QuicFrame(&window_update_)));
EXPECT_TRUE(manager_.HasPendingRetransmission());
EXPECT_EQ(
rst_stream_.control_frame_id,
manager_.NextPendingRetransmission().rst_stream_frame->control_frame_id);
manager_.OnControlFrameAcked(QuicFrame(&rst_stream_));
EXPECT_FALSE(manager_.IsControlFrameOutstanding(QuicFrame(&rst_stream_)));
EXPECT_FALSE(manager_.HasPendingRetransmission());
EXPECT_EQ(4u, manager_.size());
}
} // namespace
} // namespace test
} // namespace net
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment