summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrtenneti <rtenneti@chromium.org>2014-08-25 20:43:43 -0700
committerCommit bot <commit-bot@chromium.org>2014-08-26 03:45:04 +0000
commit4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79 (patch)
tree5c8bb1f75a87850e8cf4ba89874c518fe45d9633 /net
parent139fb7ad98ee8af20d557ff78e52473ea36f3ab1 (diff)
downloadchromium_src-4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79.zip
chromium_src-4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79.tar.gz
chromium_src-4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79.tar.bz2
Change the wire format of the ack frame to include a compressed version
of the previous CongestionFeedback Timestamp frame. Adds QUIC_VERSION_23. Deprecate CongestionFeedbackFrame 1 bytes - num_received_packets First packet: 1 byte - distance from the largest observed in sequence number space. 4 bytes - mod of microseconds since the connection's creation when the packet arrived. (1.1hrs in us) Every other packet: 1 byte - distance from the largest observed in sequence number space. 2 bytes - mod of microseconds since the previous timestamp Merge internal change: 73740829 The following are chromium specific changes: + Changed ACK frame not to send CongestionFeedback frame + Added received_packet_times to ACK frame. + The timestamp that is sent is relative to creation time, thus passed MockClock's now() as argument to AckFrame and it is used to pass QuicFramer's creation time and received_packet_times. R=cyr@google.com, ianswett@google.com, rch@chromium.org Review URL: https://codereview.chromium.org/478153003 Cr-Commit-Position: refs/heads/master@{#291830}
Diffstat (limited to 'net')
-rw-r--r--net/quic/congestion_control/receive_algorithm_interface.cc3
-rw-r--r--net/quic/crypto/crypto_protocol.h1
-rw-r--r--net/quic/quic_config_test.cc7
-rw-r--r--net/quic/quic_connection.cc20
-rw-r--r--net/quic/quic_connection_logger.cc13
-rw-r--r--net/quic/quic_connection_test.cc17
-rw-r--r--net/quic/quic_framer.cc215
-rw-r--r--net/quic/quic_framer.h14
-rw-r--r--net/quic/quic_framer_test.cc954
-rw-r--r--net/quic/quic_http_stream_test.cc4
-rw-r--r--net/quic/quic_network_transaction_unittest.cc6
-rw-r--r--net/quic/quic_packet_creator.cc15
-rw-r--r--net/quic/quic_protocol.cc29
-rw-r--r--net/quic/quic_protocol.h32
-rw-r--r--net/quic/quic_received_packet_manager.cc17
-rw-r--r--net/quic/quic_received_packet_manager.h6
-rw-r--r--net/quic/quic_received_packet_manager_test.cc2
-rw-r--r--net/quic/quic_stream_factory_test.cc4
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.cc5
-rw-r--r--net/quic/test_tools/quic_test_packet_maker.cc35
-rw-r--r--net/quic/test_tools/quic_test_packet_maker.h6
21 files changed, 1255 insertions, 150 deletions
diff --git a/net/quic/congestion_control/receive_algorithm_interface.cc b/net/quic/congestion_control/receive_algorithm_interface.cc
index 91d29dc..812aa46 100644
--- a/net/quic/congestion_control/receive_algorithm_interface.cc
+++ b/net/quic/congestion_control/receive_algorithm_interface.cc
@@ -14,9 +14,6 @@ ReceiveAlgorithmInterface* ReceiveAlgorithmInterface::Create(
switch (type) {
case kTCP:
return new TcpReceiver();
- case kTimestamp:
- LOG(DFATAL) << "Timestamp congestion feedback is not supported";
- return NULL;
}
return NULL;
}
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 30f9282..f791acb 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -49,7 +49,6 @@ const QuicTag kSRBF = TAG('S', 'R', 'B', 'F'); // Socket receive buffer
// Congestion control feedback types
const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic
-const QuicTag kTSTP = TAG('T', 'S', 'T', 'P'); // Timestamp
// Connection options (COPT) values
const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index e2e0348..6cbd4ff 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -80,7 +80,6 @@ TEST_F(QuicConfigTest, ToHandshakeMessage) {
TEST_F(QuicConfigTest, ProcessClientHello) {
QuicConfig client_config;
QuicTagVector cgst;
- cgst.push_back(kTSTP);
cgst.push_back(kQBIC);
client_config.set_congestion_feedback(cgst, kQBIC);
client_config.set_idle_connection_state_lifetime(
@@ -256,7 +255,7 @@ TEST_F(QuicConfigTest, MultipleNegotiatedValuesInVectorTag) {
QuicConfig server_config;
QuicTagVector cgst;
cgst.push_back(kQBIC);
- cgst.push_back(kTSTP);
+ cgst.push_back(kTBBR);
server_config.set_congestion_feedback(cgst, kQBIC);
CryptoHandshakeMessage msg;
@@ -271,8 +270,8 @@ TEST_F(QuicConfigTest, NoOverLapInCGST) {
QuicConfig server_config;
server_config.SetDefaults();
QuicTagVector cgst;
- cgst.push_back(kTSTP);
- server_config.set_congestion_feedback(cgst, kTSTP);
+ cgst.push_back(kTBBR);
+ server_config.set_congestion_feedback(cgst, kTBBR);
CryptoHandshakeMessage msg;
string error_details;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index b100bb9..ab1e0fe 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -211,7 +211,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
largest_seen_packet_with_ack_(0),
largest_seen_packet_with_stop_waiting_(0),
pending_version_negotiation_packet_(false),
- received_packet_manager_(kTCP, &stats_),
+ received_packet_manager_(&stats_),
ack_queued_(false),
stop_waiting_count_(0),
ack_alarm_(helper->CreateAlarm(new AckAlarm(this))),
@@ -269,7 +269,6 @@ QuicConnection::~QuicConnection() {
void QuicConnection::SetFromConfig(const QuicConfig& config) {
SetIdleNetworkTimeout(config.idle_connection_state_lifetime());
sent_packet_manager_.SetFromConfig(config);
- // TODO(satyamshekhar): Set congestion control and ICSL also.
}
bool QuicConnection::SelectMutualVersion(
@@ -1574,15 +1573,16 @@ void QuicConnection::SendPing() {
void QuicConnection::SendAck() {
ack_alarm_->Cancel();
stop_waiting_count_ = 0;
- // TODO(rch): delay this until the CreateFeedbackFrame
- // method is invoked. This requires changes SetShouldSendAck
- // to be a no-arg method, and re-jiggering its implementation.
bool send_feedback = false;
- if (received_packet_manager_.GenerateCongestionFeedback(
- &outgoing_congestion_feedback_)) {
- DVLOG(1) << ENDPOINT << "Sending feedback: "
- << outgoing_congestion_feedback_;
- send_feedback = true;
+
+ // Deprecating the Congestion Feedback Frame after QUIC_VERSION_22.
+ if (version() <= QUIC_VERSION_22) {
+ if (received_packet_manager_.GenerateCongestionFeedback(
+ &outgoing_congestion_feedback_)) {
+ DVLOG(1) << ENDPOINT << "Sending feedback: "
+ << outgoing_congestion_feedback_;
+ send_feedback = true;
+ }
}
packet_generator_.SetShouldSendAck(send_feedback, true);
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index b313ae6..8157848 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -122,19 +122,6 @@ base::Value* NetLogQuicCongestionFeedbackFrameCallback(
NetLog::LogLevel /* log_level */) {
base::DictionaryValue* dict = new base::DictionaryValue();
switch (frame->type) {
- case kTimestamp: {
- dict->SetString("type", "Timestamp");
- base::ListValue* received = new base::ListValue();
- dict->Set("received_packets", received);
- for (TimeMap::const_iterator it =
- frame->timestamp.received_packet_times.begin();
- it != frame->timestamp.received_packet_times.end(); ++it) {
- string value = base::Uint64ToString(it->first) + "@" +
- base::Uint64ToString(it->second.ToDebuggingValue());
- received->AppendString(value);
- }
- break;
- }
case kTCP:
dict->SetString("type", "TCP");
dict->SetInteger("receive_window", frame->tcp.receive_window);
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 1e036f3..5befba7 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -2568,11 +2568,20 @@ TEST_P(QuicConnectionTest, WithQuicCongestionFeedbackFrame) {
QuicCongestionFeedbackFrame info;
info.type = kTCP;
info.tcp.receive_window = 0x4030;
- SetFeedback(&info);
- SendAckPacketToPeer();
- ASSERT_FALSE(writer_->feedback_frames().empty());
- ASSERT_EQ(kTCP, writer_->feedback_frames()[0].type);
+ // After QUIC_VERSION_22, do not send TCP Congestion Feedback Frames anymore.
+ if (version() > QUIC_VERSION_22) {
+ SendAckPacketToPeer();
+ ASSERT_TRUE(writer_->feedback_frames().empty());
+ } else {
+ // Only SetFeedback in this case because SetFeedback will create a receive
+ // algorithm which is how the received_packet_manager checks if it should be
+ // creating TCP Congestion Feedback Frames.
+ SetFeedback(&info);
+ SendAckPacketToPeer();
+ ASSERT_FALSE(writer_->feedback_frames().empty());
+ ASSERT_EQ(kTCP, writer_->feedback_frames()[0].type);
+ }
}
TEST_P(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) {
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index fe70501..84c6b30 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -132,16 +132,6 @@ QuicSequenceNumberLength ReadSequenceNumberLength(uint8 flags) {
}
}
-bool CanTruncate(const QuicFrame& frame, size_t free_bytes) {
- if ((frame.type == ACK_FRAME || frame.type == CONNECTION_CLOSE_FRAME) &&
- free_bytes >=
- QuicFramer::GetMinAckFrameSize(PACKET_6BYTE_SEQUENCE_NUMBER,
- PACKET_6BYTE_SEQUENCE_NUMBER)) {
- return true;
- }
- return false;
-}
-
} // namespace
bool QuicFramerVisitorInterface::OnWindowUpdateFrame(
@@ -168,7 +158,8 @@ QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
alternative_decrypter_latch_(false),
is_server_(is_server),
validate_flags_(true),
- creation_time_(creation_time) {
+ creation_time_(creation_time),
+ last_timestamp_(QuicTime::Delta::Zero()) {
DCHECK(!supported_versions.empty());
quic_version_ = supported_versions_[0];
decrypter_.reset(QuicDecrypter::Create(kNULL));
@@ -302,7 +293,10 @@ size_t QuicFramer::GetSerializedFrameLength(
if (!first_frame) {
return 0;
}
- if (CanTruncate(frame, free_bytes)) {
+ bool can_truncate = frame.type == ACK_FRAME &&
+ free_bytes >= GetMinAckFrameSize(PACKET_6BYTE_SEQUENCE_NUMBER,
+ PACKET_6BYTE_SEQUENCE_NUMBER);
+ if (can_truncate) {
// Truncate the frame so the packet will not exceed kMaxPacketSize.
// Note that we may not use every byte of the writer in this case.
DVLOG(1) << "Truncating large frame, free bytes: " << free_bytes;
@@ -807,6 +801,30 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
return true;
}
+const QuicTime::Delta QuicFramer::CalculateTimestampFromWire(
+ uint32 time_delta_us) {
+ // The new time_delta might have wrapped to the next epoch, or it
+ // might have reverse wrapped to the previous epoch, or it might
+ // remain in the same epoch. Select the time closest to the previous
+ // time.
+ //
+ // epoch_delta is the delta between epochs. A delta is 4 bytes of
+ // microseconds.
+ const uint64 epoch_delta = GG_UINT64_C(1) << 32;
+ uint64 epoch = last_timestamp_.ToMicroseconds() & ~(epoch_delta - 1);
+ // Wrapping is safe here because a wrapped value will not be ClosestTo below.
+ uint64 prev_epoch = epoch - epoch_delta;
+ uint64 next_epoch = epoch + epoch_delta;
+
+ uint64 time = ClosestTo(last_timestamp_.ToMicroseconds(),
+ epoch + time_delta_us,
+ ClosestTo(last_timestamp_.ToMicroseconds(),
+ prev_epoch + time_delta_us,
+ next_epoch + time_delta_us));
+
+ return QuicTime::Delta::FromMicroseconds(time);
+}
+
QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire(
QuicSequenceNumberLength sequence_number_length,
QuicPacketSequenceNumber packet_sequence_number) const {
@@ -1110,8 +1128,12 @@ bool QuicFramer::ProcessFrameData(const QuicPacketHeader& header) {
// Congestion Feedback Frame
if (frame_type & kQuicFrameTypeCongestionFeedbackMask) {
+ if (quic_version_ > QUIC_VERSION_22) {
+ set_detailed_error("Congestion Feedback Frame has been deprecated.");
+ DLOG(WARNING) << "Congestion Feedback Frame has been deprecated.";
+ }
QuicCongestionFeedbackFrame frame;
- if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
+ if (!ProcessCongestionFeedbackFrame(&frame)) {
return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
}
if (!visitor_->OnCongestionFeedbackFrame(frame)) {
@@ -1333,6 +1355,10 @@ bool QuicFramer::ProcessAckFrame(uint8 frame_type, QuicAckFrame* ack_frame) {
QuicTime::Delta::FromMicroseconds(delta_time_largest_observed_us);
}
+ if (!ProcessTimestampsInAckFrame(ack_frame)) {
+ return false;
+ }
+
if (!has_nacks) {
return true;
}
@@ -1386,6 +1412,64 @@ bool QuicFramer::ProcessAckFrame(uint8 frame_type, QuicAckFrame* ack_frame) {
return true;
}
+bool QuicFramer::ProcessTimestampsInAckFrame(QuicAckFrame* ack_frame) {
+ if (version() > QUIC_VERSION_22 && !ack_frame->is_truncated) {
+ uint8 num_received_packets;
+ if (!reader_->ReadBytes(&num_received_packets, 1)) {
+ set_detailed_error("Unable to read num received packets.");
+ return false;
+ }
+
+ if (num_received_packets > 0) {
+ uint8 delta_from_largest_observed;
+ if (!reader_->ReadBytes(&delta_from_largest_observed,
+ PACKET_1BYTE_SEQUENCE_NUMBER)) {
+ set_detailed_error(
+ "Unable to read sequence delta in received packets.");
+ return false;
+ }
+ QuicPacketSequenceNumber seq_num = ack_frame->largest_observed -
+ delta_from_largest_observed;
+
+ // Time delta from the framer creation.
+ uint32 time_delta_us;
+ if (!reader_->ReadBytes(&time_delta_us, sizeof(time_delta_us))) {
+ set_detailed_error("Unable to read time delta in received packets.");
+ return false;
+ }
+
+ last_timestamp_ = CalculateTimestampFromWire(time_delta_us);
+
+ ack_frame->received_packet_times.push_back(
+ make_pair(seq_num, creation_time_.Add(last_timestamp_)));
+
+ for (uint8 i = 1; i < num_received_packets; ++i) {
+ if (!reader_->ReadBytes(&delta_from_largest_observed,
+ PACKET_1BYTE_SEQUENCE_NUMBER)) {
+ set_detailed_error(
+ "Unable to read sequence delta in received packets.");
+ return false;
+ }
+ seq_num = ack_frame->largest_observed - delta_from_largest_observed;
+
+ // Time delta from the previous timestamp.
+ uint64 incremental_time_delta_us;
+ if (!reader_->ReadUFloat16(&incremental_time_delta_us)) {
+ set_detailed_error(
+ "Unable to read incremental time delta in received packets.");
+ return false;
+ }
+
+ last_timestamp_ = last_timestamp_.Add(
+ QuicTime::Delta::FromMicroseconds(incremental_time_delta_us));
+ ack_frame->received_packet_times.push_back(
+ make_pair(seq_num, creation_time_.Add(last_timestamp_)));
+ }
+ }
+ }
+ return true;
+}
+
bool QuicFramer::ProcessStopWaitingFrame(const QuicPacketHeader& header,
QuicStopWaitingFrame* stop_waiting) {
if (!reader_->ReadBytes(&stop_waiting->entropy_hash, 1)) {
@@ -1406,7 +1490,7 @@ bool QuicFramer::ProcessStopWaitingFrame(const QuicPacketHeader& header,
return true;
}
-bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
+bool QuicFramer::ProcessCongestionFeedbackFrame(
QuicCongestionFeedbackFrame* frame) {
uint8 feedback_type;
if (!reader_->ReadBytes(&feedback_type, 1)) {
@@ -1417,10 +1501,6 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
static_cast<CongestionFeedbackType>(feedback_type);
switch (frame->type) {
- case kTimestamp: {
- set_detailed_error("Timestamp feedback not supported.");
- return false;
- }
case kTCP: {
CongestionFeedbackMessageTCP* tcp = &frame->tcp;
uint16 receive_window = 0;
@@ -1716,6 +1796,24 @@ size_t QuicFramer::GetAckFrameSize(
ack_size += min(ack.revived_packets.size(),
kMaxRevivedPackets) * largest_observed_length;
}
+
+ // In version 23, if the ack will be truncated due to too many nack ranges,
+ // then do not include the number of timestamps (1 byte).
+ if (version() > QUIC_VERSION_22 &&
+ ack_info.nack_ranges.size() <= kMaxNackRanges) {
+ // 1 byte for the number of timestamps.
+ ack_size += 1;
+ if (ack.received_packet_times.size() > 0) {
+ // 1 byte for sequence number, 4 bytes for timestamp for the first
+ // packet.
+ ack_size += 5;
+
+ // 1 byte for sequence number, 2 bytes for timestamp for the other
+ // packets.
+ ack_size += 3 * (ack.received_packet_times.size() - 1);
+ }
+ }
+
return ack_size;
}
@@ -1741,10 +1839,6 @@ size_t QuicFramer::ComputeFrameLength(
len += 1; // Congestion feedback type.
switch (congestion_feedback.type) {
- case kTimestamp: {
- set_detailed_error("Timestamp feedback not supported.");
- break;
- }
case kTCP:
len += 2; // Receive window.
break;
@@ -1977,6 +2071,13 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
return false;
}
+ // Timestamp goes at the end of the required fields.
+ if (version() > QUIC_VERSION_22 && !truncated) {
+ if (!AppendTimestampToAckFrame(frame, writer)) {
+ return false;
+ }
+ }
+
if (ack_info.nack_ranges.empty()) {
return true;
}
@@ -2038,10 +2139,6 @@ bool QuicFramer::AppendCongestionFeedbackFrame(
}
switch (frame.type) {
- case kTimestamp: {
- // Timestamp feedback not supported.
- return false;
- }
case kTCP: {
const CongestionFeedbackMessageTCP& tcp = frame.tcp;
DCHECK_LE(tcp.receive_window, 1u << 20);
@@ -2059,6 +2156,72 @@ bool QuicFramer::AppendCongestionFeedbackFrame(
return true;
}
+bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame,
+ QuicDataWriter* writer) {
+ DCHECK_GE(version(), QUIC_VERSION_23);
+ DCHECK_GE(numeric_limits<uint8>::max(), frame.received_packet_times.size());
+ // num_received_packets is only 1 byte.
+ if (frame.received_packet_times.size() > numeric_limits<uint8>::max()) {
+ return false;
+ }
+
+ uint8 num_received_packets = frame.received_packet_times.size();
+
+ if (!writer->WriteBytes(&num_received_packets, 1)) {
+ return false;
+ }
+ if (num_received_packets == 0) {
+ return true;
+ }
+
+ PacketTimeList::const_iterator it = frame.received_packet_times.begin();
+ QuicPacketSequenceNumber sequence_number = it->first;
+ QuicPacketSequenceNumber delta_from_largest_observed =
+ frame.largest_observed - sequence_number;
+
+ DCHECK_GE(numeric_limits<uint8>::max(), delta_from_largest_observed);
+ if (delta_from_largest_observed > numeric_limits<uint8>::max()) {
+ return false;
+ }
+
+ if (!writer->WriteUInt8(
+ delta_from_largest_observed & k1ByteSequenceNumberMask)) {
+ return false;
+ }
+
+ // Use the lowest 4 bytes of the time delta from the creation_time_.
+ const uint64 time_epoch_delta_us = GG_UINT64_C(1) << 32;
+ uint32 time_delta_us =
+ static_cast<uint32>(it->second.Subtract(creation_time_).ToMicroseconds()
+ & (time_epoch_delta_us - 1));
+ if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) {
+ return false;
+ }
+
+ QuicTime prev_time = it->second;
+
+ for (++it; it != frame.received_packet_times.end(); ++it) {
+ sequence_number = it->first;
+ delta_from_largest_observed = frame.largest_observed - sequence_number;
+
+ if (delta_from_largest_observed > numeric_limits<uint8>::max()) {
+ return false;
+ }
+
+ if (!writer->WriteUInt8(
+ delta_from_largest_observed & k1ByteSequenceNumberMask)) {
+ return false;
+ }
+
+ uint64 time_delta_us = it->second.Subtract(prev_time).ToMicroseconds();
+ prev_time = it->second;
+ if (!writer->WriteUFloat16(time_delta_us)) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool QuicFramer::AppendStopWaitingFrame(
const QuicPacketHeader& header,
const QuicStopWaitingFrame& frame,
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index a958786..3489803 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -45,6 +45,8 @@ const size_t kQuicEntropyHashSize = 1;
// Size in bytes reserved for the delta time of the largest observed
// sequence number in ack frames.
const size_t kQuicDeltaTimeLargestObservedSize = 2;
+// Size in bytes reserved for the number of received packets with timestamps.
+const size_t kQuicNumTimestampsSize = 1;
// Size in bytes reserved for the number of missing packets in ack frames.
const size_t kNumberOfNackRangesSize = 1;
// Maximum number of missing packet ranges that can fit within an ack frame.
@@ -409,9 +411,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
bool ProcessFrameData(const QuicPacketHeader& header);
bool ProcessStreamFrame(uint8 frame_type, QuicStreamFrame* frame);
bool ProcessAckFrame(uint8 frame_type, QuicAckFrame* frame);
+ bool ProcessTimestampsInAckFrame(QuicAckFrame* frame);
bool ProcessStopWaitingFrame(const QuicPacketHeader& public_header,
QuicStopWaitingFrame* stop_waiting);
- bool ProcessQuicCongestionFeedbackFrame(
+ bool ProcessCongestionFeedbackFrame(
QuicCongestionFeedbackFrame* congestion_feedback);
bool ProcessRstStreamFrame(QuicRstStreamFrame* frame);
bool ProcessConnectionCloseFrame(QuicConnectionCloseFrame* frame);
@@ -428,6 +431,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicSequenceNumberLength sequence_number_length,
QuicPacketSequenceNumber packet_sequence_number) const;
+ // Returns the QuicTime::Delta corresponding to the time from when the framer
+ // was created.
+ const QuicTime::Delta CalculateTimestampFromWire(uint32 time_delta_us);
+
// Computes the wire size in bytes of the |ack| frame, assuming no truncation.
size_t GetAckFrameSize(const QuicAckFrame& ack,
QuicSequenceNumberLength sequence_number_length);
@@ -463,6 +470,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicDataWriter* builder);
bool AppendCongestionFeedbackFrame(const QuicCongestionFeedbackFrame& frame,
QuicDataWriter* builder);
+ bool AppendTimestampToAckFrame(const QuicAckFrame& frame,
+ QuicDataWriter* builder);
bool AppendStopWaitingFrame(const QuicPacketHeader& header,
const QuicStopWaitingFrame& frame,
QuicDataWriter* builder);
@@ -527,6 +536,9 @@ class NET_EXPORT_PRIVATE QuicFramer {
// The time this framer was created. Time written to the wire will be
// written as a delta from this value.
QuicTime creation_time_;
+ // The time delta computed for the last timestamp frame. This is relative to
+ // the creation_time.
+ QuicTime::Delta last_timestamp_;
DISALLOW_COPY_AND_ASSIGN(QuicFramer);
};
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index d14e673..2c3d274 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -460,7 +460,7 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
void CheckStreamFrameBoundaries(unsigned char* packet,
size_t stream_id_size,
bool include_version) {
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) {
string expected_error;
if (i < kQuicFrameTypeSize + stream_id_size) {
@@ -682,7 +682,7 @@ TEST_P(QuicFramerTest, PacketHeader) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -735,7 +735,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_4BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -791,7 +791,7 @@ TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_1BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -846,7 +846,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -903,7 +903,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -958,7 +958,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_4BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -1013,7 +1013,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_2BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -1068,7 +1068,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) {
EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
EXPECT_EQ(0x00u, visitor_.header_->fec_group);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0;
i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
@@ -1307,7 +1307,7 @@ TEST_P(QuicFramerTest, StreamFrame) {
visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
- // Now test framing boundaries
+ // Now test framing boundaries.
CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, !kIncludeVersion);
}
@@ -1355,7 +1355,7 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
- // Now test framing boundaries
+ // Now test framing boundaries.
const size_t stream_id_size = 3;
CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
}
@@ -1404,7 +1404,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
- // Now test framing boundaries
+ // Now test framing boundaries.
const size_t stream_id_size = 2;
CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
}
@@ -1453,7 +1453,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
- // Now test framing boundaries
+ // Now test framing boundaries.
const size_t stream_id_size = 1;
CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
}
@@ -1506,7 +1506,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
visitor_.stream_frames_[0]->offset);
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
- // Now test framing boundaries
+ // Now test framing boundaries.
CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, kIncludeVersion);
}
@@ -1682,7 +1682,10 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
}
-TEST_P(QuicFramerTest, AckFrame) {
+TEST_P(QuicFramerTest, AckFramev22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
@@ -1745,7 +1748,123 @@ TEST_P(QuicFramerTest, AckFrame) {
PACKET_1BYTE_SEQUENCE_NUMBER;
const size_t kRevivedPacketsLength = kMissingPacketsRange +
PACKET_1BYTE_SEQUENCE_NUMBER;
- // Now test framing boundaries
+ // Now test framing boundaries.
+ const size_t ack_frame_size = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+
+TEST_P(QuicFramerTest, AckFrameTwoTimestamp) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // Number of timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x02,
+ // Delta time.
+ 0x10, 0x32,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ ASSERT_EQ(1u, frame.missing_packets.size());
+ ASSERT_EQ(2u, frame.received_packet_times.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kTimestampDeltaLargestObserved1 = kNumTimestampsOffset +
+ kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved1 =
+ kTimestampDeltaLargestObserved1 + 1;
+ const size_t kTimestampDeltaLargestObserved2 =
+ kTimestampTimeDeltaLargestObserved1 + 4;
+ const size_t kTimestampTimeDeltaLargestObserved2 =
+ kTimestampDeltaLargestObserved2 + 1;
+ const size_t kNumMissingPacketOffset =
+ kTimestampTimeDeltaLargestObserved2 + 2;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries.
const size_t ack_frame_size = kRevivedPacketsLength +
PACKET_1BYTE_SEQUENCE_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
@@ -1754,8 +1873,233 @@ TEST_P(QuicFramerTest, AckFrame) {
expected_error = "Unable to read entropy hash for received packets.";
} else if (i < kMissingDeltaTimeOffset) {
expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kTimestampDeltaLargestObserved1) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved1) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kTimestampDeltaLargestObserved2) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved2) {
+ expected_error = "Unable to read sequence delta in received packets.";
} else if (i < kNumMissingPacketOffset) {
+ expected_error =
+ "Unable to read incremental time delta in received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+
+TEST_P(QuicFramerTest, AckFrameOneTimestamp) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // Number of timestamps.
+ 0x01,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ ASSERT_EQ(1u, frame.missing_packets.size());
+ ASSERT_EQ(1u, frame.received_packet_times.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kTimestampDeltaLargestObserved = kNumTimestampsOffset +
+ kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved =
+ kTimestampDeltaLargestObserved + 1;
+ const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kTimestampDeltaLargestObserved) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+
+TEST_P(QuicFramerTest, AckFrame) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // Number of timestamps.
+ 0x00,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ ASSERT_EQ(1u, frame.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumMissingPacketOffset = kNumTimestampsOffset +
+ kQuicNumTimestampsSize;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read num received packets.";
} else if (i < kMissingPacketsOffset) {
expected_error = "Unable to read num missing packet ranges.";
} else if (i < kMissingPacketsRange) {
@@ -1774,6 +2118,9 @@ TEST_P(QuicFramerTest, AckFrame) {
}
TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
@@ -1796,6 +2143,8 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
0x34, 0x12,
// Zero delta time.
0x0, 0x0,
+ // num received packets.
+ 0x00,
// num missing packets
0x01,
// missing packet delta
@@ -1807,6 +2156,117 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
// Revived packet sequence number.
0xBE, 0x9A, 0x78, 0x56,
0x34, 0x12,
+ // Number of revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed);
+ ASSERT_EQ(1u, frame.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumMissingPacketOffset = kNumTimestampsOffset +
+ kQuicNumTimestampsSize;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size = kRevivedPacketSequenceNumberLength +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kReceivedEntropyOffset) {
+ expected_error = "Unable to read least unacked delta.";
+ } else if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else if (i < kRevivedPacketSequenceNumberLength) {
+ expected_error = "Unable to read num revived packets.";
+ } else {
+ expected_error = "Unable to read revived packet.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameRevivedPacketsv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x01,
+ // Revived packet sequence number.
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Number of revived packets.
+ 0x00,
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
@@ -1841,7 +2301,7 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
PACKET_1BYTE_SEQUENCE_NUMBER;
const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength +
PACKET_1BYTE_SEQUENCE_NUMBER;
- // Now test framing boundaries
+ // Now test framing boundaries.
const size_t ack_frame_size = kRevivedPacketSequenceNumberLength +
PACKET_6BYTE_SEQUENCE_NUMBER;
for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
@@ -1873,7 +2333,63 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
}
}
+TEST_P(QuicFramerTest, AckFrameNoNacksv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (no nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x4C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed);
+ ASSERT_EQ(0u, frame->missing_packets.size());
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, AckFrameNoNacks) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
@@ -1896,6 +2412,8 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
0x34, 0x12,
// Zero delta time.
0x0, 0x0,
+ // Number of received packets.
+ 0x00,
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
@@ -1923,7 +2441,83 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
AsChars(packet), arraysize(packet));
}
+TEST_P(QuicFramerTest, AckFrame500Nacksv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges
+ 0x02,
+ // missing packet delta
+ 0x01,
+ // 243 more missing packets in range.
+ // The ranges are listed in this order so the re-constructed packet matches.
+ 0xF3,
+ // No gap between ranges
+ 0x00,
+ // 255 more missing packets in range.
+ 0xFF,
+ // No revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed);
+ EXPECT_EQ(0u, frame->revived_packets.size());
+ ASSERT_EQ(500u, frame->missing_packets.size());
+ SequenceNumberSet::const_iterator first_missing_iter =
+ frame->missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE) - 499, *first_missing_iter);
+ SequenceNumberSet::const_reverse_iterator last_missing_iter =
+ frame->missing_packets.rbegin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *last_missing_iter);
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, AckFrame500Nacks) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte connection_id)
0x3C,
@@ -1946,6 +2540,8 @@ TEST_P(QuicFramerTest, AckFrame500Nacks) {
0x34, 0x12,
// Zero delta time.
0x0, 0x0,
+ // No received packets.
+ 0x00,
// num missing packet ranges
0x02,
// missing packet delta
@@ -2028,7 +2624,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) {
ASSERT_EQ(kTCP, frame.type);
EXPECT_EQ(0x4030u, frame.tcp.receive_window);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < 4; ++i) {
string expected_error;
if (i < 2) {
@@ -2170,7 +2766,7 @@ TEST_P(QuicFramerTest, RstStreamFrameQuic) {
EXPECT_EQ(GG_UINT64_C(0x0807060504030201),
visitor_.rst_stream_frame_.byte_offset);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetMinRstStreamFrameSize(); ++i) {
string expected_error;
@@ -2234,7 +2830,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
ASSERT_EQ(0u, visitor_.ack_frames_.size());
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) {
string expected_error;
@@ -2292,7 +2888,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
const size_t reason_size = arraysize("because I can") - 1;
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) {
string expected_error;
@@ -2347,7 +2943,7 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) {
EXPECT_EQ(GG_UINT64_C(0x0c0b0a0908070605),
visitor_.window_update_frame_.byte_offset);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize;
i < QuicFramer::GetWindowUpdateFrameSize(); ++i) {
string expected_error;
@@ -2394,7 +2990,7 @@ TEST_P(QuicFramerTest, BlockedFrame) {
EXPECT_EQ(GG_UINT64_C(0x01020304),
visitor_.blocked_frame_.stream_id);
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
++i) {
string expected_error = "Unable to read stream_id.";
@@ -2481,7 +3077,7 @@ TEST_P(QuicFramerTest, PublicResetPacket) {
EXPECT_TRUE(
visitor_.public_reset_packet_->client_address.address().empty());
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0; i < arraysize(packet); ++i) {
string expected_error;
DVLOG(1) << "iteration: " << i;
@@ -2587,7 +3183,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
client_address.address()));
EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port());
- // Now test framing boundaries
+ // Now test framing boundaries.
for (size_t i = 0; i < arraysize(packet); ++i) {
string expected_error;
DVLOG(1) << "iteration: " << i;
@@ -3052,7 +3648,73 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
AsChars(packet), arraysize(packet));
}
+TEST_P(QuicFramerTest, BuildAckFramePacketv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ ack_frame.entropy_hash = 0x43;
+ ack_frame.largest_observed = GG_UINT64_C(0x770123456789ABF);
+ ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+ ack_frame.missing_packets.insert(
+ GG_UINT64_C(0x770123456789ABE));
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, BuildAckFramePacket) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -3094,6 +3756,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) {
0x34, 0x12,
// Zero delta time.
0x0, 0x0,
+ // num received packets.
+ 0x00,
// num missing packet ranges
0x01,
// missing packet delta
@@ -3114,7 +3778,126 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) {
// TODO(jri): Add test for tuncated packets in which the original ack frame had
// revived packets. (In both the large and small packet cases below).
+
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacketv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ // This entropy hash is different from what shows up in the packet below,
+ // since entropy is recomputed by the framer on ack truncation (by
+ // TestEntropyCalculator for this test.)
+ ack_frame.entropy_hash = 0x43;
+ ack_frame.largest_observed = 2 * 300;
+ ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+ for (size_t i = 1; i < 2 * 300; i += 2) {
+ ack_frame.missing_packets.insert(i);
+ }
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet sequence number.
+ // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
+ 0xFE, 0x01,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges (limited to 255 by size of this field).
+ 0xFF,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges x 42 + 3 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildDataPacket(header, frames, kMaxPacketSize).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -3227,7 +4010,79 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
}
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacketv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ // This entropy hash is different from what shows up in the packet below,
+ // since entropy is recomputed by the framer on ack truncation (by
+ // TestEntropyCalculator for this test.)
+ ack_frame.entropy_hash = 0x43;
+ ack_frame.largest_observed = 2 * 300;
+ ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+ for (size_t i = 1; i < 2 * 300; i += 2) {
+ ack_frame.missing_packets.insert(i);
+ }
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet sequence number.
+ // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
+ 0x0C, 0x00,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges (limited to 6 by packet size of 37).
+ 0x06,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildDataPacket(header, frames, 37u).packet);
+ ASSERT_TRUE(data != NULL);
+ // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
+ EXPECT_EQ(36u, data->length());
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -3396,7 +4251,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInvalidFeedback) {
QuicCongestionFeedbackFrame congestion_feedback_frame;
congestion_feedback_frame.type =
- static_cast<CongestionFeedbackType>(kTimestamp + 1);
+ static_cast<CongestionFeedbackType>(kTCP + 1);
QuicFrames frames;
frames.push_back(QuicFrame(&congestion_feedback_frame));
@@ -3953,7 +4808,54 @@ TEST_P(QuicFramerTest, AckTruncationLargePacket) {
EXPECT_EQ(509u, *last_missing_iter);
}
+TEST_P(QuicFramerTest, AckTruncationSmallPacketv22) {
+ if (version_ > QUIC_VERSION_22) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.fec_group = 0;
+
+ // Create a packet with just the ack.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(300, 0u);
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = &ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ // Build an ack packet with truncation due to limit in number of nack ranges.
+ scoped_ptr<QuicPacket> raw_ack_packet(
+ framer_.BuildDataPacket(header, frames, 500).packet);
+ ASSERT_TRUE(raw_ack_packet != NULL);
+ scoped_ptr<QuicEncryptedPacket> ack_packet(
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet));
+ // Now make sure we can turn our ack packet back into an ack frame.
+ ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+ EXPECT_TRUE(processed_ack_frame.is_truncated);
+ EXPECT_EQ(476u, processed_ack_frame.largest_observed);
+ ASSERT_EQ(238u, processed_ack_frame.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ processed_ack_frame.missing_packets.begin();
+ EXPECT_EQ(1u, *missing_iter);
+ SequenceNumberSet::const_reverse_iterator last_missing_iter =
+ processed_ack_frame.missing_packets.rbegin();
+ EXPECT_EQ(475u, *last_missing_iter);
+}
+
+
TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
+ if (version_ <= QUIC_VERSION_22) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 14b1a11..75e533c 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -150,12 +150,13 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
read_buffer_(new IOBufferWithSize(4096)),
connection_id_(2),
stream_id_(kClientDataStreamId1),
- maker_(GetParam(), connection_id_),
+ maker_(GetParam(), connection_id_, &clock_),
random_generator_(0) {
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
peer_addr_ = IPEndPoint(ip, 443);
self_addr_ = IPEndPoint(ip, 8435);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
}
~QuicHttpStreamTest() {
@@ -243,7 +244,6 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
stream_.reset(use_closing_stream_ ?
new AutoClosingStream(session_->GetWeakPtr()) :
new QuicHttpStream(session_->GetWeakPtr()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
}
void SetRequest(const std::string& method,
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 3d119fb..c835184 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -107,8 +107,8 @@ class QuicNetworkTransactionTest
public ::testing::WithParamInterface<QuicVersion> {
protected:
QuicNetworkTransactionTest()
- : maker_(GetParam(), 0),
- clock_(new MockClock),
+ : clock_(new MockClock),
+ maker_(GetParam(), 0, clock_),
ssl_config_service_(new SSLConfigServiceDefaults),
proxy_service_(ProxyService::CreateDirect()),
auth_handler_factory_(
@@ -304,11 +304,11 @@ class QuicNetworkTransactionTest
socket_factory_.AddSocketDataProvider(&hanging_data_);
}
+ MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
QuicTestPacketMaker maker_;
scoped_refptr<HttpNetworkSession> session_;
MockClientSocketFactory socket_factory_;
MockCryptoClientStreamFactory crypto_client_stream_factory_;
- MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
MockHostResolver host_resolver_;
MockCertVerifier cert_verifier_;
TransportSecurityState transport_security_state_;
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 1c3a1a8..1ca834e 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -379,19 +379,20 @@ SerializedPacket QuicPacketCreator::SerializePacket() {
size_t max_plaintext_size =
framer_->GetMaxPlaintextSize(max_packet_length_);
DCHECK_GE(max_plaintext_size, packet_size_);
- // ACK Frames will be truncated only if they're the only frame in the packet,
- // and if packet_size_ was set to max_plaintext_size. If truncation occurred,
- // then GetSerializedFrameLength will have returned all bytes free.
- bool possibly_truncated = packet_size_ == max_plaintext_size &&
- queued_frames_.size() == 1 &&
- queued_frames_.back().type == ACK_FRAME;
+ // ACK Frames will be truncated due to length only if they're the only frame
+ // in the packet, and if packet_size_ was set to max_plaintext_size. If
+ // truncation due to length occurred, then GetSerializedFrameLength will have
+ // returned all bytes free.
+ bool possibly_truncated_by_length = packet_size_ == max_plaintext_size &&
+ queued_frames_.size() == 1 &&
+ queued_frames_.back().type == ACK_FRAME;
SerializedPacket serialized =
framer_->BuildDataPacket(header, queued_frames_, packet_size_);
LOG_IF(DFATAL, !serialized.packet)
<< "Failed to serialize " << queued_frames_.size() << " frames.";
// Because of possible truncation, we can't be confident that our
// packet size calculation worked correctly.
- if (!possibly_truncated) {
+ if (!possibly_truncated_by_length) {
DCHECK_EQ(packet_size_, serialized.packet->length());
}
packet_size_ = 0;
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 66925ba..314f0ff 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -171,6 +171,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
return MakeQuicTag('Q', '0', '2', '1');
case QUIC_VERSION_22:
return MakeQuicTag('Q', '0', '2', '2');
+ case QUIC_VERSION_23:
+ return MakeQuicTag('Q', '0', '2', '3');
default:
// This shold be an ERROR because we should never attempt to convert an
// invalid QuicVersion to be written to the wire.
@@ -203,6 +205,7 @@ string QuicVersionToString(const QuicVersion version) {
RETURN_STRING_LITERAL(QUIC_VERSION_20);
RETURN_STRING_LITERAL(QUIC_VERSION_21);
RETURN_STRING_LITERAL(QUIC_VERSION_22);
+ RETURN_STRING_LITERAL(QUIC_VERSION_23);
default:
return "QUIC_VERSION_UNSUPPORTED";
}
@@ -274,11 +277,6 @@ CongestionFeedbackMessageTCP::CongestionFeedbackMessageTCP()
: receive_window(0) {
}
-CongestionFeedbackMessageTimestamp::CongestionFeedbackMessageTimestamp() {
-}
-
-CongestionFeedbackMessageTimestamp::~CongestionFeedbackMessageTimestamp() {}
-
QuicCongestionFeedbackFrame::QuicCongestionFeedbackFrame() : type(kTCP) {}
QuicCongestionFeedbackFrame::~QuicCongestionFeedbackFrame() {}
@@ -383,7 +381,6 @@ ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) {
ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
os << "entropy_hash: " << static_cast<int>(ack_frame.entropy_hash)
- << " is_truncated: " << ack_frame.is_truncated
<< " largest_observed: " << ack_frame.largest_observed
<< " delta_time_largest_observed: "
<< ack_frame.delta_time_largest_observed.ToMicroseconds()
@@ -392,11 +389,18 @@ ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
it != ack_frame.missing_packets.end(); ++it) {
os << *it << " ";
}
- os << " ] revived_packets: [ ";
+ os << " ] is_truncated: " << ack_frame.is_truncated;
+ os << " revived_packets: [ ";
for (SequenceNumberSet::const_iterator it = ack_frame.revived_packets.begin();
it != ack_frame.revived_packets.end(); ++it) {
os << *it << " ";
}
+ os << " ] received_packets: [ ";
+ for (PacketTimeList::const_iterator it =
+ ack_frame.received_packet_times.begin();
+ it != ack_frame.received_packet_times.end(); ++it) {
+ os << it->first << " at " << it->second.ToDebuggingValue() << " ";
+ }
os << " ]";
return os;
}
@@ -504,17 +508,6 @@ ostream& operator<<(ostream& os,
const QuicCongestionFeedbackFrame& congestion_frame) {
os << "type: " << congestion_frame.type;
switch (congestion_frame.type) {
- case kTimestamp: {
- const CongestionFeedbackMessageTimestamp& timestamp =
- congestion_frame.timestamp;
- os << " received packets: [ ";
- for (TimeMap::const_iterator it = timestamp.received_packet_times.begin();
- it != timestamp.received_packet_times.end(); ++it) {
- os << it->first << "@" << it->second.ToDebuggingValue() << " ";
- }
- os << "]";
- break;
- }
case kTCP: {
const CongestionFeedbackMessageTCP& tcp = congestion_frame.tcp;
os << " receive_window: " << tcp.receive_window;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 539c6d3..0d9fb84 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <limits>
+#include <list>
#include <map>
#include <ostream>
#include <set>
@@ -291,6 +292,7 @@ enum QuicVersion {
QUIC_VERSION_20 = 20, // Independent stream/connection flow control windows.
QUIC_VERSION_21 = 21, // Headers/crypto streams are flow controlled.
QUIC_VERSION_22 = 22, // Send Server Config Update messages on crypto stream.
+ QUIC_VERSION_23 = 23, // Timestamp in the ack frame.
};
// This vector contains QUIC versions which we currently support.
@@ -300,7 +302,8 @@ enum QuicVersion {
//
// IMPORTANT: if you are adding to this list, follow the instructions at
// http://sites/quic/adding-and-removing-versions
-static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_22,
+static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_23,
+ QUIC_VERSION_22,
QUIC_VERSION_21,
QUIC_VERSION_20,
QUIC_VERSION_19,
@@ -644,8 +647,8 @@ struct NET_EXPORT_PRIVATE QuicStreamFrame {
// TODO(ianswett): Re-evaluate the trade-offs of hash_set vs set when framing
// is finalized.
typedef std::set<QuicPacketSequenceNumber> SequenceNumberSet;
-// TODO(pwestin): Add a way to enforce the max size of this map.
-typedef std::map<QuicPacketSequenceNumber, QuicTime> TimeMap;
+
+typedef std::list<std::pair<QuicPacketSequenceNumber, QuicTime>> PacketTimeList;
struct NET_EXPORT_PRIVATE QuicStopWaitingFrame {
QuicStopWaitingFrame();
@@ -696,6 +699,9 @@ struct NET_EXPORT_PRIVATE QuicAckFrame {
// Packets which have been revived via FEC.
// All of these must also be in missing_packets.
SequenceNumberSet revived_packets;
+
+ // List of <sequence_number, time> for when packets arrived.
+ PacketTimeList received_packet_times;
};
// True if the sequence number is greater than largest_observed or is listed
@@ -714,9 +720,9 @@ void NET_EXPORT_PRIVATE InsertMissingPacketsBetween(
// Defines for all types of congestion feedback that will be negotiated in QUIC,
// kTCP MUST be supported by all QUIC implementations to guarantee 100%
// compatibility.
+// TODO(cyr): Remove this when removing QUIC_VERSION_22.
enum CongestionFeedbackType {
kTCP, // Used to mimic TCP.
- kTimestamp, // Use additional inter arrival timestamp information.
};
// Defines for all types of congestion control algorithms that can be used in
@@ -734,21 +740,14 @@ enum LossDetectionType {
kTime, // Time based loss detection.
};
+// TODO(cyr): Remove this when removing QUIC_VERSION_22.
struct NET_EXPORT_PRIVATE CongestionFeedbackMessageTCP {
CongestionFeedbackMessageTCP();
QuicByteCount receive_window;
};
-struct NET_EXPORT_PRIVATE CongestionFeedbackMessageTimestamp {
- CongestionFeedbackMessageTimestamp();
- ~CongestionFeedbackMessageTimestamp();
-
- // The set of received packets since the last feedback was sent, along with
- // their arrival times.
- TimeMap received_packet_times;
-};
-
+// TODO(cyr): Remove this when removing QUIC_VERSION_22.
struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame {
QuicCongestionFeedbackFrame();
~QuicCongestionFeedbackFrame();
@@ -760,7 +759,6 @@ struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame {
// This should really be a union, but since the timestamp struct
// is non-trivial, C++ prohibits it.
CongestionFeedbackMessageTCP tcp;
- CongestionFeedbackMessageTimestamp timestamp;
};
struct NET_EXPORT_PRIVATE QuicRstStreamFrame {
@@ -861,7 +859,10 @@ struct NET_EXPORT_PRIVATE QuicFrame {
explicit QuicFrame(QuicPaddingFrame* padding_frame);
explicit QuicFrame(QuicStreamFrame* stream_frame);
explicit QuicFrame(QuicAckFrame* frame);
+
+ // TODO(cyr): Remove this when removing QUIC_VERSION_22.
explicit QuicFrame(QuicCongestionFeedbackFrame* frame);
+
explicit QuicFrame(QuicRstStreamFrame* frame);
explicit QuicFrame(QuicConnectionCloseFrame* frame);
explicit QuicFrame(QuicStopWaitingFrame* frame);
@@ -878,8 +879,11 @@ struct NET_EXPORT_PRIVATE QuicFrame {
QuicPaddingFrame* padding_frame;
QuicStreamFrame* stream_frame;
QuicAckFrame* ack_frame;
+
+ // TODO(cyr): Remove this when removing QUIC_VERSION_22.
QuicCongestionFeedbackFrame* congestion_feedback_frame;
QuicStopWaitingFrame* stop_waiting_frame;
+
QuicPingFrame* ping_frame;
QuicRstStreamFrame* rst_stream_frame;
QuicConnectionCloseFrame* connection_close_frame;
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index 15030a4..98136f8 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -7,11 +7,13 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/base/linked_hash_map.h"
+#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/quic_connection_stats.h"
using std::make_pair;
using std::max;
using std::min;
+using std::numeric_limits;
namespace net {
@@ -128,11 +130,10 @@ AdvanceFirstGapAndGarbageCollectEntropyMap() {
}
QuicReceivedPacketManager::QuicReceivedPacketManager(
- CongestionFeedbackType congestion_type,
QuicConnectionStats* stats)
: peer_least_packet_awaiting_ack_(0),
time_largest_observed_(QuicTime::Zero()),
- receive_algorithm_(ReceiveAlgorithmInterface::Create(congestion_type)),
+ receive_algorithm_(ReceiveAlgorithmInterface::Create(kTCP)),
stats_(stats) {
ack_frame_.largest_observed = 0;
ack_frame_.entropy_hash = 0;
@@ -178,6 +179,9 @@ void QuicReceivedPacketManager::RecordPacketReceived(
receive_algorithm_->RecordIncomingPacket(
bytes, sequence_number, receipt_time);
+ received_packet_times_.push_back(
+ std::make_pair(sequence_number, receipt_time));
+
ack_frame_.revived_packets.erase(sequence_number);
}
@@ -216,6 +220,15 @@ void QuicReceivedPacketManager::UpdateReceivedPacketInfo(
ack_frame->delta_time_largest_observed =
approximate_now.Subtract(time_largest_observed_);
+
+ // Remove all packets that are too far from largest_observed to express.
+ received_packet_times_.remove_if(
+ [this] (std::pair<QuicPacketSequenceNumber, QuicTime> p)
+ { return ack_frame_.largest_observed - p.first >=
+ numeric_limits<uint8>::max();});
+
+ ack_frame->received_packet_times = received_packet_times_;
+ received_packet_times_.clear();
}
bool QuicReceivedPacketManager::GenerateCongestionFeedback(
diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h
index 92c08f5..57a1175d 100644
--- a/net/quic/quic_received_packet_manager.h
+++ b/net/quic/quic_received_packet_manager.h
@@ -11,6 +11,7 @@
#include <deque>
#include "net/quic/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/quic_config.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_protocol.h"
@@ -94,8 +95,7 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
DISALLOW_COPY_AND_ASSIGN(EntropyTracker);
};
- explicit QuicReceivedPacketManager(CongestionFeedbackType congestion_type,
- QuicConnectionStats* stats);
+ explicit QuicReceivedPacketManager(QuicConnectionStats* stats);
virtual ~QuicReceivedPacketManager();
// Updates the internal state concerning which packets have been received.
@@ -172,6 +172,8 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
QuicConnectionStats* stats_;
+ PacketTimeList received_packet_times_;
+
DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacketManager);
};
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc
index 2a219d3..9e8c128 100644
--- a/net/quic/quic_received_packet_manager_test.cc
+++ b/net/quic/quic_received_packet_manager_test.cc
@@ -188,7 +188,7 @@ TEST(EntropyTrackerTest, SetCumulativeEntropyUpTo) {
class QuicReceivedPacketManagerTest : public ::testing::Test {
protected:
- QuicReceivedPacketManagerTest() : received_manager_(kTCP, &stats_) {}
+ QuicReceivedPacketManagerTest() : received_manager_(&stats_) {}
void RecordPacketReceipt(QuicPacketSequenceNumber sequence_number,
QuicPacketEntropyHash entropy_hash) {
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 5cb5b57..82ec1cd 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -90,8 +90,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
protected:
QuicStreamFactoryTest()
: random_generator_(0),
- maker_(GetParam(), 0),
clock_(new MockClock()),
+ maker_(GetParam(), 0, clock_),
cert_verifier_(CertVerifier::CreateDefault()),
channel_id_service_(new ChannelIDService(
new DefaultChannelIDStore(NULL),
@@ -187,8 +187,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
DeterministicMockClientSocketFactory socket_factory_;
MockCryptoClientStreamFactory crypto_client_stream_factory_;
MockRandom random_generator_;
- QuicTestPacketMaker maker_;
MockClock* clock_; // Owned by factory_.
+ QuicTestPacketMaker maker_;
scoped_ptr<CertVerifier> cert_verifier_;
scoped_ptr<ChannelIDService> channel_id_service_;
TransportSecurityState transport_security_state_;
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index 4d4057a..ea7b84f 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -81,7 +81,10 @@ void MockCryptoClientStream::SendOnCryptoHandshakeEvent(
void MockCryptoClientStream::SetConfigNegotiated() {
ASSERT_FALSE(session()->config()->negotiated());
QuicTagVector cgst;
- cgst.push_back(kTSTP);
+ // TODO(rtenneti): Enable the following code after BBR code is checked in.
+#if 0
+ cgst.push_back(kTBBR);
+#endif
cgst.push_back(kQBIC);
session()->config()->set_congestion_feedback(cgst, kQBIC);
session()->config()->set_idle_connection_state_lifetime(
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc
index 345b7b5..6540426 100644
--- a/net/quic/test_tools/quic_test_packet_maker.cc
+++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -4,18 +4,24 @@
#include "net/quic/test_tools/quic_test_packet_maker.h"
+#include <list>
+
#include "net/quic/quic_framer.h"
#include "net/quic/quic_http_utils.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
+using std::make_pair;
+
namespace net {
namespace test {
QuicTestPacketMaker::QuicTestPacketMaker(QuicVersion version,
- QuicConnectionId connection_id)
+ QuicConnectionId connection_id,
+ MockClock* clock)
: version_(version),
connection_id_(connection_id),
+ clock_(clock),
spdy_request_framer_(SPDY3),
spdy_response_framer_(SPDY3) {
}
@@ -63,10 +69,16 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket(
QuicAckFrame ack(MakeAckFrame(largest_received));
ack.delta_time_largest_observed = QuicTime::Delta::Zero();
+ if (version_ > QUIC_VERSION_22) {
+ for (QuicPacketSequenceNumber i = least_unacked; i <= largest_received;
+ ++i) {
+ ack.received_packet_times.push_back(make_pair(i, clock_->Now()));
+ }
+ }
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
QuicCongestionFeedbackFrame feedback;
- if (send_feedback) {
+ if (send_feedback && version_ <= QUIC_VERSION_22) {
feedback.type = kTCP;
feedback.tcp.receive_window = 256000;
@@ -80,7 +92,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket(
QuicRstStreamFrame rst(stream_id, error_code, 0);
frames.push_back(QuicFrame(&rst));
- QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), false);
+ QuicFramer framer(SupportedVersions(version_), clock_->Now(), false);
scoped_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
@@ -122,15 +134,20 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket(
QuicAckFrame ack(MakeAckFrame(largest_received));
ack.delta_time_largest_observed = QuicTime::Delta::Zero();
+ if (version_ > QUIC_VERSION_22) {
+ for (QuicPacketSequenceNumber i = least_unacked; i <= largest_received;
+ ++i) {
+ ack.received_packet_times.push_back(make_pair(i, clock_->Now()));
+ }
+ }
- QuicCongestionFeedbackFrame feedback;
- feedback.type = kTCP;
- feedback.tcp.receive_window = 256000;
-
- QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), false);
+ QuicFramer framer(SupportedVersions(version_), clock_->Now(), false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
- if (send_feedback) {
+ QuicCongestionFeedbackFrame feedback;
+ if (send_feedback && version_ <= QUIC_VERSION_22) {
+ feedback.type = kTCP;
+ feedback.tcp.receive_window = 256000;
frames.push_back(QuicFrame(&feedback));
}
diff --git a/net/quic/test_tools/quic_test_packet_maker.h b/net/quic/test_tools/quic_test_packet_maker.h
index e4f3ec0..9120eeb 100644
--- a/net/quic/test_tools/quic_test_packet_maker.h
+++ b/net/quic/test_tools/quic_test_packet_maker.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "net/base/request_priority.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_protocol.h"
@@ -19,7 +20,9 @@ namespace test {
class QuicTestPacketMaker {
public:
- QuicTestPacketMaker(QuicVersion version, QuicConnectionId connection_id);
+ QuicTestPacketMaker(QuicVersion version,
+ QuicConnectionId connection_id,
+ MockClock* clock);
~QuicTestPacketMaker();
scoped_ptr<QuicEncryptedPacket> MakeRstPacket(
@@ -77,6 +80,7 @@ class QuicTestPacketMaker {
QuicVersion version_;
QuicConnectionId connection_id_;
+ MockClock* clock_; // Owned by QuicStreamFactory.
SpdyFramer spdy_request_framer_;
SpdyFramer spdy_response_framer_;
MockRandom random_generator_;