summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/net_log_event_type_list.h6
-rw-r--r--net/net.gyp3
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc11
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h10
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc13
-rw-r--r--net/quic/congestion_control/inter_arrival_sender.cc11
-rw-r--r--net/quic/congestion_control/inter_arrival_sender.h10
-rw-r--r--net/quic/congestion_control/inter_arrival_sender_test.cc2
-rw-r--r--net/quic/congestion_control/quic_congestion_control_test.cc12
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.cc40
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.h6
-rw-r--r--net/quic/congestion_control/quic_congestion_manager_test.cc39
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h8
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc13
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h10
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc19
-rw-r--r--net/quic/quic_client_session.cc6
-rw-r--r--net/quic/quic_client_session.h2
-rw-r--r--net/quic/quic_connection.cc121
-rw-r--r--net/quic/quic_connection.h22
-rw-r--r--net/quic/quic_connection_helper_test.cc36
-rw-r--r--net/quic/quic_connection_logger.cc9
-rw-r--r--net/quic/quic_connection_logger.h1
-rw-r--r--net/quic/quic_connection_test.cc297
-rw-r--r--net/quic/quic_crypto_stream.cc4
-rw-r--r--net/quic/quic_http_stream.cc16
-rw-r--r--net/quic/quic_http_stream.h9
-rw-r--r--net/quic/quic_http_stream_test.cc89
-rw-r--r--net/quic/quic_http_utils.cc23
-rw-r--r--net/quic/quic_http_utils.h22
-rw-r--r--net/quic/quic_http_utils_test.cc35
-rw-r--r--net/quic/quic_network_transaction_unittest.cc4
-rw-r--r--net/quic/quic_packet_creator.cc32
-rw-r--r--net/quic/quic_packet_creator.h8
-rw-r--r--net/quic/quic_packet_creator_test.cc47
-rw-r--r--net/quic/quic_packet_generator.cc12
-rw-r--r--net/quic/quic_packet_generator.h1
-rw-r--r--net/quic/quic_packet_generator_test.cc44
-rw-r--r--net/quic/quic_protocol.h8
-rw-r--r--net/quic/quic_reliable_client_stream.cc8
-rw-r--r--net/quic/quic_reliable_client_stream.h8
-rw-r--r--net/quic/quic_reliable_client_stream_test.cc8
-rw-r--r--net/quic/quic_session.cc20
-rw-r--r--net/quic/quic_session.h14
-rw-r--r--net/quic/quic_session_test.cc14
-rw-r--r--net/quic/quic_stream_factory_test.cc2
-rw-r--r--net/quic/quic_stream_sequencer.cc24
-rw-r--r--net/quic/quic_stream_sequencer_test.cc6
-rw-r--r--net/quic/quic_utils.cc4
-rw-r--r--net/quic/reliable_quic_stream.cc44
-rw-r--r--net/quic/reliable_quic_stream.h21
-rw-r--r--net/quic/reliable_quic_stream_test.cc61
-rw-r--r--net/quic/test_tools/quic_test_utils.cc2
-rw-r--r--net/quic/test_tools/quic_test_utils.h16
-rw-r--r--net/tools/quic/quic_epoll_connection_helper_test.cc30
-rw-r--r--net/tools/quic/quic_reliable_server_stream_test.cc32
-rw-r--r--net/tools/quic/quic_spdy_client_stream.h4
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc9
-rw-r--r--net/tools/quic/test_tools/quic_test_client.h4
59 files changed, 1058 insertions, 334 deletions
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_PUBLIC_RESET_PACKET_RECEIVED)
// }
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 1cce2a6..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 22f759f..99aa10f 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -60,15 +60,18 @@ void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
// 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 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
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..e316f65 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -63,11 +63,14 @@ TEST_F(FixRateTest, SenderAPI) {
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 @@ TEST_F(FixRateTest, FixRatePacing) {
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::OnIncomingLoss(QuicTime ack_receive_time) {
}
}
-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 ad28ecd..2c455cc 100644
--- a/net/quic/congestion_control/inter_arrival_sender.h
+++ b/net/quic/congestion_control/inter_arrival_sender.h
@@ -43,10 +43,12 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface {
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..7392b1a 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 @@ class InterArrivalSenderTest : public ::testing::Test {
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..457538f 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 @@ TEST_F(QuicCongestionControlTest, FixedRateSenderAPI) {
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 @@ TEST_F(QuicCongestionControlTest, FixedRatePacing) {
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 @@ TEST_F(QuicCongestionControlTest, Pacing) {
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 @@ QuicCongestionManager::~QuicCongestionManager() {
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 @@ const QuicTime::Delta QuicCongestionManager::DefaultRetransmissionTime() {
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..465819b 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -50,7 +50,8 @@ class NET_EXPORT_PRIVATE QuicCongestionManager {
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 @@ class NET_EXPORT_PRIVATE QuicCongestionManager {
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 @@ TEST_F(QuicCongestionManagerTest, Bandwidth) {
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 @@ TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) {
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 @@ TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) {
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 @@ TEST_F(QuicCongestionManagerTest, Rtt) {
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 @@ TEST_F(QuicCongestionManagerTest, RttWithInvalidDelta) {
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 @@ TEST_F(QuicCongestionManagerTest, RttInfiniteDelta) {
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 @@ TEST_F(QuicCongestionManagerTest, RttZeroDelta) {
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 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
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 438dbe9..52c910e 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::OnIncomingQuicCongestionFeedbackFrame(
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 @@ void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
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 @@ void TcpCubicSender::SentPacket(QuicTime /*sent_time*/,
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 8cea0aa..db829c2 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -41,10 +41,12 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
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 @@ class TcpCubicSenderTest : public ::testing::Test {
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 @@ TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) {
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 ec87d77..ca6941c 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -314,6 +314,12 @@ void QuicClientSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
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 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
// 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::list;
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 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
}
version_negotiation_state_ = NEGOTIATED_VERSION;
+ visitor_->OnSuccessfulVersionNegotiation(received_version);
// Store the new version.
framer_.set_version(received_version);
@@ -380,6 +382,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
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 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
// 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 @@ void QuicConnection::MaybeSendInResponseToPacket(
// 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 @@ void QuicConnection::SendVersionNegotiationPacket() {
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.
- packet_generator_.FinishBatchOperations();
+ 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;
+ }
}
- QuicConsumedData consumed_data =
- packet_generator_.ConsumeData(id, data, offset, fin);
- if (crypto_frame_while_batch_mode) {
- // Restore batch mode.
- packet_generator_.StartBatchOperations();
+ // 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;
}
- return consumed_data;
+
+ // Leave the generator in the original batch state.
+ if (!already_in_batch_mode) {
+ packet_generator_.FinishBatchOperations();
+ }
+ DCHECK_EQ(already_in_batch_mode, packet_generator_.InBatchMode());
+ return QuicConsumedData(bytes_written, fin_consumed);
}
QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked(
@@ -845,6 +874,9 @@ QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked(
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 @@ bool QuicConnection::DoWrite() {
// 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 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
// 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 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
// 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 @@ int QuicConnection::WritePacketToWire(QuicPacketSequenceNumber sequence_number,
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::CloseFecGroupsBefore(
}
}
+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 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// 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 @@ class NET_EXPORT_PRIVATE QuicConnection
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 @@ class NET_EXPORT_PRIVATE QuicConnection
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 @@ class NET_EXPORT_PRIVATE QuicConnection
// 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 @@ class QuicConnectionHelperTest : public ::testing::Test {
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 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) {
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 @@ TEST_F(QuicConnectionHelperTest, TestMultipleRetransmission) {
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 @@ TEST_F(QuicConnectionHelperTest, TestMultipleRetransmission) {
// 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 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
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 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// 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 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// 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 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) {
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..5195f43 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 @@ void QuicConnectionLogger::OnConnectionClose(QuicErrorCode error,
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 f9080d6..d498b12 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -56,6 +56,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger
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 e57e7ae..147d8bc 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -389,6 +389,15 @@ class TestConnection : public QuicConnection {
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 @@ class TestConnection : public QuicConnection {
// 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 @@ class QuicConnectionTest : public ::testing::Test {
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 @@ class QuicConnectionTest : public ::testing::Test {
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 @@ class QuicConnectionTest : public ::testing::Test {
};
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, PacketsInOrder) {
}
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, PacketsRejected) {
}
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, PacketsOutOfOrder) {
}
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, DuplicatePacket) {
}
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, RejectPacketTooFarOut) {
}
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, TruncatedAck) {
}
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, AckReceiptCausesAckSendBadEntropy) {
}
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 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) {
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, AckReceiptCausesAckSend) {
}
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 @@ TEST_F(QuicConnectionTest, LeastUnackedLower) {
// 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, LargestObservedLower) {
}
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, LeastUnackedGreaterThanPacketSequenceNumber) {
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,
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, SendingDifferentSequenceNumberLengthsUnackedDelta) {
}
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 @@ TEST_F(QuicConnectionTest, FECSending) {
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, FECQueueing) {
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 @@ TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) {
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, AbandonFECFromCongestionWindow) {
}
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 @@ TEST_F(QuicConnectionTest, DontAbandonAckedFEC) {
// 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 @@ TEST_F(QuicConnectionTest, FramePacking) {
// 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 @@ TEST_F(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
// 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 @@ TEST_F(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
// 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 @@ TEST_F(QuicConnectionTest, FramePackingFEC) {
// 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 @@ TEST_F(QuicConnectionTest, FramePackingFEC) {
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 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
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 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
// 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 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
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 @@ TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) {
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 @@ TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) {
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 @@ TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) {
// 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 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
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 @@ TEST_F(QuicConnectionTest, MultipleAcks) {
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 @@ TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
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, DontLatchUnackedPacket) {
}
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, ReviveMissingPacketAfterDataPacketThenFecPacket) {
}
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, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
}
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, ReviveMissingPacketAfterDataPacket) {
}
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 @@ TEST_F(QuicConnectionTest, TestRetransmit) {
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 @@ TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
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 @@ TEST_F(QuicConnectionTest,
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 @@ TEST_F(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
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, BufferNonDecryptablePackets) {
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 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) {
{
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 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
// 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 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
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, TestQueued) {
}
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, WithQuicCongestionFeedbackFrame) {
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, DontUpdateQuicCongestionFeedbackFrameForRevived) {
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 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
// 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 @@ TEST_F(QuicConnectionTest, SendScheduler) {
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 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) {
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 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) {
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 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
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 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
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 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
.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 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
// 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, SendSchedulerDelayAndQueue) {
}
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 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
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, SendSchedulerDelayThenAckAndSend) {
}
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 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
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, LoopThroughSendingPackets) {
}
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 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) {
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, PublicReset) {
}
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 @@ TEST_F(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
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, ReceivedEntropyHashCalculation) {
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, UpdateEntropyForReceivedPackets) {
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, UpdateEntropyHashUptoCurrentPacket) {
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 @@ TEST_F(QuicConnectionTest, ClientHandlesVersionNegotiation) {
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, BadVersionNegotiation) {
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 @@ TEST_F(QuicConnectionTest, CheckSendStats) {
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, CheckSendStats) {
}
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 @@ TEST_F(QuicConnectionTest, DontProcessFramesIfPacketClosedConnection) {
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, ConnectionCloseWhenNothingPending) {
}
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, AckNotifierTriggerCallback) {
}
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, AckNotifierFailToTriggerCallback) {
}
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 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
// 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 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
// 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 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) {
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 @@ void QuicCryptoStream::SendHandshakeMessage(
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 @@ QuicHttpStream::QuicHttpStream(const base::WeakPtr<QuicClientSession> session)
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 @@ int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
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 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
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 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
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 @@ void QuicHttpStream::Close(bool not_reusable) {
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::Drain(HttpNetworkSession* session) {
}
void QuicHttpStream::SetPriority(RequestPriority priority) {
- // Nothing to do here (yet).
+ priority_ = priority;
}
int QuicHttpStream::OnSendData() {
@@ -336,6 +342,10 @@ void QuicHttpStream::OnError(int error) {
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 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
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 @@ class NET_EXPORT_PRIVATE QuicHttpStream :
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 @@ class AutoClosingStream : public QuicHttpStream {
} // 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 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
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 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
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 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
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 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
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, IsConnectionReusable) {
}
TEST_F(QuicHttpStreamTest, GetRequest) {
- SetRequestString("GET", "/");
+ SetRequestString("GET", "/", DEFAULT_PRIORITY);
AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0,
request_data_));
Initialize();
@@ -393,7 +409,7 @@ TEST_F(QuicHttpStreamTest, GetRequest) {
// 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, GetRequestLargeResponse) {
}
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, GetRequestFullResponseInSinglePacket) {
}
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, SendPostRequest) {
}
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, SendChunkedPostRequest) {
}
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,9 +629,54 @@ TEST_F(QuicHttpStreamTest, DestroyedEarly) {
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.
+ 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());
+}
+
+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);
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 801c7ef..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 @@ class QuicNetworkTransactionTest : public PlatformTest {
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::StopSendingVersion() {
}
}
+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 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
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 0e0a8c7..68b6216 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -70,6 +70,12 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// 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 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
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 193bb88..51133b6 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -333,6 +333,53 @@ TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
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 41161eb..4650068 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -88,6 +88,9 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
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 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
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 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
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 8832042..eabbec1 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -40,6 +40,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface {
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 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) {
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..26e6c02 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -269,8 +269,8 @@ NET_EXPORT_PRIVATE size_t GetStartOfEncryptedData(
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 @@ enum QuicErrorCode {
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 @@ enum QuicErrorCode {
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 @@ void QuicReliableClientStream::OnCanWrite() {
}
}
+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 @@ class NET_EXPORT_PRIVATE QuicReliableClientStream : public ReliableQuicStream {
// 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 @@ class NET_EXPORT_PRIVATE QuicReliableClientStream : public ReliableQuicStream {
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 5041591..aaebda2 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -28,6 +28,7 @@ class MockDelegate : public QuicReliableClientStream::Delegate {
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 @@ TEST_F(QuicReliableClientStreamTest, WriteStreamData) {
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, WriteStreamData) {
}
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 @@ TEST_F(QuicReliableClientStreamTest, WriteStreamDataAsync) {
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 @@ class VisitorShim : public QuicConnectionVisitorInterface {
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 @@ bool QuicSession::OnCanWrite() {
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 @@ size_t QuicSession::GetNumOpenStreams() const {
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 c37b6e1..9916e58 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -66,6 +66,8 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
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 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// 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 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// 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 @@ class TestSession : public QuicSession {
// Helper method for gmock
void MarkTwoWriteBlocked() {
- this->MarkWriteBlocked(2);
+ this->MarkWriteBlocked(2, 0);
}
TestCryptoStream crypto_stream_;
@@ -240,9 +240,9 @@ TEST_F(QuicSessionTest, OnCanWrite) {
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 @@ TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) {
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 fb9d474..a546d87 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -52,7 +52,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
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 7cf67d3..a57c05f 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -74,17 +74,21 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
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 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
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 @@ void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
<< " 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 @@ void QuicStreamSequencer::FlushBufferedFrames() {
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..21568d6 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -71,6 +71,7 @@ class MockStream : public ReliableQuicStream {
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, FullFrameConsumed) {
}
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 @@ TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
// 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 74c90a0..cfb3cb7 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -120,7 +120,7 @@ const char* QuicUtils::StreamErrorToString(QuicRstStreamErrorCode error) {
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 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
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 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
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 45b4fce..7a44713 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 @@ QuicConsumedData ReliableQuicStream::WriteData(StringPiece data, bool fin) {
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 @@ void ReliableQuicStream::OnCanWrite() {
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 @@ uint32 ReliableQuicStream::ProcessRawData(const char* data, uint32 data_len) {
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 @@ uint32 ReliableQuicStream::StripPriorityAndHeaderId(
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 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public
// 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 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public
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 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public
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 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public
// 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 1df13cf..063554d 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -126,9 +126,7 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
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 @@ TEST_F(ReliableQuicStreamTest, NoBlockingIfNoDataOrFin) {
// 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 @@ TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
// 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 @@ TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
// 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 @@ TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
// 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 @@ TEST_F(ReliableQuicStreamTest, WriteData) {
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 @@ TEST_F(ReliableQuicStreamTest, WriteData) {
// 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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeaders) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBody) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyFragments) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyFragments) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessCorruptHeadersEarly) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessPartialHeadersEarly) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) {
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 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersDelay) {
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 @@ bool PacketSavingConnection::SendOrQueuePacket(
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..38aa852 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -184,6 +184,8 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface {
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 @@ class MockSession : public QuicSession {
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 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
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 6d6ea13..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 @@ class QuicEpollConnectionHelperTest : public ::testing::Test {
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 @@ TEST_F(QuicEpollConnectionHelperTest, DISABLED_TestRetransmission) {
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, DISABLED_TestRetransmission) {
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 @@ TEST_F(QuicEpollConnectionHelperTest, TimeoutAfterSend) {
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 @@ TEST_F(QuicEpollConnectionHelperTest, TimeoutAfterSend) {
// 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 @@ TEST_F(QuicEpollConnectionHelperTest, SendSchedulerDelayThenSend) {
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 @@ class QuicReliableServerStreamTest : public ::testing::Test {
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 @@ class QuicReliableServerStreamTest : public ::testing::Test {
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, TestFraming) {
}
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 @@ TEST_F(QuicReliableServerStreamTest, TestFramingExtraData) {
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 @@ TEST_F(QuicReliableServerStreamTest, TestSendResponse) {
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 @@ TEST_F(QuicReliableServerStreamTest, TestSendErrorResponse) {
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..5d32b30 100644
--- a/net/tools/quic/quic_spdy_client_stream.h
+++ b/net/tools/quic/quic_spdy_client_stream.h
@@ -34,6 +34,10 @@ class QuicSpdyClientStream : public QuicReliableClientStream {
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 03600f2..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 @@ void QuicTestClient::Initialize(IPEndPoint address,
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 @@ QuicReliableClientStream* QuicTestClient::GetOrCreateStream() {
}
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 74bfc24..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 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
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 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
QuicRstStreamErrorCode stream_error_;
BalsaHeaders headers_;
+ QuicPriority priority_;
+
string response_;
uint64 bytes_read_;
uint64 bytes_written_;