summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-18 15:36:58 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-18 15:36:58 +0000
commit24e5bc5874e356015e2bc8319c072e9d13eac582 (patch)
tree1194a9f7a437ba8f2ec332e1f3283c53007fdf24
parent423b6d68c4ad554805d3248d352caa7f8fd188b4 (diff)
downloadchromium_src-24e5bc5874e356015e2bc8319c072e9d13eac582.zip
chromium_src-24e5bc5874e356015e2bc8319c072e9d13eac582.tar.gz
chromium_src-24e5bc5874e356015e2bc8319c072e9d13eac582.tar.bz2
Land Recent QUIC changes.
Pass HasRetransmittableData to the congestion manager and the send algorithm. This allows tcp_cubic_sender to not count ACK-only packets against the congestion window. Merge internal change: 51829697 If a previously zombie'd QUIC stream is closed and the headers have been decompressed, remove that entry from the zombie stream map. Merge internal change: 51697989 Change the value used to set the sequence number with to both correctly calculate the widest packet spread currently outstanding and fix a DCHECK failure in EndToEnd's Uber test when packets were transmitted sufficiently out of order that the packet being sent was less than the last packet the peer was awaiting. Merge internal change: 51644967 Fix a bug where frames are queued and not enough room for the next stream frame is available, but we attempt to create a STREAM frame anyway in ConsumeData. Merge internal change: 51604946 Changed Delayed Ack Timer to go off before the sender's retransmission timer goes off. Merge internal change: 51594956 Using the priorities sent by the client, including bounds checking, and bumping the priority of initial writes to avoid the HOL header blocking issue. Merge internal change: 51586426 Fix memory leak uncovered by https://codereview.chromium.org/23587004 Merge internal change: 51569066 Added logging of QUIC version negotiated. Export number of QUIC sessions and streams for each QUIC version. Merge internal change: 51540178 A refactor of QuicFdWrapper's writev to pass the iovec all the way to QuicConnection, allowing better packet packing. Merge internal change: 51530908 Enabled priorities in chrome quic streams. R=rch@chromium.org Review URL: https://chromiumcodereview.appspot.com/23597045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223880 0039d316-1c4b-4281-b951-d872f2087c98
-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_;