Do not issue a new connection ID if it has been taken by another connection in the session map.
Protected by FLAGS_quic_reloadable_flag_quic_check_cid_collision_when_issue_new_cid.
PiperOrigin-RevId: 456851394
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index ad7a103..f5bf7be 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -6398,11 +6398,12 @@
return connected_;
}
-void QuicConnection::OnNewConnectionIdIssued(
+bool QuicConnection::MaybeReserveConnectionId(
const QuicConnectionId& connection_id) {
if (perspective_ == Perspective::IS_SERVER) {
- visitor_->OnServerConnectionIdIssued(connection_id);
+ return visitor_->MaybeReserveConnectionId(connection_id);
}
+ return true;
}
void QuicConnection::OnSelfIssuedConnectionIdRetired(
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 87f9c14..db2d320 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -164,8 +164,9 @@
// Called to send a RETIRE_CONNECTION_ID frame.
virtual void SendRetireConnectionId(uint64_t sequence_number) = 0;
- // Called when server starts to use a server issued connection ID.
- virtual void OnServerConnectionIdIssued(
+ // Called when server starts to use a server issued connection ID. Returns
+ // true if this connection ID hasn't been used by another connection.
+ virtual bool MaybeReserveConnectionId(
const QuicConnectionId& server_connection_id) = 0;
// Called when server stops to use a server issued connection ID.
@@ -718,7 +719,7 @@
// QuicConnectionIdManagerVisitorInterface
void OnPeerIssuedConnectionIdRetired() override;
bool SendNewConnectionId(const QuicNewConnectionIdFrame& frame) override;
- void OnNewConnectionIdIssued(const QuicConnectionId& connection_id) override;
+ bool MaybeReserveConnectionId(const QuicConnectionId& connection_id) override;
void OnSelfIssuedConnectionIdRetired(
const QuicConnectionId& connection_id) override;
diff --git a/quiche/quic/core/quic_connection_id_manager.cc b/quiche/quic/core/quic_connection_id_manager.cc
index 46ff85f..17f7a72 100644
--- a/quiche/quic/core/quic_connection_id_manager.cc
+++ b/quiche/quic/core/quic_connection_id_manager.cc
@@ -10,6 +10,7 @@
#include "quiche/quic/core/quic_connection_id.h"
#include "quiche/quic/core/quic_error_codes.h"
#include "quiche/quic/core/quic_utils.h"
+#include "quiche/quic/platform/api/quic_flag_utils.h"
#include "quiche/common/platform/api/quiche_logging.h"
namespace quic {
@@ -298,14 +299,28 @@
return QuicUtils::CreateReplacementConnectionId(old_connection_id);
}
-QuicNewConnectionIdFrame
-QuicSelfIssuedConnectionIdManager::IssueNewConnectionId() {
+absl::optional<QuicNewConnectionIdFrame>
+QuicSelfIssuedConnectionIdManager::MaybeIssueNewConnectionId() {
+ const bool check_cid_collision_when_issue_new_cid =
+ GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid);
+ QuicConnectionId new_cid = GenerateNewConnectionId(last_connection_id_);
+ if (check_cid_collision_when_issue_new_cid) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_cid_collision_when_issue_new_cid, 1,
+ 2);
+ if (!visitor_->MaybeReserveConnectionId(new_cid)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_cid_collision_when_issue_new_cid,
+ 2, 2);
+ return {};
+ }
+ }
QuicNewConnectionIdFrame frame;
- frame.connection_id = GenerateNewConnectionId(last_connection_id_);
+ frame.connection_id = new_cid;
frame.sequence_number = next_connection_id_sequence_number_++;
frame.stateless_reset_token =
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
- visitor_->OnNewConnectionIdIssued(frame.connection_id);
+ if (!check_cid_collision_when_issue_new_cid) {
+ visitor_->MaybeReserveConnectionId(frame.connection_id);
+ }
active_connection_ids_.emplace_back(frame.connection_id,
frame.sequence_number);
frame.retire_prior_to = active_connection_ids_.front().second;
@@ -313,10 +328,10 @@
return frame;
}
-QuicNewConnectionIdFrame
-QuicSelfIssuedConnectionIdManager::IssueNewConnectionIdForPreferredAddress() {
- QuicNewConnectionIdFrame frame = IssueNewConnectionId();
- QUICHE_DCHECK_EQ(frame.sequence_number, 1u);
+absl::optional<QuicNewConnectionIdFrame> QuicSelfIssuedConnectionIdManager::
+ MaybeIssueNewConnectionIdForPreferredAddress() {
+ absl::optional<QuicNewConnectionIdFrame> frame = MaybeIssueNewConnectionId();
+ QUICHE_DCHECK(!frame.has_value() || (frame->sequence_number == 1u));
return frame;
}
@@ -406,8 +421,12 @@
void QuicSelfIssuedConnectionIdManager::MaybeSendNewConnectionIds() {
while (active_connection_ids_.size() < active_connection_id_limit_) {
- QuicNewConnectionIdFrame frame = IssueNewConnectionId();
- if (!visitor_->SendNewConnectionId(frame)) {
+ absl::optional<QuicNewConnectionIdFrame> frame =
+ MaybeIssueNewConnectionId();
+ if (!frame.has_value()) {
+ break;
+ }
+ if (!visitor_->SendNewConnectionId(*frame)) {
break;
}
}
diff --git a/quiche/quic/core/quic_connection_id_manager.h b/quiche/quic/core/quic_connection_id_manager.h
index 501310b..7f271e2 100644
--- a/quiche/quic/core/quic_connection_id_manager.h
+++ b/quiche/quic/core/quic_connection_id_manager.h
@@ -47,7 +47,7 @@
virtual ~QuicConnectionIdManagerVisitorInterface() = default;
virtual void OnPeerIssuedConnectionIdRetired() = 0;
virtual bool SendNewConnectionId(const QuicNewConnectionIdFrame& frame) = 0;
- virtual void OnNewConnectionIdIssued(
+ virtual bool MaybeReserveConnectionId(
const QuicConnectionId& connection_id) = 0;
virtual void OnSelfIssuedConnectionIdRetired(
const QuicConnectionId& connection_id) = 0;
@@ -130,7 +130,8 @@
virtual ~QuicSelfIssuedConnectionIdManager();
- QuicNewConnectionIdFrame IssueNewConnectionIdForPreferredAddress();
+ absl::optional<QuicNewConnectionIdFrame>
+ MaybeIssueNewConnectionIdForPreferredAddress();
QuicErrorCode OnRetireConnectionIdFrame(
const QuicRetireConnectionIdFrame& frame, QuicTime::Delta pto_delay,
@@ -164,7 +165,8 @@
private:
friend class test::QuicConnectionIdManagerPeer;
- QuicNewConnectionIdFrame IssueNewConnectionId();
+ // Issue a new connection ID. Can return nullopt.
+ absl::optional<QuicNewConnectionIdFrame> MaybeIssueNewConnectionId();
// This should be set to the min of:
// (1) # of active connection IDs that peer can maintain.
diff --git a/quiche/quic/core/quic_connection_id_manager_test.cc b/quiche/quic/core/quic_connection_id_manager_test.cc
index 1c2657d..dbd239f 100644
--- a/quiche/quic/core/quic_connection_id_manager_test.cc
+++ b/quiche/quic/core/quic_connection_id_manager_test.cc
@@ -64,8 +64,10 @@
bool SendNewConnectionId(const QuicNewConnectionIdFrame& /*frame*/) override {
return false;
}
- void OnNewConnectionIdIssued(
- const QuicConnectionId& /*connection_id*/) override {}
+ bool MaybeReserveConnectionId(const QuicConnectionId&) override {
+ return false;
+ }
+
void OnSelfIssuedConnectionIdRetired(
const QuicConnectionId& /*connection_id*/) override {}
@@ -522,7 +524,7 @@
MOCK_METHOD(bool, SendNewConnectionId,
(const QuicNewConnectionIdFrame& frame), (override));
- MOCK_METHOD(void, OnNewConnectionIdIssued,
+ MOCK_METHOD(bool, MaybeReserveConnectionId,
(const QuicConnectionId& connection_id), (override));
MOCK_METHOD(void, OnSelfIssuedConnectionIdRetired,
(const QuicConnectionId& connection_id), (override));
@@ -568,7 +570,8 @@
QuicConnectionId cid5 = cid_manager_.GenerateNewConnectionId(cid4);
// Sends CID #1 to peer.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid1));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid1, 1u, 0u)))
.WillOnce(Return(true));
@@ -578,7 +581,8 @@
// Peer retires CID #0;
// Sends CID #2 and asks peer to retire CIDs prior to #1.
// Outcome: (#1, #2) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid2));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid2))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid2, 2u, 1u)))
.WillOnce(Return(true));
@@ -593,7 +597,8 @@
// Peer retires CID #1;
// Sends CID #3 and asks peer to retire CIDs prior to #2.
// Outcome: (#2, #3) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid3));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid3))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid3, 3u, 2u)))
.WillOnce(Return(true));
@@ -608,7 +613,8 @@
// Peer retires CID #2;
// Sends CID #4 and asks peer to retire CIDs prior to #3.
// Outcome: (#3, #4) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid4));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid4))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid4, 4u, 3u)))
.WillOnce(Return(true));
@@ -623,7 +629,8 @@
// Peer retires CID #3;
// Sends CID #5 and asks peer to retire CIDs prior to #4.
// Outcome: (#4, #5) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid5));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid5))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid5, 5u, 4u)))
.WillOnce(Return(true));
@@ -644,7 +651,8 @@
QuicConnectionId cid4 = cid_manager_.GenerateNewConnectionId(cid3);
// Sends CID #1 to peer.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid1));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid1, 1u, 0u)))
.WillOnce(Return(true));
@@ -654,7 +662,8 @@
// Peer retires CID #1;
// Sends CID #2 and asks peer to retire CIDs prior to #0.
// Outcome: (#0, #2) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid2));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid2))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid2, 2u, 0u)))
.WillOnce(Return(true));
@@ -678,7 +687,8 @@
// Peer retires CID #0;
// Sends CID #3 and asks peer to retire CIDs prior to #2.
// Outcome: (#2, #3) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid3));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid3))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid3, 3u, 2u)))
.WillOnce(Return(true));
@@ -693,7 +703,8 @@
// Peer retires CID #3;
// Sends CID #4 and asks peer to retire CIDs prior to #2.
// Outcome: (#2, #4) are active.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid4));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid4))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_,
SendNewConnectionId(ExpectedNewConnectionIdFrame(cid4, 4u, 2u)))
.WillOnce(Return(true));
@@ -720,7 +731,9 @@
QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(3);
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+ .Times(3)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
.Times(3)
.WillRepeatedly(Return(true));
@@ -777,7 +790,9 @@
QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(3);
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+ .Times(3)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
.Times(3)
.WillRepeatedly(Return(true));
@@ -834,7 +849,9 @@
QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
QuicConnectionId cid3 = cid_manager_.GenerateNewConnectionId(cid2);
QuicConnectionId cid;
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(3);
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+ .Times(3)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
.Times(3)
.WillRepeatedly(Return(true));
@@ -893,7 +910,8 @@
QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
// CID #1 is sent to peer.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(1);
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
.WillOnce(Return(true));
cid_manager_.MaybeSendNewConnectionIds();
@@ -909,7 +927,8 @@
TEST_F(QuicSelfIssuedConnectionIdManagerTest,
ErrorWhenTooManyConnectionIdWaitingToBeRetired) {
// CID #0 & #1 are issued.
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
.WillOnce(Return(true));
cid_manager_.MaybeSendNewConnectionIds();
@@ -918,7 +937,8 @@
QuicConnectionId last_connection_id =
cid_manager_.GenerateNewConnectionId(initial_connection_id_);
for (int i = 0; i < 8; ++i) {
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Return(true));
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_));
QuicRetireConnectionIdFrame retire_cid_frame;
retire_cid_frame.sequence_number = i;
@@ -937,17 +957,60 @@
IsError(QUIC_TOO_MANY_CONNECTION_ID_WAITING_TO_RETIRE));
}
+TEST_F(QuicSelfIssuedConnectionIdManagerTest, CannotIssueNewCidDueToVisitor) {
+ QuicConnectionId cid0 = initial_connection_id_;
+ QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
+ .WillOnce(Return(false));
+ if (GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid)) {
+ EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_)).Times(0);
+ } else {
+ EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_)).Times(1);
+ }
+ cid_manager_.MaybeSendNewConnectionIds();
+}
+
+TEST_F(QuicSelfIssuedConnectionIdManagerTest,
+ CannotIssueNewCidUponRetireConnectionIdDueToVisitor) {
+ QuicConnectionId cid0 = initial_connection_id_;
+ QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
+ QuicConnectionId cid2 = cid_manager_.GenerateNewConnectionId(cid1);
+ // CID #0 & #1 are issued.
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_))
+ .WillOnce(Return(true));
+ cid_manager_.MaybeSendNewConnectionIds();
+
+ // CID #2 is not issued.
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid2))
+ .WillOnce(Return(false));
+ if (GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid)) {
+ EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_)).Times(0);
+ } else {
+ EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_)).Times(1);
+ }
+ QuicRetireConnectionIdFrame retire_cid_frame;
+ retire_cid_frame.sequence_number = 1;
+ ASSERT_THAT(cid_manager_.OnRetireConnectionIdFrame(
+ retire_cid_frame, pto_delay_, &error_details_),
+ IsQuicNoError());
+}
+
TEST_F(QuicSelfIssuedConnectionIdManagerTest,
DoNotIssueConnectionIdVoluntarilyIfOneHasIssuedForPerferredAddress) {
QuicConnectionId cid0 = initial_connection_id_;
QuicConnectionId cid1 = cid_manager_.GenerateNewConnectionId(cid0);
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(cid1));
- ASSERT_THAT(cid_manager_.IssueNewConnectionIdForPreferredAddress(),
- ExpectedNewConnectionIdFrame(cid1, 1u, 0u));
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(cid1))
+ .WillOnce(Return(true));
+ absl::optional<QuicNewConnectionIdFrame> new_cid_frame =
+ cid_manager_.MaybeIssueNewConnectionIdForPreferredAddress();
+ ASSERT_TRUE(new_cid_frame.has_value());
+ ASSERT_THAT(*new_cid_frame, ExpectedNewConnectionIdFrame(cid1, 1u, 0u));
EXPECT_THAT(cid_manager_.GetUnretiredConnectionIds(),
ElementsAre(cid0, cid1));
- EXPECT_CALL(cid_manager_visitor_, OnNewConnectionIdIssued(_)).Times(0);
+ EXPECT_CALL(cid_manager_visitor_, MaybeReserveConnectionId(_)).Times(0);
EXPECT_CALL(cid_manager_visitor_, SendNewConnectionId(_)).Times(0);
cid_manager_.MaybeSendNewConnectionIds();
}
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 35c30f4..d33a090 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -1866,9 +1866,11 @@
QuicConnectionPeer::SetAddressValidated(&connection_);
// Sends new server CID to client.
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(
- Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ server_cid1 = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.OnHandshakeComplete();
@@ -2057,8 +2059,11 @@
// Sends new server CID to client.
QuicConnectionId new_cid;
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(Invoke([&](const QuicConnectionId& cid) { new_cid = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ new_cid = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
// Discard INITIAL key.
connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
@@ -2111,8 +2116,11 @@
// Sends new server CID to client.
QuicConnectionId new_cid;
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(Invoke([&](const QuicConnectionId& cid) { new_cid = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ new_cid = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
// Discard INITIAL key.
connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
@@ -2176,9 +2184,11 @@
QuicConnectionId server_cid0 = connection_.connection_id();
QuicConnectionId server_cid1;
// Sends new server CID to client.
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(
- Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ server_cid1 = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.OnHandshakeComplete();
// Receives new client CID from client.
@@ -13315,9 +13325,11 @@
QuicConnectionId client_cid1 = TestConnectionId(2);
QuicConnectionId server_cid1;
// Sends new server CID to client.
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(
- Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ server_cid1 = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.MaybeSendConnectionIdToClient();
// Receives new client CID from client.
@@ -13461,9 +13473,11 @@
QuicConnectionId server_cid0 = connection_.connection_id();
QuicConnectionId server_cid1;
// Sends new server CID to client.
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(
- Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ server_cid1 = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.MaybeSendConnectionIdToClient();
auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
@@ -13580,9 +13594,11 @@
QuicConnectionId client_cid1 = TestConnectionId(2);
QuicConnectionId server_cid1;
// Sends new server CID to client.
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
- .WillOnce(
- Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .WillOnce(Invoke([&](const QuicConnectionId& cid) {
+ server_cid1 = cid;
+ return true;
+ }));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.MaybeSendConnectionIdToClient();
// Receives new client CID from client.
@@ -13682,6 +13698,27 @@
}
}
+TEST_P(QuicConnectionTest, DoNotIssueNewCidIfVisitorSaysNo) {
+ set_perspective(Perspective::IS_SERVER);
+ if (!connection_.connection_migration_use_new_cid()) {
+ return;
+ }
+
+ connection_.CreateConnectionIdManager();
+
+ QuicConnectionId server_cid0 = connection_.connection_id();
+ QuicConnectionId client_cid1 = TestConnectionId(2);
+ QuicConnectionId server_cid1;
+ // Sends new server CID to client.
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_)).WillOnce(Return(false));
+ if (GetQuicReloadableFlag(quic_check_cid_collision_when_issue_new_cid)) {
+ EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(0);
+ } else {
+ EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(1);
+ }
+ connection_.MaybeSendConnectionIdToClient();
+}
+
TEST_P(QuicConnectionTest,
ProbedOnAnotherPathAfterPeerIpAddressChangeAtServer) {
PathProbeTestInit(Perspective::IS_SERVER);
@@ -14217,7 +14254,7 @@
set_perspective(Perspective::IS_SERVER);
connection_.CreateConnectionIdManager();
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_));
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.MaybeSendConnectionIdToClient();
@@ -14250,7 +14287,9 @@
QuicRetireConnectionIdFrame frame;
frame.sequence_number = 0u;
if (connection_.connection_migration_use_new_cid()) {
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_)).Times(2);
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
+ .Times(2)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, SendNewConnectionId(_)).Times(2);
}
EXPECT_TRUE(connection_.OnRetireConnectionIdFrame(frame));
@@ -14270,8 +14309,9 @@
set_perspective(Perspective::IS_SERVER);
connection_.CreateConnectionIdManager();
QuicConnectionId recorded_cid;
- auto cid_recorder = [&recorded_cid](const QuicConnectionId& cid) {
+ auto cid_recorder = [&recorded_cid](const QuicConnectionId& cid) -> bool {
recorded_cid = cid;
+ return true;
};
QuicConnectionId cid0 = connection_id_;
QuicConnectionId cid1;
@@ -14280,7 +14320,7 @@
EXPECT_EQ(connection_.GetOneActiveServerConnectionId(), cid0);
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
.WillOnce(Invoke(cid_recorder));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
connection_.MaybeSendConnectionIdToClient();
@@ -14311,7 +14351,7 @@
// Packet2 with RetireConnectionId frame trigers sending NewConnectionId
// immediately.
- EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+ EXPECT_CALL(visitor_, MaybeReserveConnectionId(_))
.WillOnce(Invoke(cid_recorder));
EXPECT_CALL(visitor_, SendNewConnectionId(_));
peer_creator_.SetServerConnectionId(cid1);
diff --git a/quiche/quic/core/quic_dispatcher.cc b/quiche/quic/core/quic_dispatcher.cc
index 30a93df..883a59d 100644
--- a/quiche/quic/core/quic_dispatcher.cc
+++ b/quiche/quic/core/quic_dispatcher.cc
@@ -1099,7 +1099,7 @@
void QuicDispatcher::OnStopSendingReceived(
const QuicStopSendingFrame& /*frame*/) {}
-void QuicDispatcher::OnNewConnectionIdSent(
+bool QuicDispatcher::TryAddNewConnectionId(
const QuicConnectionId& server_connection_id,
const QuicConnectionId& new_connection_id) {
auto it = reference_counted_session_map_.find(server_connection_id);
@@ -1108,13 +1108,16 @@
<< "Couldn't locate the session that issues the connection ID in "
"reference_counted_session_map_. server_connection_id:"
<< server_connection_id << " new_connection_id: " << new_connection_id;
- return;
+ return false;
}
// Count new connection ID added to the dispatcher map.
QUIC_RELOADABLE_FLAG_COUNT_N(quic_connection_migration_use_new_cid_v2, 6, 6);
auto insertion_result = reference_counted_session_map_.insert(
std::make_pair(new_connection_id, it->second));
- QUICHE_DCHECK(insertion_result.second);
+ if (!insertion_result.second) {
+ QUIC_CODE_COUNT(quic_cid_already_in_session_map);
+ }
+ return insertion_result.second;
}
void QuicDispatcher::OnConnectionIdRetired(
diff --git a/quiche/quic/core/quic_dispatcher.h b/quiche/quic/core/quic_dispatcher.h
index 0a103cd..878f6ac 100644
--- a/quiche/quic/core/quic_dispatcher.h
+++ b/quiche/quic/core/quic_dispatcher.h
@@ -102,8 +102,9 @@
// QuicSession::Visitor interface implementation (via inheritance of
// QuicTimeWaitListManager::Visitor):
- // Add the newly issued connection ID to the session map.
- void OnNewConnectionIdSent(
+ // Try to add the new connection ID to the session map. Returns true on
+ // success.
+ bool TryAddNewConnectionId(
const QuicConnectionId& server_connection_id,
const QuicConnectionId& new_connection_id) override;
diff --git a/quiche/quic/core/quic_dispatcher_test.cc b/quiche/quic/core/quic_dispatcher_test.cc
index f8c169c..b8b8b44 100644
--- a/quiche/quic/core/quic_dispatcher_test.cc
+++ b/quiche/quic/core/quic_dispatcher_test.cc
@@ -170,7 +170,10 @@
active_connection_ids_({connection_id}) {}
void AddNewConnectionId(QuicConnectionId id) {
- dispatcher_->OnNewConnectionIdSent(active_connection_ids_.back(), id);
+ if (!dispatcher_->TryAddNewConnectionId(active_connection_ids_.back(),
+ id)) {
+ return;
+ }
QuicConnectionPeer::SetServerConnectionId(this, id);
active_connection_ids_.push_back(id);
}
@@ -2243,7 +2246,14 @@
::testing::PrintToStringParamName());
TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest,
- OnNewConnectionIdSent) {
+ FailToAddExistingConnectionId) {
+ AddConnection1();
+ EXPECT_FALSE(dispatcher_->TryAddNewConnectionId(TestConnectionId(1),
+ TestConnectionId(1)));
+}
+
+TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest,
+ TryAddNewConnectionId) {
AddConnection1();
ASSERT_EQ(dispatcher_->NumSessions(), 1u);
ASSERT_THAT(session1_, testing::NotNull());
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index d297600..22b05ef 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -2098,12 +2098,13 @@
control_frame_manager_.WriteOrBufferRetireConnectionId(sequence_number);
}
-void QuicSession::OnServerConnectionIdIssued(
+bool QuicSession::MaybeReserveConnectionId(
const QuicConnectionId& server_connection_id) {
if (visitor_) {
- visitor_->OnNewConnectionIdSent(
+ return visitor_->TryAddNewConnectionId(
connection_->GetOneActiveServerConnectionId(), server_connection_id);
}
+ return true;
}
void QuicSession::OnServerConnectionIdRetired(
diff --git a/quiche/quic/core/quic_session.h b/quiche/quic/core/quic_session.h
index 7bdcaa9..0da3b6c 100644
--- a/quiche/quic/core/quic_session.h
+++ b/quiche/quic/core/quic_session.h
@@ -89,8 +89,8 @@
// peer.
virtual void OnStopSendingReceived(const QuicStopSendingFrame& frame) = 0;
- // Called when a NewConnectionId frame has been sent.
- virtual void OnNewConnectionIdSent(
+ // Called when on whether a NewConnectionId frame can been sent.
+ virtual bool TryAddNewConnectionId(
const QuicConnectionId& server_connection_id,
const QuicConnectionId& new_connection_id) = 0;
@@ -145,7 +145,12 @@
void SendAckFrequency(const QuicAckFrequencyFrame& frame) override;
void SendNewConnectionId(const QuicNewConnectionIdFrame& frame) override;
void SendRetireConnectionId(uint64_t sequence_number) override;
- void OnServerConnectionIdIssued(
+ // Returns true if server_connection_id can be issued. If returns true,
+ // |visitor_| may establish a mapping from |server_connection_id| to this
+ // session, if that's not desired,
+ // OnServerConnectionIdRetired(server_connection_id) can be used to remove the
+ // mapping.
+ bool MaybeReserveConnectionId(
const QuicConnectionId& server_connection_id) override;
void OnServerConnectionIdRetired(
const QuicConnectionId& server_connection_id) override;
diff --git a/quiche/quic/test_tools/mock_quic_session_visitor.h b/quiche/quic/test_tools/mock_quic_session_visitor.h
index 53c09d8..61dc5d5 100644
--- a/quiche/quic/test_tools/mock_quic_session_visitor.h
+++ b/quiche/quic/test_tools/mock_quic_session_visitor.h
@@ -27,7 +27,7 @@
(override));
MOCK_METHOD(void, OnStopSendingReceived, (const QuicStopSendingFrame& frame),
(override));
- MOCK_METHOD(void, OnNewConnectionIdSent,
+ MOCK_METHOD(bool, TryAddNewConnectionId,
(const QuicConnectionId& server_connection_id,
const QuicConnectionId& new_connection_id),
(override));
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index 0e2c20c..5e4b52e 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -475,7 +475,7 @@
(const QuicNewConnectionIdFrame& frame), (override));
MOCK_METHOD(void, SendRetireConnectionId, (uint64_t sequence_number),
(override));
- MOCK_METHOD(void, OnServerConnectionIdIssued,
+ MOCK_METHOD(bool, MaybeReserveConnectionId,
(const QuicConnectionId& server_connection_id), (override));
MOCK_METHOD(void, OnServerConnectionIdRetired,
(const QuicConnectionId& server_connection_id), (override));
diff --git a/quiche/quic/test_tools/simulator/quic_endpoint.h b/quiche/quic/test_tools/simulator/quic_endpoint.h
index d3741c5..7654d89 100644
--- a/quiche/quic/test_tools/simulator/quic_endpoint.h
+++ b/quiche/quic/test_tools/simulator/quic_endpoint.h
@@ -74,8 +74,10 @@
void SendNewConnectionId(const QuicNewConnectionIdFrame& /*frame*/) override {
}
void SendRetireConnectionId(uint64_t /*sequence_number*/) override {}
- void OnServerConnectionIdIssued(
- const QuicConnectionId& /*server_connection_id*/) override {}
+ bool MaybeReserveConnectionId(
+ const QuicConnectionId& /*server_connection_id*/) override {
+ return true;
+ }
void OnServerConnectionIdRetired(
const QuicConnectionId& /*server_connection_id*/) override {}
bool AllowSelfAddressChange() const override;