Land Recent QUIC changes.
Pass HasRetransmittableData to the congestion manager and the send
algorithm. This allows tcp_cubic_sender to not count ACK-only packets
against the congestion window.
Merge internal change: 51829697
If a previously zombie'd QUIC stream is closed and the headers have been
decompressed, remove that entry from the zombie stream map.
Merge internal change: 51697989
Change the value used to set the sequence number with to both correctly
calculate the widest packet spread currently outstanding and fix a
DCHECK failure in EndToEnd's Uber test when packets were transmitted
sufficiently out of order that the packet being sent was less than the
last packet the peer was awaiting.
Merge internal change: 51644967
Fix a bug where frames are queued and not enough room for the next
stream frame is available, but we attempt to create a STREAM frame
anyway in ConsumeData.
Merge internal change: 51604946
Changed Delayed Ack Timer to go off before the sender's retransmission
timer goes off.
Merge internal change: 51594956
Using the priorities sent by the client, including bounds checking,
and bumping the priority of initial writes to avoid the HOL header
blocking issue.
Merge internal change: 51586426
Fix memory leak uncovered by https://codereview.chromium.org/23587004
Merge internal change: 51569066
Added logging of QUIC version negotiated.
Export number of QUIC sessions and streams for each QUIC version.
Merge internal change: 51540178
A refactor of QuicFdWrapper's writev to pass the iovec all the way to
QuicConnection, allowing better packet packing.
Merge internal change: 51530908
Enabled priorities in chrome quic streams.
[email protected]
Review URL: https://chromiumcodereview.appspot.com/23597045
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223880 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 83d6bb7..837de5f 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -1460,6 +1460,12 @@
// }
EVENT_TYPE(QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED)
+// Session sucessfully negotiated QUIC version number.
+// {
+// "version": <String of QUIC version negotiated with the server>,
+// }
+EVENT_TYPE(QUIC_SESSION_VERSION_NEGOTIATED)
+
// Session revived a QUIC packet packet via FEC.
// {
// "guid": <The 64-bit GUID for this connection, as a base-10 string>,
diff --git a/net/net.gyp b/net/net.gyp
index 1cce2a62..f8cb550 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -825,6 +825,8 @@
'quic/quic_framer.h',
'quic/quic_http_stream.cc',
'quic/quic_http_stream.h',
+ 'quic/quic_http_utils.cc',
+ 'quic/quic_http_utils.h',
'quic/quic_packet_creator.cc',
'quic/quic_packet_creator.h',
'quic/quic_packet_generator.cc',
@@ -1768,6 +1770,7 @@
'quic/quic_fec_group_test.cc',
'quic/quic_framer_test.cc',
'quic/quic_http_stream_test.cc',
+ 'quic/quic_http_utils_test.cc',
'quic/quic_network_transaction_unittest.cc',
'quic/quic_packet_creator_test.cc',
'quic/quic_packet_generator_test.cc',
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 22f759fa..99aa10fa 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -60,15 +60,18 @@
// Ignore losses for fix rate sender.
}
-void FixRateSender::SentPacket(QuicTime sent_time,
- QuicPacketSequenceNumber /*sequence_number*/,
- QuicByteCount bytes,
- Retransmission is_retransmission) {
+bool FixRateSender::SentPacket(
+ QuicTime sent_time,
+ QuicPacketSequenceNumber /*sequence_number*/,
+ QuicByteCount bytes,
+ Retransmission is_retransmission,
+ HasRetransmittableData /*has_retransmittable_data*/) {
fix_rate_leaky_bucket_.Add(sent_time, bytes);
paced_sender_.SentPacket(sent_time, bytes);
if (is_retransmission == NOT_RETRANSMISSION) {
data_in_flight_ += bytes;
}
+ return true;
}
void FixRateSender::AbandoningPacket(
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index 38cebad1..781dead 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -32,10 +32,12 @@
QuicByteCount acked_bytes,
QuicTime::Delta rtt) OVERRIDE;
virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE;
- virtual void SentPacket(QuicTime sent_time,
- QuicPacketSequenceNumber equence_number,
- QuicByteCount bytes,
- Retransmission is_retransmission) OVERRIDE;
+ virtual bool SentPacket(
+ QuicTime sent_time,
+ QuicPacketSequenceNumber equence_number,
+ QuicByteCount bytes,
+ Retransmission is_retransmission,
+ HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index f914ed6..e316f651 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -63,11 +63,14 @@
EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond());
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
- sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION);
+ sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
- sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, NOT_RETRANSMISSION);
- sender_->SentPacket(clock_.Now(), 3, 600, NOT_RETRANSMISSION);
+ sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
+ sender_->SentPacket(clock_.Now(), 3, 600, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
sender_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE));
@@ -98,12 +101,12 @@
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE).IsZero());
sender_->SentPacket(clock_.Now(), sequence_number++, packet_size,
- NOT_RETRANSMISSION);
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE).IsZero());
sender_->SentPacket(clock_.Now(), sequence_number++, packet_size,
- NOT_RETRANSMISSION);
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE);
clock_.AdvanceTime(advance_time);
diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc
index 3afa378..5640a73 100644
--- a/net/quic/congestion_control/inter_arrival_sender.cc
+++ b/net/quic/congestion_control/inter_arrival_sender.cc
@@ -235,14 +235,17 @@
}
}
-void InterArrivalSender::SentPacket(QuicTime sent_time,
- QuicPacketSequenceNumber sequence_number,
- QuicByteCount bytes,
- Retransmission /*retransmit*/) {
+bool InterArrivalSender::SentPacket(
+ QuicTime sent_time,
+ QuicPacketSequenceNumber sequence_number,
+ QuicByteCount bytes,
+ Retransmission /*is_retransmit*/,
+ HasRetransmittableData /*has_retransmittable_data*/) {
if (probing_) {
probe_->OnSentPacket(bytes);
}
paced_sender_->SentPacket(sent_time, bytes);
+ return true;
}
void InterArrivalSender::AbandoningPacket(
diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h
index ad28ecd2..2c455cc 100644
--- a/net/quic/congestion_control/inter_arrival_sender.h
+++ b/net/quic/congestion_control/inter_arrival_sender.h
@@ -43,10 +43,12 @@
virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE;
- virtual void SentPacket(QuicTime sent_time,
- QuicPacketSequenceNumber sequence_number,
- QuicByteCount bytes,
- Retransmission is_retransmit) OVERRIDE;
+ virtual bool SentPacket(
+ QuicTime sent_time,
+ QuicPacketSequenceNumber sequence_number,
+ QuicByteCount bytes,
+ Retransmission is_retransmit,
+ HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes) OVERRIDE;
diff --git a/net/quic/congestion_control/inter_arrival_sender_test.cc b/net/quic/congestion_control/inter_arrival_sender_test.cc
index d0faca0..7392b1a3 100644
--- a/net/quic/congestion_control/inter_arrival_sender_test.cc
+++ b/net/quic/congestion_control/inter_arrival_sender_test.cc
@@ -41,7 +41,7 @@
bytes_in_packet, send_clock_.Now());
sender_.SentPacket(send_clock_.Now(), sequence_number_, bytes_in_packet,
- NOT_RETRANSMISSION);
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
sequence_number_++;
}
EXPECT_FALSE(sender_.TimeUntilSend(send_clock_.Now(),
diff --git a/net/quic/congestion_control/quic_congestion_control_test.cc b/net/quic/congestion_control/quic_congestion_control_test.cc
index 0051aca..457538f4 100644
--- a/net/quic/congestion_control/quic_congestion_control_test.cc
+++ b/net/quic/congestion_control/quic_congestion_control_test.cc
@@ -49,7 +49,8 @@
clock_.Now());
EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(1, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+ manager_->SentPacket(1, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE));
@@ -78,7 +79,8 @@
for (QuicPacketSequenceNumber i = 1; i <= 100; ++i) {
EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(i, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+ manager_->SentPacket(i, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
QuicTime::Delta advance_time = manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE);
clock_.AdvanceTime(advance_time);
@@ -108,10 +110,12 @@
for (QuicPacketSequenceNumber i = 1; i <= 100;) {
EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+ manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+ manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
QuicTime::Delta advance_time = manager_->TimeUntilSend(clock_.Now(),
NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE);
clock_.AdvanceTime(advance_time);
diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc
index ba6bab8..ec519db 100644
--- a/net/quic/congestion_control/quic_congestion_manager.cc
+++ b/net/quic/congestion_control/quic_congestion_manager.cc
@@ -48,18 +48,21 @@
STLDeleteValues(&packet_history_map_);
}
-void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number,
- QuicTime sent_time,
- QuicByteCount bytes,
- Retransmission retransmission) {
+void QuicCongestionManager::SentPacket(
+ QuicPacketSequenceNumber sequence_number,
+ QuicTime sent_time,
+ QuicByteCount bytes,
+ Retransmission retransmission,
+ HasRetransmittableData has_retransmittable_data) {
DCHECK(!ContainsKey(pending_packets_, sequence_number));
- send_algorithm_->SentPacket(sent_time, sequence_number, bytes,
- retransmission);
- packet_history_map_[sequence_number] =
- new class SendAlgorithmInterface::SentPacket(bytes, sent_time);
- pending_packets_[sequence_number] = bytes;
- CleanupPacketHistory();
+ if (send_algorithm_->SentPacket(sent_time, sequence_number, bytes,
+ retransmission, has_retransmittable_data)) {
+ packet_history_map_[sequence_number] =
+ new class SendAlgorithmInterface::SentPacket(bytes, sent_time);
+ pending_packets_[sequence_number] = bytes;
+ CleanupPacketHistory();
+ }
}
// Called when a packet is timed out.
@@ -156,6 +159,23 @@
return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
}
+// Ensures that the Delayed Ack timer is always set to a value lesser
+// than the retransmission timer's minimum value (MinRTO). We want the
+// delayed ack to get back to the QUIC peer before the sender's
+// retransmission timer triggers. Since we do not know the
+// reverse-path one-way delay, we assume equal delays for forward and
+// reverse paths, and ensure that the timer is set to less than half
+// of the MinRTO.
+// There may be a value in making this delay adaptive with the help of
+// the sender and a signaling mechanism -- if the sender uses a
+// different MinRTO, we may get spurious retransmissions. May not have
+// any benefits, but if the delayed ack becomes a significant source
+// of (likely, tail) latency, then consider such a mechanism.
+
+const QuicTime::Delta QuicCongestionManager::DelayedAckTime() {
+ return QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs/2);
+}
+
const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay(
size_t unacked_packets_count,
size_t number_retransmissions) {
diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h
index 8bfa3c1..465819be 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -50,7 +50,8 @@
virtual void SentPacket(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes,
- Retransmission retransmission);
+ Retransmission retransmission,
+ HasRetransmittableData has_retransmittable_data);
// Called when a packet is timed out.
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number);
@@ -85,6 +86,9 @@
const QuicTime::Delta DefaultRetransmissionTime();
+ // Returns amount of time for delayed ack timer.
+ const QuicTime::Delta DelayedAckTime();
+
const QuicTime::Delta GetRetransmissionDelay(
size_t unacked_packets_count,
size_t number_retransmissions);
diff --git a/net/quic/congestion_control/quic_congestion_manager_test.cc b/net/quic/congestion_control/quic_congestion_manager_test.cc
index 1cf44a2..80460f55 100644
--- a/net/quic/congestion_control/quic_congestion_manager_test.cc
+++ b/net/quic/congestion_control/quic_congestion_manager_test.cc
@@ -14,6 +14,7 @@
using testing::_;
using testing::StrictMock;
+using testing::Return;
namespace net {
namespace test {
@@ -64,7 +65,8 @@
clock_.AdvanceTime(advance_time);
EXPECT_TRUE(manager_->TimeUntilSend(
clock_.Now(), NOT_RETRANSMISSION, kIgnored, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(i, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(i, clock_.Now(), 1000, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
// Ack the packet we sent.
ack.received_info.largest_observed = i;
manager_->OnIncomingAckFrame(ack, clock_.Now());
@@ -92,8 +94,8 @@
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
EXPECT_TRUE(manager_->TimeUntilSend(
clock_.Now(), NOT_RETRANSMISSION, kIgnored, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(
- sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(sequence_number, clock_.Now(), 1000,
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
// Ack the packet we sent.
ack.received_info.largest_observed = sequence_number;
manager_->OnIncomingAckFrame(ack, clock_.Now());
@@ -118,7 +120,8 @@
for (int i = 1; i <= 150; ++i) {
EXPECT_TRUE(manager_->TimeUntilSend(
clock_.Now(), NOT_RETRANSMISSION, kIgnored, NOT_HANDSHAKE).IsZero());
- manager_->SentPacket(i + 100, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(i + 100, clock_.Now(), 1000, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
// Ack the packet we sent.
ack.received_info.largest_observed = i + 100;
@@ -141,11 +144,13 @@
QuicPacketSequenceNumber sequence_number = 1;
QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15);
- EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _))
+ .Times(1).WillOnce(Return(true));
EXPECT_CALL(*send_algorithm,
OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
- manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
QuicAckFrame ack;
@@ -167,11 +172,13 @@
QuicPacketSequenceNumber sequence_number = 1;
QuicTime::Delta expected_rtt = QuicTime::Delta::Infinite();
- EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _))
+ .Times(1).WillOnce(Return(true));
EXPECT_CALL(*send_algorithm,
OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
- manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
QuicAckFrame ack;
@@ -193,11 +200,13 @@
QuicPacketSequenceNumber sequence_number = 1;
QuicTime::Delta expected_rtt = QuicTime::Delta::Infinite();
- EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _))
+ .Times(1).WillOnce(Return(true));
EXPECT_CALL(*send_algorithm,
OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
- manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
QuicAckFrame ack;
@@ -218,11 +227,13 @@
QuicPacketSequenceNumber sequence_number = 1;
QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
- EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
- EXPECT_CALL(*send_algorithm,
- OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
+ EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _))
+ .Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*send_algorithm, OnIncomingAck(sequence_number, _, expected_rtt))
+ .Times(1);
- manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+ manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(expected_rtt);
QuicAckFrame ack;
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 8896b2b..c29f225 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -55,11 +55,15 @@
virtual void OnIncomingLoss(QuicTime ack_receive_time) = 0;
// Inform that we sent x bytes to the wire, and if that was a retransmission.
+ // Returns true if the packet should be tracked by the congestion manager,
+ // false otherwise. This is used by implementations such as tcp_cubic_sender
+ // that do not count outgoing ACK packets against the congestion window.
// Note: this function must be called for every packet sent to the wire.
- virtual void SentPacket(QuicTime sent_time,
+ virtual bool SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- Retransmission is_retransmission) = 0;
+ Retransmission is_retransmission,
+ HasRetransmittableData is_retransmittable) = 0;
// Called when a packet is timed out.
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 438dbe91..52c910e8 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -65,6 +65,7 @@
void TcpCubicSender::OnIncomingAck(
QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes,
QuicTime::Delta rtt) {
+ DCHECK_GE(bytes_in_flight_, acked_bytes);
bytes_in_flight_ -= acked_bytes;
CongestionAvoidance(acked_sequence_number);
AckAccounting(rtt);
@@ -93,10 +94,16 @@
DLOG(INFO) << "Incoming loss; congestion window:" << congestion_window_;
}
-void TcpCubicSender::SentPacket(QuicTime /*sent_time*/,
+bool TcpCubicSender::SentPacket(QuicTime /*sent_time*/,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- Retransmission is_retransmission) {
+ Retransmission is_retransmission,
+ HasRetransmittableData is_retransmittable) {
+ // Only update bytes_in_flight_ for data packets.
+ if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) {
+ return false;
+ }
+
bytes_in_flight_ += bytes;
if (is_retransmission == NOT_RETRANSMISSION && update_end_sequence_number_) {
end_sequence_number_ = sequence_number;
@@ -105,10 +112,12 @@
DLOG(INFO) << "Stop update end sequence number @" << sequence_number;
}
}
+ return true;
}
void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes) {
+ DCHECK_GE(bytes_in_flight_, abandoned_bytes);
bytes_in_flight_ -= abandoned_bytes;
}
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 8cea0aa4..db829c2 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -41,10 +41,12 @@
QuicByteCount acked_bytes,
QuicTime::Delta rtt) OVERRIDE;
virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE;
- virtual void SentPacket(QuicTime sent_time,
- QuicPacketSequenceNumber sequence_number,
- QuicByteCount bytes,
- Retransmission is_retransmission) OVERRIDE;
+ virtual bool SentPacket(
+ QuicTime sent_time,
+ QuicPacketSequenceNumber sequence_number,
+ QuicByteCount bytes,
+ Retransmission is_retransmission,
+ HasRetransmittableData is_retransmittable) OVERRIDE;
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index fb67fcd..c7046fc 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -45,7 +45,7 @@
while (bytes_to_send > 0) {
QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send);
sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet,
- NOT_RETRANSMISSION);
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
bytes_to_send -= bytes_in_packet;
if (bytes_to_send > 0) {
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION,
@@ -352,5 +352,22 @@
EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
}
+TEST_F(TcpCubicSenderTest, CongestionWindowNotAffectedByAcks) {
+ QuicByteCount congestion_window = sender_->AvailableCongestionWindow();
+
+ // Send a packet with no retransmittable data, and ensure that the congestion
+ // window doesn't change.
+ QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, congestion_window);
+ sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet,
+ NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
+ EXPECT_EQ(congestion_window, sender_->AvailableCongestionWindow());
+
+ // Send a data packet with retransmittable data, and ensure that the
+ // congestion window has shrunk.
+ sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet,
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ EXPECT_GT(congestion_window, sender_->AvailableCongestionWindow());
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index ec87d779..ca6941c 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -314,6 +314,12 @@
NotifyFactoryOfSessionCloseLater();
}
+void QuicClientSession::OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) {
+ logger_.OnSuccessfulVersionNegotiation(version);
+ QuicSession::OnSuccessfulVersionNegotiation(version);
+}
+
void QuicClientSession::StartReading() {
if (read_pending_) {
return;
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index a5973b6..d167237 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -113,6 +113,8 @@
// QuicConnectionVisitorInterface methods:
virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
+ virtual void OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) OVERRIDE;
// Performs a crypto handshake with the server.
int CryptoConnect(bool require_confirmation,
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 748821e..0633f90 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -19,6 +19,7 @@
using std::make_pair;
using std::min;
using std::max;
+using std::numeric_limits;
using std::vector;
using std::set;
using std::string;
@@ -282,6 +283,7 @@
}
version_negotiation_state_ = NEGOTIATED_VERSION;
+ visitor_->OnSuccessfulVersionNegotiation(received_version);
// Store the new version.
framer_.set_version(received_version);
@@ -380,6 +382,7 @@
DCHECK_EQ(1u, header.public_header.versions.size());
DCHECK_EQ(header.public_header.versions[0], version());
version_negotiation_state_ = NEGOTIATED_VERSION;
+ visitor_->OnSuccessfulVersionNegotiation(version());
}
} else {
DCHECK(!header.public_header.version_flag);
@@ -387,6 +390,7 @@
// it should stop sending version since the version negotiation is done.
packet_creator_.StopSendingVersion();
version_negotiation_state_ = NEGOTIATED_VERSION;
+ visitor_->OnSuccessfulVersionNegotiation(version());
}
}
@@ -781,7 +785,7 @@
// Set the ack alarm for when any retransmittable frame is received.
if (!ack_alarm_->IsSet()) {
ack_alarm_->Set(clock_->ApproximateNow().Add(
- congestion_manager_.DefaultRetransmissionTime()));
+ congestion_manager_.DelayedAckTime()));
}
}
send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_;
@@ -817,26 +821,51 @@
delete encrypted;
}
-QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
- StringPiece data,
- QuicStreamOffset offset,
- bool fin) {
- // To make reasoning about crypto frames easier, we don't combine them with
- // any other frames in a single packet.
- const bool crypto_frame_while_batch_mode =
- id == kCryptoStreamId && packet_generator_.InBatchMode();
+QuicConsumedData QuicConnection::SendvStreamData(QuicStreamId id,
+ const struct iovec* iov,
+ int count,
+ QuicStreamOffset offset,
+ bool fin) {
+ // TODO(ianswett): Further improve sending by passing the iovec down
+ // instead of batching into multiple stream frames in a single packet.
+ const bool already_in_batch_mode = packet_generator_.InBatchMode();
+ packet_generator_.StartBatchOperations();
- if (crypto_frame_while_batch_mode) {
- // Flush pending frames to make room for a crypto frame.
+ size_t bytes_written = 0;
+ bool fin_consumed = false;
+ for (int i = 0; i < count; ++i) {
+ bool send_fin = fin && (i == count - 1);
+ if (!send_fin && iov[i].iov_len == 0) {
+ LOG(DFATAL) << "Attempt to send empty stream frame";
+ }
+ QuicConsumedData data_consumed = packet_generator_.ConsumeData(
+ id,
+ StringPiece(static_cast<char*>(iov[i].iov_base), iov[i].iov_len),
+ offset + bytes_written,
+ send_fin);
+ DCHECK_LE(data_consumed.bytes_consumed, numeric_limits<uint32>::max());
+ bytes_written += data_consumed.bytes_consumed;
+ fin_consumed = data_consumed.fin_consumed;
+ // If no bytes were consumed, bail now, because the stream can not write
+ // more data.
+ if (data_consumed.bytes_consumed < iov[i].iov_len) {
+ break;
+ }
+ }
+ // Handle the 0 byte write properly.
+ if (count == 0) {
+ DCHECK(fin);
+ QuicConsumedData data_consumed = packet_generator_.ConsumeData(
+ id, StringPiece(), offset, fin);
+ fin_consumed = data_consumed.fin_consumed;
+ }
+
+ // Leave the generator in the original batch state.
+ if (!already_in_batch_mode) {
packet_generator_.FinishBatchOperations();
}
- QuicConsumedData consumed_data =
- packet_generator_.ConsumeData(id, data, offset, fin);
- if (crypto_frame_while_batch_mode) {
- // Restore batch mode.
- packet_generator_.StartBatchOperations();
- }
- return consumed_data;
+ DCHECK_EQ(already_in_batch_mode, packet_generator_.InBatchMode());
+ return QuicConsumedData(bytes_written, fin_consumed);
}
QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked(
@@ -845,6 +874,9 @@
QuicStreamOffset offset,
bool fin,
QuicAckNotifier::DelegateInterface* delegate) {
+ if (!fin && data.empty()) {
+ LOG(DFATAL) << "Attempt to send empty stream frame";
+ }
// This notifier will be deleted in ProcessAckFrame once it has seen ACKs for
// all the consumed data (or below if no data was consumed).
QuicAckNotifier* notifier = new QuicAckNotifier(delegate);
@@ -953,12 +985,12 @@
// write more.
if (CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
maybe_handshake)) {
- const bool in_batch_mode = packet_generator_.InBatchMode();
- if (!in_batch_mode) {
+ const bool already_in_batch_mode = packet_generator_.InBatchMode();
+ if (!already_in_batch_mode) {
packet_generator_.StartBatchOperations();
}
bool all_bytes_written = visitor_->OnCanWrite();
- if (!in_batch_mode) {
+ if (!already_in_batch_mode) {
packet_generator_.FinishBatchOperations();
}
@@ -1305,7 +1337,11 @@
// If the socket buffers the the data, then the packet should not
// be queued and sent again, which would result in an unnecessary
// duplicate packet being sent.
- return helper_->IsWriteBlockedDataBuffered();
+ if (helper_->IsWriteBlockedDataBuffered()) {
+ delete packet;
+ return true;
+ }
+ return false;
}
// We can't send an error as the socket is presumably borked.
CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
@@ -1323,11 +1359,13 @@
// TODO(ianswett): Change the sequence number length and other packet creator
// options by a more explicit API than setting a struct value directly.
- packet_creator_.options()->send_sequence_number_length =
- CalculateSequenceNumberLength(sequence_number);
+ packet_creator_.UpdateSequenceNumberLength(
+ received_packet_manager_.least_packet_awaited_by_peer(),
+ congestion_manager_.BandwidthEstimate().ToBytesPerPeriod(
+ congestion_manager_.SmoothedRtt()));
congestion_manager_.SentPacket(sequence_number, now, packet->length(),
- retransmission);
+ retransmission, retransmittable);
stats_.bytes_sent += encrypted->length();
++stats_.packets_sent;
@@ -1355,31 +1393,6 @@
return bytes_written;
}
-QuicSequenceNumberLength QuicConnection::CalculateSequenceNumberLength(
- QuicPacketSequenceNumber sequence_number) {
- DCHECK_LE(received_packet_manager_.least_packet_awaited_by_peer(),
- sequence_number);
- // Since the packet creator will not change sequence number length mid FEC
- // group, include the size of an FEC group to be safe.
- const QuicPacketSequenceNumber current_delta =
- packet_creator_.options()->max_packets_per_fec_group + sequence_number
- - received_packet_manager_.least_packet_awaited_by_peer();
- const uint64 congestion_window =
- congestion_manager_.BandwidthEstimate().ToBytesPerPeriod(
- congestion_manager_.SmoothedRtt()) /
- packet_creator_.options()->max_packet_length;
- const uint64 delta = max(current_delta, congestion_window);
-
- if (delta < 1 << ((PACKET_1BYTE_SEQUENCE_NUMBER * 8) - 2)) {
- return PACKET_1BYTE_SEQUENCE_NUMBER;
- } else if (delta < 1 << ((PACKET_2BYTE_SEQUENCE_NUMBER * 8) - 2)) {
- return PACKET_2BYTE_SEQUENCE_NUMBER;
- } else if (delta < 1 << ((PACKET_4BYTE_SEQUENCE_NUMBER * 8) - 2)) {
- return PACKET_4BYTE_SEQUENCE_NUMBER;
- }
- return PACKET_6BYTE_SEQUENCE_NUMBER;
-}
-
bool QuicConnection::OnSerializedPacket(
const SerializedPacket& serialized_packet) {
if (serialized_packet.retransmittable_frames != NULL) {
@@ -1716,6 +1729,14 @@
}
}
+void QuicConnection::Flush() {
+ if (!packet_generator_.InBatchMode()) {
+ return;
+ }
+ packet_generator_.FinishBatchOperations();
+ packet_generator_.StartBatchOperations();
+}
+
bool QuicConnection::HasQueuedData() const {
return !queued_packets_.empty() || packet_generator_.HasQueuedFrames();
}
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index a23ecf0..8420752 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -24,6 +24,7 @@
#include <vector>
#include "base/containers/hash_tables.h"
+#include "net/base/iovec.h"
#include "net/base/ip_endpoint.h"
#include "net/base/linked_hash_map.h"
#include "net/quic/congestion_control/quic_congestion_manager.h"
@@ -76,6 +77,9 @@
// Called when packets are acked by the peer.
virtual void OnAck(const SequenceNumberSet& acked_packets) = 0;
+ // Called once a specific QUIC version is agreed by both endpoints.
+ virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) = 0;
+
// Called when a blocked socket becomes writable. If all pending bytes for
// this visitor are consumed by the connection successfully this should
// return true, otherwise it should return false.
@@ -205,15 +209,17 @@
QuicVersion version);
virtual ~QuicConnection();
- // Send the data payload to the peer.
+ // Send the data in |iov| to the peer in as few packets as possible.
// Returns a pair with the number of bytes consumed from data, and a boolean
// indicating if the fin bit was consumed. This does not indicate the data
// has been sent on the wire: it may have been turned into a packet and queued
// if the socket was unexpectedly blocked.
- QuicConsumedData SendStreamData(QuicStreamId id,
- base::StringPiece data,
- QuicStreamOffset offset,
- bool fin);
+ QuicConsumedData SendvStreamData(QuicStreamId id,
+ const struct iovec* iov,
+ int count,
+ QuicStreamOffset offset,
+ bool fin);
+
// Same as above, except that the provided delegate will be informed once ACKs
// have been received for all the packets written.
// The |delegate| is not owned by the QuicConnection and must outlive it.
@@ -240,7 +246,7 @@
virtual void SendConnectionCloseWithDetails(QuicErrorCode error,
const std::string& details);
// Notifies the visitor of the close and marks the connection as disconnected.
- void CloseConnection(QuicErrorCode error, bool from_peer);
+ virtual void CloseConnection(QuicErrorCode error, bool from_peer) OVERRIDE;
virtual void SendGoAway(QuicErrorCode error,
QuicStreamId last_good_stream_id,
const std::string& reason);
@@ -335,6 +341,10 @@
// Testing only.
size_t NumQueuedPackets() const { return queued_packets_.size(); }
+ // Flush any queued frames immediately. Preserves the batch write mode and
+ // does nothing if there are no pending frames.
+ void Flush();
+
// Returns true if the connection has queued packets or frames.
bool HasQueuedData() const;
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 9f1bcac..366e97b 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -125,6 +125,8 @@
testing::Return(QuicBandwidth::FromKBitsPerSecond(100)));
EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(
testing::Return(QuicTime::Delta::FromMilliseconds(100)));
+ ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _))
+ .WillByDefault(testing::Return(true));
connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_));
connection_->set_visitor(&visitor_);
connection_->SetSendAlgorithm(send_algorithm_);
@@ -315,12 +317,14 @@
QuicTime::Delta::FromMilliseconds(500);
QuicTime start = clock_.ApproximateNow();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _));
// Send a packet.
- connection_->SendStreamData(1, kData, 0, false);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION));
+ struct iovec iov = {const_cast<char*>(kData),
+ static_cast<size_t>(strlen(kData))};
+ connection_->SendvStreamData(1, &iov, 1, 0, false);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION, _));
// Since no ack was received, the retransmission alarm will fire and
// retransmit it.
runner_->RunNextTask();
@@ -343,11 +347,14 @@
QuicTime::Delta::FromMilliseconds(500);
QuicTime start = clock_.ApproximateNow();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _));
+
// Send a packet.
- connection_->SendStreamData(1, kData, 0, false);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION));
+ struct iovec iov = {const_cast<char*>(kData),
+ static_cast<size_t>(strlen(kData))};
+ connection_->SendvStreamData(1, &iov, 1, 0, false);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION, _));
// Since no ack was received, the retransmission alarm will fire and
// retransmit it.
runner_->RunNextTask();
@@ -357,7 +364,7 @@
// Since no ack was received, the retransmission alarm will fire and
// retransmit it.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 3, _, IS_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 3, _, IS_RETRANSMISSION, _));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _));
runner_->RunNextTask();
@@ -376,7 +383,7 @@
EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultInitialTimeoutSecs),
runner_->GetPostedTasks().front().delay);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _));
// After we run the next task, we should close the connection.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
@@ -423,7 +430,8 @@
// kDefaultInitialTimeoutSecs.
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000));
EXPECT_EQ(5000u, clock_.ApproximateNow().Subtract(start).ToMicroseconds());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_,
+ SentPacket(_, 1, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA));
// Send an ack so we don't set the retransmission alarm.
connection_->SendAck();
@@ -439,7 +447,8 @@
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_,
+ SentPacket(_, 2, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA));
runner_->RunNextTask();
EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000 + 5000,
clock_.ApproximateNow().Subtract(
@@ -460,9 +469,10 @@
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
QuicPacket* packet = ConstructRawDataPacket(1);
- connection_->SendOrQueuePacket(
- ENCRYPTION_NONE, 1, packet, 0, HAS_RETRANSMITTABLE_DATA);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ connection_->SendOrQueuePacket(ENCRYPTION_NONE, 1, packet, 0,
+ HAS_RETRANSMITTABLE_DATA);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION,
+ _));
EXPECT_EQ(1u, connection_->NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 2221b50..5195f439 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -12,6 +12,8 @@
#include "net/base/net_log.h"
#include "net/quic/crypto/crypto_handshake.h"
+using std::string;
+
namespace net {
namespace {
@@ -416,4 +418,11 @@
base::Bind(&NetLogQuicConnectionClosedCallback, error, from_peer));
}
+void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) {
+ string quic_version = QuicVersionToString(version);
+ net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATED,
+ NetLog::StringCallback("version", &quic_version));
+}
+
} // namespace net
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index f9080d64..d498b12 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -56,6 +56,7 @@
void OnCryptoHandshakeMessageSent(
const CryptoHandshakeMessage& message);
void OnConnectionClose(QuicErrorCode error, bool from_peer);
+ void OnSuccessfulVersionNegotiation(const QuicVersion& version);
private:
BoundNetLog net_log_;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index e57e7aea..147d8bc 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -389,6 +389,15 @@
QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
}
+ QuicConsumedData SendStreamData(QuicStreamId id,
+ StringPiece data,
+ QuicStreamOffset offset,
+ bool fin) {
+ struct iovec iov = {const_cast<char*>(data.data()),
+ static_cast<size_t>(data.size())};
+ return SendvStreamData(id, &iov, 1, offset, fin);
+ }
+
QuicConsumedData SendStreamData3() {
return SendStreamData(kStreamId3, "food", 0, !kFin);
}
@@ -403,7 +412,11 @@
// split needlessly across packet boundaries). As a result, we have separate
// tests for some cases for this stream.
QuicConsumedData SendCryptoStreamData() {
- return SendStreamData(kCryptoStreamId, "chlo", 0, !kFin);
+ this->Flush();
+ QuicConsumedData consumed =
+ SendStreamData(kCryptoStreamId, "chlo", 0, !kFin);
+ this->Flush();
+ return consumed;
}
bool is_server() {
@@ -467,13 +480,15 @@
QuicTime::Delta::Zero()));
EXPECT_CALL(*receive_algorithm_,
RecordIncomingPacket(_, _, _, _)).Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber());
EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(Return(
QuicBandwidth::FromKBitsPerSecond(100)));
EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(Return(
QuicTime::Delta::FromMilliseconds(100)));
+ ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _))
+ .WillByDefault(Return(true));
// TODO(rch): remove this.
QuicConnection::g_acks_do_not_instigate_acks = true;
}
@@ -630,21 +645,21 @@
QuicStreamOffset offset, bool fin,
QuicPacketSequenceNumber* last_packet) {
QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
- SaveArg<2>(&packet_size));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<2>(&packet_size), Return(true)));
connection_.SendStreamData(id, data, offset, fin);
if (last_packet != NULL) {
*last_packet =
QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number();
}
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber());
return packet_size;
}
void SendAckPacketToPeer() {
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
connection_.SendAck();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber());
}
QuicPacketEntropyHash ProcessAckPacket(QuicAckFrame* frame,
@@ -741,6 +756,8 @@
};
TEST_F(QuicConnectionTest, PacketsInOrder) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessPacket(1);
EXPECT_EQ(1u, outgoing_ack()->received_info.largest_observed);
EXPECT_EQ(0u, outgoing_ack()->received_info.missing_packets.size());
@@ -755,6 +772,8 @@
}
TEST_F(QuicConnectionTest, PacketsRejected) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessPacket(1);
EXPECT_EQ(1u, outgoing_ack()->received_info.largest_observed);
EXPECT_EQ(0u, outgoing_ack()->received_info.missing_packets.size());
@@ -767,6 +786,8 @@
}
TEST_F(QuicConnectionTest, PacketsOutOfOrder) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessPacket(3);
EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed);
EXPECT_TRUE(IsMissing(2));
@@ -784,6 +805,8 @@
}
TEST_F(QuicConnectionTest, DuplicatePacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessPacket(3);
EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed);
EXPECT_TRUE(IsMissing(2));
@@ -798,6 +821,8 @@
}
TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessPacket(3);
EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed);
EXPECT_TRUE(IsMissing(2));
@@ -833,6 +858,7 @@
}
TEST_F(QuicConnectionTest, TruncatedAck) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnAck(_)).Times(testing::AnyNumber());
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
@@ -861,6 +887,8 @@
}
TEST_F(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessPacket(1);
// Delay sending, then queue up an ack.
EXPECT_CALL(*send_algorithm_,
@@ -880,11 +908,13 @@
}
TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
QuicPacketSequenceNumber largest_observed;
QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION))
- .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size)));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _))
+ .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size),
+ Return(true)));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
connection_.SendStreamData(1, "foo", 0, !kFin);
QuicAckFrame frame(1, QuicTime::Zero(), largest_observed);
@@ -895,13 +925,13 @@
ProcessAckPacket(&frame, true);
// Third nack should retransmit the largest observed packet.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize,
- IS_RETRANSMISSION));
+ IS_RETRANSMISSION, _));
ProcessAckPacket(&frame, true);
// Now if the peer sends an ack which still reports the retransmitted packet
// as missing, then that will count as a packet which instigates an ack.
ProcessAckPacket(&frame, true);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _));
ProcessAckPacket(&frame, true);
// But an ack with no new missing packest will not send an ack.
@@ -911,6 +941,8 @@
}
TEST_F(QuicConnectionTest, LeastUnackedLower) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
SendStreamDataToPeer(1, "bar", 3, !kFin, NULL);
SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
@@ -930,12 +962,14 @@
// Now claim it's one, but set the ordering so it was sent "after" the first
// one. This should cause a connection error.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
creator_.set_sequence_number(7);
ProcessAckPacket(&frame2, false);
}
TEST_F(QuicConnectionTest, LargestObservedLower) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
SendStreamDataToPeer(1, "bar", 3, !kFin, NULL);
SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
@@ -955,8 +989,9 @@
}
TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
// Create an ack with least_unacked is 2 in packet number 1.
creator_.set_sequence_number(0);
QuicAckFrame frame(0, QuicTime::Zero(), 2);
@@ -965,12 +1000,14 @@
TEST_F(QuicConnectionTest,
NackSequenceNumberGreaterThanLargestReceived) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
SendStreamDataToPeer(1, "bar", 3, !kFin, NULL);
SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
QuicAckFrame frame(0, QuicTime::Zero(), 1);
frame.received_info.missing_packets.insert(3);
ProcessAckPacket(&frame, false);
@@ -979,12 +1016,14 @@
TEST_F(QuicConnectionTest, AckUnsentData) {
// Ack a packet which has not been sent.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
QuicAckFrame frame(1, QuicTime::Zero(), 0);
ProcessAckPacket(&frame, false);
}
TEST_F(QuicConnectionTest, AckAll) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
creator_.set_sequence_number(1);
@@ -1093,6 +1132,7 @@
}
TEST_F(QuicConnectionTest, BasicSending) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6);
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
@@ -1162,7 +1202,7 @@
connection_.options()->max_packets_per_fec_group = 2;
// Send 4 data packets and 2 FEC packets.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(6);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(6);
// The first stream frame will consume 2 fewer bytes than the other three.
const string payload(payload_length * 4 - 6, 'a');
connection_.SendStreamData(1, payload, 0, !kFin);
@@ -1192,7 +1232,7 @@
TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) {
connection_.options()->max_packets_per_fec_group = 1;
// 1 Data and 1 FEC packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(2);
connection_.SendStreamData(1, "foo", 0, !kFin);
// Larger timeout for FEC bytes to expire.
@@ -1201,7 +1241,7 @@
clock_.AdvanceTime(retransmission_time);
// Send only data packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
// Abandon both FEC and data packet.
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
@@ -1209,12 +1249,13 @@
}
TEST_F(QuicConnectionTest, DontAbandonAckedFEC) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.options()->max_packets_per_fec_group = 1;
const QuicPacketSequenceNumber sequence_number =
QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number() + 1;
// 1 Data and 1 FEC packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(2);
connection_.SendStreamData(1, "foo", 0, !kFin);
QuicAckFrame ack_fec(2, QuicTime::Zero(), 1);
@@ -1235,7 +1276,7 @@
// Abandon only data packet, FEC has been acked.
EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1);
// Send only data packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
connection_.OnRetransmissionTimeout();
}
@@ -1256,7 +1297,7 @@
// Unblock the connection.
connection_.GetSendAlarm()->Cancel();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION))
+ SentPacket(_, _, _, NOT_RETRANSMISSION, _))
.Times(1);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1289,7 +1330,7 @@
// Unblock the connection.
connection_.GetSendAlarm()->Cancel();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION))
+ SentPacket(_, _, _, NOT_RETRANSMISSION, _))
.Times(2);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1320,7 +1361,7 @@
// Unblock the connection.
connection_.GetSendAlarm()->Cancel();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION))
+ SentPacket(_, _, _, NOT_RETRANSMISSION, _))
.Times(3);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1352,7 +1393,7 @@
// Unblock the connection.
connection_.GetSendAlarm()->Cancel();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION)).Times(2);
+ SentPacket(_, _, _, NOT_RETRANSMISSION, _)).Times(2);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -1362,6 +1403,76 @@
EXPECT_EQ(0u, helper_->frame_count());
}
+TEST_F(QuicConnectionTest, FramePackingSendv) {
+ // Send two stream frames in 1 packet by using writev.
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _));
+
+ char data[] = "ABCD";
+ iovec iov[2] = { {static_cast<void*>(data), 2},
+ {static_cast<void*>(data + 2), 2} };
+ connection_.SendvStreamData(1, iov, 2, 0, !kFin);
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's two stream frames from one stream.
+ // TODO(ianswett): Ideally this would arrive in one frame in the future.
+ EXPECT_EQ(2u, helper_->frame_count());
+ EXPECT_EQ(2u, helper_->stream_frames()->size());
+ EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
+ EXPECT_EQ(1u, (*helper_->stream_frames())[1].stream_id);
+}
+
+TEST_F(QuicConnectionTest, FramePackingSendvQueued) {
+ // Try to send two stream frames in 1 packet by using writev.
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _));
+
+ helper_->set_blocked(true);
+ char data[] = "ABCD";
+ iovec iov[2] = { {static_cast<void*>(data), 2},
+ {static_cast<void*>(data + 2), 2} };
+ connection_.SendvStreamData(1, iov, 2, 0, !kFin);
+
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ EXPECT_TRUE(connection_.HasQueuedData());
+
+ // Attempt to send all packets, but since we're actually still
+ // blocked, they should all remain queued.
+ EXPECT_FALSE(connection_.OnCanWrite());
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+
+ // Unblock the writes and actually send.
+ helper_->set_blocked(false);
+ EXPECT_CALL(visitor_, OnCanWrite());
+ EXPECT_TRUE(connection_.OnCanWrite());
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+
+ // Parse the last packet and ensure it's two stream frames from one stream.
+ // TODO(ianswett): Ideally this would arrive in one frame in the future.
+ EXPECT_EQ(2u, helper_->frame_count());
+ EXPECT_EQ(2u, helper_->stream_frames()->size());
+ EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
+ EXPECT_EQ(1u, (*helper_->stream_frames())[1].stream_id);
+}
+
+TEST_F(QuicConnectionTest, SendingZeroBytes) {
+ // Send a zero byte write with a fin using writev.
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _));
+
+ iovec iov[1];
+ connection_.SendvStreamData(1, iov, 0, 0, kFin);
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's two stream frames from one stream.
+ // TODO(ianswett): Ideally this would arrive in one frame in the future.
+ EXPECT_EQ(1u, helper_->frame_count());
+ EXPECT_EQ(1u, helper_->stream_frames()->size());
+ EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
+ EXPECT_TRUE((*helper_->stream_frames())[0].fin);
+}
+
TEST_F(QuicConnectionTest, OnCanWrite) {
// Visitor's OnCanWill send data, but will return false.
EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
@@ -1399,6 +1510,7 @@
SequenceNumberSet expected_acks;
expected_acks.insert(1);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Peer acks one but not two or three. Right now we only retransmit on
// explicit nack, so it should not trigger a retransimission.
@@ -1427,16 +1539,18 @@
// The third nack should trigger a retransimission.
EXPECT_CALL(*send_algorithm_,
SentPacket(_, _, second_packet_size - kQuicVersionSize,
- IS_RETRANSMISSION)).Times(1);
+ IS_RETRANSMISSION, _)).Times(1);
ProcessAckPacket(&nack_two, true);
}
TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
QuicPacketSequenceNumber largest_observed;
QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION))
- .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size)));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _))
+ .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size),
+ Return(true)));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
connection_.SendStreamData(1, "foo", 0, !kFin);
QuicAckFrame frame(1, QuicTime::Zero(), largest_observed);
@@ -1447,13 +1561,13 @@
ProcessAckPacket(&frame, true);
// Third nack should retransmit the largest observed packet.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize,
- IS_RETRANSMISSION));
+ IS_RETRANSMISSION, _));
ProcessAckPacket(&frame, true);
}
TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) {
for (int i = 0; i < 200; ++i) {
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
connection_.SendStreamData(1, "foo", i * 3, !kFin);
}
@@ -1468,6 +1582,7 @@
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
EXPECT_CALL(visitor_, OnAck(_)).Times(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&frame, true);
EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
@@ -1475,7 +1590,7 @@
clock_.AdvanceTime(DefaultRetransmissionTime());
// Only packets that are less than largest observed should be retransmitted.
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(192);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(192);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(192);
connection_.OnRetransmissionTimeout();
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
@@ -1483,11 +1598,12 @@
// Retransmit already retransmitted packets event though the sequence number
// greater than the largest observed.
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(192);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(192);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(192);
connection_.OnRetransmissionTimeout();
}
TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(11);
@@ -1515,11 +1631,11 @@
ProcessAckPacket(&nack, true);
ProcessAckPacket(&nack, true);
// The third call should trigger retransmitting 10 packets.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(10);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(10);
ProcessAckPacket(&nack, true);
// The fourth call should trigger retransmitting the 11th packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
ProcessAckPacket(&nack, true);
}
@@ -1556,6 +1672,8 @@
expected_acks.insert(5);
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessAckPacket(&frame1, true);
// Now the client implicitly acks 2, and explicitly acks 6
@@ -1582,6 +1700,7 @@
expected_acks.insert(1);
// Peer acks packet 1.
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicAckFrame frame(1, QuicTime::Zero(), 0);
frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
&connection_, 1);
@@ -1606,12 +1725,16 @@
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
// Don't send missing packet 1.
ProcessFecPacket(2, 1, true, !kEntropyFlag, NULL);
EXPECT_FALSE(revived_header_.entropy_flag);
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessFecProtectedPacket(1, false, kEntropyFlag);
// Don't send missing packet 2.
ProcessFecPacket(3, 1, true, !kEntropyFlag, NULL);
@@ -1619,6 +1742,8 @@
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessFecProtectedPacket(1, false, !kEntropyFlag);
// Don't send missing packet 2.
ProcessFecProtectedPacket(3, false, !kEntropyFlag);
@@ -1627,6 +1752,8 @@
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
// Don't send missing packet 1.
ProcessFecPacket(3, 1, false, !kEntropyFlag, NULL);
// out of order
@@ -1635,6 +1762,8 @@
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
ProcessFecProtectedPacket(1, false, !kEntropyFlag);
// Don't send missing packet 2.
ProcessFecPacket(6, 1, false, kEntropyFlag, NULL);
@@ -1655,7 +1784,7 @@
connection_.GetRetransmissionAlarm()->deadline());
// Simulate the retransimission alarm firing
clock_.AdvanceTime(DefaultRetransmissionTime());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
connection_.RetransmitPacket(1);
EXPECT_EQ(2u, last_header()->packet_sequence_number);
@@ -1684,12 +1813,12 @@
clock_.AdvanceTime(DefaultRetransmissionTime());
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
connection_.RetransmitPacket(1);
// Packet should have been sent with ENCRYPTION_NONE.
EXPECT_EQ(0x01010101u, final_bytes_of_last_packet());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
connection_.RetransmitPacket(2);
// Packet should have been sent with ENCRYPTION_INITIAL.
EXPECT_EQ(0x02020202u, final_bytes_of_last_packet());
@@ -1706,7 +1835,7 @@
new TaggingEncrypter(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(0);
EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1);
QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
@@ -1731,13 +1860,14 @@
SendStreamDataToPeer(2, "bar", 0, !kFin, NULL);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(1);
connection_.RetransmitUnackedPackets(QuicConnection::INITIAL_ENCRYPTION_ONLY);
}
TEST_F(QuicConnectionTest, BufferNonDecryptablePackets) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
use_tagging_decrypter();
const uint8 tag = 0x07;
@@ -1765,14 +1895,14 @@
TEST_F(QuicConnectionTest, TestRetransmitOrder) {
QuicByteCount first_packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
- SaveArg<2>(&first_packet_size));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).WillOnce(
+ DoAll(SaveArg<2>(&first_packet_size), Return(true)));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
connection_.SendStreamData(1, "first_packet", 0, !kFin);
QuicByteCount second_packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
- SaveArg<2>(&second_packet_size));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).WillOnce(
+ DoAll(SaveArg<2>(&second_packet_size), Return(true)));
connection_.SendStreamData(1, "second_packet", 12, !kFin);
EXPECT_NE(first_packet_size, second_packet_size);
// Advance the clock by huge time to make sure packets will be retransmitted.
@@ -1780,20 +1910,20 @@
{
InSequence s;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, first_packet_size, _));
+ SentPacket(_, _, first_packet_size, _, _));
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, second_packet_size, _));
+ SentPacket(_, _, second_packet_size, _, _));
}
connection_.OnRetransmissionTimeout();
}
TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
QuicPacketSequenceNumber original_sequence_number;
- EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION))
- .WillOnce(SaveArg<1>(&original_sequence_number));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _))
+ .WillOnce(DoAll(SaveArg<1>(&original_sequence_number), Return(true)));
connection_.SendStreamData(1, "foo", 0, !kFin);
EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
&connection_, original_sequence_number));
@@ -1802,9 +1932,8 @@
// Force retransmission due to RTO.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
QuicPacketSequenceNumber rto_sequence_number;
- EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, IS_RETRANSMISSION))
- .WillOnce(SaveArg<1>(&rto_sequence_number));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION, _))
+ .WillOnce(DoAll(SaveArg<1>(&rto_sequence_number), Return(true)));
connection_.OnRetransmissionTimeout();
EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission(
&connection_, original_sequence_number));
@@ -1816,10 +1945,10 @@
QuicPacketSequenceNumber nack_sequence_number;
// Ack packets might generate some other packets, which are not
// retransmissions. (More ack packets).
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION))
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _))
.Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION))
- .WillOnce(SaveArg<1>(&nack_sequence_number));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION, _))
+ .WillOnce(DoAll(SaveArg<1>(&nack_sequence_number), Return(true)));
QuicAckFrame ack(rto_sequence_number, QuicTime::Zero(), 0);
// Ack the retransmitted packet.
ack.received_info.missing_packets.insert(rto_sequence_number);
@@ -1868,6 +1997,7 @@
}
TEST_F(QuicConnectionTest, CloseFecGroup) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't send missing packet 1
// Don't send missing packet 2
ProcessFecProtectedPacket(3, false, !kEntropyFlag);
@@ -1900,10 +2030,12 @@
TEST_F(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) {
SendAckPacketToPeer();
EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
}
TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
SendAckPacketToPeer();
// Process an FEC packet, and revive the missing data packet
// but only contact the receive_algorithm once.
@@ -1914,7 +2046,7 @@
TEST_F(QuicConnectionTest, InitialTimeout) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
QuicTime default_timeout = clock_.ApproximateNow().Add(
QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs));
@@ -1953,7 +2085,7 @@
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
clock_.ApproximateNow());
@@ -1968,7 +2100,7 @@
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
connection_.SendOrQueuePacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1980,7 +2112,7 @@
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0);
connection_.SendOrQueuePacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1991,7 +2123,7 @@
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, IS_RETRANSMISSION, _, _)).Times(0);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
connection_.SendOrQueuePacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
// XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce);
@@ -2004,7 +2136,7 @@
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0);
connection_.SendOrQueuePacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -2027,7 +2159,7 @@
testing::Return(QuicTime::Delta::Zero()));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
connection_.GetSendAlarm()->Cancel();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _));
EXPECT_CALL(visitor_, OnCanWrite());
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -2038,7 +2170,7 @@
.WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ SentPacket(_, 1, _, NOT_RETRANSMISSION, _));
connection_.SendStreamData(1, "foo", 0, !kFin);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
// Advance the time for retransmission of lost packet.
@@ -2058,7 +2190,7 @@
// Ensure the scheduler is notified this is a retransmit.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, IS_RETRANSMISSION));
+ SentPacket(_, _, _, IS_RETRANSMISSION, _));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
connection_.GetSendAlarm()->Cancel();
EXPECT_CALL(visitor_, OnCanWrite());
@@ -2083,6 +2215,7 @@
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
@@ -2098,7 +2231,7 @@
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, _));
+ SentPacket(_, _, _, _, _));
ProcessAckPacket(&frame, true);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -2107,6 +2240,7 @@
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
@@ -2168,7 +2302,7 @@
NOT_IN_FEC_GROUP, &payload_length);
// Queue the first packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(7);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(7);
// The first stream frame will consume 2 fewer bytes than the other six.
const string payload(payload_length * 7 - 12, 'a');
EXPECT_EQ(payload.size(),
@@ -2176,10 +2310,11 @@
}
TEST_F(QuicConnectionTest, NoAckForClose) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(0);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(0);
ProcessClosePacket(2, 0);
}
@@ -2189,7 +2324,7 @@
connection_.CloseConnection(QUIC_PEER_GOING_AWAY, false);
EXPECT_FALSE(connection_.connected());
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0);
connection_.SendOrQueuePacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
}
@@ -2207,6 +2342,8 @@
}
TEST_F(QuicConnectionTest, GoAway) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
QuicGoAwayFrame goaway;
goaway.last_good_stream_id = 1;
goaway.error_code = QUIC_PEER_GOING_AWAY;
@@ -2219,12 +2356,14 @@
QuicAckFrame ack(0, QuicTime::Zero(), 4);
// Set the sequence number of the ack packet to be least unacked (4)
creator_.set_sequence_number(3);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&ack, true);
EXPECT_TRUE(outgoing_ack()->received_info.missing_packets.empty());
}
TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessDataPacket(1, 1, kEntropyFlag);
ProcessDataPacket(4, 1, kEntropyFlag);
ProcessDataPacket(3, 1, !kEntropyFlag);
@@ -2234,6 +2373,7 @@
TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessDataPacket(1, 1, kEntropyFlag);
ProcessDataPacket(5, 1, kEntropyFlag);
ProcessDataPacket(4, 1, !kEntropyFlag);
@@ -2254,6 +2394,7 @@
TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessDataPacket(1, 1, kEntropyFlag);
ProcessDataPacket(5, 1, !kEntropyFlag);
ProcessDataPacket(22, 1, kEntropyFlag);
@@ -2273,6 +2414,7 @@
TEST_F(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacketEntropyHash entropy[51];
entropy[0] = 0;
for (int i = 1; i < 51; ++i) {
@@ -2397,6 +2539,7 @@
framer_.BuildUnsizedDataPacket(header, frames).packet);
encrypted.reset(framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
ASSERT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(
@@ -2431,18 +2574,18 @@
TEST_F(QuicConnectionTest, CheckSendStats) {
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3);
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION));
+ SentPacket(_, _, _, NOT_RETRANSMISSION, _));
connection_.SendStreamData(1u, "first", 0, !kFin);
size_t first_packet_size = last_sent_packet_size();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, NOT_RETRANSMISSION));
+ SentPacket(_, _, _, NOT_RETRANSMISSION, _));
connection_.SendStreamData(1u, "second", 0, !kFin);
size_t second_packet_size = last_sent_packet_size();
// 2 retransmissions due to rto, 1 due to explicit nack.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, IS_RETRANSMISSION)).Times(3);
+ SentPacket(_, _, _, IS_RETRANSMISSION, _)).Times(3);
// Retransmit due to RTO.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
@@ -2460,6 +2603,7 @@
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
EXPECT_CALL(visitor_, OnCanWrite()).Times(3).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFramePacket(frame);
ProcessFramePacket(frame);
@@ -2481,6 +2625,8 @@
}
TEST_F(QuicConnectionTest, CheckReceiveStats) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
size_t received_bytes = 0;
received_bytes += ProcessFecProtectedPacket(1, false, !kEntropyFlag);
received_bytes += ProcessFecProtectedPacket(3, false, !kEntropyFlag);
@@ -2550,6 +2696,7 @@
EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true));
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(0);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
@@ -2622,6 +2769,8 @@
}
TEST_F(QuicConnectionTest, AckNotifierTriggerCallback) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
// Create a delegate which we expect to be called.
MockAckNotifierDelegate delegate;
EXPECT_CALL(delegate, OnAckNotification()).Times(1);;
@@ -2637,6 +2786,8 @@
}
TEST_F(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
// Create a delegate which we don't expect to be called.
MockAckNotifierDelegate delegate;
EXPECT_CALL(delegate, OnAckNotification()).Times(0);;
@@ -2661,6 +2812,8 @@
}
TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
// Create a delegate which we expect to be called.
MockAckNotifierDelegate delegate;
EXPECT_CALL(delegate, OnAckNotification()).Times(1);;
@@ -2688,7 +2841,7 @@
// Advance time to trigger RTO, for packet 2 (which should be retransmitted as
// packet 5).
EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1);
clock_.AdvanceTime(DefaultRetransmissionTime());
connection_.OnRetransmissionTimeout();
@@ -2702,6 +2855,7 @@
// TODO(rjshade): Add a similar test that FEC recovery on peer (and resulting
// ACK) triggers notification on our end.
TEST_F(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnCanWrite()).Times(1).WillOnce(Return(true));
// Create a delegate which we expect to be called.
@@ -2723,8 +2877,7 @@
frames.push_back(QuicFrame(&ack_frame));
// Dummy stream frame to satisfy expectations set elsewhere.
- QuicFrame frame(&frame1_);
- frames.push_back(frame);
+ frames.push_back(QuicFrame(&frame1_));
QuicPacketHeader ack_header;
ack_header.public_header.guid = guid_;
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 569648f..3c10c5b 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -59,8 +59,12 @@
const CryptoHandshakeMessage& message) {
session()->OnCryptoHandshakeMessageSent(message);
const QuicData& data = message.GetSerialized();
+ // To make reasoning about crypto frames easier, we don't combine them with
+ // any other frames in a single packet.
+ session()->connection()->Flush();
// TODO(wtc): check the return value.
WriteData(string(data.data(), data.length()), false);
+ session()->connection()->Flush();
}
const QuicCryptoNegotiatedParameters&
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index a91b9e2..0122c64 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -11,6 +11,7 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/quic/quic_client_session.h"
+#include "net/quic/quic_http_utils.h"
#include "net/quic/quic_reliable_client_stream.h"
#include "net/quic/quic_utils.h"
#include "net/socket/next_proto.h"
@@ -29,6 +30,7 @@
stream_(NULL),
request_info_(NULL),
request_body_stream_(NULL),
+ priority_(MINIMUM_PRIORITY),
response_info_(NULL),
response_status_(OK),
response_headers_received_(false),
@@ -52,6 +54,7 @@
stream_net_log_ = stream_net_log;
request_info_ = request_info;
+ priority_ = priority;
int rv = stream_request_.StartRequest(
session_, &stream_, base::Bind(&QuicHttpStream::OnStreamReady,
@@ -82,6 +85,8 @@
CHECK(!callback.is_null());
CHECK(response);
+ QuicPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
+ stream_->set_priority(priority);
// Store the serialized request headers.
SpdyHeaderBlock headers;
CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
@@ -89,7 +94,8 @@
if (session_->connection()->version() < QUIC_VERSION_9) {
request_ = stream_->compressor()->CompressHeaders(headers);
} else {
- request_ = stream_->compressor()->CompressHeadersWithPriority(0, headers);
+ request_ = stream_->compressor()->CompressHeadersWithPriority(priority,
+ headers);
}
// Log the actual request with the URL Request's net log.
stream_net_log_.AddEvent(
@@ -207,7 +213,7 @@
stream_->SetDelegate(NULL);
// TODO(rch): use new CANCELLED error code here once quic 11
// is everywhere.
- stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ stream_->Close(QUIC_ERROR_PROCESSING_STREAM);
stream_ = NULL;
}
}
@@ -264,7 +270,7 @@
}
void QuicHttpStream::SetPriority(RequestPriority priority) {
- // Nothing to do here (yet).
+ priority_ = priority;
}
int QuicHttpStream::OnSendData() {
@@ -336,6 +342,10 @@
DoCallback(response_status_);
}
+bool QuicHttpStream::HasSendHeadersComplete() {
+ return next_state_ > STATE_SEND_HEADERS_COMPLETE;
+}
+
void QuicHttpStream::OnIOComplete(int rv) {
rv = DoLoop(rv);
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index cc2b973..71fb515 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -15,6 +15,10 @@
namespace net {
+namespace test {
+class QuicHttpStreamPeer;
+} // namespace test
+
// The QuicHttpStream is a QUIC-specific HttpStream subclass. It holds a
// non-owning pointer to a QuicReliableClientStream which it uses to
// send and receive data.
@@ -62,8 +66,11 @@
virtual int OnDataReceived(const char* data, int length) OVERRIDE;
virtual void OnClose(QuicErrorCode error) OVERRIDE;
virtual void OnError(int error) OVERRIDE;
+ virtual bool HasSendHeadersComplete() OVERRIDE;
private:
+ friend class test::QuicHttpStreamPeer;
+
enum State {
STATE_NONE,
STATE_SEND_HEADERS,
@@ -106,6 +113,8 @@
const HttpRequestInfo* request_info_;
// The request body to send, if any, owned by the caller.
UploadDataStream* request_body_stream_;
+ // The priority of the request.
+ RequestPriority priority_;
// |response_info_| is the HTTP response data object which is filled in
// when a the response headers are read. It is not owned by this stream.
HttpResponseInfo* response_info_;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 6a584f1..37242bf 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -19,6 +19,8 @@
#include "net/quic/quic_client_session.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_connection_helper.h"
+#include "net/quic/quic_http_utils.h"
+#include "net/quic/quic_reliable_client_stream.h"
#include "net/quic/spdy_utils.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
@@ -31,6 +33,7 @@
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/write_blocked_list.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -102,6 +105,14 @@
} // namespace
+class QuicHttpStreamPeer {
+ public:
+ static QuicReliableClientStream* GetQuicReliableClientStream(
+ QuicHttpStream* stream) {
+ return stream->stream_;
+ }
+};
+
class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
protected:
const static bool kFin = true;
@@ -177,7 +188,7 @@
receive_algorithm_ = new TestReceiveAlgorithm(NULL);
EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _)).
Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber());
EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _, _)).
@@ -206,14 +217,16 @@
new QuicHttpStream(session_->GetWeakPtr()));
}
- void SetRequestString(const std::string& method, const std::string& path) {
+ void SetRequestString(const std::string& method,
+ const std::string& path,
+ RequestPriority priority) {
SpdyHeaderBlock headers;
headers[":method"] = method;
headers[":host"] = "www.google.com";
headers[":path"] = path;
headers[":scheme"] = "http";
headers[":version"] = "HTTP/1.1";
- request_data_ = SerializeHeaderBlock(headers, true);
+ request_data_ = SerializeHeaderBlock(headers, true, priority);
}
void SetResponseString(const std::string& status, const std::string& body) {
@@ -221,14 +234,17 @@
headers[":status"] = status;
headers[":version"] = "HTTP/1.1";
headers["content-type"] = "text/plain";
- response_data_ = SerializeHeaderBlock(headers, false) + body;
+ response_data_ = SerializeHeaderBlock(headers, false, DEFAULT_PRIORITY) +
+ body;
}
std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers,
- bool write_priority) {
+ bool write_priority,
+ RequestPriority priority) {
QuicSpdyCompressor compressor;
if (framer_.version() >= QUIC_VERSION_9 && write_priority) {
- return compressor.CompressHeadersWithPriority(0, headers);
+ return compressor.CompressHeadersWithPriority(
+ ConvertRequestPriorityToQuicPriority(priority), headers);
}
return compressor.CompressHeaders(headers);
}
@@ -249,7 +265,7 @@
QuicEncryptedPacket* ConstructRstStreamPacket(
QuicPacketSequenceNumber sequence_number) {
InitializeHeader(sequence_number, false);
- QuicRstStreamFrame frame(3, QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ QuicRstStreamFrame frame(3, QUIC_ERROR_PROCESSING_STREAM);
return ConstructPacket(header_, QuicFrame(&frame));
}
@@ -350,7 +366,7 @@
}
TEST_F(QuicHttpStreamTest, GetRequest) {
- SetRequestString("GET", "/");
+ SetRequestString("GET", "/", DEFAULT_PRIORITY);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0,
request_data_));
Initialize();
@@ -393,7 +409,7 @@
// Regression test for http://crbug.com/288128
TEST_F(QuicHttpStreamTest, GetRequestLargeResponse) {
- SetRequestString("GET", "/");
+ SetRequestString("GET", "/", DEFAULT_PRIORITY);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0,
request_data_));
Initialize();
@@ -440,7 +456,7 @@
}
TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
- SetRequestString("GET", "/");
+ SetRequestString("GET", "/", DEFAULT_PRIORITY);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_));
Initialize();
@@ -482,7 +498,7 @@
}
TEST_F(QuicHttpStreamTest, SendPostRequest) {
- SetRequestString("POST", "/");
+ SetRequestString("POST", "/", DEFAULT_PRIORITY);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, !kFin, 0, request_data_));
AddWrite(SYNCHRONOUS, ConstructDataPacket(2, true, kFin,
request_data_.length(),
@@ -539,7 +555,7 @@
}
TEST_F(QuicHttpStreamTest, SendChunkedPostRequest) {
- SetRequestString("POST", "/");
+ SetRequestString("POST", "/", DEFAULT_PRIORITY);
size_t chunk_size = strlen(kUploadData);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, !kFin, 0, request_data_));
AddWrite(SYNCHRONOUS, ConstructDataPacket(2, true, !kFin,
@@ -601,7 +617,7 @@
}
TEST_F(QuicHttpStreamTest, DestroyedEarly) {
- SetRequestString("GET", "/");
+ SetRequestString("GET", "/", DEFAULT_PRIORITY);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_));
AddWrite(SYNCHRONOUS, ConstructRstStreamPacket(2));
use_closing_stream_ = true;
@@ -613,7 +629,7 @@
EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
net_log_, callback_.callback()));
EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
- callback_.callback()));
+ callback_.callback()));
EXPECT_EQ(&response_, stream_->GetResponseInfo());
// Ack the request.
@@ -633,6 +649,51 @@
EXPECT_TRUE(AtEof());
}
+TEST_F(QuicHttpStreamTest, Priority) {
+ SetRequestString("GET", "/", MEDIUM);
+ AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_));
+ AddWrite(SYNCHRONOUS, ConstructRstStreamPacket(2));
+ use_closing_stream_ = true;
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.google.com/");
+
+ EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM,
+ net_log_, callback_.callback()));
+
+ // Check that priority is highest.
+ QuicReliableClientStream* reliable_stream =
+ QuicHttpStreamPeer::GetQuicReliableClientStream(stream_.get());
+ DCHECK(reliable_stream);
+ DCHECK_EQ(static_cast<QuicPriority>(kHighestPriority),
+ reliable_stream->EffectivePriority());
+
+ EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
+ callback_.callback()));
+ EXPECT_EQ(&response_, stream_->GetResponseInfo());
+
+ // Check that priority has now dropped back to MEDIUM.
+ DCHECK_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority(
+ reliable_stream->EffectivePriority()));
+
+ // Ack the request.
+ scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0, 0));
+ ProcessPacket(*ack);
+ EXPECT_EQ(ERR_IO_PENDING,
+ stream_->ReadResponseHeaders(callback_.callback()));
+
+ // Send the response with a body.
+ SetResponseString("404 OK", "hello world!");
+ scoped_ptr<QuicEncryptedPacket> resp(
+ ConstructDataPacket(2, false, kFin, 0, response_data_));
+
+ // In the course of processing this packet, the QuicHttpStream close itself.
+ ProcessPacket(*resp);
+
+ EXPECT_TRUE(AtEof());
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/quic_http_utils.cc b/net/quic/quic_http_utils.cc
new file mode 100644
index 0000000..4a48626
--- /dev/null
+++ b/net/quic/quic_http_utils.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_http_utils.h"
+
+namespace net {
+
+QuicPriority ConvertRequestPriorityToQuicPriority(
+ const RequestPriority priority) {
+ DCHECK_GE(priority, MINIMUM_PRIORITY);
+ DCHECK_LT(priority, NUM_PRIORITIES);
+ return static_cast<QuicPriority>(HIGHEST - priority);
+}
+
+NET_EXPORT_PRIVATE RequestPriority ConvertQuicPriorityToRequestPriority(
+ QuicPriority priority) {
+ // Handle invalid values gracefully.
+ return (priority >= 5) ?
+ IDLE : static_cast<RequestPriority>(HIGHEST - priority);
+}
+
+} // namespace net
diff --git a/net/quic/quic_http_utils.h b/net/quic/quic_http_utils.h
new file mode 100644
index 0000000..c7e031a
--- /dev/null
+++ b/net/quic/quic_http_utils.h
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_HTTP_UTILS_H_
+#define NET_QUIC_QUIC_HTTP_UTILS_H_
+
+#include "net/base/net_export.h"
+#include "net/base/request_priority.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+NET_EXPORT_PRIVATE QuicPriority ConvertRequestPriorityToQuicPriority(
+ RequestPriority priority);
+
+NET_EXPORT_PRIVATE RequestPriority ConvertQuicPriorityToRequestPriority(
+ QuicPriority priority);
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_HTTP_UTILS_H_
diff --git a/net/quic/quic_http_utils_test.cc b/net/quic/quic_http_utils_test.cc
new file mode 100644
index 0000000..93b62e2
--- /dev/null
+++ b/net/quic/quic_http_utils_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_http_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicHttpUtilsTest, ConvertRequestPriorityToQuicPriority) {
+ EXPECT_EQ(0u, ConvertRequestPriorityToQuicPriority(HIGHEST));
+ EXPECT_EQ(1u, ConvertRequestPriorityToQuicPriority(MEDIUM));
+ EXPECT_EQ(2u, ConvertRequestPriorityToQuicPriority(LOW));
+ EXPECT_EQ(3u, ConvertRequestPriorityToQuicPriority(LOWEST));
+ EXPECT_EQ(4u, ConvertRequestPriorityToQuicPriority(IDLE));
+}
+
+TEST(QuicHttpUtilsTest, ConvertQuicPriorityToRequestPriority) {
+ EXPECT_EQ(HIGHEST, ConvertQuicPriorityToRequestPriority(0));
+ EXPECT_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority(1));
+ EXPECT_EQ(LOW, ConvertQuicPriorityToRequestPriority(2));
+ EXPECT_EQ(LOWEST, ConvertQuicPriorityToRequestPriority(3));
+ EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(4));
+ // These are invalid values, but we should still handle them
+ // gracefully. TODO(rtenneti): should we test for all possible values of
+ // uint32?
+ for (int i = 5; i < kuint8max; ++i) {
+ EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(i));
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 801c7ef7..a6cbff1 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -25,6 +25,7 @@
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_framer.h"
+#include "net/quic/quic_http_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
@@ -178,7 +179,8 @@
std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) {
QuicSpdyCompressor compressor;
if (QuicVersionMax() >= QUIC_VERSION_9) {
- return compressor.CompressHeadersWithPriority(0, headers);
+ return compressor.CompressHeadersWithPriority(
+ ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), headers);
}
return compressor.CompressHeaders(headers);
}
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index e1d0e21..819c872 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -12,6 +12,7 @@
using base::StringPiece;
using std::make_pair;
+using std::max;
using std::min;
using std::pair;
using std::vector;
@@ -71,6 +72,30 @@
}
}
+void QuicPacketCreator::UpdateSequenceNumberLength(
+ QuicPacketSequenceNumber least_packet_awaited_by_peer,
+ QuicByteCount bytes_per_second) {
+ DCHECK_LE(least_packet_awaited_by_peer, sequence_number_ + 1);
+ // Since the packet creator will not change sequence number length mid FEC
+ // group, include the size of an FEC group to be safe.
+ const QuicPacketSequenceNumber current_delta =
+ options_.max_packets_per_fec_group + sequence_number_ + 1
+ - least_packet_awaited_by_peer;
+ const uint64 congestion_window =
+ bytes_per_second / options_.max_packet_length;
+ const uint64 delta = max(current_delta, congestion_window);
+
+ if (delta < 1 << ((PACKET_1BYTE_SEQUENCE_NUMBER * 8) - 2)) {
+ options_.send_sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
+ } else if (delta < 1 << ((PACKET_2BYTE_SEQUENCE_NUMBER * 8) - 2)) {
+ options_.send_sequence_number_length = PACKET_2BYTE_SEQUENCE_NUMBER;
+ } else if (delta < 1 << ((PACKET_4BYTE_SEQUENCE_NUMBER * 8) - 2)) {
+ options_.send_sequence_number_length = PACKET_4BYTE_SEQUENCE_NUMBER;
+ } else {
+ options_.send_sequence_number_length = PACKET_6BYTE_SEQUENCE_NUMBER;
+ }
+}
+
bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
QuicStreamOffset offset) const {
return BytesFree() >
@@ -99,7 +124,12 @@
StreamFramePacketOverhead(
framer_->version(), PACKET_8BYTE_GUID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, IN_FEC_GROUP));
- DCHECK(HasRoomForStreamFrame(id, offset));
+ if (!HasRoomForStreamFrame(id, offset)) {
+ LOG(DFATAL) << "No room for Stream frame, BytesFree: " << BytesFree()
+ << " MinStreamFrameSize: "
+ << QuicFramer::GetMinStreamFrameSize(
+ framer_->version(), id, offset, true);
+ }
const size_t free_bytes = BytesFree();
size_t bytes_consumed = 0;
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 0e0a8c77..68b6216 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -70,6 +70,12 @@
// Makes the framer not serialize the protocol version in sent packets.
void StopSendingVersion();
+ // Update the sequence number length to use in future packets as soon as it
+ // can be safely changed.
+ void UpdateSequenceNumberLength(
+ QuicPacketSequenceNumber least_packet_awaited_by_peer,
+ QuicByteCount bytes_per_second);
+
// The overhead the framing will add for a packet with one frame.
static size_t StreamFramePacketOverhead(
QuicVersion version,
@@ -152,6 +158,8 @@
QuicEncryptedPacket* SerializeVersionNegotiationPacket(
const QuicVersionVector& supported_versions);
+ // Sequence number of the last created packet, or 0 if no packets have been
+ // created.
QuicPacketSequenceNumber sequence_number() const {
return sequence_number_;
}
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 193bb889..51133b6 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -333,6 +333,53 @@
client_framer_.ProcessPacket(*encrypted.get());
}
+TEST_F(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
+ EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.set_sequence_number(64);
+ creator_.UpdateSequenceNumberLength(2, 10000);
+ EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.set_sequence_number(64 * 256);
+ creator_.UpdateSequenceNumberLength(2, 10000);
+ EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.set_sequence_number(64 * 256 * 256);
+ creator_.UpdateSequenceNumberLength(2, 10000);
+ EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.set_sequence_number(GG_UINT64_C(64) * 256 * 256 * 256 * 256);
+ creator_.UpdateSequenceNumberLength(2, 10000);
+ EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+}
+
+TEST_F(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthBandwidth) {
+ EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.UpdateSequenceNumberLength(1, 10000);
+ EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.UpdateSequenceNumberLength(1, 10000 * 256);
+ EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.UpdateSequenceNumberLength(1, 10000 * 256 * 256);
+ EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+
+ creator_.UpdateSequenceNumberLength(
+ 1, GG_UINT64_C(1000) * 256 * 256 * 256 * 256);
+ EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
+ creator_.options()->send_sequence_number_length);
+}
+
INSTANTIATE_TEST_CASE_P(ToggleVersionSerialization,
QuicPacketCreatorTest,
::testing::Values(false, true));
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 41161eb2..4650068 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -88,6 +88,9 @@
size_t total_bytes_consumed = 0;
bool fin_consumed = false;
+ if (!packet_creator_->HasRoomForStreamFrame(id, offset)) {
+ SerializeAndSendPacket();
+ }
while (delegate_->CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
handshake)) {
QuicFrame frame;
@@ -100,8 +103,13 @@
bytes_consumed = packet_creator_->CreateStreamFrame(
id, data, offset + total_bytes_consumed, fin, &frame);
}
- bool success = AddFrame(frame);
- DCHECK(success);
+ if (!AddFrame(frame)) {
+ LOG(DFATAL) << "Failed to add stream frame.";
+ // Inability to add a STREAM frame creates an unrecoverable hole in a
+ // the stream, so it's best to close the connection.
+ delegate_->CloseConnection(QUIC_INTERNAL_ERROR, false);
+ return QuicConsumedData(0, false);
+ }
total_bytes_consumed += bytes_consumed;
fin_consumed = fin && bytes_consumed == data.size();
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 75472a1..8d415bf 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -71,6 +71,7 @@
virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() = 0;
// Takes ownership of |packet.packet| and |packet.retransmittable_frames|.
virtual bool OnSerializedPacket(const SerializedPacket& packet) = 0;
+ virtual void CloseConnection(QuicErrorCode error, bool from_peer) = 0;
};
// Interface which gets callbacks from the QuicPacketGenerator at interesting
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 88320426..eabbec1e 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -40,6 +40,7 @@
MOCK_METHOD0(CreateAckFrame, QuicAckFrame*());
MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*());
MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet));
+ MOCK_METHOD2(CloseConnection, void(QuicErrorCode, bool));
void SetCanWriteAnything() {
EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, _, _))
@@ -455,6 +456,49 @@
CheckPacketIsFec(packet3_, 1);
}
+TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
+ // Set the packet size be enough for two stream frames with 0 stream offset,
+ // but not enough for a stream frame of 0 offset and one with non-zero offset.
+ creator_.options()->max_packet_length =
+ NullEncrypter().GetCiphertextSize(0) +
+ GetPacketHeaderSize(creator_.options()->send_guid_length,
+ true,
+ creator_.options()->send_sequence_number_length,
+ NOT_IN_FEC_GROUP) +
+ // Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger
+ // than the GetMinStreamFrameSize.
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, false) + 3 +
+ QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, true) + 1;
+ delegate_.SetCanWriteAnything();
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ DoAll(SaveArg<0>(&packet_), Return(true)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
+ DoAll(SaveArg<0>(&packet2_), Return(true)));
+ }
+ generator_.StartBatchOperations();
+ // Queue enough data to prevent a stream frame with a non-zero offset from
+ // fitting.
+ QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 0, false);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // This frame will not fit with the existing frame, causing the queued frame
+ // to be serialized, and it will not fit with another frame like it, so it is
+ // serialized by itself.
+ consumed = generator_.ConsumeData(1, "bar", 3, true);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, packet_);
+ CheckPacketContains(contents, packet2_);
+}
+
TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
delegate_.SetCanNotWrite();
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 73a00c1..26e6c027 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -269,8 +269,8 @@
enum QuicRstStreamErrorCode {
QUIC_STREAM_NO_ERROR = 0,
- // There was some server error which halted stream processing.
- QUIC_SERVER_ERROR_PROCESSING_STREAM,
+ // There was some error which halted stream processing.
+ QUIC_ERROR_PROCESSING_STREAM,
// We got two fin or reset offsets which did not match.
QUIC_MULTIPLE_TERMINATION_OFFSETS,
// We got bad payload and can not respond to it at the protocol level.
@@ -333,6 +333,8 @@
QUIC_PEER_GOING_AWAY = 16,
// A stream ID was invalid.
QUIC_INVALID_STREAM_ID = 17,
+ // A priority was invalid.
+ QUIC_INVALID_PRIORITY = 49,
// Too many streams already open.
QUIC_TOO_MANY_OPEN_STREAMS = 18,
// Received public reset for this connection.
@@ -355,6 +357,8 @@
QUIC_PACKET_WRITE_ERROR = 27,
// There was an error while reading from the socket.
QUIC_PACKET_READ_ERROR = 51,
+ // We received a STREAM_FRAME with no data and no fin flag set.
+ QUIC_INVALID_STREAM_FRAME = 50,
// Crypto errors.
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index 26e6815..0a3ec6d 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -7,6 +7,7 @@
#include "base/callback_helpers.h"
#include "net/base/net_errors.h"
#include "net/quic/quic_session.h"
+#include "net/spdy/write_blocked_list.h"
namespace net {
@@ -54,6 +55,13 @@
}
}
+QuicPriority QuicReliableClientStream::EffectivePriority() const {
+ if (delegate_->HasSendHeadersComplete()) {
+ return ReliableQuicStream::EffectivePriority();
+ }
+ return kHighestPriority;
+}
+
int QuicReliableClientStream::WriteStreamData(
base::StringPiece data,
bool fin,
diff --git a/net/quic/quic_reliable_client_stream.h b/net/quic/quic_reliable_client_stream.h
index c482ee6..bf3fc15 100644
--- a/net/quic/quic_reliable_client_stream.h
+++ b/net/quic/quic_reliable_client_stream.h
@@ -48,6 +48,9 @@
// Called when the stream is closed because of an error.
virtual void OnError(int error) = 0;
+ // Returns true if sending of headers has completed.
+ virtual bool HasSendHeadersComplete() = 0;
+
protected:
virtual ~Delegate() {}
@@ -65,6 +68,11 @@
virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE;
virtual void TerminateFromPeer(bool half_close) OVERRIDE;
virtual void OnCanWrite() OVERRIDE;
+ virtual QuicPriority EffectivePriority() const OVERRIDE;
+
+ // While the server's set_priority shouldn't be called externally, the creator
+ // of client-side streams should be able to set the priority.
+ using ReliableQuicStream::set_priority;
int WriteStreamData(base::StringPiece data,
bool fin,
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index 50415915..aaebda2 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -28,6 +28,7 @@
MOCK_METHOD2(OnDataReceived, int(const char*, int));
MOCK_METHOD1(OnClose, void(QuicErrorCode));
MOCK_METHOD1(OnError, void(int));
+ MOCK_METHOD0(HasSendHeadersComplete, bool());
private:
DISALLOW_COPY_AND_ASSIGN(MockDelegate);
@@ -86,7 +87,7 @@
const size_t kDataLen = arraysize(kData1);
// All data written.
- EXPECT_CALL(session_, WriteData(stream_.id(), _, _, _)).WillOnce(
+ EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
TestCompletionCallback callback;
EXPECT_EQ(OK, stream_.WriteStreamData(base::StringPiece(kData1, kDataLen),
@@ -94,13 +95,14 @@
}
TEST_F(QuicReliableClientStreamTest, WriteStreamDataAsync) {
+ EXPECT_CALL(delegate_, HasSendHeadersComplete());
EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR));
const char kData1[] = "hello world";
const size_t kDataLen = arraysize(kData1);
// No data written.
- EXPECT_CALL(session_, WriteData(stream_.id(), _, _, _)).WillOnce(
+ EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _)).WillOnce(
Return(QuicConsumedData(0, false)));
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
@@ -109,7 +111,7 @@
ASSERT_FALSE(callback.have_result());
// All data written.
- EXPECT_CALL(session_, WriteData(stream_.id(), _, _, _)).WillOnce(
+ EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
stream_.OnCanWrite();
ASSERT_TRUE(callback.have_result());
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 5b7dc38..da980ca 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -63,6 +63,11 @@
return rc;
}
+ virtual void OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) OVERRIDE {
+ session_->OnSuccessfulVersionNegotiation(version);
+ }
+
virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE {
session_->ConnectionClose(error, from_peer);
// The session will go away, so don't bother with cleanup.
@@ -233,11 +238,12 @@
return !write_blocked_streams_.HasWriteBlockedStreams();
}
-QuicConsumedData QuicSession::WriteData(QuicStreamId id,
- StringPiece data,
- QuicStreamOffset offset,
- bool fin) {
- return connection_->SendStreamData(id, data, offset, fin);
+QuicConsumedData QuicSession::WritevData(QuicStreamId id,
+ const struct iovec* iov,
+ int count,
+ QuicStreamOffset offset,
+ bool fin) {
+ return connection_->SendvStreamData(id, iov, count, offset, fin);
}
void QuicSession::SendRstStream(QuicStreamId id,
@@ -474,8 +480,8 @@
zombie_streams_.size();
}
-void QuicSession::MarkWriteBlocked(QuicStreamId id) {
- write_blocked_streams_.PushBack(id, 0);
+void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) {
+ write_blocked_streams_.PushBack(id, priority);
}
void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id,
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index c37b6e11..9916e58 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -66,6 +66,8 @@
virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE;
virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE;
virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
+ virtual void OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) OVERRIDE{}
// Not needed for HTTP.
virtual void OnAck(const SequenceNumberSet& acked_packets) OVERRIDE {}
virtual bool OnCanWrite() OVERRIDE;
@@ -75,10 +77,12 @@
// indicating if the fin bit was consumed. This does not indicate the data
// has been sent on the wire: it may have been turned into a packet and queued
// if the socket was unexpectedly blocked.
- virtual QuicConsumedData WriteData(QuicStreamId id,
- base::StringPiece data,
- QuicStreamOffset offset,
- bool fin);
+ virtual QuicConsumedData WritevData(QuicStreamId id,
+ const struct iovec* iov,
+ int count,
+ QuicStreamOffset offset,
+ bool fin);
+
// Called by streams when they want to close the stream in both directions.
virtual void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error);
@@ -137,7 +141,7 @@
// been implicitly created.
virtual size_t GetNumOpenStreams() const;
- void MarkWriteBlocked(QuicStreamId id);
+ void MarkWriteBlocked(QuicStreamId id, QuicPriority priority);
// Marks that |stream_id| is blocked waiting to decompress the
// headers identified by |decompression_id|.
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index b7953ae..9d229a1 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -95,7 +95,7 @@
// Helper method for gmock
void MarkTwoWriteBlocked() {
- this->MarkWriteBlocked(2);
+ this->MarkWriteBlocked(2, 0);
}
TestCryptoStream crypto_stream_;
@@ -240,9 +240,9 @@
TestStream* stream4 = session_.CreateOutgoingReliableStream();
TestStream* stream6 = session_.CreateOutgoingReliableStream();
- session_.MarkWriteBlocked(2);
- session_.MarkWriteBlocked(6);
- session_.MarkWriteBlocked(4);
+ session_.MarkWriteBlocked(2, 0);
+ session_.MarkWriteBlocked(6, 0);
+ session_.MarkWriteBlocked(4, 0);
InSequence s;
EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(
@@ -259,9 +259,9 @@
TestStream* stream4 = session_.CreateOutgoingReliableStream();
session_.CreateOutgoingReliableStream(); // stream 6
- session_.MarkWriteBlocked(2);
- session_.MarkWriteBlocked(6);
- session_.MarkWriteBlocked(4);
+ session_.MarkWriteBlocked(2, 0);
+ session_.MarkWriteBlocked(6, 0);
+ session_.MarkWriteBlocked(4, 0);
CloseStream(6);
InSequence s;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index fb9d474e..a546d874 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -52,7 +52,7 @@
header.fec_flag = false;
header.fec_group = 0;
- QuicRstStreamFrame rst(stream_id, QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ QuicRstStreamFrame rst(stream_id, QUIC_ERROR_PROCESSING_STREAM);
return scoped_ptr<QuicEncryptedPacket>(
ConstructPacket(header, QuicFrame(&rst)));
}
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 7cf67d351..a57c05f 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -74,17 +74,21 @@
return true;
}
- if (frame.fin) {
- CloseStreamAtOffset(frame.offset + frame.data.size());
- }
-
QuicStreamOffset byte_offset = frame.offset;
const char* data = frame.data.data();
size_t data_len = frame.data.size();
- if (data_len == 0) {
- // TODO(rch): Close the stream if there was no data and no fin.
- return true;
+ if (data_len == 0 && !frame.fin) {
+ // Stream frames must have data or a fin flag.
+ stream_->ConnectionClose(QUIC_INVALID_STREAM_FRAME, false);
+ return false;
+ }
+
+ if (frame.fin) {
+ CloseStreamAtOffset(frame.offset + frame.data.size());
+ if (data_len == 0) {
+ return true;
+ }
}
if (byte_offset == num_bytes_consumed_) {
@@ -96,7 +100,7 @@
return true;
}
if (bytes_consumed > data_len) {
- stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ stream_->Close(QUIC_ERROR_PROCESSING_STREAM);
return false;
} else if (bytes_consumed == data_len) {
FlushBufferedFrames();
@@ -211,7 +215,7 @@
<< " end_offset: " << end_offset
<< " offset: " << it->first
<< " length: " << it->second.length();
- stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ stream_->Close(QUIC_ERROR_PROCESSING_STREAM);
return;
}
@@ -262,7 +266,7 @@
return;
}
if (bytes_consumed > data->size()) {
- stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM); // Programming error
+ stream_->Close(QUIC_ERROR_PROCESSING_STREAM); // Programming error
return;
} else if (bytes_consumed == data->size()) {
frames_.erase(it);
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 878585b..21568d60 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -71,6 +71,7 @@
MOCK_METHOD1(TerminateFromPeer, void(bool half_close));
MOCK_METHOD2(ProcessData, uint32(const char* data, uint32 data_len));
+ MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer));
MOCK_METHOD1(Close, void(QuicRstStreamErrorCode error));
MOCK_METHOD0(OnCanWrite, void());
};
@@ -182,7 +183,8 @@
}
TEST_F(QuicStreamSequencerTest, EmptyFrame) {
- EXPECT_TRUE(sequencer_->OnFrame(0, ""));
+ EXPECT_CALL(stream_, ConnectionClose(QUIC_INVALID_STREAM_FRAME, false));
+ EXPECT_FALSE(sequencer_->OnFrame(0, ""));
EXPECT_EQ(0u, sequencer_->frames()->size());
EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
}
@@ -399,7 +401,7 @@
// Now, attempt to mark consumed more data than was readable
// and expect the stream to be closed.
- EXPECT_CALL(stream_, Close(QUIC_SERVER_ERROR_PROCESSING_STREAM));
+ EXPECT_CALL(stream_, Close(QUIC_ERROR_PROCESSING_STREAM));
EXPECT_DFATAL(sequencer_->MarkConsumed(4),
"Invalid argument to MarkConsumed. num_bytes_consumed_: 3 "
"end_offset: 4 offset: 9 length: 17");
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 74c90a0b..cfb3cb7d 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -120,7 +120,7 @@
switch (error) {
RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR);
RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR);
- RETURN_STRING_LITERAL(QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ RETURN_STRING_LITERAL(QUIC_ERROR_PROCESSING_STREAM);
RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS);
RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD);
RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY);
@@ -171,6 +171,7 @@
RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP);
RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND);
RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PRIORITY);
RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS);
RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET);
RETURN_STRING_LITERAL(QUIC_INVALID_VERSION);
@@ -182,6 +183,7 @@
RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_ADDRESS);
RETURN_STRING_LITERAL(QUIC_PACKET_WRITE_ERROR);
RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR);
+ RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_FRAME);
RETURN_STRING_LITERAL(QUIC_PROOF_INVALID);
RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG);
RETURN_STRING_LITERAL(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT);
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 45b4fce4..7a447135 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -6,6 +6,7 @@
#include "net/quic/quic_session.h"
#include "net/quic/quic_spdy_decompressor.h"
+#include "net/spdy/write_blocked_list.h"
using base::StringPiece;
using std::min;
@@ -193,6 +194,12 @@
return WriteOrBuffer(data, fin);
}
+
+void ReliableQuicStream::set_priority(QuicPriority priority) {
+ DCHECK_EQ(0u, stream_bytes_written_);
+ priority_ = priority;
+}
+
QuicConsumedData ReliableQuicStream::WriteOrBuffer(StringPiece data, bool fin) {
DCHECK(!fin_buffered_);
@@ -235,27 +242,43 @@
QuicConsumedData ReliableQuicStream::WriteDataInternal(
StringPiece data, bool fin) {
+ struct iovec iov = {const_cast<char*>(data.data()),
+ static_cast<size_t>(data.size())};
+ return WritevDataInternal(&iov, 1, fin);
+}
+
+QuicConsumedData ReliableQuicStream::WritevDataInternal(const struct iovec* iov,
+ int count,
+ bool fin) {
if (write_side_closed_) {
DLOG(ERROR) << "Attempt to write when the write side is closed";
return QuicConsumedData(0, false);
}
+ size_t write_length = 0u;
+ for (int i = 0; i < count; ++i) {
+ write_length += iov[i].iov_len;
+ }
QuicConsumedData consumed_data =
- session()->WriteData(id(), data, stream_bytes_written_, fin);
+ session()->WritevData(id(), iov, count, stream_bytes_written_, fin);
stream_bytes_written_ += consumed_data.bytes_consumed;
- if (consumed_data.bytes_consumed == data.length()) {
+ if (consumed_data.bytes_consumed == write_length) {
if (fin && consumed_data.fin_consumed) {
fin_sent_ = true;
CloseWriteSide();
} else if (fin && !consumed_data.fin_consumed) {
- session_->MarkWriteBlocked(id());
+ session_->MarkWriteBlocked(id(), EffectivePriority());
}
} else {
- session_->MarkWriteBlocked(id());
+ session_->MarkWriteBlocked(id(), EffectivePriority());
}
return consumed_data;
}
+QuicPriority ReliableQuicStream::EffectivePriority() const {
+ return priority();
+}
+
void ReliableQuicStream::CloseReadSide() {
if (read_side_closed_) {
return;
@@ -283,7 +306,7 @@
total_bytes_consumed += StripPriorityAndHeaderId(data, data_len);
data += total_bytes_consumed;
data_len -= total_bytes_consumed;
- if (data_len == 0) {
+ if (data_len == 0 || !session_->connection()->connected()) {
return total_bytes_consumed;
}
}
@@ -465,11 +488,18 @@
if (!priority_parsed_ &&
session_->connection()->version() >= QUIC_VERSION_9 &&
session_->connection()->is_server()) {
+ QuicPriority temporary_priority = priority_;
total_bytes_parsed = StripUint32(
- data, data_len, &headers_id_and_priority_buffer_, &priority_);
+ data, data_len, &headers_id_and_priority_buffer_, &temporary_priority);
if (total_bytes_parsed > 0 && headers_id_and_priority_buffer_.size() == 0) {
- // TODO(alyssar) check for priority out of bounds.
priority_parsed_ = true;
+ // Spdy priorities are inverted, so the highest numerical value is the
+ // lowest legal priority.
+ if (temporary_priority > static_cast<QuicPriority>(kLowestPriority)) {
+ session_->connection()->SendConnectionClose(QUIC_INVALID_PRIORITY);
+ return 0;
+ }
+ priority_ = temporary_priority;
}
data += total_bytes_parsed;
data_len -= total_bytes_parsed;
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 7ba5428..4fe4134 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -95,6 +95,12 @@
// becomes unblocked.
virtual void OnDecompressorAvailable();
+ // By default, this is the same as priority(), however it allows streams
+ // to temporarily alter effective priority. For example if a SPDY stream has
+ // compressed but not written headers it can write the headers with a higher
+ // priority.
+ virtual QuicPriority EffectivePriority() const;
+
QuicStreamId id() const { return id_; }
QuicRstStreamErrorCode stream_error() const { return stream_error_; }
@@ -116,7 +122,6 @@
bool GetSSLInfo(SSLInfo* ssl_info);
bool headers_decompressed() const { return headers_decompressed_; }
- QuicPriority priority() const { return priority_; }
protected:
// Returns a pair with the number of bytes consumed from data, and a boolean
@@ -141,6 +146,13 @@
QuicSession* session() { return session_; }
+ // Sets priority_ to priority. This should only be called before bytes are
+ // written to the server.
+ void set_priority(QuicPriority priority);
+ // This is protected because external classes should use EffectivePriority
+ // instead.
+ QuicPriority priority() const { return priority_; }
+
// Sends as much of 'data' to the connection as the connection will consume,
// and then buffers any remaining data in queued_data_.
// Returns (data.size(), true) as it always consumed all data: it returns for
@@ -151,6 +163,13 @@
// Returns the number of bytes consumed by the connection.
QuicConsumedData WriteDataInternal(base::StringPiece data, bool fin);
+ // Sends as many bytes in the first |count| buffers of |iov| to the connection
+ // as the connection will consume.
+ // Returns the number of bytes consumed by the connection.
+ QuicConsumedData WritevDataInternal(const struct iovec* iov,
+ int count,
+ bool fin);
+
private:
friend class test::ReliableQuicStreamPeer;
friend class QuicStreamUtils;
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 1df13cfc..063554d8 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -126,9 +126,7 @@
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
- // TODO(rch): figure out how to get StrEq working here.
- //EXPECT_CALL(*session_, WriteData(kStreamId, StrEq(kData1), _, _)).WillOnce(
- EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed);
EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
@@ -142,7 +140,7 @@
// Write no data and no fin. If we consume nothing we should not be write
// blocked.
EXPECT_DEBUG_DEATH({
- EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce(
Return(QuicConsumedData(0, false)));
stream_->WriteData(StringPiece(), false);
EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
@@ -155,7 +153,7 @@
// Write some data and no fin. If we consume some but not all of the data,
// we should be write blocked a not all the data was consumed.
- EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce(
Return(QuicConsumedData(1, false)));
stream_->WriteData(StringPiece(kData1, 2), false);
ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams());
@@ -169,7 +167,7 @@
// we should be write blocked because the fin was not consumed.
// (This should never actually happen as the fin should be sent out with the
// last data)
- EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce(
Return(QuicConsumedData(2, false)));
stream_->WriteData(StringPiece(kData1, 2), true);
ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams());
@@ -180,7 +178,7 @@
// Write no data and a fin. If we consume nothing we should be write blocked,
// as the fin was not consumed.
- EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce(
Return(QuicConsumedData(0, false)));
stream_->WriteData(StringPiece(), true);
ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams());
@@ -194,9 +192,7 @@
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
- // TODO(rch): figure out how to get StrEq working here.
- //EXPECT_CALL(*session_, WriteData(_, StrEq(kData1), _, _)).WillOnce(
- EXPECT_CALL(*session_, WriteData(_, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen - 1, false)));
// The return will be kDataLen, because the last byte gets buffered.
EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed);
@@ -207,17 +203,14 @@
// Make sure we get the tail of the first write followed by the bytes_consumed
InSequence s;
- //EXPECT_CALL(*session_, WriteData(_, StrEq(&kData1[kDataLen - 1]), _, _)).
- EXPECT_CALL(*session_, WriteData(_, _, _, _)).
+ EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)).
WillOnce(Return(QuicConsumedData(1, false)));
- //EXPECT_CALL(*session_, WriteData(_, StrEq(kData2), _, _)).
- EXPECT_CALL(*session_, WriteData(_, _, _, _)).
+ EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)).
WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
stream_->OnCanWrite();
- // And finally the end of the bytes_consumed
- //EXPECT_CALL(*session_, WriteData(_, StrEq(&kData2[kDataLen - 2]), _, _)).
- EXPECT_CALL(*session_, WriteData(_, _, _, _)).
+ // And finally the end of the bytes_consumed.
+ EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)).
WillOnce(Return(QuicConsumedData(2, true)));
stream_->OnCanWrite();
}
@@ -238,19 +231,20 @@
Initialize(kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
QuicStreamFrame frame(kStreamId, false, 0, compressed_headers);
stream_->OnStreamFrame(frame);
EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_), stream_->data());
- EXPECT_EQ(0u, stream_->priority());
+ EXPECT_EQ(static_cast<QuicPriority>(kHighestPriority),
+ stream_->EffectivePriority());
}
TEST_F(ReliableQuicStreamTest, ProcessHeadersWithInvalidHeaderId) {
Initialize(kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
compressed_headers.replace(4, 1, 1, '\xFF'); // Illegal header id.
QuicStreamFrame frame(kStreamId, false, 0, compressed_headers);
@@ -262,7 +256,7 @@
Initialize(kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
string body = "this is the body";
string data = compressed_headers + body;
QuicStreamFrame frame(kStreamId, false, 0, data);
@@ -276,7 +270,7 @@
Initialize(kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(7, headers_);
+ compressor_->CompressHeadersWithPriority(kLowestPriority, headers_);
string body = "this is the body";
string data = compressed_headers + body;
@@ -308,14 +302,15 @@
ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body,
stream_->data()) << "split_point: " << split_point;
}
- EXPECT_EQ(7u, stream_->priority());
+ EXPECT_EQ(static_cast<QuicPriority>(kLowestPriority),
+ stream_->EffectivePriority());
}
TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) {
Initialize(!kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
string body = "this is the body";
string data = compressed_headers + body;
QuicStreamFrame frame(kStreamId, false, 0, data);
@@ -345,7 +340,7 @@
Initialize(!kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
string body = "this is the body";
string data = compressed_headers + body;
QuicStreamFrame frame(kStreamId, false, 0, data);
@@ -371,7 +366,7 @@
Initialize(!kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
string body = "this is the body";
string data = compressed_headers + body;
QuicStreamFrame frame(kStreamId, false, 0, data);
@@ -401,14 +396,14 @@
Initialize(kShouldProcessData);
string compressed_headers1 =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1);
string decompressed_headers1 =
SpdyUtils::SerializeUncompressedHeaders(headers_);
headers_["content-type"] = "text/plain";
string compressed_headers2 =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
// Corrupt the compressed data.
compressed_headers2[compressed_headers2.length() - 1] ^= 0xA1;
QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2);
@@ -441,14 +436,14 @@
Initialize(kShouldProcessData);
string compressed_headers1 =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1);
string decompressed_headers1 =
SpdyUtils::SerializeUncompressedHeaders(headers_);
headers_["content-type"] = "text/plain";
string compressed_headers2 =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
string partial_compressed_headers =
compressed_headers2.substr(0, compressed_headers2.length() / 2);
QuicStreamFrame frame2(stream2_->id(), false, 0, partial_compressed_headers);
@@ -492,14 +487,14 @@
Initialize(kShouldProcessData);
string compressed_headers1 =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1);
string decompressed_headers1 =
SpdyUtils::SerializeUncompressedHeaders(headers_);
headers_["content-type"] = "text/plain";
string compressed_headers2 =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2);
string decompressed_headers2 =
SpdyUtils::SerializeUncompressedHeaders(headers_);
@@ -528,7 +523,7 @@
Initialize(!kShouldProcessData);
string compressed_headers =
- compressor_->CompressHeadersWithPriority(0, headers_);
+ compressor_->CompressHeadersWithPriority(kHighestPriority, headers_);
QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers);
string decompressed_headers =
SpdyUtils::SerializeUncompressedHeaders(headers_);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 9381e05..750f9c7 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -254,7 +254,7 @@
MockSession::MockSession(QuicConnection* connection, bool is_server)
: QuicSession(connection, DefaultQuicConfig(), is_server) {
- ON_CALL(*this, WriteData(_, _, _, _))
+ ON_CALL(*this, WritevData(_, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index a90b212..38aa8522 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -184,6 +184,8 @@
MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer));
MOCK_METHOD1(OnAck, void(const SequenceNumberSet& acked_packets));
MOCK_METHOD0(OnCanWrite, bool());
+ MOCK_METHOD1(OnSuccessfulVersionNegotiation,
+ void(const QuicVersion& version));
private:
DISALLOW_COPY_AND_ASSIGN(MockConnectionVisitor);
@@ -285,10 +287,11 @@
ReliableQuicStream*(QuicStreamId id));
MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*());
- MOCK_METHOD4(WriteData, QuicConsumedData(QuicStreamId id,
- base::StringPiece data,
- QuicStreamOffset offset,
- bool fin));
+ MOCK_METHOD5(WritevData, QuicConsumedData(QuicStreamId id,
+ const struct iovec* iov,
+ int count,
+ QuicStreamOffset offset,
+ bool fin));
MOCK_METHOD0(IsHandshakeComplete, bool());
private:
@@ -327,8 +330,9 @@
MOCK_METHOD3(OnIncomingAck,
void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta));
MOCK_METHOD1(OnIncomingLoss, void(QuicTime));
- MOCK_METHOD4(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber,
- QuicByteCount, Retransmission));
+ MOCK_METHOD5(SentPacket,
+ bool(QuicTime sent_time, QuicPacketSequenceNumber, QuicByteCount,
+ Retransmission, HasRetransmittableData));
MOCK_METHOD2(AbandoningPacket, void(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes));
MOCK_METHOD4(TimeUntilSend, QuicTime::Delta(QuicTime now, Retransmission,
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc
index 6d6ea13d..9f0321a 100644
--- a/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -91,6 +91,8 @@
QuicBandwidth::FromKBitsPerSecond(100)));
EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(Return(
QuicTime::Delta::FromMilliseconds(100)));
+ ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _))
+ .WillByDefault(Return(true));
}
QuicPacket* ConstructDataPacket(QuicPacketSequenceNumber number,
@@ -136,12 +138,14 @@
arraysize(buffer) - 1;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, 1, packet_size, NOT_RETRANSMISSION));
+ SentPacket(_, 1, packet_size, NOT_RETRANSMISSION, _));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, packet_size));
- connection_.SendStreamData(1, buffer, 0, false);
+ struct iovec iov = {const_cast<char*>(buffer),
+ static_cast<size_t>(3)};
+ connection_.SendvStreamData(1, &iov, 1, 0, false);
EXPECT_EQ(1u, helper_->header()->packet_sequence_number);
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, 2, packet_size, IS_RETRANSMISSION));
+ SentPacket(_, 2, packet_size, IS_RETRANSMISSION, _));
epoll_server_.AdvanceByAndCallCallbacks(kDefaultRetransmissionTimeMs * 1000);
EXPECT_EQ(2u, helper_->header()->packet_sequence_number);
@@ -150,7 +154,7 @@
TEST_F(QuicEpollConnectionHelperTest, InitialTimeout) {
EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _));
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
epoll_server_.WaitForEventsAndExecuteCallbacks();
EXPECT_FALSE(connection_.connected());
@@ -167,7 +171,8 @@
EXPECT_EQ(5000, epoll_server_.NowInUsec());
// Send an ack so we don't set the retransmission alarm.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_,
+ SentPacket(_, 1, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA));
connection_.SendAck();
// The original alarm will fire. We should not time out because we had a
@@ -177,7 +182,8 @@
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_,
+ SentPacket(_, 2, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA));
epoll_server_.WaitForEventsAndExecuteCallbacks();
EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000 + 5000,
epoll_server_.NowInUsec());
@@ -191,17 +197,19 @@
QuicPacket* packet = ConstructDataPacket(1, 0);
EXPECT_CALL(
*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendOrQueuePacket(ENCRYPTION_NONE, 1, packet, 0,
HAS_RETRANSMITTABLE_DATA);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION,
+ _));
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).
- WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly(
+ Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true));
epoll_server_.AdvanceByAndCallCallbacks(1);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
diff --git a/net/tools/quic/quic_reliable_server_stream_test.cc b/net/tools/quic/quic_reliable_server_stream_test.cc
index b946d94..8e4ae4c 100644
--- a/net/tools/quic/quic_reliable_server_stream_test.cc
+++ b/net/tools/quic/quic_reliable_server_stream_test.cc
@@ -58,7 +58,9 @@
stream_.reset(new QuicSpdyServerStream(3, &session_));
}
- QuicConsumedData ValidateHeaders(StringPiece headers) {
+ QuicConsumedData ValidateHeaders(const struct iovec* iov) {
+ StringPiece headers =
+ StringPiece(static_cast<const char*>(iov[0].iov_base), iov[0].iov_len);
headers_string_ = SpdyUtils::SerializeResponseHeaders(
response_headers_);
QuicSpdyDecompressor decompressor;
@@ -119,13 +121,17 @@
string body_;
};
-QuicConsumedData ConsumeAllData(QuicStreamId id, StringPiece data,
- QuicStreamOffset offset, bool fin) {
- return QuicConsumedData(data.size(), fin);
+QuicConsumedData ConsumeAllData(QuicStreamId id, const struct iovec* iov,
+ int count, QuicStreamOffset offset, bool fin) {
+ ssize_t consumed_length = 0;
+ for (int i = 0; i < count; ++i) {
+ consumed_length += iov[i].iov_len;
+ }
+ return QuicConsumedData(consumed_length, fin);
}
TEST_F(QuicReliableServerStreamTest, TestFraming) {
- EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(AnyNumber()).
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
@@ -138,7 +144,7 @@
}
TEST_F(QuicReliableServerStreamTest, TestFramingOnePacket) {
- EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(AnyNumber()).
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
string message = headers_string_ + body_;
@@ -156,7 +162,7 @@
string large_body = "hello world!!!!!!";
// We'll automatically write out an error (headers + body)
- EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(2).
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(2).
WillRepeatedly(Invoke(ConsumeAllData));
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
@@ -183,11 +189,11 @@
response_headers_.ReplaceOrAppendHeader("content-length", "3");
InSequence s;
- EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(1)
+ EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1)
.WillOnce(WithArgs<1>(Invoke(
this, &QuicReliableServerStreamTest::ValidateHeaders)));
- StringPiece kBody = "Yum";
- EXPECT_CALL(session_, WriteData(_, kBody, _, _)).Times(1).
+
+ EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1).
WillOnce(Return(QuicConsumedData(3, true)));
stream_->SendResponse();
@@ -201,11 +207,11 @@
response_headers_.ReplaceOrAppendHeader("content-length", "3");
InSequence s;
- EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(1)
+ EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1)
.WillOnce(WithArgs<1>(Invoke(
this, &QuicReliableServerStreamTest::ValidateHeaders)));
- StringPiece kBody = "bad";
- EXPECT_CALL(session_, WriteData(_, kBody, _, _)).Times(1).
+
+ EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1).
WillOnce(Return(QuicConsumedData(3, true)));
stream_->SendErrorResponse();
diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h
index ec4d257..5d32b30d 100644
--- a/net/tools/quic/quic_spdy_client_stream.h
+++ b/net/tools/quic/quic_spdy_client_stream.h
@@ -34,6 +34,10 @@
base::StringPiece body,
bool fin) OVERRIDE;
+ // While the server's set_priority shouldn't be called externally, the creator
+ // of client-side streams should be able to set the priority.
+ using QuicReliableClientStream::set_priority;
+
private:
int ParseResponseHeaders();
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 03600f27..272786e 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -11,6 +11,7 @@
#include "net/quic/crypto/proof_verifier.h"
#include "net/tools/flip_server/balsa_headers.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_spdy_client_stream.h"
#include "net/tools/quic/test_tools/http_message_test_utils.h"
#include "url/gurl.h"
@@ -157,6 +158,7 @@
server_address_ = address;
stream_ = NULL;
stream_error_ = QUIC_STREAM_NO_ERROR;
+ priority_ = 3;
bytes_read_ = 0;
bytes_written_= 0;
never_connected_ = true;
@@ -243,10 +245,13 @@
}
if (!stream_) {
stream_ = client_->CreateReliableClientStream();
- if (stream_ != NULL) {
- stream_->set_visitor(this);
+ if (stream_ == NULL) {
+ return NULL;
}
+ stream_->set_visitor(this);
+ reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_);
}
+
return stream_;
}
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 74bfc246..3cd71d5 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -107,6 +107,8 @@
void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
+ void set_priority(QuicPriority priority) { priority_ = priority; }
+
private:
void Initialize(IPEndPoint address, const string& hostname, bool secure);
@@ -118,6 +120,8 @@
QuicRstStreamErrorCode stream_error_;
BalsaHeaders headers_;
+ QuicPriority priority_;
+
string response_;
uint64 bytes_read_;
uint64 bytes_written_;