Commit 782c6704 authored by Zhongyi Shi's avatar Zhongyi Shi Committed by Commit Bot

Add logic to send connectivity probing packet to designated destination

using given packet writer. Probing packet effectively is a padded PING
packet.

relnote: n/a currently unused code.

Manual merge internal change: 175555522

Bug: 774622
Cq-Include-Trybots: master.tryserver.chromium.android:android_cronet_tester;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I3c355c31138fa7999c7a36e6b84cb548b701d91c
Reviewed-on: https://chromium-review.googlesource.com/767011Reviewed-by: 's avatarRyan Hamilton <rch@chromium.org>
Commit-Queue: Zhongyi Shi <zhongyi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#516148}
parent 2af1c4f3
......@@ -2376,6 +2376,47 @@ void QuicConnection::SendMtuDiscoveryPacket(QuicByteCount target_mtu) {
packet_generator_.GenerateMtuDiscoveryPacket(target_mtu);
}
void QuicConnection::SendConnectivityProbingPacket(
QuicPacketWriter* probing_writer,
const QuicSocketAddress& peer_address) {
if (perspective_ == Perspective::IS_SERVER && probing_writer == nullptr) {
// Server can use default packet writer to write probing packet.
probing_writer = writer_;
}
DCHECK(!probing_writer && peer_address.IsInitialized());
if (probing_writer->IsWriteBlocked()) {
QUIC_BUG << "Writer blocked when send connectivity probing packet";
visitor_->OnWriteBlocked();
return;
}
QUIC_DLOG(INFO) << ENDPOINT << "Sending connectivity probing packet for "
<< "connection_id = " << connection_id_;
std::unique_ptr<QuicEncryptedPacket> probing_packet(
packet_generator_.SerializeConnectivityProbingPacket());
WriteResult result = probing_writer->WritePacket(
probing_packet->data(), probing_packet->length(), self_address().host(),
peer_address, per_packet_options_);
if (result.status == WRITE_STATUS_ERROR) {
OnWriteError(result.error_code);
QUIC_BUG << "Write probing packet failed with error = "
<< result.error_code;
return;
}
if (result.status == WRITE_STATUS_BLOCKED) {
visitor_->OnWriteBlocked();
if (probing_writer->IsWriteBlockedDataBuffered()) {
QUIC_BUG << "Write probing packet blocked";
}
}
}
void QuicConnection::DiscoverMtu() {
DCHECK(!mtu_discovery_alarm_->IsSet());
......
......@@ -666,6 +666,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection
// |target_mtu|.
void SendMtuDiscoveryPacket(QuicByteCount target_mtu);
// Sends a connectivity probing packet to |peer_address| with
// |probing_writer|. If |probing_writer| is nullptr, will use default
// packet writer to write the packet.
void SendConnectivityProbingPacket(QuicPacketWriter* probing_writer,
const QuicSocketAddress& peer_address);
// Sends an MTU discovery packet of size |mtu_discovery_target_| and updates
// the MTU discovery alarm.
void DiscoverMtu();
......
......@@ -447,6 +447,39 @@ size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
return writer.length();
}
size_t QuicFramer::BuildConnectivityProbingPacket(
const QuicPacketHeader& header,
char* buffer,
size_t packet_length) {
QuicDataWriter writer(packet_length, buffer, endianness());
if (!AppendPacketHeader(header, &writer)) {
QUIC_BUG << "AppendPacketHeader failed";
return 0;
}
// Write a PING frame, which has no data payload.
QuicPingFrame ping_frame;
if (!AppendTypeByte(QuicFrame(ping_frame), false, &writer)) {
QUIC_BUG << "AppendTypeByte failed for ping frame in probing packet";
return 0;
}
// Add padding to the rest of the packet.
QuicPaddingFrame padding_frame;
if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
return 0;
}
if (!AppendPaddingFrame(padding_frame, &writer)) {
QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
<< " failed";
return 0;
}
return writer.length();
}
// static
std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildPublicResetPacket(
const QuicPublicResetPacket& packet) {
......
......@@ -66,7 +66,7 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface {
// Called if an error is detected in the QUIC protocol.
virtual void OnError(QuicFramer* framer) = 0;
// Called only when |perspective_| is IS_SERVER and the the framer gets a
// Called only when |perspective_| is IS_SERVER and the framer gets a
// packet with version flag true and the version on the packet doesn't match
// |quic_version_|. The visitor should return true after it updates the
// version of the |framer_| to |received_version| or false to stop processing
......@@ -248,6 +248,12 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
char* buffer,
size_t packet_length);
// Serializes a probing packet, which is a padded PING packet. Returns the
// length of the packet. Returns 0 if it fails to serialize.
size_t BuildConnectivityProbingPacket(const QuicPacketHeader& header,
char* buffer,
size_t packet_length);
// Returns a new public reset packet.
static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket(
const QuicPublicResetPacket& packet);
......
......@@ -4948,6 +4948,73 @@ TEST_P(QuicFramerTest, BuildPingPacket) {
arraysize(packet));
}
// Test that the connectivity probing packet is serialized correctly as a
// padded PING packet.
TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) {
QuicPacketHeader header;
header.connection_id = kConnectionId;
header.reset_flag = false;
header.version_flag = false;
header.packet_number = kPacketNumber;
// clang-format off
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// frame type (ping frame)
0x07,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned char packet39[] = {
// public flags (8 byte connection_id)
0x38,
// connection_id
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
// packet number
0x12, 0x34, 0x56, 0x78,
0x9A, 0xBC,
// frame type (ping frame)
0x07,
// frame type (padding frame)
0x00,
0x00, 0x00, 0x00, 0x00
};
// clang-format on
unsigned char* p = packet;
size_t packet_size = arraysize(packet);
if (framer_.transport_version() > QUIC_VERSION_38) {
p = packet39;
packet_size = arraysize(packet39);
}
std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
size_t length =
framer_.BuildConnectivityProbingPacket(header, buffer.get(), packet_size);
EXPECT_NE(0u, length);
QuicPacket data(buffer.release(), length, true, header.connection_id_length,
header.version_flag, header.nonce != nullptr,
header.packet_number_length);
test::CompareCharArraysWithHexError(
"constructed packet", data.data(), data.length(),
AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet
: packet39),
arraysize(packet));
}
// Test that the MTU discovery packet is serialized correctly as a PING packet.
TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
QuicPacketHeader header;
......
......@@ -472,6 +472,27 @@ QuicPacketCreator::SerializeVersionNegotiationPacket(
return encrypted;
}
std::unique_ptr<QuicEncryptedPacket>
QuicPacketCreator::SerializeConnectivityProbingPacket() {
QuicPacketHeader header;
// FillPacketHeader increments packet_number_.
FillPacketHeader(&header);
std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
size_t length = framer_->BuildConnectivityProbingPacket(header, buffer.get(),
max_packet_length_);
DCHECK(length);
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
kMaxPacketSize, buffer.get());
DCHECK(encrypted_length);
return QuicMakeUnique<QuicEncryptedPacket>(buffer.release(), encrypted_length,
/*owns_buffer = */ true);
}
// TODO(jri): Make this a public method of framer?
SerializedPacket QuicPacketCreator::NoPacket() {
return SerializedPacket(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false,
......
......@@ -156,6 +156,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator {
std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket(
const QuicTransportVersionVector& supported_versions);
// Creates a connectivity probing packet.
std::unique_ptr<QuicEncryptedPacket> SerializeConnectivityProbingPacket();
// Returns a dummy packet that is valid but contains no useful information.
static SerializedPacket NoPacket();
......
......@@ -678,6 +678,30 @@ TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
client_framer_.ProcessPacket(*encrypted);
}
TEST_P(QuicPacketCreatorTest, SerializeConnectivityProbingPacket) {
for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
EncryptionLevel level = static_cast<EncryptionLevel>(i);
creator_.set_encryption_level(level);
std::unique_ptr<QuicEncryptedPacket> encrypted(
creator_.SerializeConnectivityProbingPacket());
{
InSequence s;
EXPECT_CALL(framer_visitor_, OnPacket());
EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
EXPECT_CALL(framer_visitor_, OnPingFrame(_));
EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
// QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
server_framer_.ProcessPacket(*encrypted);
}
}
TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
......
......@@ -311,6 +311,11 @@ QuicPacketGenerator::SerializeVersionNegotiationPacket(
return packet_creator_.SerializeVersionNegotiationPacket(supported_versions);
}
std::unique_ptr<QuicEncryptedPacket>
QuicPacketGenerator::SerializeConnectivityProbingPacket() {
return packet_creator_.SerializeConnectivityProbingPacket();
}
void QuicPacketGenerator::ReserializeAllFrames(
const QuicPendingRetransmission& retransmission,
char* buffer,
......
......@@ -139,6 +139,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator {
std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket(
const QuicTransportVersionVector& supported_versions);
// Creates a connectivity probing packet.
std::unique_ptr<QuicEncryptedPacket> SerializeConnectivityProbingPacket();
// Re-serializes frames with the original packet's packet number length.
// Used for retransmitting packets to ensure they aren't too long.
void ReserializeAllFrames(const QuicPendingRetransmission& retransmission,
......
......@@ -938,6 +938,20 @@ TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
CheckAllPacketsHaveSingleStreamFrame();
}
// Test sending a connectivity probing packet.
TEST_F(QuicPacketGeneratorTest, GenerateConnectivityProbingPacket) {
delegate_.SetCanWriteAnything();
std::unique_ptr<QuicEncryptedPacket> probing_packet(
generator_.SerializeConnectivityProbingPacket());
ASSERT_TRUE(simple_framer_.ProcessPacket(*probing_packet));
EXPECT_EQ(2u, simple_framer_.num_frames());
EXPECT_EQ(1u, simple_framer_.ping_frames().size());
EXPECT_EQ(1u, simple_framer_.padding_frames().size());
}
// Test sending an MTU probe, without any surrounding data.
TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) {
delegate_.SetCanWriteAnything();
......
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