summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/net.gyp7
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc28
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h12
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc35
-rw-r--r--net/quic/congestion_control/hybrid_slow_start.cc5
-rw-r--r--net/quic/congestion_control/hybrid_slow_start.h2
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.cc56
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.h23
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h13
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc34
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h9
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc24
-rw-r--r--net/quic/crypto/crypto_framer.cc2
-rw-r--r--net/quic/crypto/crypto_framer.h2
-rw-r--r--net/quic/crypto/crypto_framer_test.cc1
-rw-r--r--net/quic/crypto/crypto_handshake.cc224
-rw-r--r--net/quic/crypto/crypto_handshake.h93
-rw-r--r--net/quic/crypto/crypto_protocol.cc154
-rw-r--r--net/quic/crypto/crypto_protocol.h61
-rw-r--r--net/quic/crypto/null_decrypter.cc8
-rw-r--r--net/quic/crypto/null_decrypter.h2
-rw-r--r--net/quic/crypto/null_encrypter.cc8
-rw-r--r--net/quic/crypto/null_encrypter.h2
-rw-r--r--net/quic/crypto/quic_decrypter.cc4
-rw-r--r--net/quic/crypto/quic_decrypter.h4
-rw-r--r--net/quic/crypto/quic_encrypter.cc4
-rw-r--r--net/quic/crypto/quic_encrypter.h4
-rw-r--r--net/quic/quic_client_session_test.cc5
-rw-r--r--net/quic/quic_connection.cc246
-rw-r--r--net/quic/quic_connection.h57
-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.h4
-rw-r--r--net/quic/quic_connection_test.cc435
-rw-r--r--net/quic/quic_crypto_client_stream.cc8
-rw-r--r--net/quic/quic_crypto_client_stream.h6
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc2
-rw-r--r--net/quic/quic_crypto_server_stream.cc9
-rw-r--r--net/quic/quic_crypto_server_stream.h6
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc2
-rw-r--r--net/quic/quic_crypto_stream.cc11
-rw-r--r--net/quic/quic_crypto_stream.h1
-rw-r--r--net/quic/quic_crypto_stream_test.cc3
-rw-r--r--net/quic/quic_data_reader.h1
-rw-r--r--net/quic/quic_framer.cc102
-rw-r--r--net/quic/quic_framer.h38
-rw-r--r--net/quic/quic_framer_test.cc111
-rw-r--r--net/quic/quic_http_stream_test.cc31
-rw-r--r--net/quic/quic_network_transaction_unittest.cc17
-rw-r--r--net/quic/quic_packet_creator.cc41
-rw-r--r--net/quic/quic_packet_creator.h23
-rw-r--r--net/quic/quic_packet_creator_test.cc116
-rw-r--r--net/quic/quic_packet_generator.cc6
-rw-r--r--net/quic/quic_packet_generator.h3
-rw-r--r--net/quic/quic_packet_generator_test.cc12
-rw-r--r--net/quic/quic_protocol.cc37
-rw-r--r--net/quic/quic_protocol.h32
-rw-r--r--net/quic/quic_reliable_client_stream_test.cc2
-rw-r--r--net/quic/quic_session_test.cc3
-rw-r--r--net/quic/quic_stats.cc29
-rw-r--r--net/quic/quic_stats.h50
-rw-r--r--net/quic/quic_stream_factory.cc2
-rw-r--r--net/quic/quic_stream_factory_test.cc17
-rw-r--r--net/quic/quic_time.cc2
-rw-r--r--net/quic/quic_utils.cc3
-rw-r--r--net/quic/reliable_quic_stream_test.cc2
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc59
-rw-r--r--net/quic/test_tools/crypto_test_utils.h11
-rw-r--r--net/quic/test_tools/quic_connection_peer.cc13
-rw-r--r--net/quic/test_tools/quic_connection_peer.h5
-rw-r--r--net/quic/test_tools/quic_framer_peer.cc36
-rw-r--r--net/quic/test_tools/quic_framer_peer.h35
-rw-r--r--net/quic/test_tools/quic_packet_creator_peer.cc30
-rw-r--r--net/quic/test_tools/quic_packet_creator_peer.h32
-rw-r--r--net/quic/test_tools/quic_test_utils.cc49
-rw-r--r--net/quic/test_tools/quic_test_utils.h39
-rw-r--r--net/quic/test_tools/simple_quic_framer.cc11
77 files changed, 2009 insertions, 652 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 6980f78..49e0b0e 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -700,7 +700,6 @@
'quic/crypto/crypto_framer.h',
'quic/crypto/crypto_handshake.cc',
'quic/crypto/crypto_handshake.h',
- 'quic/crypto/crypto_protocol.cc',
'quic/crypto/crypto_protocol.h',
'quic/crypto/crypto_utils.cc',
'quic/crypto/crypto_utils.h',
@@ -761,6 +760,8 @@
'quic/quic_reliable_client_stream.h',
'quic/quic_session.cc',
'quic/quic_session.h',
+ 'quic/quic_stats.cc',
+ 'quic/quic_stats.h',
'quic/quic_stream_factory.cc',
'quic/quic_stream_factory.h',
'quic/quic_stream_sequencer.cc',
@@ -1552,6 +1553,10 @@
'quic/test_tools/mock_random.h',
'quic/test_tools/quic_connection_peer.cc',
'quic/test_tools/quic_connection_peer.h',
+ 'quic/test_tools/quic_framer_peer.cc',
+ 'quic/test_tools/quic_framer_peer.h',
+ 'quic/test_tools/quic_packet_creator_peer.cc',
+ 'quic/test_tools/quic_packet_creator_peer.h',
'quic/test_tools/quic_session_peer.cc',
'quic/test_tools/quic_session_peer.h',
'quic/test_tools/quic_test_utils.cc',
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 924a7b4..19549a47 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -20,10 +20,14 @@ FixRateSender::FixRateSender(const QuicClock* clock)
: bitrate_(QuicBandwidth::FromBytesPerSecond(kInitialBitrate)),
fix_rate_leaky_bucket_(bitrate_),
paced_sender_(bitrate_),
- data_in_flight_(0) {
+ data_in_flight_(0),
+ latest_rtt_(QuicTime::Delta::Zero()) {
DLOG(INFO) << "FixRateSender";
}
+FixRateSender::~FixRateSender() {
+}
+
void FixRateSender::OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& feedback,
QuicTime feedback_receive_time,
@@ -42,7 +46,8 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame(
void FixRateSender::OnIncomingAck(
QuicPacketSequenceNumber /*acked_sequence_number*/,
QuicByteCount bytes_acked,
- QuicTime::Delta /*rtt*/) {
+ QuicTime::Delta rtt) {
+ latest_rtt_ = rtt;
data_in_flight_ -= bytes_acked;
}
@@ -53,8 +58,7 @@ void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
void FixRateSender::SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber /*sequence_number*/,
QuicByteCount bytes,
- bool is_retransmission,
- bool /*has_retransmittable_data*/) {
+ bool is_retransmission) {
fix_rate_leaky_bucket_.Add(sent_time, bytes);
paced_sender_.SentPacket(sent_time, bytes);
if (!is_retransmission) {
@@ -62,8 +66,15 @@ void FixRateSender::SentPacket(QuicTime sent_time,
}
}
-QuicTime::Delta FixRateSender::TimeUntilSend(QuicTime now,
- bool /*is_retransmission*/) {
+void FixRateSender::AbandoningPacket(
+ QuicPacketSequenceNumber /*sequence_number*/,
+ QuicByteCount /*abandoned_bytes*/) {
+}
+
+QuicTime::Delta FixRateSender::TimeUntilSend(
+ QuicTime now,
+ bool /*is_retransmission*/,
+ bool /*has_retransmittable_data*/) {
if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) {
if (CongestionWindow() <= data_in_flight_) {
// We need an ack before we send more.
@@ -90,4 +101,9 @@ QuicBandwidth FixRateSender::BandwidthEstimate() {
return bitrate_;
}
+QuicTime::Delta FixRateSender::SmoothedRtt() {
+ // TODO(satyamshekhar): Calculate and return smoothed rtt.
+ return latest_rtt_;
+}
+
} // namespace net
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index d47462a..e81981a 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -19,9 +19,9 @@
namespace net {
class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
-
public:
explicit FixRateSender(const QuicClock* clock);
+ virtual ~FixRateSender();
// Start implementation of SendAlgorithmInterface.
virtual void OnIncomingQuicCongestionFeedbackFrame(
@@ -36,11 +36,14 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
virtual void SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber equence_number,
QuicByteCount bytes,
- bool is_retransmission,
- bool has_retransmittable_data) OVERRIDE;
+ bool is_retransmission) OVERRIDE;
+ virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
+ QuicByteCount abandoned_bytes) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- bool is_retransmission) OVERRIDE;
+ bool is_retransmission,
+ bool has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
+ virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
// End implementation of SendAlgorithmInterface.
private:
@@ -50,6 +53,7 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
LeakyBucket fix_rate_leaky_bucket_;
PacedSender paced_sender_;
QuicByteCount data_in_flight_;
+ QuicTime::Delta latest_rtt_;
DISALLOW_COPY_AND_ASSIGN(FixRateSender);
};
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index d32e336..bbbb3cd 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Test for FixRate sender and receiver.
+
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/congestion_control/fix_rate_receiver.h"
@@ -24,7 +26,6 @@ class FixRateReceiverPeer : public FixRateReceiver {
}
};
-const bool kHasRetransmittableData = true;
class FixRateTest : public ::testing::Test {
protected:
FixRateTest()
@@ -60,24 +61,21 @@ TEST_F(FixRateTest, SenderAPI) {
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
unused_bandwidth_, unused_packet_map_);
EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond());
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
- sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, false,
- kHasRetransmittableData);
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
- sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, false,
- kHasRetransmittableData);
- sender_->SentPacket(clock_.Now(), 3, 600, false,
- kHasRetransmittableData);
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, false);
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, false);
+ sender_->SentPacket(clock_.Now(), 3, 600, false);
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- sender_->TimeUntilSend(clock_.Now(), false));
+ sender_->TimeUntilSend(clock_.Now(), false, true));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
EXPECT_EQ(QuicTime::Delta::Infinite(),
- sender_->TimeUntilSend(clock_.Now(), false));
+ sender_->TimeUntilSend(clock_.Now(), false, true));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
sender_->OnIncomingAck(1, kMaxPacketSize, rtt_);
sender_->OnIncomingAck(2, kMaxPacketSize, rtt_);
sender_->OnIncomingAck(3, 600, rtt_);
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
}
TEST_F(FixRateTest, FixRatePacing) {
@@ -92,13 +90,12 @@ TEST_F(FixRateTest, FixRatePacing) {
QuicTime acc_advance_time(QuicTime::Zero());
QuicPacketSequenceNumber sequence_number = 0;
for (int i = 0; i < num_packets; i += 2) {
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
- sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false,
- kHasRetransmittableData);
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
- sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false,
- kHasRetransmittableData);
- QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), false);
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false);
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false);
+ QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), false,
+ true);
clock_.AdvanceTime(advance_time);
sender_->OnIncomingAck(sequence_number - 1, packet_size, rtt_);
sender_->OnIncomingAck(sequence_number - 2, packet_size, rtt_);
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 8a42524..62b28f8 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -105,4 +105,9 @@ bool HybridSlowStart::Exit() {
return false;
}
+QuicTime::Delta HybridSlowStart::SmoothedRtt() {
+ // TODO(satyamshekhar): Calculate and return smooth average of rtt over time.
+ return current_rtt_;
+}
+
} // namespace net
diff --git a/net/quic/congestion_control/hybrid_slow_start.h b/net/quic/congestion_control/hybrid_slow_start.h
index cee9c73..b0e4248 100644
--- a/net/quic/congestion_control/hybrid_slow_start.h
+++ b/net/quic/congestion_control/hybrid_slow_start.h
@@ -46,6 +46,8 @@ class NET_EXPORT_PRIVATE HybridSlowStart {
bool started() { return started_; }
+ QuicTime::Delta SmoothedRtt();
+
private:
const QuicClock* clock_;
bool started_;
diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc
index e5c6973..79b6c4d 100644
--- a/net/quic/congestion_control/quic_congestion_manager.cc
+++ b/net/quic/congestion_control/quic_congestion_manager.cc
@@ -35,7 +35,8 @@ QuicCongestionManager::QuicCongestionManager(
: clock_(clock),
receive_algorithm_(ReceiveAlgorithmInterface::Create(clock, type)),
send_algorithm_(SendAlgorithmInterface::Create(clock, type)),
- largest_missing_(0) {
+ largest_missing_(0),
+ current_rtt_(QuicTime::Delta::Infinite()) {
}
QuicCongestionManager::~QuicCongestionManager() {
@@ -45,11 +46,10 @@ QuicCongestionManager::~QuicCongestionManager() {
void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes,
- bool is_retransmission,
- bool has_retransmittable_data) {
+ bool is_retransmission) {
DCHECK(!ContainsKey(pending_packets_, sequence_number));
send_algorithm_->SentPacket(sent_time, sequence_number, bytes,
- is_retransmission, has_retransmittable_data);
+ is_retransmission);
packet_history_map_[sequence_number] =
new class SendAlgorithmInterface::SentPacket(bytes, sent_time);
@@ -57,6 +57,16 @@ void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number,
CleanupPacketHistory();
}
+// Called when a packet is timed out.
+void QuicCongestionManager::AbandoningPacket(
+ QuicPacketSequenceNumber sequence_number) {
+ PendingPacketsMap::iterator it = pending_packets_.find(sequence_number);
+ if (it != pending_packets_.end()) {
+ send_algorithm_->AbandoningPacket(sequence_number, it->second);
+ pending_packets_.erase(it);
+ }
+}
+
void QuicCongestionManager::OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame, QuicTime feedback_receive_time) {
QuicBandwidth sent_bandwidth = SentBandwidth(feedback_receive_time);
@@ -68,12 +78,17 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame,
QuicTime ack_receive_time) {
// We calculate the RTT based on the highest ACKed sequence number, the lower
// sequence numbers will include the ACK aggregation delay.
- QuicTime::Delta rtt = QuicTime::Delta::Zero();
SendAlgorithmInterface::SentPacketsMap::iterator history_it =
packet_history_map_.find(frame.received_info.largest_observed);
- if (history_it != packet_history_map_.end()) {
- // TODO(pwestin): we need to add the delta to the feedback message.
- rtt = ack_receive_time.Subtract(history_it->second->SendTimestamp());
+ // TODO(satyamshekhar): largest_observed might be missing.
+ if (history_it != packet_history_map_.end() &&
+ !frame.received_info.delta_time_largest_observed.IsInfinite()) {
+ QuicTime::Delta send_delta = ack_receive_time.Subtract(
+ history_it->second->SendTimestamp());
+ if (send_delta > frame.received_info.delta_time_largest_observed) {
+ current_rtt_ = send_delta.Subtract(
+ frame.received_info.delta_time_largest_observed);
+ }
}
// We want to.
// * Get all packets lower(including) than largest_observed
@@ -89,9 +104,7 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame,
QuicPacketSequenceNumber sequence_number = it->first;
if (!IsAwaitingPacket(frame.received_info, sequence_number)) {
// Not missing, hence implicitly acked.
- send_algorithm_->OnIncomingAck(sequence_number,
- it->second,
- rtt);
+ send_algorithm_->OnIncomingAck(sequence_number, it->second, current_rtt_);
pending_packets_.erase(it++); // Must be incremented post to work.
} else {
if (sequence_number > largest_missing_) {
@@ -107,9 +120,12 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame,
}
}
-QuicTime::Delta QuicCongestionManager::TimeUntilSend(QuicTime now,
- bool is_retransmission) {
- return send_algorithm_->TimeUntilSend(now, is_retransmission);
+QuicTime::Delta QuicCongestionManager::TimeUntilSend(
+ QuicTime now,
+ bool is_retransmission,
+ bool has_retransmittable_data) {
+ return send_algorithm_->TimeUntilSend(now, is_retransmission,
+ has_retransmittable_data);
}
bool QuicCongestionManager::GenerateCongestionFeedback(
@@ -126,15 +142,19 @@ void QuicCongestionManager::RecordIncomingPacket(
revived);
}
-// static
+const QuicTime::Delta QuicCongestionManager::rtt() {
+ return current_rtt_;
+}
+
const QuicTime::Delta QuicCongestionManager::DefaultRetransmissionTime() {
return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
}
-// static
const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay(
size_t unacked_packets_count,
size_t number_retransmissions) {
+ // TODO(pwestin): This should take the RTT into account instead of a hard
+ // coded kDefaultRetransmissionTimeMs. Ideally the variance of the RTT too.
if (unacked_packets_count <= kTailDropWindowSize) {
return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
}
@@ -144,6 +164,10 @@ const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay(
(1 << min<size_t>(number_retransmissions, kMaxRetransmissions)));
}
+const QuicTime::Delta QuicCongestionManager::SmoothedRtt() {
+ return send_algorithm_->SmoothedRtt();
+}
+
QuicBandwidth QuicCongestionManager::SentBandwidth(
QuicTime feedback_receive_time) const {
const QuicTime::Delta kBitrateSmoothingPeriod =
diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h
index 981c14f..4560957 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -46,8 +46,10 @@ class QuicCongestionManager {
virtual void SentPacket(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes,
- bool is_retransmission,
- bool has_retransmittable_data);
+ bool is_retransmission);
+
+ // Called when a packet is timed out.
+ virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number);
// Calculate the time until we can send the next packet to the wire.
// Note 1: When kUnknownWaitTime is returned, there is no need to poll
@@ -55,7 +57,8 @@ class QuicCongestionManager {
// Note 2: Send algorithms may or may not use |retransmit| in their
// calculations.
virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- bool is_retransmission);
+ bool is_retransmission,
+ bool has_retransmittable_data);
// Should be called before sending an ACK packet, to decide if we need
// to attach a QuicCongestionFeedbackFrame block.
@@ -65,7 +68,7 @@ class QuicCongestionManager {
QuicCongestionFeedbackFrame* feedback);
// Should be called for each incoming packet.
- // bytes: the packet size in bytes including IP headers.
+ // bytes: the packet size in bytes including Quic Headers.
// sequence_number: the unique sequence number from the QUIC packet header.
// timestamp: the arrival time of the packet.
// revived: true if the packet was lost and then recovered with help of a
@@ -81,14 +84,21 @@ class QuicCongestionManager {
size_t unacked_packets_count,
size_t number_retransmissions);
+ // Returns the estimated smoothed RTT calculated by the congestion algorithm.
+ const QuicTime::Delta SmoothedRtt();
+
+ // Returns the estimated bandwidth calculated by the congestion algorithm.
+ QuicBandwidth BandwidthEstimate();
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicCongestionManagerPeer;
typedef std::map<QuicPacketSequenceNumber, size_t> PendingPacketsMap;
+ // Get the current(last) rtt. Infinite is returned if invalid.
+ const QuicTime::Delta rtt();
+
QuicBandwidth SentBandwidth(QuicTime feedback_receive_time) const;
- // TODO(pwestin): Currently only used for testing. How do we surface this?
- QuicBandwidth BandwidthEstimate();
void CleanupPacketHistory();
const QuicClock* clock_;
@@ -97,6 +107,7 @@ class QuicCongestionManager {
SendAlgorithmInterface::SentPacketsMap packet_history_map_;
PendingPacketsMap pending_packets_;
QuicPacketSequenceNumber largest_missing_;
+ QuicTime::Delta current_rtt_;
DISALLOW_COPY_AND_ASSIGN(QuicCongestionManager);
};
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 95843d1..effa671 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -58,16 +58,23 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
virtual void SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- bool is_retransmission,
- bool has_retransmittable_data) = 0;
+ bool is_retransmission) = 0;
+
+ // Called when a packet is timed out.
+ virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
+ QuicByteCount abandoned_bytes) = 0;
// Calculate the time until we can send the next packet.
virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- bool is_retransmission) = 0;
+ bool is_retransmission,
+ bool has_retransmittable_data) = 0;
// What's the current estimated bandwidth in bytes per second.
// Returns 0 when it does not have an estimate.
virtual QuicBandwidth BandwidthEstimate() = 0;
+
+ // TODO(satyamshekhar): Monitor MinRtt.
+ virtual QuicTime::Delta SmoothedRtt() = 0;
};
} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 4c82a35..70367ff 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -14,6 +14,7 @@ const QuicByteCount kDefaultReceiveWindow = 64000;
const int64 kInitialCongestionWindow = 10;
const int64 kMaxCongestionWindow = 10000;
const int kMaxBurstLength = 3;
+const int kInitialRttMs = 60; // At a typical RTT 60 ms.
};
TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno)
@@ -84,11 +85,8 @@ void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
void TcpCubicSender::SentPacket(QuicTime /*sent_time*/,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- bool is_retransmission,
- bool has_retransmittable_data) {
- if (!is_retransmission && has_retransmittable_data) {
- bytes_in_flight_ += bytes;
- }
+ bool is_retransmission) {
+ bytes_in_flight_ += bytes;
if (!is_retransmission && update_end_sequence_number_) {
end_sequence_number_ = sequence_number;
if (AvailableCongestionWindow() == 0) {
@@ -98,10 +96,16 @@ void TcpCubicSender::SentPacket(QuicTime /*sent_time*/,
}
}
+void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number,
+ QuicByteCount abandoned_bytes) {
+ bytes_in_flight_ -= abandoned_bytes;
+}
+
QuicTime::Delta TcpCubicSender::TimeUntilSend(QuicTime now,
- bool is_retransmission) {
- if (is_retransmission) {
- // For TCP we can always send a retransmission immediately.
+ bool is_retransmission,
+ bool has_retransmittable_data) {
+ if (is_retransmission || !has_retransmittable_data) {
+ // For TCP we can always send a retransmission and/or an ACK immediately.
return QuicTime::Delta::Zero();
}
if (AvailableCongestionWindow() == 0) {
@@ -130,6 +134,14 @@ QuicBandwidth TcpCubicSender::BandwidthEstimate() {
return QuicBandwidth::Zero();
}
+QuicTime::Delta TcpCubicSender::SmoothedRtt() {
+ // TODO(satyamshekhar): Return the smoothed averaged RTT.
+ if (delay_min_.IsZero()) {
+ return QuicTime::Delta::FromMilliseconds(kInitialRttMs);
+ }
+ return delay_min_;
+}
+
void TcpCubicSender::Reset() {
delay_min_ = QuicTime::Delta::Zero();
hybrid_slow_start_.Restart();
@@ -192,10 +204,12 @@ void TcpCubicSender::OnTimeOut() {
}
void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) {
- if (rtt.ToMicroseconds() <= 0) {
- // RTT can't be 0 or negative.
+ if (rtt.IsInfinite() || rtt.IsZero()) {
return;
}
+ // RTT can't be negative.
+ DCHECK_LT(0, rtt.ToMicroseconds());
+
// TODO(pwestin): Discard delay samples right after fast recovery,
// during 1 second?.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 85f0988..6943044 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -42,11 +42,14 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
virtual void SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- bool is_retransmission,
- bool has_retransmittable_data) OVERRIDE;
+ bool is_retransmission) OVERRIDE;
+ virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
+ QuicByteCount abandoned_bytes) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- bool is_retransmission) OVERRIDE;
+ bool is_retransmission,
+ bool has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
+ virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
// End implementation of SendAlgorithmInterface.
private:
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 395088c..2aab55a 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -40,10 +40,10 @@ 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,
- false, true);
+ false);
bytes_to_send -= bytes_in_packet;
if (bytes_to_send > 0) {
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
}
}
}
@@ -73,31 +73,31 @@ TEST_F(TcpCubicSenderTest, SimpleSender) {
EXPECT_EQ(kDefaultWindowTCP,
sender_->AvailableCongestionWindow());
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
fake_bandwidth_, not_used_);
// Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
// And that window is un-affected.
EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow());
// A retransmitt should always retun 0.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), true, true).IsZero());
}
TEST_F(TcpCubicSenderTest, ExponentialSlowStart) {
const int kNumberOfAck = 20;
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
fake_bandwidth_, not_used_);
// Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
for (int n = 0; n < kNumberOfAck; ++n) {
// Send our full congestion window.
@@ -118,13 +118,13 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
const int kNumberOfAck = 65;
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
fake_bandwidth_, not_used_);
// Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
for (int n = 0; n < kNumberOfAck; ++n) {
// Send our full congestion window.
@@ -159,13 +159,13 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
const int kNumberOfAck = 10;
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
fake_bandwidth_, not_used_);
// Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
for (int i = 0; i < kNumberOfAck; ++i) {
// Send our full congestion window.
@@ -180,7 +180,7 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
sender_->OnIncomingLoss(clock_.Now());
// Make sure that we should not send right now.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsInfinite());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsInfinite());
// We should now have fallen out of slow start.
// We expect window to be cut in half.
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
index 86b2df7..e2909d4 100644
--- a/net/quic/crypto/crypto_framer.cc
+++ b/net/quic/crypto/crypto_framer.cc
@@ -4,9 +4,9 @@
#include "net/quic/crypto/crypto_framer.h"
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/quic_data_reader.h"
#include "net/quic/quic_data_writer.h"
-#include "net/quic/quic_protocol.h"
using base::StringPiece;
diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h
index efa5259..1d289a6 100644
--- a/net/quic/crypto/crypto_framer.h
+++ b/net/quic/crypto/crypto_framer.h
@@ -6,7 +6,6 @@
#define NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
#include <map>
-#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
@@ -21,6 +20,7 @@ namespace net {
class CryptoFramer;
class QuicDataReader;
class QuicData;
+struct CryptoHandshakeMessage;
class NET_EXPORT_PRIVATE CryptoFramerVisitorInterface {
public:
diff --git a/net/quic/crypto/crypto_framer_test.cc b/net/quic/crypto/crypto_framer_test.cc
index 93d7d58..58c4f45 100644
--- a/net/quic/crypto/crypto_framer_test.cc
+++ b/net/quic/crypto/crypto_framer_test.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/crypto/crypto_framer.h"
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/test_tools/quic_test_utils.h"
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index 7faa21d..9d8c48f 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -6,12 +6,15 @@
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
+#include "crypto/hkdf.h"
#include "crypto/secure_hash.h"
#include "net/base/net_util.h"
#include "net/quic/crypto/crypto_framer.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/curve25519_key_exchange.h"
#include "net/quic/crypto/key_exchange.h"
+#include "net/quic/crypto/quic_decrypter.h"
+#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_protocol.h"
@@ -25,6 +28,8 @@ namespace net {
// implement.
static const uint16 kVersion = 0;
+static const char kLabel[] = "QUIC key expansion";
+
using crypto::SecureHash;
QuicServerConfigProtobuf::QuicServerConfigProtobuf() {
@@ -34,6 +39,169 @@ QuicServerConfigProtobuf::~QuicServerConfigProtobuf() {
STLDeleteElements(&keys_);
}
+CryptoHandshakeMessage::CryptoHandshakeMessage() {}
+
+CryptoHandshakeMessage::CryptoHandshakeMessage(
+ const CryptoHandshakeMessage& other)
+ : tag(other.tag),
+ tag_value_map(other.tag_value_map) {
+ // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
+ // The new object can reconstruct serialized_ lazily.
+}
+
+CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
+
+CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
+ const CryptoHandshakeMessage& other) {
+ tag = other.tag;
+ tag_value_map = other.tag_value_map;
+ // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
+ // However, invalidate serialized_.
+ serialized_.reset();
+ return *this;
+}
+
+const QuicData& CryptoHandshakeMessage::GetSerialized() const {
+ if (!serialized_.get()) {
+ serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
+ }
+ return *serialized_.get();
+}
+
+void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) {
+ // Warning, if sizeof(CryptoTag) > sizeof(int) then this function will break
+ // because the terminating 0 will only be promoted to int.
+ COMPILE_ASSERT(sizeof(CryptoTag) <= sizeof(int),
+ crypto_tag_not_be_larger_than_int_or_varargs_will_break);
+
+ vector<CryptoTag> tags;
+ va_list ap;
+
+ va_start(ap, tag);
+ for (;;) {
+ CryptoTag tag = va_arg(ap, CryptoTag);
+ if (tag == 0) {
+ break;
+ }
+ tags.push_back(tag);
+ }
+
+ // Because of the way that we keep tags in memory, we can copy the contents
+ // of the vector and get the correct bytes in wire format. See
+ // crypto_protocol.h. This assumes that the system is little-endian.
+ SetVector(tag, tags);
+
+ va_end(ap);
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag,
+ const CryptoTag** out_tags,
+ size_t* out_len) const {
+ CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
+
+ if (it == tag_value_map.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() % sizeof(CryptoTag) != 0) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (ret != QUIC_NO_ERROR) {
+ *out_tags = NULL;
+ *out_len = 0;
+ return ret;
+ }
+
+ *out_tags = reinterpret_cast<const CryptoTag*>(it->second.data());
+ *out_len = it->second.size() / sizeof(CryptoTag);
+ return ret;
+}
+
+bool CryptoHandshakeMessage::GetStringPiece(CryptoTag tag,
+ StringPiece* out) const {
+ CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
+ if (it == tag_value_map.end()) {
+ return false;
+ }
+ *out = it->second;
+ return true;
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetNthValue16(
+ CryptoTag tag,
+ unsigned index,
+ StringPiece* out) const {
+ StringPiece value;
+ if (!GetStringPiece(tag, &value)) {
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+
+ for (unsigned i = 0;; i++) {
+ if (value.empty()) {
+ return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
+ }
+ if (value.size() < 2) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(value.data());
+ size_t size = static_cast<size_t>(data[0]) |
+ (static_cast<size_t>(data[1]) << 8);
+ value.remove_prefix(2);
+
+ if (value.size() < size) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (i == index) {
+ *out = StringPiece(value.data(), size);
+ return QUIC_NO_ERROR;
+ }
+
+ value.remove_prefix(size);
+ }
+}
+
+bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const {
+ CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
+ if (it == tag_value_map.end()) {
+ return false;
+ }
+ *out = it->second;
+ return true;
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint16(CryptoTag tag,
+ uint16* out) const {
+ return GetPOD(tag, out, sizeof(uint16));
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint32(CryptoTag tag,
+ uint32* out) const {
+ return GetPOD(tag, out, sizeof(uint32));
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetPOD(
+ CryptoTag tag, void* out, size_t len) const {
+ CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
+
+ if (it == tag_value_map.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() != len) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (ret != QUIC_NO_ERROR) {
+ memset(out, 0, len);
+ return ret;
+ }
+
+ memcpy(out, it->second.data(), len);
+ return ret;
+}
+
QuicCryptoNegotiatedParams::QuicCryptoNegotiatedParams()
: version(0),
key_exchange(0),
@@ -43,7 +211,6 @@ QuicCryptoNegotiatedParams::QuicCryptoNegotiatedParams()
QuicCryptoNegotiatedParams::~QuicCryptoNegotiatedParams() {
}
-
QuicCryptoConfig::QuicCryptoConfig()
: version(0) {
}
@@ -56,7 +223,7 @@ bool QuicCryptoConfig::ProcessPeerHandshake(
const CryptoHandshakeMessage& peer_msg,
CryptoUtils::Priority priority,
QuicCryptoNegotiatedParams* out_params,
- string *error_details) const {
+ string* error_details) const {
if (peer_msg.GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR ||
out_params->version != kVersion) {
if (error_details) {
@@ -125,6 +292,10 @@ bool QuicCryptoConfig::ProcessPeerHandshake(
return true;
}
+QuicCryptoClientConfig::QuicCryptoClientConfig()
+ : hkdf_info(kLabel, arraysize(kLabel)) {
+}
+
void QuicCryptoClientConfig::SetDefaults(QuicRandom* rand) {
// Version must be 0.
version = kVersion;
@@ -183,6 +354,7 @@ void QuicCryptoClientConfig::FillClientHello(const string& nonce,
QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
const CryptoHandshakeMessage& server_hello,
+ const string& nonce,
QuicCryptoNegotiatedParams* out_params,
string* error_details) {
if (server_hello.tag != kSHLO) {
@@ -198,8 +370,7 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
scoped_ptr<CryptoHandshakeMessage> scfg(
CryptoFramer::ParseMessage(scfg_bytes));
- if (!scfg.get() ||
- scfg->tag != kSCFG) {
+ if (!scfg.get() || scfg->tag != kSCFG) {
*error_details = "Invalid SCFG";
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
@@ -209,11 +380,29 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
+ hkdf_info.append(scfg_bytes.data(), scfg_bytes.size());
+
+ out_params->encrypter.reset(QuicEncrypter::Create(out_params->aead));
+ out_params->decrypter.reset(QuicDecrypter::Create(out_params->aead));
+ size_t key_bytes = out_params->encrypter->GetKeySize();
+ size_t nonce_prefix_bytes = out_params->encrypter->GetNoncePrefixSize();
+ uint32 key_length_in_bits = 8 * 2 * (key_bytes + nonce_prefix_bytes);
+ hkdf_info.append(reinterpret_cast<char*>(&key_length_in_bits),
+ sizeof(key_length_in_bits));
+
+ crypto::HKDF hkdf(out_params->premaster_secret, nonce,
+ hkdf_info, key_bytes, nonce_prefix_bytes);
+ out_params->encrypter->SetKey(hkdf.client_write_key());
+ out_params->encrypter->SetNoncePrefix(hkdf.client_write_iv());
+ out_params->decrypter->SetKey(hkdf.server_write_key());
+ out_params->decrypter->SetNoncePrefix(hkdf.server_write_iv());
+
return QUIC_NO_ERROR;
}
-QuicCryptoServerConfig::QuicCryptoServerConfig() {
+QuicCryptoServerConfig::QuicCryptoServerConfig()
+ : hkdf_info(kLabel, arraysize(kLabel)) {
}
QuicCryptoServerConfig::~QuicCryptoServerConfig() {
@@ -400,6 +589,31 @@ bool QuicCryptoServerConfig::ProcessClientHello(
return false;
}
+ StringPiece client_nonce;
+ if (!client_hello.GetStringPiece(kNONC, &client_nonce)) {
+ return false;
+ }
+
+ const QuicData& client_hello_serialized = client_hello.GetSerialized();
+ hkdf_info.append(client_hello_serialized.data(),
+ client_hello_serialized.length());
+ hkdf_info.append(config->serialized);
+
+ out_params->encrypter.reset(QuicEncrypter::Create(out_params->aead));
+ out_params->decrypter.reset(QuicDecrypter::Create(out_params->aead));
+ size_t key_bytes = out_params->encrypter->GetKeySize();
+ size_t nonce_prefix_bytes = out_params->encrypter->GetNoncePrefixSize();
+ uint32 key_length_in_bits = 8 * 2 * (key_bytes + nonce_prefix_bytes);
+ hkdf_info.append(reinterpret_cast<char*>(&key_length_in_bits),
+ sizeof(key_length_in_bits));
+
+ crypto::HKDF hkdf(out_params->premaster_secret, client_nonce,
+ hkdf_info, key_bytes, nonce_prefix_bytes);
+ out_params->encrypter->SetKey(hkdf.server_write_key());
+ out_params->encrypter->SetNoncePrefix(hkdf.server_write_iv());
+ out_params->decrypter->SetKey(hkdf.client_write_key());
+ out_params->decrypter->SetNoncePrefix(hkdf.client_write_iv());
+
// TODO(agl): This is obviously missing most of the handshake.
out->tag = kSHLO;
out->tag_value_map[kNONC] = nonce;
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index aca4aa0..92f8f9b 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -7,7 +7,10 @@
#include <map>
#include <string>
+#include <vector>
+#include "base/memory/scoped_ptr.h"
+#include "base/string_piece.h"
#include "net/base/net_export.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
@@ -15,9 +18,84 @@
namespace net {
class KeyExchange;
+class QuicDecrypter;
+class QuicEncrypter;
class QuicRandom;
class QuicClock;
+// An intermediate format of a handshake message that's convenient for a
+// CryptoFramer to serialize from or parse into.
+struct NET_EXPORT_PRIVATE CryptoHandshakeMessage {
+ CryptoHandshakeMessage();
+ CryptoHandshakeMessage(const CryptoHandshakeMessage& other);
+ ~CryptoHandshakeMessage();
+
+ CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other);
+
+ // GetSerialized returns the serialized form of this message and caches the
+ // result. Subsequently altering the message does not invalidate the cache.
+ const QuicData& GetSerialized() const;
+
+ // SetValue sets an element with the given tag to the raw, memory contents of
+ // |v|.
+ template<class T> void SetValue(CryptoTag tag, const T& v) {
+ tag_value_map[tag] = std::string(reinterpret_cast<const char*>(&v),
+ sizeof(v));
+ }
+
+ // SetVector sets an element with the given tag to the raw contents of an
+ // array of elements in |v|.
+ template<class T> void SetVector(CryptoTag tag, const std::vector<T>& v) {
+ if (v.empty()) {
+ tag_value_map[tag] = std::string();
+ } else {
+ tag_value_map[tag] = std::string(reinterpret_cast<const char*>(&v[0]),
+ v.size() * sizeof(T));
+ }
+ }
+
+ // SetTaglist sets an element with the given tag to contain a list of tags,
+ // passed as varargs. The argument list must be terminated with a 0 element.
+ void SetTaglist(CryptoTag tag, ...);
+
+ // GetTaglist finds an element with the given tag containing zero or more
+ // tags. If such a tag doesn't exist, it returns false. Otherwise it sets
+ // |out_tags| and |out_len| to point to the array of tags and returns true.
+ // The array points into the CryptoHandshakeMessage and is valid only for as
+ // long as the CryptoHandshakeMessage exists and is not modified.
+ QuicErrorCode GetTaglist(CryptoTag tag, const CryptoTag** out_tags,
+ size_t* out_len) const;
+
+ bool GetStringPiece(CryptoTag tag, base::StringPiece* out) const;
+
+ // GetNthValue16 interprets the value with the given tag to be a series of
+ // 16-bit length prefixed values and it returns the subvalue with the given
+ // index.
+ QuicErrorCode GetNthValue16(CryptoTag tag,
+ unsigned index,
+ base::StringPiece* out) const;
+ bool GetString(CryptoTag tag, std::string* out) const;
+ QuicErrorCode GetUint16(CryptoTag tag, uint16* out) const;
+ QuicErrorCode GetUint32(CryptoTag tag, uint32* out) const;
+
+ CryptoTag tag;
+ CryptoTagValueMap tag_value_map;
+
+ private:
+ // GetPOD is a utility function for extracting a plain-old-data value. If
+ // |tag| exists in the message, and has a value of exactly |len| bytes then
+ // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out|
+ // are zeroed out.
+ //
+ // If used to copy integers then this assumes that the machine is
+ // little-endian.
+ QuicErrorCode GetPOD(CryptoTag tag, void* out, size_t len) const;
+
+ // The serialized form of the handshake message. This member is constructed
+ // lasily.
+ mutable scoped_ptr<QuicData> serialized_;
+};
+
// TODO(rch): sync with server more rationally
class NET_EXPORT_PRIVATE QuicServerConfigProtobuf {
public:
@@ -81,6 +159,8 @@ struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParams {
CryptoTag key_exchange;
CryptoTag aead;
std::string premaster_secret;
+ scoped_ptr<QuicEncrypter> encrypter;
+ scoped_ptr<QuicDecrypter> decrypter;
};
// QuicCryptoConfig contains common configuration between clients and servers.
@@ -102,7 +182,7 @@ class NET_EXPORT_PRIVATE QuicCryptoConfig {
// index.
CryptoTagVector kexs;
std::vector<KeyExchange*> key_exchanges;
- // Authenticated encryption with associated data (AEAD) algorithms
+ // Authenticated encryption with associated data (AEAD) algorithms.
CryptoTagVector aead;
private:
@@ -113,6 +193,8 @@ class NET_EXPORT_PRIVATE QuicCryptoConfig {
// client.
class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
public:
+ QuicCryptoClientConfig();
+
// Sets the members to reasonable, default values. |rand| is used in order to
// generate ephemeral ECDH keys.
void SetDefaults(QuicRandom* rand);
@@ -123,13 +205,17 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
const std::string& server_hostname,
CryptoHandshakeMessage* out);
- // ProcessServerHello processes the tags in |server_hello|, writes the
+ // ProcessServerHello processes the message in |server_hello|, writes the
// negotiated parameters to |out_params| and returns QUIC_NO_ERROR. If
// |server_hello| is unacceptable then it puts an error message in
// |error_details| and returns an error code.
QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello,
+ const std::string& nonce,
QuicCryptoNegotiatedParams* out_params,
std::string* error_details);
+
+ // The |info| string for the HKDF function.
+ std::string hkdf_info;
};
// QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
@@ -171,6 +257,9 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
QuicCryptoNegotiatedParams* out_params,
std::string* error_details);
+ // The |info| string for the HKDF function.
+ std::string hkdf_info;
+
private:
// Config represents a server config: a collection of preferences and
// Diffie-Hellman public values.
diff --git a/net/quic/crypto/crypto_protocol.cc b/net/quic/crypto/crypto_protocol.cc
deleted file mode 100644
index 322e7cc..0000000
--- a/net/quic/crypto/crypto_protocol.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright (c) 2012 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/crypto/crypto_protocol.h"
-
-#include <stdarg.h>
-#include <string.h>
-
-#include "base/memory/scoped_ptr.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-CryptoHandshakeMessage::CryptoHandshakeMessage() {}
-CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
-
-void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) {
- // Warning, if sizeof(CryptoTag) > sizeof(int) then this function will break
- // because the terminating 0 will only be promoted to int.
- COMPILE_ASSERT(sizeof(CryptoTag) <= sizeof(int),
- crypto_tag_not_be_larger_than_int_or_varargs_will_break);
-
- std::vector<CryptoTag> tags;
- va_list ap;
-
- va_start(ap, tag);
- for (;;) {
- CryptoTag tag = va_arg(ap, CryptoTag);
- if (tag == 0) {
- break;
- }
- tags.push_back(tag);
- }
-
- // Because of the way that we keep tags in memory, we can copy the contents
- // of the vector and get the correct bytes in wire format. See
- // crypto_protocol.h. This assumes that the system is little-endian.
- SetVector(tag, tags);
-
- va_end(ap);
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag,
- const CryptoTag** out_tags,
- size_t* out_len) const {
- CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
- QuicErrorCode ret = QUIC_NO_ERROR;
-
- if (it == tag_value_map.end()) {
- ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- } else if (it->second.size() % sizeof(CryptoTag) != 0) {
- ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (ret != QUIC_NO_ERROR) {
- *out_tags = NULL;
- *out_len = 0;
- return ret;
- }
-
- *out_tags = reinterpret_cast<const CryptoTag*>(it->second.data());
- *out_len = it->second.size() / sizeof(CryptoTag);
- return ret;
-}
-
-bool CryptoHandshakeMessage::GetStringPiece(CryptoTag tag,
- StringPiece* out) const {
- CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
- if (it == tag_value_map.end()) {
- return false;
- }
- *out = it->second;
- return true;
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetNthValue16(
- CryptoTag tag,
- unsigned index,
- StringPiece* out) const {
- StringPiece value;
- if (!GetStringPiece(tag, &value)) {
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
-
- for (unsigned i = 0;; i++) {
- if (value.empty()) {
- return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
- }
- if (value.size() < 2) {
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- const unsigned char* data =
- reinterpret_cast<const unsigned char*>(value.data());
- size_t size = static_cast<size_t>(data[0]) |
- (static_cast<size_t>(data[1]) << 8);
- value.remove_prefix(2);
-
- if (value.size() < size) {
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (i == index) {
- *out = StringPiece(value.data(), size);
- return QUIC_NO_ERROR;
- }
-
- value.remove_prefix(size);
- }
-}
-
-bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const {
- CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
- if (it == tag_value_map.end()) {
- return false;
- }
- *out = it->second;
- return true;
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetUint16(CryptoTag tag,
- uint16* out) const {
- return GetPOD(tag, out, sizeof(uint16));
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetUint32(CryptoTag tag,
- uint32* out) const {
- return GetPOD(tag, out, sizeof(uint32));
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetPOD(
- CryptoTag tag, void* out, size_t len) const {
- CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
- QuicErrorCode ret = QUIC_NO_ERROR;
-
- if (it == tag_value_map.end()) {
- ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- } else if (it->second.size() != len) {
- ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (ret != QUIC_NO_ERROR) {
- memset(out, 0, len);
- return ret;
- }
-
- memcpy(out, it->second.data(), len);
- return ret;
-}
-
-} // namespace net
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 4a3212b..010b1d0 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -22,67 +22,6 @@ typedef uint32 CryptoTag;
typedef std::string ServerConfigID;
typedef std::map<CryptoTag, std::string> CryptoTagValueMap;
typedef std::vector<CryptoTag> CryptoTagVector;
-// An intermediate format of a handshake message that's convenient for a
-// CryptoFramer to serialize from or parse into.
-struct NET_EXPORT_PRIVATE CryptoHandshakeMessage {
- CryptoHandshakeMessage();
- ~CryptoHandshakeMessage();
-
- // SetValue sets an element with the given tag to the raw, memory contents of
- // |v|.
- template<class T> void SetValue(CryptoTag tag, const T& v) {
- tag_value_map[tag] = std::string(reinterpret_cast<const char*>(&v),
- sizeof(v));
- }
-
- // SetVector sets an element with the given tag to the raw contents of an
- // array of elements in |v|.
- template<class T> void SetVector(CryptoTag tag, const std::vector<T>& v) {
- if (v.empty()) {
- tag_value_map[tag] = std::string();
- } else {
- tag_value_map[tag] = std::string(reinterpret_cast<const char*>(&v[0]),
- v.size() * sizeof(T));
- }
- }
-
- // SetTaglist sets an element with the given tag to contain a list of tags,
- // passed as varargs. The argument list must be terminated with a 0 element.
- void SetTaglist(CryptoTag tag, ...);
-
- // GetTaglist finds an element with the given tag containing zero or more
- // tags. If such a tag doesn't exist, it returns false. Otherwise it sets
- // |out_tags| and |out_len| to point to the array of tags and returns true.
- // The array points into the CryptoHandshakeMessage and is valid only for as
- // long as the CryptoHandshakeMessage exists and is not modified.
- QuicErrorCode GetTaglist(CryptoTag tag, const CryptoTag** out_tags,
- size_t* out_len) const;
-
- bool GetStringPiece(CryptoTag tag, base::StringPiece* out) const;
-
- // GetNthValue16 interprets the value with the given tag to be a series of
- // 16-bit length prefixed values and it returns the subvalue with the given
- // index.
- QuicErrorCode GetNthValue16(CryptoTag tag,
- unsigned index,
- base::StringPiece* out) const;
- bool GetString(CryptoTag tag, std::string* out) const;
- QuicErrorCode GetUint16(CryptoTag tag, uint16* out) const;
- QuicErrorCode GetUint32(CryptoTag tag, uint32* out) const;
-
- CryptoTag tag;
- CryptoTagValueMap tag_value_map;
-
- private:
- // GetPOD is a utility function for extracting a plain-old-data value. If
- // |tag| exists in the message, and has a value of exactly |len| bytes then
- // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out|
- // are zeroed out.
- //
- // If used to copy integers then this assumes that the machine is
- // little-endian.
- QuicErrorCode GetPOD(CryptoTag tag, void* out, size_t len) const;
-};
const CryptoTag kCHLO = MAKE_TAG('C', 'H', 'L', 'O'); // Client hello
const CryptoTag kSHLO = MAKE_TAG('S', 'H', 'L', 'O'); // Server hello
diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc
index 92b9204..05d6bda 100644
--- a/net/quic/crypto/null_decrypter.cc
+++ b/net/quic/crypto/null_decrypter.cc
@@ -41,4 +41,12 @@ QuicData* NullDecrypter::Decrypt(QuicPacketSequenceNumber /*sequence_number*/,
return new QuicData(plaintext.data(), plaintext.length());
}
+StringPiece NullDecrypter::GetKey() const {
+ return StringPiece();
+}
+
+StringPiece NullDecrypter::GetNoncePrefix() const {
+ return StringPiece();
+}
+
} // namespace net
diff --git a/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h
index 93315a8..bd4a7ea 100644
--- a/net/quic/crypto/null_decrypter.h
+++ b/net/quic/crypto/null_decrypter.h
@@ -24,6 +24,8 @@ class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter {
virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number,
base::StringPiece associated_data,
base::StringPiece ciphertext) OVERRIDE;
+ virtual base::StringPiece GetKey() const OVERRIDE;
+ virtual base::StringPiece GetNoncePrefix() const OVERRIDE;
};
} // namespace net
diff --git a/net/quic/crypto/null_encrypter.cc b/net/quic/crypto/null_encrypter.cc
index 49fc927..b563107 100644
--- a/net/quic/crypto/null_encrypter.cc
+++ b/net/quic/crypto/null_encrypter.cc
@@ -51,4 +51,12 @@ size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const {
return plaintext_size + kHashSize;
}
+StringPiece NullEncrypter::GetKey() const {
+ return StringPiece();
+}
+
+StringPiece NullEncrypter::GetNoncePrefix() const {
+ return StringPiece();
+}
+
} // namespace net
diff --git a/net/quic/crypto/null_encrypter.h b/net/quic/crypto/null_encrypter.h
index 62f4ef6..c452348 100644
--- a/net/quic/crypto/null_encrypter.h
+++ b/net/quic/crypto/null_encrypter.h
@@ -28,6 +28,8 @@ class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter {
virtual size_t GetNoncePrefixSize() const OVERRIDE;
virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE;
virtual size_t GetCiphertextSize(size_t plaintext_size) const OVERRIDE;
+ virtual base::StringPiece GetKey() const OVERRIDE;
+ virtual base::StringPiece GetNoncePrefix() const OVERRIDE;
};
} // namespace net
diff --git a/net/quic/crypto/quic_decrypter.cc b/net/quic/crypto/quic_decrypter.cc
index 997a311..aa036df 100644
--- a/net/quic/crypto/quic_decrypter.cc
+++ b/net/quic/crypto/quic_decrypter.cc
@@ -10,6 +10,10 @@ namespace net {
// static
QuicDecrypter* QuicDecrypter::Create(CryptoTag algorithm) {
switch (algorithm) {
+ case kAESG:
+ // TODO(wtc): add support for Aes128GcmDecrypter.
+ // return new Aes128GcmDecrypter();
+ return new NullDecrypter();
case kNULL:
return new NullDecrypter();
default:
diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h
index c8b691d..c648668 100644
--- a/net/quic/crypto/quic_decrypter.h
+++ b/net/quic/crypto/quic_decrypter.h
@@ -49,6 +49,10 @@ class NET_EXPORT_PRIVATE QuicDecrypter {
virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number,
base::StringPiece associated_data,
base::StringPiece ciphertext) = 0;
+
+ // For use by unit tests only.
+ virtual base::StringPiece GetKey() const = 0;
+ virtual base::StringPiece GetNoncePrefix() const = 0;
};
} // namespace net
diff --git a/net/quic/crypto/quic_encrypter.cc b/net/quic/crypto/quic_encrypter.cc
index cc13013..ec521ec 100644
--- a/net/quic/crypto/quic_encrypter.cc
+++ b/net/quic/crypto/quic_encrypter.cc
@@ -10,6 +10,10 @@ namespace net {
// static
QuicEncrypter* QuicEncrypter::Create(CryptoTag algorithm) {
switch (algorithm) {
+ case kAESG:
+ // TODO(wtc): add support for Aes128GcmEncrypter.
+ // return new Aes128GcmEncrypter();
+ return new NullEncrypter();
case kNULL:
return new NullEncrypter();
default:
diff --git a/net/quic/crypto/quic_encrypter.h b/net/quic/crypto/quic_encrypter.h
index 214ce2d..013aff1 100644
--- a/net/quic/crypto/quic_encrypter.h
+++ b/net/quic/crypto/quic_encrypter.h
@@ -66,6 +66,10 @@ class NET_EXPORT_PRIVATE QuicEncrypter {
// Returns the length of the ciphertext that would be generated by encrypting
// to plaintext of size |plaintext_size|.
virtual size_t GetCiphertextSize(size_t plaintext_size) const = 0;
+
+ // For use by unit tests only.
+ virtual base::StringPiece GetKey() const = 0;
+ virtual base::StringPiece GetNoncePrefix() const = 0;
};
} // namespace net
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index f2f819a..6d2c368 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -28,7 +28,7 @@ class QuicClientSessionTest : public ::testing::Test {
protected:
QuicClientSessionTest()
: guid_(1),
- connection_(new PacketSavingConnection(guid_, IPEndPoint())),
+ connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
session_(connection_, NULL, NULL, kServerHostname, &net_log_) {
}
@@ -92,7 +92,8 @@ TEST_F(QuicClientSessionTest, Logging) {
// Receive a packet, and verify that it was logged.
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
QuicRstStreamFrame frame;
frame.stream_id = 2;
frame.error_code = QUIC_CONNECTION_TIMED_OUT;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index c81f50b..955d82c 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -69,7 +69,7 @@ const int kMaxPacketsPerRetransmissionAlarm = 10;
const bool kForce = true;
// Named constant for CanWrite().
const bool kIsRetransmission = true;
-// Named constatn for WritePacket.
+// Named constant for WritePacket.
const bool kHasRetransmittableData = true;
bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
@@ -81,11 +81,13 @@ bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
QuicConnection::QuicConnection(QuicGuid guid,
IPEndPoint address,
- QuicConnectionHelperInterface* helper)
+ QuicConnectionHelperInterface* helper,
+ bool is_server)
: helper_(helper),
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)),
+ QuicEncrypter::Create(kNULL),
+ is_server),
clock_(helper->GetClock()),
random_generator_(helper->GetRandomGenerator()),
guid_(guid),
@@ -97,16 +99,21 @@ QuicConnection::QuicConnection(QuicGuid guid,
handling_retransmission_timeout_(false),
write_blocked_(false),
debug_visitor_(NULL),
- packet_creator_(guid_, &framer_, random_generator_),
+ packet_creator_(guid_, &framer_, random_generator_, is_server),
packet_generator_(this, &packet_creator_),
timeout_(QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)),
time_of_last_received_packet_(clock_->ApproximateNow()),
time_of_last_sent_packet_(clock_->ApproximateNow()),
congestion_manager_(clock_, kTCP),
+ version_negotiation_state_(START_NEGOTIATION),
+ quic_version_(kQuicVersion1),
+ is_server_(is_server),
connected_(true),
received_truncated_ack_(false),
send_ack_in_response_to_packet_(false) {
helper_->SetConnection(this);
+ // TODO(satyamshekhar): Have a smaller timeout till version is negotiated and
+ // connection is established (CHLO fully processed).
helper_->SetTimeoutAlarm(timeout_);
framer_.set_visitor(this);
framer_.set_entropy_calculator(&entropy_manager_);
@@ -134,11 +141,27 @@ QuicConnection::~QuicConnection() {
}
}
+bool QuicConnection::SelectMutualVersion(
+ const QuicVersionTagList& available_versions) {
+ // TODO(satyamshekhar): Make this generic.
+ if (std::find(available_versions.begin(), available_versions.end(),
+ kQuicVersion1) == available_versions.end()) {
+ return false;
+ }
+
+ // Right now we only support kQuicVersion1 so it's okay not to
+ // update the framer and quic_version_. When start supporting more
+ // versions please update both.
+ return true;
+}
+
void QuicConnection::OnError(QuicFramer* framer) {
SendConnectionClose(framer->error());
}
void QuicConnection::OnPacket() {
+ // TODO(satyamshekhar): Validate packet before updating the time
+ // since it affects the timeout of the connection.
time_of_last_received_packet_ = clock_->Now();
DVLOG(1) << "time of last received packet: "
<< time_of_last_received_packet_.ToMicroseconds();
@@ -156,6 +179,91 @@ void QuicConnection::OnPublicResetPacket(
CloseConnection(QUIC_PUBLIC_RESET, true);
}
+bool QuicConnection::OnProtocolVersionMismatch(
+ QuicVersionTag received_version) {
+ // TODO(satyamshekhar): Implement no server state in this mode.
+ if (!is_server_) {
+ LOG(DFATAL) << "Framer called OnProtocolVersionMismatch for server. "
+ << "Closing connection.";
+ CloseConnection(QUIC_INTERNAL_ERROR, false);
+ }
+ DCHECK_NE(quic_version_, received_version);
+
+ if (debug_visitor_) {
+ debug_visitor_->OnProtocolVersionMismatch(received_version);
+ }
+
+ switch (version_negotiation_state_) {
+ case START_NEGOTIATION:
+ if (!framer_.IsSupportedVersion(received_version)) {
+ SendVersionNegotiationPacket();
+ version_negotiation_state_ = SENT_NEGOTIATION_PACKET;
+ return false;
+ }
+ break;
+
+ case SENT_NEGOTIATION_PACKET:
+ if (!framer_.IsSupportedVersion(received_version)) {
+ // Drop packets which can't be parsed due to version mismatch.
+ return false;
+ }
+ break;
+
+ case NEGOTIATED_VERSION:
+ // Might be old packets that were sent by the client before the version
+ // was negotiated. Drop these.
+ return false;
+
+ default:
+ DCHECK(false);
+ }
+
+ // Right now we only support kQuicVersion1 so it's okay not to
+ // update the framer and quic_version_. When start supporting more
+ // versions please update both.
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ // TODO(satyamshekhar): Store the sequence number of this packet and close the
+ // connection if we ever received a packet with incorrect version and whose
+ // sequence number is greater.
+ return true;
+}
+
+// Handles version negotiation for client connection.
+void QuicConnection::OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {
+ if (is_server_) {
+ LOG(DFATAL) << "Framer parsed VersionNegotiationPacket for server."
+ << "Closing connection.";
+ CloseConnection(QUIC_INTERNAL_ERROR, false);
+ }
+ if (debug_visitor_) {
+ debug_visitor_->OnVersionNegotiationPacket(packet);
+ }
+
+ if (version_negotiation_state_ == NEGOTIATED_VERSION) {
+ // Possibly a duplicate version negotiation packet.
+ return;
+ }
+
+ if (std::find(packet.versions.begin(),
+ packet.versions.end(), quic_version_) !=
+ packet.versions.end()) {
+ DLOG(WARNING) << "The server already supports our version. It should have "
+ << "accepted our connection.";
+ // Just drop the connection.
+ CloseConnection(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, false);
+ return;
+ }
+
+ if (!SelectMutualVersion(packet.versions)) {
+ SendConnectionCloseWithDetails(QUIC_INVALID_VERSION,
+ "no common version found");
+ }
+
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ RetransmitAllUnackedPackets();
+}
+
void QuicConnection::OnRevivedPacket() {
}
@@ -163,6 +271,10 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
if (debug_visitor_) {
debug_visitor_->OnPacketHeader(header);
}
+
+ // Will be decrement below if we fall through to return true;
+ ++stats_.packets_dropped;
+
if (header.public_header.guid != guid_) {
DLOG(INFO) << "Ignoring packet from unexpected GUID: "
<< header.public_header.guid << " instead of " << guid_;
@@ -184,6 +296,32 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
return false;
}
+ if (version_negotiation_state_ != NEGOTIATED_VERSION) {
+ if (is_server_) {
+ if (!header.public_header.version_flag) {
+ DLOG(WARNING) << "Got packet without version flag before version "
+ << "negotiated.";
+ // Packets should have the version flag till version negotiation is
+ // done.
+ CloseConnection(QUIC_INVALID_VERSION, false);
+ return false;
+ } else {
+ DCHECK_EQ(1u, header.public_header.versions.size());
+ DCHECK_EQ(header.public_header.versions[0], quic_version_);
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ }
+ } else {
+ DCHECK(!header.public_header.version_flag);
+ // If the client gets a packet without the version flag from the server
+ // it should stop sending version since the version negotiation is done.
+ packet_creator_.StopSendingVersion();
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ }
+ }
+
+ DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_);
+
+ --stats_.packets_dropped;
DVLOG(1) << "Received packet header: " << header;
last_header_ = header;
return true;
@@ -239,15 +377,16 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
if (queued_packets_.empty()) {
return;
}
+ bool has_retransmittable_data = true;
QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
- time_of_last_received_packet_, false);
+ time_of_last_received_packet_, false, has_retransmittable_data);
if (delay.IsZero()) {
helper_->UnregisterSendAlarmIfRegistered();
if (!write_blocked_) {
OnCanWrite();
}
- } else {
+ } else if (!delay.IsInfinite()) {
helper_->SetSendAlarm(delay);
}
}
@@ -402,11 +541,11 @@ bool QuicConnection::DontWaitForPacketsBefore(
QuicPacketSequenceNumber least_unacked) {
size_t missing_packets_count =
outgoing_ack_.received_info.missing_packets.size();
- outgoing_ack_.received_info.missing_packets.erase(
+ outgoing_ack_.received_info.missing_packets.erase(
outgoing_ack_.received_info.missing_packets.begin(),
outgoing_ack_.received_info.missing_packets.lower_bound(least_unacked));
- return missing_packets_count !=
- outgoing_ack_.received_info.missing_packets.size();
+ return missing_packets_count !=
+ outgoing_ack_.received_info.missing_packets.size();
}
void QuicConnection::UpdatePacketInformationSentByPeer(
@@ -516,6 +655,17 @@ void QuicConnection::MaybeSendAckInResponseToPacket() {
send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_;
}
+void QuicConnection::SendVersionNegotiationPacket() {
+ QuicVersionTagList supported_versions;
+ supported_versions.push_back(kQuicVersion1);
+ QuicEncryptedPacket* encrypted =
+ packet_creator_.SerializeVersionNegotiationPacket(supported_versions);
+ // TODO(satyamshekhar): implement zero server state negotiation.
+ int error;
+ helper_->WritePacketToWire(*encrypted, &error);
+ delete encrypted;
+}
+
QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
base::StringPiece data,
QuicStreamOffset offset,
@@ -529,6 +679,14 @@ void QuicConnection::SendRstStream(QuicStreamId id,
QuicFrame(new QuicRstStreamFrame(id, error)));
}
+const QuicConnectionStats& QuicConnection::GetStats() {
+ // Update rtt and estimated bandwidth.
+ stats_.rtt = congestion_manager_.SmoothedRtt().ToMicroseconds();
+ stats_.estimated_bandwidth =
+ congestion_manager_.BandwidthEstimate().ToBytesPerSecond();
+ return stats_;
+}
+
void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) {
@@ -539,12 +697,15 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
last_size_ = packet.length();
last_self_address_ = self_address;
last_peer_address_ = peer_address;
+
+ stats_.bytes_received += packet.length();
+ ++stats_.packets_received;
+
framer_.ProcessPacket(packet);
MaybeProcessRevivedPacket();
}
bool QuicConnection::OnCanWrite() {
- LOG(INFO) << "here!!!";
write_blocked_ = false;
WriteQueuedPackets();
@@ -553,15 +714,14 @@ bool QuicConnection::OnCanWrite() {
// or the congestion manager to prohibit sending. If we've sent everything
// we had queued and we're still not blocked, let the visitor know it can
// write more.
- // TODO(rch): shouldn't this be "if (CanWrite(false))"
- if (!write_blocked_) {
+ if (CanWrite(false, true)) {
packet_generator_.StartBatchOperations();
bool all_bytes_written = visitor_->OnCanWrite();
packet_generator_.FinishBatchOperations();
// After the visitor writes, it may have caused the socket to become write
// blocked or the congestion manager to prohibit sending, so check again.
- if (!write_blocked_ && !all_bytes_written && !helper_->IsSendAlarmSet()) {
+ if (!write_blocked_ && !all_bytes_written && CanWrite(false, true)) {
// We're not write blocked, but some stream didn't write out all of its
// bytes. Register for 'immediate' resumption so we'll keep writing after
// other quic connections have had a chance to use the socket.
@@ -577,19 +737,20 @@ bool QuicConnection::WriteQueuedPackets() {
size_t num_queued_packets = queued_packets_.size() + 1;
QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
- while (!write_blocked_ && !helper_->IsSendAlarmSet() &&
- packet_iterator != queued_packets_.end()) {
+ while (!write_blocked_ && packet_iterator != queued_packets_.end()) {
// Ensure that from one iteration of this loop to the next we
// succeeded in sending a packet so we don't infinitely loop.
// TODO(rch): clean up and close the connection if we really hit this.
DCHECK_LT(queued_packets_.size(), num_queued_packets);
num_queued_packets = queued_packets_.size();
if (WritePacket(packet_iterator->sequence_number,
- packet_iterator->packet, kHasRetransmittableData,
+ packet_iterator->packet,
+ packet_iterator->has_retransmittable_data,
!kForce)) {
packet_iterator = queued_packets_.erase(packet_iterator);
} else {
// Continue, because some queued packets may still be writable.
+ // This can happen if a retransmit send fail.
++packet_iterator;
}
}
@@ -618,6 +779,7 @@ void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) {
outgoing_ack_.received_info.largest_observed = max(
outgoing_ack_.received_info.largest_observed,
header.packet_sequence_number);
+ // TODO(pwestin): update received_info with time_of_last_received_packet_.
entropy_manager_.RecordReceivedPacketEntropyHash(sequence_number,
header.entropy_hash);
}
@@ -643,11 +805,19 @@ bool QuicConnection::MaybeRetransmitPacketForRTO(
sequence_number > peer_largest_observed_packet_) {
return false;
} else {
+ ++stats_.rto_count;
RetransmitPacket(sequence_number);
return true;
}
}
+void QuicConnection::RetransmitAllUnackedPackets() {
+ for (UnackedPacketMap::iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it) {
+ RetransmitPacket(it->first);
+ }
+}
+
void QuicConnection::RetransmitPacket(
QuicPacketSequenceNumber sequence_number) {
UnackedPacketMap::iterator unacked_it =
@@ -661,6 +831,9 @@ void QuicConnection::RetransmitPacket(
DCHECK(unacked_it != unacked_packets_.end());
DCHECK(retransmission_it != retransmission_map_.end());
RetransmittableFrames* unacked = unacked_it->second;
+ // TODO(pwestin): Need to fix potential issue with FEC and a 1 packet
+ // congestion window see b/8331807 for details.
+ congestion_manager_.AbandoningPacket(sequence_number);
// TODO(ianswett): Never change the sequence number of the connect packet.
// Re-packetize the frames with a new sequence number for retransmission.
// Retransmitted data packets do not use FEC, even when it's enabled.
@@ -686,17 +859,22 @@ void QuicConnection::RetransmitPacket(
true);
}
-bool QuicConnection::CanWrite(bool is_retransmission) {
+bool QuicConnection::CanWrite(bool is_retransmission,
+ bool has_retransmittable_data) {
// TODO(ianswett): If the packet is a retransmit, the current send alarm may
// be too long.
if (write_blocked_ || helper_->IsSendAlarmSet()) {
return false;
}
- QuicTime::Delta delay = congestion_manager_.TimeUntilSend(clock_->Now(),
- is_retransmission);
+
+ QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
+ clock_->Now(), is_retransmission, has_retransmittable_data);
+ if (delay.IsInfinite()) {
+ return false;
+ }
+
// If the scheduler requires a delay, then we can not send this packet now.
- if (!delay.IsZero() && !delay.IsInfinite()) {
- // TODO(pwestin): we need to handle delay.IsInfinite() separately.
+ if (!delay.IsZero()) {
helper_->SetSendAlarm(delay);
return false;
}
@@ -752,7 +930,7 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
bool is_retransmission = IsRetransmission(sequence_number);
// If we are not forced and we can't write, then simply return false;
- if (!forced && !CanWrite(is_retransmission)) {
+ if (!forced && !CanWrite(is_retransmission, has_retransmittable_data)) {
return false;
}
@@ -760,13 +938,13 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
framer_.EncryptPacket(sequence_number, *packet));
DLOG(INFO) << "Sending packet number " << sequence_number << " : "
<< (packet->is_fec_packet() ? "FEC " :
- (ContainsKey(retransmission_map_, sequence_number) ?
- "data bearing " : " ack only "));
+ (has_retransmittable_data ? "data bearing " : " ack only "))
+ << " Packet length:" << packet->length();
DCHECK(encrypted->length() <= kMaxPacketSize)
<< "Packet " << sequence_number << " will not be read; too large: "
<< packet->length() << " " << encrypted->length() << " "
- << outgoing_ack_;
+ << outgoing_ack_ << " forced: " << (forced ? "yes" : "no");
int error;
QuicTime now = clock_->Now();
@@ -788,7 +966,16 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
MaybeSetupRetransmission(sequence_number);
congestion_manager_.SentPacket(sequence_number, now, packet->length(),
- is_retransmission, has_retransmittable_data);
+ is_retransmission);
+
+ stats_.bytes_sent += encrypted->length();
+ ++stats_.packets_sent;
+
+ if (is_retransmission) {
+ stats_.bytes_retransmitted += encrypted->length();
+ ++stats_.packets_retransmitted;
+ }
+
delete packet;
return true;
}
@@ -821,7 +1008,8 @@ bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
entropy_hash);
if (!WritePacket(sequence_number, packet, has_retransmittable_data,
!kForce)) {
- queued_packets_.push_back(QueuedPacket(sequence_number, packet));
+ queued_packets_.push_back(QueuedPacket(sequence_number, packet,
+ has_retransmittable_data));
return false;
}
return true;
@@ -931,6 +1119,8 @@ void QuicConnection::MaybeProcessRevivedPacket() {
debug_visitor_->OnRevivedPacket(revived_header,
StringPiece(revived_payload, len));
}
+
+ ++stats_.packets_revived;
framer_.ProcessRevivedPacket(&revived_header,
StringPiece(revived_payload, len));
}
@@ -976,8 +1166,6 @@ void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error,
}
void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
- // TODO(satyamshekhar): Ask the dispatcher to delete visitor and hence self
- // if the visitor will always be deleted by closing the connection.
connected_ = false;
visitor_->ConnectionClose(error, from_peer);
}
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index a1411e2..17f0a11 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -32,6 +32,7 @@
#include "net/quic/quic_packet_entropy_manager.h"
#include "net/quic/quic_packet_generator.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_stats.h"
namespace net {
@@ -89,7 +90,12 @@ class NET_EXPORT_PRIVATE QuicConnectionDebugVisitorInterface {
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) = 0;
- // Called when the header of a packet has been parsed.
+ // Called when the protocol version on the received packet doensn't match
+ // current protocol version of the connection.
+ virtual void OnProtocolVersionMismatch(
+ QuicVersionTag version) = 0;
+
+ // Called when the complete header of a packet has been parsed.
virtual void OnPacketHeader(const QuicPacketHeader& header) = 0;
// Called when a StreamFrame has been parsed.
@@ -112,6 +118,10 @@ class NET_EXPORT_PRIVATE QuicConnectionDebugVisitorInterface {
// Called when a public reset packet has been received.
virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) = 0;
+ // Called when a version negotiation packet has been received.
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) = 0;
+
// Called after a packet has been successfully parsed which results
// in the revival of a packet via FEC.
virtual void OnRevivedPacket(const QuicPacketHeader& revived_header,
@@ -182,7 +192,8 @@ class NET_EXPORT_PRIVATE QuicConnection
// |helper| will be owned by this connection.
QuicConnection(QuicGuid guid,
IPEndPoint address,
- QuicConnectionHelperInterface* helper);
+ QuicConnectionHelperInterface* helper,
+ bool is_server);
virtual ~QuicConnection();
static void DeleteEnclosedFrame(QuicFrame* frame);
@@ -217,6 +228,9 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicStreamId last_good_stream_id,
const std::string& reason);
+ // Returns statistics tracked for this connection.
+ const QuicConnectionStats& GetStats();
+
// Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from
// the peer. If processing this packet permits a packet to be revived from
// its FEC group that packet will be revived and processed.
@@ -229,11 +243,19 @@ class NET_EXPORT_PRIVATE QuicConnection
// queued writes to happen. Returns false if the socket has become blocked.
virtual bool OnCanWrite() OVERRIDE;
+ QuicVersionTag version() const {
+ return quic_version_;
+ }
+
// From QuicFramerVisitorInterface
virtual void OnError(QuicFramer* framer) OVERRIDE;
+ virtual bool OnProtocolVersionMismatch(
+ QuicVersionTag received_version) OVERRIDE;
virtual void OnPacket() OVERRIDE;
virtual void OnPublicResetPacket(
const QuicPublicResetPacket& packet) OVERRIDE;
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) OVERRIDE;
virtual void OnRevivedPacket() OVERRIDE;
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
virtual void OnFecProtectedPayload(base::StringPiece payload) OVERRIDE;
@@ -358,13 +380,16 @@ class NET_EXPORT_PRIVATE QuicConnection
// Owns the QuicPacket* packet.
struct QueuedPacket {
QueuedPacket(QuicPacketSequenceNumber sequence_number,
- QuicPacket* packet)
+ QuicPacket* packet,
+ bool has_retransmittable_data)
: sequence_number(sequence_number),
- packet(packet) {
+ packet(packet),
+ has_retransmittable_data(has_retransmittable_data) {
}
QuicPacketSequenceNumber sequence_number;
QuicPacket* packet;
+ bool has_retransmittable_data;
};
struct RetransmissionInfo {
@@ -402,11 +427,21 @@ class NET_EXPORT_PRIVATE QuicConnection
RetransmissionInfoComparator>
RetransmissionTimeouts;
+ // Selects and updates the version of the protocol being used by selecting a
+ // version from |available_versions| which is also supported. Returns true if
+ // such a version exists, false otherwise.
+ bool SelectMutualVersion(
+ const QuicVersionTagList& available_versions);
+ // Sends a version negotiation packet to the peer.
+ void SendVersionNegotiationPacket();
+
// Checks if a packet can be written now, and sets the timer if necessary.
- virtual bool CanWrite(bool is_retransmission) OVERRIDE;
+ virtual bool CanWrite(bool is_retransmission,
+ bool has_retransmittable_data) OVERRIDE;
void MaybeSetupRetransmission(QuicPacketSequenceNumber sequence_number);
bool IsRetransmission(QuicPacketSequenceNumber sequence_number);
+ void RetransmitAllUnackedPackets();
// Writes as many queued packets as possible. The connection must not be
// blocked when this is called.
@@ -500,6 +535,9 @@ class NET_EXPORT_PRIVATE QuicConnection
// Network idle time before we kill of this connection.
const QuicTime::Delta timeout_;
+ // Statistics for this session.
+ QuicConnectionStats stats_;
+
// The time that we got a packet for this connection.
QuicTime time_of_last_received_packet_;
@@ -510,6 +548,15 @@ class NET_EXPORT_PRIVATE QuicConnection
// as well as collecting and generating congestion feedback.
QuicCongestionManager congestion_manager_;
+ // The state of connection in version negotiation finite state machine.
+ QuicVersionNegotiationState version_negotiation_state_;
+
+ // The version of the protocol this connection is using.
+ QuicVersionTag quic_version_;
+
+ // Tracks if the connection was created by the server.
+ bool is_server_;
+
// True by default. False if we've received or sent an explicit connection
// close.
bool connected_;
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 544dec4..59ba5f75 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -30,7 +30,7 @@ class TestConnection : public QuicConnection {
TestConnection(QuicGuid guid,
IPEndPoint address,
QuicConnectionHelper* helper)
- : QuicConnection(guid, address, helper) {
+ : QuicConnection(guid, address, helper, false) {
}
void SendAck() {
@@ -61,8 +61,8 @@ class QuicConnectionHelperTest : public ::testing::Test {
: guid_(2),
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)),
- creator_(guid_, &framer_, QuicRandom::GetInstance()),
+ QuicEncrypter::Create(kNULL),
+ false),
net_log_(BoundNetLog()),
frame_(1, false, 0, kData) {
Initialize();
@@ -107,7 +107,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
&random_generator_, socket));
send_algorithm_ = new testing::StrictMock<MockSendAlgorithm>();
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)).
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).
WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_.get()));
connection_->set_visitor(&visitor_);
@@ -137,7 +137,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
QuicPacketSequenceNumber sequence_number) {
InitializeHeader(sequence_number);
- QuicAckFrame ack(0, sequence_number);
+ QuicAckFrame ack(0, QuicTime::Zero(), sequence_number);
ack.sent_info.entropy_hash = 0;
ack.received_info.entropy_hash = 0;
@@ -161,7 +161,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
InitializeHeader(sequence_number);
QuicFrames frames;
- QuicAckFrame ack(0, least_waiting + 1);
+ QuicAckFrame ack(0, QuicTime::Zero(), least_waiting + 1);
ack.sent_info.entropy_hash = 0;
ack.received_info.entropy_hash = 0;
QuicConnectionCloseFrame close;
@@ -184,7 +184,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
header_.public_header.guid = guid_;
header_.public_header.reset_flag = false;
- header_.public_header.version_flag = false;
+ header_.public_header.version_flag = true;
header_.packet_sequence_number = sequence_number;
header_.entropy_flag = false;
header_.fec_entropy_flag = false;
@@ -203,7 +203,6 @@ class QuicConnectionHelperTest : public ::testing::Test {
QuicGuid guid_;
QuicFramer framer_;
- QuicPacketCreator creator_;
QuicPacketHeader header_;
BoundNetLog net_log_;
QuicStreamFrame frame_;
@@ -249,7 +248,7 @@ TEST_F(QuicConnectionHelperTest, SetAckAlarm) {
EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
runner_->GetPostedTasks()[1].delay);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
runner_->RunNextTask();
EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.ApproximateNow());
}
@@ -293,7 +292,7 @@ TEST_F(QuicConnectionHelperTest, ResetAckAlarm) {
// Verify that the ack alarm task has been re-posted.
ASSERT_EQ(2u, runner_->GetPostedTasks().size());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
runner_->RunNextTask();
EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.ApproximateNow());
}
@@ -307,10 +306,11 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) {
QuicTime::Delta::FromMilliseconds(500);
QuicTime start = clock_.ApproximateNow();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false, kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _));
// Send a packet.
connection_->SendStreamData(1, kData, 0, false);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, true, kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, true));
// Since no ack was received, the retransmission alarm will fire and
// retransmit it.
runner_->RunNextTask();
@@ -329,7 +329,7 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
EXPECT_EQ(base::TimeDelta::FromMicroseconds(kDefaultTimeoutUs),
runner_->GetPostedTasks().front().delay);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
// After we run the next task, we should close the connection.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
@@ -374,7 +374,7 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// When we send a packet, the timeout will change to 5000 + kDefaultTimeout.
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000));
EXPECT_EQ(5000u, clock_.ApproximateNow().ToMicroseconds());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
// Send an ack so we don't set the retransmission alarm.
connection_->SendAck();
@@ -389,7 +389,7 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, false, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, false));
runner_->RunNextTask();
EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.ApproximateNow().ToMicroseconds());
EXPECT_FALSE(connection_->connected());
@@ -401,17 +401,17 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) {
Initialize();
// Test that if we send a packet with a delay, it ends up queued.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false)).WillOnce(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
QuicPacket* packet = ConstructRawDataPacket(1);
connection_->SendOrQueuePacket(1, packet, 0, kHasData);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false, kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
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(_, false)).WillOnce(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true));
runner_->RunNextTask();
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 6545f2d..3679d1ce3 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -147,6 +147,11 @@ void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address,
packet.length()));
}
+void QuicConnectionLogger::OnProtocolVersionMismatch(
+ QuicVersionTag received_version) {
+ // TODO(rtenneti): Add logging.
+}
+
void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) {
net_log_.AddEvent(
NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED,
@@ -189,6 +194,10 @@ void QuicConnectionLogger::OnPublicResetPacket(
const QuicPublicResetPacket& packet) {
}
+void QuicConnectionLogger::OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {
+}
+
void QuicConnectionLogger::OnRevivedPacket(
const QuicPacketHeader& revived_header,
base::StringPiece payload) {
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 36d322d..4fe390b 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -24,6 +24,8 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger
virtual void OnPacketReceived(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) OVERRIDE;
+ virtual void OnProtocolVersionMismatch(
+ QuicVersionTag version) OVERRIDE;
virtual void OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE;
virtual void OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
@@ -34,6 +36,8 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger
const QuicConnectionCloseFrame& frame) OVERRIDE;
virtual void OnPublicResetPacket(
const QuicPublicResetPacket& packet) OVERRIDE;
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) OVERRIDE;
virtual void OnRevivedPacket(const QuicPacketHeader& revived_header,
base::StringPiece payload) OVERRIDE;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index d55850b..6cb5dea 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -15,6 +15,8 @@
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_framer_peer.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/quic_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -81,7 +83,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
retransmission_alarm_(QuicTime::Zero()),
send_alarm_(QuicTime::FromMilliseconds(-1)),
timeout_alarm_(QuicTime::Zero()),
- blocked_(false) {
+ blocked_(false),
+ is_server_(true) {
}
// QuicConnectionHelperInterface
@@ -99,7 +102,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
int* error) OVERRIDE {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ is_server_);
FramerVisitorCapturingFrames visitor;
framer.set_visitor(&visitor);
EXPECT_TRUE(framer.ProcessPacket(packet));
@@ -114,12 +118,17 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
if (visitor.stream_frames() != NULL && !visitor.stream_frames()->empty()) {
stream_frames_ = *visitor.stream_frames();
}
+ if (visitor.version_negotiation_packet() != NULL) {
+ version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(
+ *visitor.version_negotiation_packet()));
+ }
if (blocked_) {
*error = ERR_IO_PENDING;
return -1;
}
*error = 0;
- return packet.length();
+ last_packet_size_ = packet.length();
+ return last_packet_size_;
}
virtual void SetRetransmissionAlarm(QuicTime::Delta delay) OVERRIDE {
@@ -163,8 +172,18 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
return &stream_frames_;
}
+ size_t last_packet_size() {
+ return last_packet_size_;
+ }
+
+ QuicVersionNegotiationPacket* version_negotiation_packet() {
+ return version_negotiation_packet_.get();
+ }
+
void set_blocked(bool blocked) { blocked_ = blocked; }
+ void set_is_server(bool is_server) { is_server_ = is_server; }
+
private:
MockClock* clock_;
MockRandom* random_generator_;
@@ -176,7 +195,10 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
scoped_ptr<QuicAckFrame> ack_;
scoped_ptr<QuicCongestionFeedbackFrame> feedback_;
vector<QuicStreamFrame> stream_frames_;
+ scoped_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
+ size_t last_packet_size_;
bool blocked_;
+ bool is_server_;
DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
};
@@ -185,8 +207,11 @@ class TestConnection : public QuicConnection {
public:
TestConnection(QuicGuid guid,
IPEndPoint address,
- TestConnectionHelper* helper)
- : QuicConnection(guid, address, helper) {
+ TestConnectionHelper* helper,
+ bool is_server)
+ : QuicConnection(guid, address, helper, is_server),
+ helper_(helper) {
+ helper_->set_is_server(!is_server);
}
void SendAck() {
@@ -209,10 +234,21 @@ class TestConnection : public QuicConnection {
return SendStreamData(2u, "food2", 0, !kFin);
}
+ bool is_server() {
+ return QuicConnectionPeer::IsServer(this);
+ }
+
+ void set_is_server(bool is_server) {
+ helper_->set_is_server(!is_server);
+ QuicConnectionPeer::SetIsServer(this, is_server);
+ }
+
using QuicConnection::SendOrQueuePacket;
using QuicConnection::DontWaitForPacketsBefore;
private:
+ TestConnectionHelper* helper_;
+
DISALLOW_COPY_AND_ASSIGN(TestConnection);
};
@@ -222,11 +258,12 @@ class QuicConnectionTest : public ::testing::Test {
: guid_(42),
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)),
- creator_(guid_, &framer_, QuicRandom::GetInstance()),
+ QuicEncrypter::Create(kNULL),
+ false),
+ creator_(guid_, &framer_, QuicRandom::GetInstance(), false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
helper_(new TestConnectionHelper(&clock_, &random_generator_)),
- connection_(guid_, IPEndPoint(), helper_.get()),
+ connection_(guid_, IPEndPoint(), helper_.get(), false),
frame1_(1, false, 0, data1),
frame2_(1, false, 3, data2),
accept_packet_(true) {
@@ -234,11 +271,11 @@ class QuicConnectionTest : public ::testing::Test {
connection_.SetSendAlgorithm(send_algorithm_);
// Simplify tests by not sending feedback unless specifically configured.
SetFeedback(NULL);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)).WillRepeatedly(Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillRepeatedly(Return(
QuicTime::Delta::Zero()));
EXPECT_CALL(*receive_algorithm_,
RecordIncomingPacket(_, _, _, _)).Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
}
QuicAckFrame* outgoing_ack() {
@@ -257,6 +294,10 @@ class QuicConnectionTest : public ::testing::Test {
return helper_->header();
}
+ size_t last_sent_packet_size() {
+ return helper_->last_packet_size();
+ }
+
void ProcessPacket(QuicPacketSequenceNumber number) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _))
.WillOnce(Return(accept_packet_));
@@ -266,6 +307,8 @@ class QuicConnectionTest : public ::testing::Test {
QuicPacketEntropyHash ProcessFramePacket(QuicFrame frame) {
QuicFrames frames;
frames.push_back(QuicFrame(frame));
+ QuicPacketCreatorPeer::SetSendVersionInPacket(&creator_,
+ connection_.is_server());
SerializedPacket serialized_packet = creator_.SerializeAllFrames(frames);
scoped_ptr<QuicPacket> packet(serialized_packet.packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
@@ -274,7 +317,7 @@ class QuicConnectionTest : public ::testing::Test {
return serialized_packet.entropy_hash;
}
- void ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
+ size_t ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
bool expect_revival) {
if (expect_revival) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(2).WillRepeatedly(
@@ -283,10 +326,10 @@ class QuicConnectionTest : public ::testing::Test {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(
Return(accept_packet_));
}
- ProcessDataPacket(number, 1, !kEntropyFlag);
+ return ProcessDataPacket(number, 1, !kEntropyFlag);
}
- void ProcessDataPacket(QuicPacketSequenceNumber number,
+ size_t ProcessDataPacket(QuicPacketSequenceNumber number,
QuicFecGroupNumber fec_group,
bool entropy_flag) {
scoped_ptr<QuicPacket> packet(ConstructDataPacket(number, fec_group,
@@ -294,6 +337,7 @@ class QuicConnectionTest : public ::testing::Test {
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(number,
*packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+ return encrypted->length();
}
void ProcessClosePacket(QuicPacketSequenceNumber number,
@@ -304,7 +348,7 @@ class QuicConnectionTest : public ::testing::Test {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
- void ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
+ size_t ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
bool expect_revival, bool entropy_flag) {
if (expect_revival) {
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(DoAll(
@@ -312,11 +356,11 @@ class QuicConnectionTest : public ::testing::Test {
}
EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(Return(accept_packet_))
.RetiresOnSaturation();
- ProcessDataPacket(number, 1, entropy_flag);
+ return ProcessDataPacket(number, 1, entropy_flag);
}
// Sends an FEC packet that covers the packets that would have been sent.
- void ProcessFecPacket(QuicPacketSequenceNumber number,
+ size_t ProcessFecPacket(QuicPacketSequenceNumber number,
QuicPacketSequenceNumber min_protected_packet,
bool expect_revival,
bool fec_entropy_flag) {
@@ -357,24 +401,28 @@ class QuicConnectionTest : public ::testing::Test {
framer_.EncryptPacket(number, *fec_packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+ return encrypted->length();
}
- void SendStreamDataToPeer(QuicStreamId id, StringPiece data,
- QuicStreamOffset offset, bool fin,
- QuicPacketSequenceNumber* last_packet) {
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData));
+ QuicByteCount SendStreamDataToPeer(QuicStreamId id, StringPiece data,
+ QuicStreamOffset offset, bool fin,
+ QuicPacketSequenceNumber* last_packet) {
+ QuicByteCount packet_size;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
+ SaveArg<2>(&packet_size));
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(_, _, _, _, !kHasData)).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) {
@@ -423,7 +471,7 @@ class QuicConnectionTest : public ::testing::Test {
QuicConnectionCloseFrame qccf;
qccf.error_code = QUIC_PEER_GOING_AWAY;
- qccf.ack_frame = QuicAckFrame(0, 1);
+ qccf.ack_frame = QuicAckFrame(0, QuicTime::Zero(), 1);
QuicFrames frames;
QuicFrame frame(&qccf);
@@ -538,7 +586,7 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
// awaiting' is 4. The connection should then realize 1 will not be
// retransmitted, and will remove it from the missing list.
creator_.set_sequence_number(5);
- QuicAckFrame frame(0, 4);
+ QuicAckFrame frame(0, QuicTime::Zero(), 4);
ProcessAckPacket(&frame);
// Force an ack to be sent.
@@ -563,7 +611,7 @@ TEST_F(QuicConnectionTest, TruncatedAck) {
SendStreamDataToPeer(1, "foo", i * 3, !kFin, NULL);
}
- QuicAckFrame frame(0, 1);
+ QuicAckFrame frame(0, QuicTime::Zero(), 1);
frame.received_info.largest_observed = 192;
InsertMissingPacketsBetween(&frame.received_info, 1, 192);
frame.received_info.entropy_hash =
@@ -590,20 +638,20 @@ TEST_F(QuicConnectionTest, LeastUnackedLower) {
// Start out saying the least unacked is 2
creator_.set_sequence_number(5);
- QuicAckFrame frame(0, 2);
+ QuicAckFrame frame(0, QuicTime::Zero(), 2);
ProcessAckPacket(&frame);
// Change it to 1, but lower the sequence number to fake out-of-order packets.
// This should be fine.
creator_.set_sequence_number(1);
- QuicAckFrame frame2(0, 1);
+ QuicAckFrame frame2(0, QuicTime::Zero(), 1);
// The scheduler will not process out of order acks.
ProcessAckPacket(&frame2);
// 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(_, _, _, _, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
creator_.set_sequence_number(7);
ProcessAckPacket(&frame2);
}
@@ -615,24 +663,24 @@ TEST_F(QuicConnectionTest, LargestObservedLower) {
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2);
// Start out saying the largest observed is 2.
- QuicAckFrame frame(2, 0);
+ QuicAckFrame frame(2, QuicTime::Zero(), 0);
frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
&connection_, 2);
EXPECT_CALL(visitor_, OnAck(_));
ProcessAckPacket(&frame);
// Now change it to 1, and it should cause a connection error.
- QuicAckFrame frame2(1, 0);
+ QuicAckFrame frame2(1, QuicTime::Zero(), 0);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
ProcessAckPacket(&frame2);
}
TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) {
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, !kHasData));
+ 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, 2);
+ QuicAckFrame frame(0, QuicTime::Zero(), 2);
ProcessAckPacket(&frame);
}
@@ -643,8 +691,8 @@ TEST_F(QuicConnectionTest,
SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, !kHasData));
- QuicAckFrame frame(0, 1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ QuicAckFrame frame(0, QuicTime::Zero(), 1);
frame.received_info.missing_packets.insert(3);
ProcessAckPacket(&frame);
}
@@ -652,8 +700,8 @@ 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(_, _, _, _, !kHasData));
- QuicAckFrame frame(1, 0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ QuicAckFrame frame(1, QuicTime::Zero(), 0);
ProcessAckPacket(&frame);
}
@@ -661,7 +709,7 @@ TEST_F(QuicConnectionTest, AckAll) {
ProcessPacket(1);
creator_.set_sequence_number(1);
- QuicAckFrame frame1(0, 1);
+ QuicAckFrame frame1(0, QuicTime::Zero(), 1);
ProcessAckPacket(&frame1);
}
@@ -694,7 +742,7 @@ TEST_F(QuicConnectionTest, BasicSending) {
// Client acks up to packet 3
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
- QuicAckFrame frame(3, 0);
+ QuicAckFrame frame(3, QuicTime::Zero(), 0);
frame.received_info.entropy_hash =
QuicConnectionPeer::GetSentEntropyHash(&connection_, 3);
ProcessAckPacket(&frame);
@@ -709,7 +757,7 @@ TEST_F(QuicConnectionTest, BasicSending) {
// Client acks up to packet 4, the last packet
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
- QuicAckFrame frame2(6, 0);
+ QuicAckFrame frame2(6, QuicTime::Zero(), 0);
frame2.received_info.entropy_hash =
QuicConnectionPeer::GetSentEntropyHash(&connection_, 6);
ProcessAckPacket(&frame2); // Even parity triggers ack packet 7
@@ -730,14 +778,14 @@ TEST_F(QuicConnectionTest, BasicSending) {
TEST_F(QuicConnectionTest, FECSending) {
// Limit to one byte per packet.
+ // All packets carry version info till version is negotiated.
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(!kIncludeVersion, 1);
+ GetPacketLengthForOneStream(kIncludeVersion, 1);
// And send FEC every two packets.
connection_.options()->max_packets_per_fec_group = 2;
// Send 4 data packets and 2 FEC packets.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).Times(4);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, !kHasData)).Times(2);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(6);
connection_.SendStreamData(1, "food", 0, !kFin);
// Expect the FEC group to be closed after SendStreamData.
EXPECT_FALSE(creator_.ShouldSendFec(true));
@@ -745,8 +793,9 @@ TEST_F(QuicConnectionTest, FECSending) {
TEST_F(QuicConnectionTest, FECQueueing) {
// Limit to one byte per packet.
+ // All packets carry version info till version is negotiated.
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(!kIncludeVersion, 1);
+ GetPacketLengthForOneStream(kIncludeVersion, 1);
// And send FEC every two packets.
connection_.options()->max_packets_per_fec_group = 2;
@@ -774,7 +823,7 @@ TEST_F(QuicConnectionTest, FramePacking) {
// Unblock the connection.
helper_->UnregisterSendAlarmIfRegistered();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission, kHasData))
+ SentPacket(_, _, _, !kIsRetransmission))
.Times(1);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -807,9 +856,7 @@ TEST_F(QuicConnectionTest, FramePackingFEC) {
// Unblock the connection.
helper_->UnregisterSendAlarmIfRegistered();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission, kHasData));
- EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission, !kHasData));
+ SentPacket(_, _, _, !kIsRetransmission)).Times(2);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -829,7 +876,7 @@ TEST_F(QuicConnectionTest, OnCanWrite) {
Return(false)));
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission)).WillRepeatedly(
+ TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
// Unblock the connection.
@@ -845,9 +892,12 @@ TEST_F(QuicConnectionTest, OnCanWrite) {
TEST_F(QuicConnectionTest, RetransmitOnNack) {
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _)).Times(1);
QuicPacketSequenceNumber last_packet;
+ QuicByteCount second_packet_size;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
- SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2
+ second_packet_size =
+ SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2
SendStreamDataToPeer(1, "fooos", 7, !kFin, &last_packet); // Packet 3
SequenceNumberSet expected_acks;
@@ -856,7 +906,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
// Client acks one but not two or three. Right now we only retransmit on
// explicit nack, so it should not trigger a retransimission.
- QuicAckFrame ack_one(1, 0);
+ QuicAckFrame ack_one(1, QuicTime::Zero(), 0);
ack_one.received_info.entropy_hash =
QuicConnectionPeer::GetSentEntropyHash(&connection_, 1);
ProcessAckPacket(&ack_one);
@@ -869,7 +919,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
// Client acks up to 3 with two explicitly missing. Two nacks should cause no
// change.
- QuicAckFrame nack_two(3, 0);
+ QuicAckFrame nack_two(3, QuicTime::Zero(), 0);
nack_two.received_info.missing_packets.insert(2);
nack_two.received_info.entropy_hash =
QuicConnectionPeer::GetSentEntropyHash(&connection_, 3) ^
@@ -880,8 +930,8 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
// The third nack should trigger a retransimission.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, 37, kIsRetransmission, kHasData))
- .Times(1);
+ SentPacket(_, _, second_packet_size - kQuicVersionSize,
+ kIsRetransmission)).Times(1);
ProcessAckPacket(&nack_two);
}
@@ -889,29 +939,29 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
QuicPacketSequenceNumber largest_observed;
QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission, kHasData))
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission))
.WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size)));
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
connection_.SendStreamData(1, "foo", 0, !kFin);
- QuicAckFrame frame(1, largest_observed);
+ QuicAckFrame frame(1, QuicTime::Zero(), largest_observed);
frame.received_info.missing_packets.insert(largest_observed);
frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
&connection_, largest_observed - 1);
ProcessAckPacket(&frame);
// Second udp packet will force an ack frame.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission, !kHasData));
+ SentPacket(_, _, _, !kIsRetransmission));
ProcessAckPacket(&frame);
// Third nack should retransmit the largest observed packet.
- EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, packet_size, kIsRetransmission, kHasData));
-
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize,
+ kIsRetransmission));
ProcessAckPacket(&frame);
}
TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(11);
int offset = 0;
// Send packets 1 to 12
for (int i = 0; i < 12; ++i) {
@@ -920,7 +970,7 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
}
// Ack 12, nack 1-11
- QuicAckFrame nack(12, 0);
+ QuicAckFrame nack(12, QuicTime::Zero(), 0);
for (int i = 1; i < 12; ++i) {
nack.received_info.missing_packets.insert(i);
}
@@ -935,15 +985,14 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
// Nack three times.
ProcessAckPacket(&nack);
// The second call will trigger an ack.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, !kHasData)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
ProcessAckPacket(&nack);
// The third call should trigger retransmitting 10 packets.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).Times(10);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(10);
ProcessAckPacket(&nack);
// The fourth call should trigger retransmitting the 11th packet and an ack.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).Times(1);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, !kHasData)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(2);
ProcessAckPacket(&nack);
}
@@ -965,7 +1014,7 @@ TEST_F(QuicConnectionTest, MultipleAcks) {
EXPECT_EQ(6u, last_packet);
// Client will ack packets 1, [!2], 3, 4, 5
- QuicAckFrame frame1(5, 0);
+ QuicAckFrame frame1(5, QuicTime::Zero(), 0);
frame1.received_info.missing_packets.insert(2);
frame1.received_info.entropy_hash =
QuicConnectionPeer::GetSentEntropyHash(&connection_, 5) ^
@@ -983,7 +1032,7 @@ TEST_F(QuicConnectionTest, MultipleAcks) {
ProcessAckPacket(&frame1);
// Now the client implicitly acks 2, and explicitly acks 6
- QuicAckFrame frame2(6, 0);
+ QuicAckFrame frame2(6, QuicTime::Zero(), 0);
frame2.received_info.entropy_hash =
QuicConnectionPeer::GetSentEntropyHash(&connection_, 6);
expected_acks.clear();
@@ -1006,7 +1055,7 @@ TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
expected_acks.insert(1);
// Client acks packet 1
EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks)));
- QuicAckFrame frame(1, 0);
+ QuicAckFrame frame(1, QuicTime::Zero(), 0);
frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
&connection_, 1);
ProcessAckPacket(&frame);
@@ -1081,7 +1130,8 @@ TEST_F(QuicConnectionTest, TestRetransmit) {
EXPECT_EQ(default_retransmission_time, helper_->retransmission_alarm());
// Simulate the retransimission alarm firing
clock_.AdvanceTime(kDefaultRetransmissionTime);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
connection_.RetransmitPacket(1);
EXPECT_EQ(2u, last_header()->packet_sequence_number);
EXPECT_EQ(2u, outgoing_ack()->sent_info.least_unacked);
@@ -1089,11 +1139,13 @@ TEST_F(QuicConnectionTest, TestRetransmit) {
TEST_F(QuicConnectionTest, TestRetransmitOrder) {
QuicByteCount first_packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).WillOnce(
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
SaveArg<2>(&first_packet_size));
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
+
connection_.SendStreamData(1, "first_packet", 0, !kFin);
QuicByteCount second_packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).WillOnce(
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce(
SaveArg<2>(&second_packet_size));
connection_.SendStreamData(1, "second_packet", 12, !kFin);
EXPECT_NE(first_packet_size, second_packet_size);
@@ -1102,18 +1154,19 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) {
{
InSequence s;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, first_packet_size, _, kHasData));
+ SentPacket(_, _, first_packet_size, _));
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, second_packet_size, _, kHasData));
+ SentPacket(_, _, second_packet_size, _));
}
connection_.OnRetransmissionTimeout();
}
TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
QuicPacketSequenceNumber original_sequence_number;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission, kHasData))
+ SentPacket(_, _, _, !kIsRetransmission))
.WillOnce(SaveArg<1>(&original_sequence_number));
connection_.SendStreamData(1, "foo", 0, !kFin);
EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
@@ -1124,7 +1177,7 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
QuicPacketSequenceNumber rto_sequence_number;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, kIsRetransmission, kHasData))
+ SentPacket(_, _, _, kIsRetransmission))
.WillOnce(SaveArg<1>(&rto_sequence_number));
connection_.OnRetransmissionTimeout();
EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission(
@@ -1137,13 +1190,12 @@ 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(_, _, _, !kIsRetransmission, _))
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission))
.Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission, _))
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission))
.WillOnce(SaveArg<1>(&nack_sequence_number));
- QuicAckFrame ack(rto_sequence_number, 0);
+ QuicAckFrame ack(rto_sequence_number, QuicTime::Zero(), 0);
// Ack the retransmitted packet.
- EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
ack.received_info.missing_packets.insert(rto_sequence_number);
ack.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
&connection_, rto_sequence_number - 1);
@@ -1197,7 +1249,7 @@ TEST_F(QuicConnectionTest, CloseFecGroup) {
ASSERT_EQ(1u, connection_.NumFecGroups());
// Now send non-fec protected ack packet and close the group
- QuicAckFrame frame(0, 5);
+ QuicAckFrame frame(0, QuicTime::Zero(), 5);
creator_.set_sequence_number(4);
ProcessAckPacket(&frame);
ASSERT_EQ(0u, connection_.NumFecGroups());
@@ -1236,7 +1288,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(_, _, _, _, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
QuicTime default_timeout = clock_.ApproximateNow().Add(
QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
@@ -1273,7 +1325,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(_, _, _, _, !kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
clock_.ApproximateNow());
@@ -1285,9 +1337,10 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
TEST_F(QuicConnectionTest, SendScheduler) {
// Test that if we send a packet without delay, it is not queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
@@ -1295,9 +1348,10 @@ TEST_F(QuicConnectionTest, SendScheduler) {
TEST_F(QuicConnectionTest, SendSchedulerDelay) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, kHasData)).Times(0);
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
@@ -1305,8 +1359,9 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) {
TEST_F(QuicConnectionTest, SendSchedulerForce) {
// Test that if we force send a packet, it is not queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, kIsRetransmission)).Times(0);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, kIsRetransmission, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
// XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1315,9 +1370,10 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) {
TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
helper_->set_blocked(true);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, kHasData)).Times(0);
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
@@ -1325,46 +1381,51 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
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(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly(
+ testing::Return(QuicTime::Delta::Zero()));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
helper_->UnregisterSendAlarmIfRegistered();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
EXPECT_CALL(visitor_, OnCanWrite());
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission))
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission, _))
.WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, 1, _, !kIsRetransmission, kHasData));
+ SentPacket(_, 1, _, !kIsRetransmission));
connection_.SendStreamData(1, "foo", 0, !kFin);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
// Advance the time for retransmission of lost packet.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501));
// Test that if we send a retransmit with a delay, it ends up queued.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.OnRetransmissionTimeout();
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(_, kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::Zero()));
// Ensure the scheduler is notified this is a retransmit.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, kIsRetransmission, kHasData));
+ SentPacket(_, _, _, kIsRetransmission));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
helper_->UnregisterSendAlarmIfRegistered();
EXPECT_CALL(visitor_, OnCanWrite());
@@ -1374,8 +1435,9 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1387,19 +1449,20 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(10)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to
// retransmit 3. The far end should stop waiting for it.
- QuicAckFrame frame(0, 1);
+ QuicAckFrame frame(0, QuicTime::Zero(), 1);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission)).WillRepeatedly(
+ TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, _, kHasData));
+ SentPacket(_, _, _, _));
EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true));
ProcessAckPacket(&frame);
@@ -1410,16 +1473,18 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(10)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to
// retransmit 3. The far end should stop waiting for it.
- QuicAckFrame frame(0, 1);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ QuicAckFrame frame(0, QuicTime::Zero(), 1);
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(1)));
ProcessAckPacket(&frame);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1427,26 +1492,28 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(10)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// OnCanWrite should not send the packet (because of the delay)
// but should still return true.
- EXPECT_CALL(visitor_, OnCanWrite());
EXPECT_TRUE(connection_.OnCanWrite());
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// Limit to one byte per packet.
+ // All packets carry version info till version is negotiated.
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(!kIncludeVersion, 1);
+ GetPacketLengthForOneStream(kIncludeVersion, 1);
// Queue the first packet.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(10)));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(10)));
EXPECT_EQ(0u, connection_.SendStreamData(
1, "EnoughDataToQueue", 0, !kFin).bytes_consumed);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -1454,11 +1521,12 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
// Limit to one byte per packet.
+ // All packets carry version info till version is negotiated.
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(!kIncludeVersion, 1);
+ GetPacketLengthForOneStream(kIncludeVersion, 1);
// Queue the first packet.
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).Times(17);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(17);
EXPECT_EQ(17u, connection_.SendStreamData(
1, "EnoughDataToQueue", 0, !kFin).bytes_consumed);
}
@@ -1467,7 +1535,7 @@ TEST_F(QuicConnectionTest, NoAckForClose) {
ProcessPacket(1);
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(0);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, kHasData)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0);
ProcessClosePacket(2, 0);
}
@@ -1477,7 +1545,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, _, _, kHasData)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData);
}
@@ -1503,7 +1571,7 @@ TEST_F(QuicConnectionTest, GoAway) {
}
TEST_F(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
- QuicAckFrame ack(0, 4);
+ QuicAckFrame ack(0, QuicTime::Zero(), 4);
// Set the sequence number of the ack packet to be least unacked (4)
creator_.set_sequence_number(3);
ProcessAckPacket(&ack);
@@ -1526,7 +1594,7 @@ TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
ProcessDataPacket(4, 1, !kEntropyFlag);
EXPECT_EQ(34u, outgoing_ack()->received_info.entropy_hash);
// Make 4th packet my least unacked, and update entropy for 2, 3 packets.
- QuicAckFrame ack(0, 4);
+ QuicAckFrame ack(0, QuicTime::Zero(), 4);
QuicPacketEntropyHash kRandomEntropyHash = 129u;
ack.sent_info.entropy_hash = kRandomEntropyHash;
creator_.set_sequence_number(5);
@@ -1548,7 +1616,7 @@ TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
creator_.set_sequence_number(22);
QuicPacketEntropyHash kRandomEntropyHash = 85u;
// Current packet is the least unacked packet.
- QuicAckFrame ack(0, 23);
+ QuicAckFrame ack(0, QuicTime::Zero(), 23);
ack.sent_info.entropy_hash = kRandomEntropyHash;
QuicPacketEntropyHash ack_entropy_hash = ProcessAckPacket(&ack);
EXPECT_EQ((kRandomEntropyHash + ack_entropy_hash),
@@ -1610,6 +1678,111 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) {
<< "";
}
+// TODO(satyamsehkhar): Add more test when we start supporting more versions.
+TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) {
+ QuicVersionTag kRandomVersion = 143;
+ QuicFramerPeer::SetVersion(&framer_, kRandomVersion);
+
+ QuicPacketHeader header;
+ header.public_header.guid = guid_;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = true;
+ header.entropy_flag = false;
+ header.fec_flag = false;
+ header.fec_entropy_flag = false;
+ header.packet_sequence_number = 12;
+ header.fec_group = 0;
+
+ QuicFrames frames;
+ QuicFrame frame(&frame1_);
+ frames.push_back(frame);
+ scoped_ptr<QuicPacket> packet(
+ framer_.ConstructFrameDataPacket(header, frames).packet);
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(12, *packet));
+
+ QuicFramerPeer::SetVersion(&framer_, kQuicVersion1);
+ connection_.set_is_server(true);
+ connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+ EXPECT_TRUE(helper_->version_negotiation_packet() != NULL);
+ EXPECT_EQ(1u,
+ helper_->version_negotiation_packet()->versions.size());
+ EXPECT_EQ(kQuicVersion1,
+ helper_->version_negotiation_packet()->versions[0]);
+}
+
+TEST_F(QuicConnectionTest, CheckSendStats) {
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3);
+ EXPECT_CALL(*send_algorithm_,
+ SentPacket(_, _, _, !kIsRetransmission));
+ connection_.SendStreamData(1u, "first", 0, !kFin);
+ size_t first_packet_size = last_sent_packet_size();
+
+ EXPECT_CALL(*send_algorithm_,
+ SentPacket(_, _, _, !kIsRetransmission)).Times(2);
+ 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(_, _, _, kIsRetransmission)).Times(3);
+
+ // Retransmit due to RTO.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
+ connection_.OnRetransmissionTimeout();
+
+ // Retransmit due to explicit nacks
+ QuicAckFrame nack_three(4, QuicTime::Zero(), 0);
+ nack_three.received_info.missing_packets.insert(3);
+ nack_three.received_info.entropy_hash =
+ QuicConnectionPeer::GetSentEntropyHash(&connection_, 4) ^
+ QuicConnectionPeer::GetSentEntropyHash(&connection_, 3) ^
+ QuicConnectionPeer::GetSentEntropyHash(&connection_, 2);
+ QuicFrame frame(&nack_three);
+ EXPECT_CALL(visitor_, OnAck(_));
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
+
+ ProcessFramePacket(frame);
+ ProcessFramePacket(frame);
+ size_t ack_packet_size = last_sent_packet_size();
+ ProcessFramePacket(frame);
+
+ EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillOnce(
+ Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(
+ Return(QuicBandwidth::Zero()));
+
+ const QuicConnectionStats& stats = connection_.GetStats();
+ EXPECT_EQ(3 * first_packet_size + 2 * second_packet_size + ack_packet_size -
+ kQuicVersionSize, stats.bytes_sent);
+ EXPECT_EQ(6u, stats.packets_sent);
+ EXPECT_EQ(2 * first_packet_size + second_packet_size - kQuicVersionSize,
+ stats.bytes_retransmitted);
+ EXPECT_EQ(3u, stats.packets_retransmitted);
+ EXPECT_EQ(2u, stats.rto_count);
+}
+
+TEST_F(QuicConnectionTest, CheckReceiveStats) {
+ size_t received_bytes = 0;
+ received_bytes += ProcessFecProtectedPacket(1, false, !kEntropyFlag);
+ received_bytes += ProcessFecProtectedPacket(3, false, !kEntropyFlag);
+ // Should be counted against dropped packets.
+ received_bytes += ProcessDataPacket(3, 1, !kEntropyFlag);
+ received_bytes += ProcessFecPacket(4, 1, true, !kEntropyFlag); // Fec packet
+
+ EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillOnce(
+ Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(
+ Return(QuicBandwidth::Zero()));
+
+ const QuicConnectionStats& stats = connection_.GetStats();
+ EXPECT_EQ(received_bytes, stats.bytes_received);
+ EXPECT_EQ(4u, stats.packets_received);
+
+ EXPECT_EQ(1u, stats.packets_revived);
+ EXPECT_EQ(1u, stats.packets_dropped);
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index cccbc0a..a84a756 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -16,6 +16,10 @@ QuicCryptoClientStream::QuicCryptoClientStream(QuicSession* session,
: QuicCryptoStream(session),
server_hostname_(server_hostname) {
config_.SetDefaults();
+
+ QuicGuid guid = session->connection()->guid();
+ crypto_config_.hkdf_info.append(reinterpret_cast<char*>(&guid),
+ sizeof(guid));
}
QuicCryptoClientStream::~QuicCryptoClientStream() {
@@ -46,7 +50,7 @@ void QuicCryptoClientStream::OnHandshakeMessage(
}
QuicErrorCode err = crypto_config_.ProcessServerHello(
- message, &crypto_negotiated_params_, &error_details);
+ message, nonce_, &crypto_negotiated_params_, &error_details);
if (err != QUIC_NO_ERROR) {
CloseConnectionWithDetails(err, error_details);
return;
@@ -64,6 +68,8 @@ bool QuicCryptoClientStream::CryptoConnect() {
CryptoHandshakeMessage message;
crypto_config_.FillClientHello(nonce_, server_hostname_, &message);
config_.ToHandshakeMessage(&message);
+ const QuicData& data = message.GetSerialized();
+ crypto_config_.hkdf_info.append(data.data(), data.length());
SendHandshakeMessage(message);
return true;
}
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index 1f76c110..33cf6c4 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -15,6 +15,10 @@ namespace net {
class QuicSession;
struct CryptoHandshakeMessage;
+namespace test {
+class CryptoTestUtils;
+} // namespace test
+
class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
public:
QuicCryptoClientStream(QuicSession* session, const string& server_hostname);
@@ -29,6 +33,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
bool CryptoConnect();
private:
+ friend class test::CryptoTestUtils;
+
QuicConfig config_;
QuicCryptoClientConfig crypto_config_;
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 29ae7cb..10dcb5b 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -61,7 +61,7 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
public:
QuicCryptoClientStreamTest()
: addr_(),
- connection_(new PacketSavingConnection(1, addr_)),
+ connection_(new PacketSavingConnection(1, addr_, true)),
session_(connection_, true),
stream_(&session_, kServerHostname) {
}
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 0f4d4f4..8fdd9da 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -17,6 +17,10 @@ QuicCryptoServerStream::QuicCryptoServerStream(QuicSession* session)
// Use hardcoded crypto parameters for now.
CryptoHandshakeMessage extra_tags;
config_.ToHandshakeMessage(&extra_tags);
+
+ QuicGuid guid = session->connection()->guid();
+ crypto_config_.hkdf_info.append(reinterpret_cast<char*>(&guid),
+ sizeof(guid));
// TODO(agl): AddTestingConfig generates a new, random config. In the future
// this will be replaced with a real source of configs.
scoped_ptr<CryptoTagValueMap> config_tags(
@@ -56,9 +60,8 @@ void QuicCryptoServerStream::OnHandshakeMessage(
CryptoUtils::GenerateNonce(session()->connection()->clock(),
session()->connection()->random_generator(),
&server_nonce_);
- QuicCryptoNegotiatedParams params;
- crypto_config_.ProcessClientHello(message, server_nonce_, &shlo, &params,
- &error_details);
+ crypto_config_.ProcessClientHello(message, server_nonce_, &shlo,
+ &crypto_negotiated_params_, &error_details);
if (!error_details.empty()) {
DLOG(INFO) << "Rejecting CHLO: " << error_details;
}
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 5f9ddd1..ac63495 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -15,6 +15,10 @@ namespace net {
class QuicSession;
struct CryptoHandshakeMessage;
+namespace test {
+class CryptoTestUtils;
+} // namespace test
+
class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
public:
explicit QuicCryptoServerStream(QuicSession* session);
@@ -25,6 +29,8 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
const CryptoHandshakeMessage& message) OVERRIDE;
private:
+ friend class test::CryptoTestUtils;
+
// config_ contains non-crypto parameters that are negotiated in the crypto
// handshake.
QuicConfig config_;
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 995cb6b..db8841d 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -67,7 +67,7 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
QuicCryptoServerStreamTest()
: guid_(1),
addr_(),
- connection_(new PacketSavingConnection(guid_, addr_)),
+ connection_(new PacketSavingConnection(guid_, addr_, true)),
session_(connection_, true),
stream_(&session_) {
}
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 712c8fd..d34e6ec 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -3,8 +3,15 @@
// found in the LICENSE file.
#include "net/quic/quic_crypto_stream.h"
+
+#include <string>
+
+#include "base/string_piece.h"
+#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/quic_connection.h"
#include "net/quic/quic_session.h"
+using std::string;
using base::StringPiece;
namespace net {
@@ -49,9 +56,9 @@ void QuicCryptoStream::SetHandshakeComplete(QuicErrorCode error) {
void QuicCryptoStream::SendHandshakeMessage(
const CryptoHandshakeMessage& message) {
- scoped_ptr<QuicData> data(crypto_framer_.ConstructHandshakeMessage(message));
+ const QuicData& data = message.GetSerialized();
// TODO(wtc): check the return value.
- WriteData(string(data->data(), data->length()), false);
+ WriteData(string(data.data(), data.length()), false);
}
QuicNegotiatedParameters::QuicNegotiatedParameters()
diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h
index fa12ce3..fb2f6c0 100644
--- a/net/quic/quic_crypto_stream.h
+++ b/net/quic/quic_crypto_stream.h
@@ -28,7 +28,6 @@ struct CryptoHandshakeMessage;
class NET_EXPORT_PRIVATE QuicCryptoStream
: public ReliableQuicStream,
public CryptoFramerVisitorInterface {
-
public:
explicit QuicCryptoStream(QuicSession* session);
diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc
index 10f1657..98d3fb2 100644
--- a/net/quic/quic_crypto_stream_test.cc
+++ b/net/quic/quic_crypto_stream_test.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/memory/scoped_ptr.h"
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -44,7 +45,7 @@ class QuicCryptoStreamTest : public ::testing::Test {
public:
QuicCryptoStreamTest()
: addr_(IPAddressNumber(), 1),
- connection_(new MockConnection(1, addr_)),
+ connection_(new MockConnection(1, addr_, false)),
session_(connection_, true),
stream_(&session_) {
message_.tag = kSHLO;
diff --git a/net/quic/quic_data_reader.h b/net/quic/quic_data_reader.h
index 46f37bf..5477bd1 100644
--- a/net/quic/quic_data_reader.h
+++ b/net/quic/quic_data_reader.h
@@ -58,6 +58,7 @@ class NET_EXPORT_PRIVATE QuicDataReader {
// Forwards the internal iterator on success.
// Returns true on success, false otherwise.
bool ReadUInt128(uint128* result);
+
// Reads a string prefixed with 16-bit length into the given output parameter.
//
// NOTE: Does not copy but rather references strings in the underlying buffer.
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 2329605..462172c 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -45,15 +45,17 @@ QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target,
QuicFramer::QuicFramer(QuicVersionTag version,
QuicDecrypter* decrypter,
- QuicEncrypter* encrypter)
+ QuicEncrypter* encrypter,
+ bool is_server)
: visitor_(NULL),
fec_builder_(NULL),
error_(QUIC_NO_ERROR),
last_sequence_number_(0),
quic_version_(version),
decrypter_(decrypter),
- encrypter_(encrypter) {
- DCHECK_EQ(kQuicVersion1, version);
+ encrypter_(encrypter),
+ is_server_(is_server) {
+ DCHECK(IsSupportedVersion(version));
}
QuicFramer::~QuicFramer() {}
@@ -96,6 +98,15 @@ size_t QuicFramer::GetMinGoAwayFrameSize() {
kQuicStreamIdSize;
}
+bool QuicFramer::IsSupportedVersion(QuicVersionTag version) {
+ return version == kQuicVersion1;
+}
+
+size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) {
+ return kQuicGuidSize + kPublicFlagsSize +
+ number_versions * kQuicVersionSize;
+}
+
size_t QuicFramer::GetSerializedFrameLength(
const QuicFrame& frame, size_t free_bytes, bool first_frame) {
if (frame.type == PADDING_FRAME) {
@@ -245,7 +256,6 @@ SerializedPacket QuicFramer::ConstructFecPacket(const QuicPacketHeader& header,
QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
const QuicPublicResetPacket& packet) {
DCHECK(packet.public_header.reset_flag);
- DCHECK(!packet.public_header.version_flag);
size_t len = GetPublicResetPacketSize();
QuicDataWriter writer(len);
@@ -270,23 +280,56 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
return new QuicEncryptedPacket(writer.take(), len, true);
}
+QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket(
+ const QuicPacketPublicHeader& header,
+ const QuicVersionTagList& supported_versions) {
+ DCHECK(header.version_flag);
+ size_t len = GetVersionNegotiationPacketSize(supported_versions.size());
+ QuicDataWriter writer(len);
+
+ if (!writer.WriteUInt64(header.guid)) {
+ return NULL;
+ }
+
+ uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_VERSION);
+ if (!writer.WriteUInt8(flags)) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < supported_versions.size(); ++i) {
+ if (!writer.WriteUInt32(supported_versions[i])) {
+ return NULL;
+ }
+ }
+
+ return new QuicEncryptedPacket(writer.take(), len, true);
+}
+
bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
DCHECK(!reader_.get());
reader_.reset(new QuicDataReader(packet.data(), packet.length()));
+ visitor_->OnPacket();
+
// First parse the public header.
QuicPacketPublicHeader public_header;
if (!ProcessPublicHeader(&public_header)) {
DLOG(WARNING) << "Unable to process public header.";
return RaiseError(QUIC_INVALID_PACKET_HEADER);
}
- // TODO(satyamshekhar): Handle version negotiation.
- if (public_header.version_flag && public_header.version != quic_version_) {
- return false;
+
+ if (is_server_ && public_header.version_flag &&
+ public_header.versions[0] != quic_version_) {
+ if (!visitor_->OnProtocolVersionMismatch(public_header.versions[0])) {
+ reader_.reset(NULL);
+ return true;
+ }
}
bool rv;
- if (public_header.reset_flag) {
+ if (!is_server_ && public_header.version_flag) {
+ rv = ProcessVersionNegotiationPacket(&public_header);
+ } else if (public_header.reset_flag) {
rv = ProcessPublicResetPacket(public_header);
} else {
rv = ProcessDataPacket(public_header, packet);
@@ -296,11 +339,26 @@ bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
return rv;
}
+bool QuicFramer::ProcessVersionNegotiationPacket(
+ QuicPacketPublicHeader* public_header) {
+ DCHECK(!is_server_);
+ // Try reading at least once to raise error if the packet is invalid.
+ do {
+ QuicVersionTag version;
+ if (!reader_->ReadBytes(&version, kQuicVersionSize)) {
+ set_detailed_error("Unable to read supported version in negotiation.");
+ return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
+ }
+ public_header->versions.push_back(version);
+ } while (!reader_->IsDoneReading());
+
+ visitor_->OnVersionNegotiationPacket(*public_header);
+ return true;
+}
+
bool QuicFramer::ProcessDataPacket(
const QuicPacketPublicHeader& public_header,
const QuicEncryptedPacket& packet) {
- visitor_->OnPacket();
-
QuicPacketHeader header(public_header);
if (!ProcessPacketHeader(&header, packet)) {
DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessPacketHeader sets the error.
@@ -344,6 +402,7 @@ bool QuicFramer::ProcessPublicResetPacket(
const QuicPacketPublicHeader& public_header) {
QuicPublicResetPacket packet(public_header);
if (!reader_->ReadUInt64(&packet.nonce_proof)) {
+ // TODO(satyamshekhar): Raise error.
set_detailed_error("Unable to read nonce proof.");
return false;
}
@@ -403,6 +462,7 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header,
}
if (header.public_header.version_flag) {
+ DCHECK(!is_server_);
writer->WriteUInt32(quic_version_);
}
@@ -481,12 +541,21 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
public_header->version_flag =
(public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0;
- if (public_header->version_flag &&
- !reader_->ReadUInt32(&public_header->version)) {
- set_detailed_error("Unable to read protocol version.");
+ if (public_header->reset_flag && public_header->version_flag) {
+ set_detailed_error("Got version flag in reset packet");
return false;
}
+ if (public_header->version_flag && is_server_) {
+ QuicVersionTag version;
+ if (!reader_->ReadUInt32(&version)) {
+ // Read the version only if the packet is from the client.
+ // version flag from the server means version negotiation packet.
+ set_detailed_error("Unable to read protocol version.");
+ return false;
+ }
+ public_header->versions.push_back(version);
+ }
return true;
}
@@ -673,6 +742,7 @@ bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) {
set_detailed_error("Unable to read largest observed.");
return false;
}
+ // TODO(pwestin): read and update delta_time_largest_observed.
uint8 num_missing_packets;
if (!reader_->ReadBytes(&num_missing_packets, 1)) {
@@ -889,8 +959,8 @@ bool QuicFramer::ProcessGoAwayFrame() {
StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
const QuicEncryptedPacket& encrypted, bool includes_version) {
return StringPiece(encrypted.data() + kStartOfHashData,
- GetStartOfEncryptedData(includes_version)
- - kStartOfHashData);
+ GetStartOfEncryptedData(includes_version) -
+ kStartOfHashData);
}
QuicEncryptedPacket* QuicFramer::EncryptPacket(
@@ -1076,6 +1146,8 @@ bool QuicFramer::AppendAckFramePayload(
writer)) {
return false;
}
+ // TODO(pwestin): calculate and add delta_time_largest_observed to the
+ // message.
// We don't check for overflowing uint8 here, because we only can fit 192 acks
// per packet, so if we overflow we will be truncated.
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 86b255d..7a00aaa 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -56,6 +56,13 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
// Called if an error is detected in the QUIC protocol.
virtual void OnError(QuicFramer* framer) = 0;
+ // Called only when |is_server_| is true and the the framer gets a packet with
+ // version flag true and the version on the packet doesn't match
+ // |quic_version_|. The visitor should return true after it updates the
+ // version of the |framer_| to |received_version| or false to stop processing
+ // this packet.
+ virtual bool OnProtocolVersionMismatch(QuicVersionTag received_version) = 0;
+
// Called when a new packet has been received, before it
// has been validated or processed.
virtual void OnPacket() = 0;
@@ -65,12 +72,17 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
virtual void OnPublicResetPacket(
const QuicPublicResetPacket& packet) = 0;
+ // Called only when |is_server_| is false and a version negotiation packet has
+ // been parsed.
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) = 0;
+
// Called when a lost packet has been recovered via FEC,
// before it has been processed.
virtual void OnRevivedPacket() = 0;
- // Called when the header of a packet had been parsed.
- // If OnPacketHeader returns false, parsing for this packet will cease.
+ // Called when the complete header of a packet had been parsed.
+ // If OnPacketHeader returns false, framing for this packet will cease.
virtual bool OnPacketHeader(const QuicPacketHeader& header) = 0;
// Called when a data packet is parsed that is part of an FEC group.
@@ -138,10 +150,14 @@ class NET_EXPORT_PRIVATE QuicFramer {
// Constructs a new framer that will own |decrypter| and |encrypter|.
QuicFramer(QuicVersionTag quic_version,
QuicDecrypter* decrypter,
- QuicEncrypter* encrypter);
+ QuicEncrypter* encrypter,
+ bool is_server);
virtual ~QuicFramer();
+ // Returns true if |version| is a supported protocol version.
+ bool IsSupportedVersion(QuicVersionTag version);
+
// Calculates the largest observed packet to advertise in the case an Ack
// Frame was truncated. last_written in this case is the iterator for the
// last missing packet which fit in the outgoing ack.
@@ -168,6 +184,11 @@ class NET_EXPORT_PRIVATE QuicFramer {
return quic_version_;
}
+ void set_version(QuicVersionTag version) {
+ DCHECK(IsSupportedVersion(version));
+ quic_version_ = version;
+ }
+
// Set entropy calculator to be called from the framer when it needs the
// entropy of a truncated ack frame. An entropy calculator must be set or else
// the framer will likely crash. If this is called multiple times, only the
@@ -206,6 +227,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
static size_t GetMinConnectionCloseFrameSize();
// Size in bytes of all GoAway frame fields without the reason phrase.
static size_t GetMinGoAwayFrameSize();
+ // Size in bytes required for a serialized version negotiation packet
+ size_t GetVersionNegotiationPacketSize(size_t number_versions);
// Returns the number of bytes added to the packet for the specified frame,
// and 0 if the frame doesn't fit. Includes the header size for the first
@@ -242,6 +265,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
static QuicEncryptedPacket* ConstructPublicResetPacket(
const QuicPublicResetPacket& packet);
+ QuicEncryptedPacket* ConstructVersionNegotiationPacket(
+ const QuicPacketPublicHeader& header,
+ const QuicVersionTagList& supported_versions);
+
// Returns a new encrypted packet, owned by the caller.
QuicEncryptedPacket* EncryptPacket(QuicPacketSequenceNumber sequence_number,
const QuicPacket& packet);
@@ -268,6 +295,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
bool ProcessPublicResetPacket(const QuicPacketPublicHeader& public_header);
+ bool ProcessVersionNegotiationPacket(QuicPacketPublicHeader* public_header);
+
bool WritePacketHeader(const QuicPacketHeader& header,
QuicDataWriter* writer);
@@ -344,6 +373,9 @@ class NET_EXPORT_PRIVATE QuicFramer {
scoped_ptr<QuicDecrypter> decrypter_;
// Encrypter used to encrypt packets via EncryptPacket().
scoped_ptr<QuicEncrypter> encrypter_;
+ // Tracks if the framer is being used by the entity that received the
+ // connection or the entity that initiated it.
+ bool is_server_;
DISALLOW_COPY_AND_ASSIGN(QuicFramer);
};
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index eeecd08..8af9baf 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -17,6 +17,7 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
using base::hash_set;
@@ -64,21 +65,6 @@ const size_t kPublicResetPacketNonceProofOffset =
const size_t kPublicResetPacketRejectedSequenceNumberOffset =
kPublicResetPacketNonceProofOffset + kPublicResetNonceSize;
-class QuicFramerPeer {
- public:
- static QuicPacketSequenceNumber CalculatePacketSequenceNumberFromWire(
- QuicFramer* framer,
- QuicPacketSequenceNumber packet_sequence_number) {
- return framer->CalculatePacketSequenceNumberFromWire(
- packet_sequence_number);
- }
- static void SetLastSequenceNumber(
- QuicFramer* framer,
- QuicPacketSequenceNumber packet_sequence_number) {
- framer->last_sequence_number_ = packet_sequence_number;
- }
-};
-
class TestEncrypter : public QuicEncrypter {
public:
virtual ~TestEncrypter() {}
@@ -108,6 +94,12 @@ class TestEncrypter : public QuicEncrypter {
virtual size_t GetCiphertextSize(size_t plaintext_size) const OVERRIDE {
return plaintext_size;
}
+ virtual StringPiece GetKey() const {
+ return StringPiece();
+ }
+ virtual StringPiece GetNoncePrefix() const {
+ return StringPiece();
+ }
QuicPacketSequenceNumber sequence_number_;
string associated_data_;
string plaintext_;
@@ -130,6 +122,12 @@ class TestDecrypter : public QuicDecrypter {
ciphertext_ = ciphertext.as_string();
return new QuicData(ciphertext.data(), ciphertext.length());
}
+ virtual StringPiece GetKey() const {
+ return StringPiece();
+ }
+ virtual StringPiece GetNoncePrefix() const {
+ return StringPiece();
+ }
QuicPacketSequenceNumber sequence_number_;
string associated_data_;
string ciphertext_;
@@ -167,10 +165,21 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
public_reset_packet_.reset(new QuicPublicResetPacket(packet));
}
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) OVERRIDE {
+ version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet));
+ }
+
virtual void OnRevivedPacket() OVERRIDE {
revived_packets_++;
}
+ virtual bool OnProtocolVersionMismatch(
+ QuicVersionTag version) OVERRIDE {
+ DCHECK(false);
+ return true;
+ }
+
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE {
packet_count_++;
header_.reset(new QuicPacketHeader(header));
@@ -231,6 +240,7 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
scoped_ptr<QuicPacketHeader> header_;
scoped_ptr<QuicPublicResetPacket> public_reset_packet_;
+ scoped_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
vector<QuicStreamFrame*> stream_frames_;
vector<QuicAckFrame*> ack_frames_;
vector<QuicCongestionFeedbackFrame*> congestion_feedback_frames_;
@@ -246,7 +256,7 @@ class QuicFramerTest : public ::testing::Test {
QuicFramerTest()
: encrypter_(new test::TestEncrypter()),
decrypter_(new test::TestDecrypter()),
- framer_(kQuicVersion1, decrypter_, encrypter_) {
+ framer_(kQuicVersion1, decrypter_, encrypter_, true) {
framer_.set_visitor(&visitor_);
framer_.set_entropy_calculator(&entropy_calculator_);
}
@@ -555,7 +565,7 @@ TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) {
visitor_.header_->public_header.guid);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
- EXPECT_EQ(kQuicVersion1, visitor_.header_->public_header.version);
+ EXPECT_EQ(kQuicVersion1, visitor_.header_->public_header.versions[0]);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_FALSE(visitor_.header_->fec_entropy_flag);
@@ -814,7 +824,7 @@ TEST_F(QuicFramerTest, StreamFrameWithVersion) {
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_TRUE(visitor_.header_.get()->public_header.version_flag);
- EXPECT_EQ(kQuicVersion1, visitor_.header_.get()->public_header.version);
+ EXPECT_EQ(kQuicVersion1, visitor_.header_.get()->public_header.versions[0]);
EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion));
ASSERT_EQ(1u, visitor_.stream_frames_.size());
@@ -1562,6 +1572,7 @@ TEST_F(QuicFramerTest, PublicResetPacket) {
// Now test framing boundaries
for (size_t i = 0; i < GetPublicResetPacketSize(); ++i) {
string expected_error;
+ DLOG(INFO) << "iteration: " << i;
if (i < kPublicFlagsOffset) {
expected_error = "Unable to read GUID.";
} else if (i < kPublicResetPacketNonceProofOffset) {
@@ -1575,6 +1586,42 @@ TEST_F(QuicFramerTest, PublicResetPacket) {
}
}
+TEST_F(QuicFramerTest, VersionNegotiationPacket) {
+ unsigned char packet[] = {
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags (version)
+ 0x01,
+ // version tag
+ 'Q', '1', '.', '0',
+ 'Q', '2', '.', '0',
+ };
+
+ QuicFramerPeer::SetIsServer(&framer_, false);
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
+ EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
+ EXPECT_EQ(kQuicVersion1,
+ visitor_.version_negotiation_packet_->versions[0]);
+
+ for (size_t i = 0; i <= kQuicGuidSize + kPublicFlagsSize; ++i) {
+ string expected_error;
+ QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
+ if (i < kPublicFlagsOffset) {
+ expected_error = "Unable to read GUID.";
+ } else if (i < kVersionOffset) {
+ expected_error = "Unable to read public flags.";
+ } else {
+ expected_error = "Unable to read supported version in negotiation.";
+ error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
+ }
+ CheckProcessingFails(packet, i, expected_error, error_code);
+ }
+}
+
TEST_F(QuicFramerTest, FecPacket) {
unsigned char packet[] = {
// guid
@@ -1771,6 +1818,7 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
'r', 'l', 'd', '!',
};
+ QuicFramerPeer::SetIsServer(&framer_, false);
scoped_ptr<QuicPacket> data(
framer_.ConstructFrameDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
@@ -1780,6 +1828,33 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
AsChars(packet), arraysize(packet));
}
+TEST_F(QuicFramerTest, ConstructVersionNegotiationPacket) {
+ QuicPacketPublicHeader header;
+ header.guid = GG_UINT64_C(0xFEDCBA9876543210);
+ header.reset_flag = false;
+ header.version_flag = true;
+
+ unsigned char packet[] = {
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags (version)
+ 0x01,
+ // version tag
+ 'Q', '1', '.', '0',
+ 'Q', '2', '.', '0',
+ };
+
+ const int kQuicVersion2 = MAKE_TAG('Q', '2', '.', '0');
+ QuicVersionTagList versions;
+ versions.push_back(kQuicVersion1);
+ versions.push_back(kQuicVersion2);
+ scoped_ptr<QuicEncryptedPacket> data(
+ framer_.ConstructVersionNegotiationPacket(header, versions));
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
TEST_F(QuicFramerTest, ConstructAckFramePacket) {
QuicPacketHeader header;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index e0bfee7..4f5aa1c 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -44,7 +44,7 @@ class TestQuicConnection : public QuicConnection {
TestQuicConnection(QuicGuid guid,
IPEndPoint address,
QuicConnectionHelper* helper)
- : QuicConnection(guid, address, helper) {
+ : QuicConnection(guid, address, helper, false) {
}
void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
@@ -118,8 +118,9 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
guid_(2),
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)),
- creator_(guid_, &framer_, &random_) {
+ QuicEncrypter::Create(kNULL),
+ false),
+ creator_(guid_, &framer_, &random_, false) {
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
peer_addr_ = IPEndPoint(ip, 443);
@@ -168,7 +169,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
runner_ = new TestTaskRunner(&clock_);
send_algorithm_ = new MockSendAlgorithm();
receive_algorithm_ = new TestReceiveAlgorithm(NULL);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)).
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).
WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
helper_ = new QuicConnectionHelper(runner_.get(), &clock_,
&random_generator_, socket);
@@ -178,10 +179,12 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
connection_->SetReceiveAlgorithm(receive_algorithm_);
session_.reset(new QuicClientSession(connection_, helper_, NULL,
"www.google.com", NULL));
- CryptoHandshakeMessage message =
- CreateShloMessage(&clock_, &random_generator_, "www.google.com");
+ scoped_ptr<QuicPacket> shlo(ConstructServerHelloPacket(
+ guid_, &clock_, &random_generator_, "www.google.com"));
+ scoped_ptr<QuicEncryptedPacket> shlo_packet(
+ framer_.EncryptPacket(1, *shlo));
session_->GetCryptoStream()->CryptoConnect();
- session_->GetCryptoStream()->OnHandshakeMessage(message);
+ ProcessPacket(*shlo_packet);
EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
QuicReliableClientStream* stream =
session_->CreateOutgoingReliableStream();
@@ -219,7 +222,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
QuicEncryptedPacket* ConstructChloPacket() {
scoped_ptr<QuicPacket> chlo(
ConstructClientHelloPacket(guid_, &clock_, &random_generator_,
- "www.google.com"));
+ "www.google.com", true));
return framer_.EncryptPacket(1, *chlo);
}
@@ -241,7 +244,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
QuicPacketSequenceNumber least_unacked) {
InitializeHeader(sequence_number);
- QuicAckFrame ack(largest_received, least_unacked);
+ QuicAckFrame ack(largest_received, QuicTime::Zero(), least_unacked);
ack.sent_info.entropy_hash = 0;
ack.received_info.entropy_hash = 0;
@@ -340,7 +343,7 @@ TEST_F(QuicHttpStreamTest, GetRequest) {
AddWrite(SYNCHRONOUS, ConstructChloPacket());
AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, 0,
request_data_));
- AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 2));
+ AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 1));
Initialize();
request_.method = "GET";
@@ -383,7 +386,7 @@ TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
SetRequestString("GET", "/");
AddWrite(SYNCHRONOUS, ConstructChloPacket());
AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, 0, request_data_));
- AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 2));
+ AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 1));
Initialize();
request_.method = "GET";
@@ -429,7 +432,7 @@ TEST_F(QuicHttpStreamTest, SendPostRequest) {
AddWrite(SYNCHRONOUS, ConstructDataPacket(2, !kFin, 0, request_data_));
AddWrite(SYNCHRONOUS, ConstructDataPacket(3, kFin, request_data_.length(),
kUploadData));
- AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 2, 3));
+ AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 2, 1));
Initialize();
@@ -489,7 +492,7 @@ TEST_F(QuicHttpStreamTest, SendChunkedPostRequest) {
AddWrite(SYNCHRONOUS, ConstructDataPacket(4, kFin,
request_data_.length() + chunk_size,
kUploadData));
- AddWrite(SYNCHRONOUS, ConstructAckPacket(5, 2, 3));
+ AddWrite(SYNCHRONOUS, ConstructAckPacket(5, 2, 1));
Initialize();
@@ -545,7 +548,7 @@ TEST_F(QuicHttpStreamTest, DestroyedEarly) {
AddWrite(SYNCHRONOUS, ConstructChloPacket());
AddWrite(SYNCHRONOUS, ConstructDataPacket(2, kFin, 0, request_data_));
AddWrite(SYNCHRONOUS, ConstructRstPacket(3, 3));
- AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 2, 2));
+ AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 2, 1));
use_closing_stream_ = true;
Initialize();
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index d184f29..10c1ad9 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -88,10 +88,12 @@ class QuicNetworkTransactionTest : public PlatformTest {
scoped_ptr<QuicPacket> chlo(ConstructClientHelloPacket(0xDEADBEEF,
clock_,
&random_generator_,
- host));
+ host,
+ true));
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo));
}
@@ -103,7 +105,8 @@ class QuicNetworkTransactionTest : public PlatformTest {
host));
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo));
}
@@ -138,7 +141,7 @@ class QuicNetworkTransactionTest : public PlatformTest {
header.fec_entropy_flag = false;
header.fec_group = 0;
- QuicAckFrame ack(largest_received, least_unacked);
+ QuicAckFrame ack(largest_received, QuicTime::Zero(), least_unacked);
QuicCongestionFeedbackFrame feedback;
feedback.type = kTCP;
@@ -147,7 +150,8 @@ class QuicNetworkTransactionTest : public PlatformTest {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
@@ -201,7 +205,8 @@ class QuicNetworkTransactionTest : public PlatformTest {
const QuicFrame& frame) {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index ea1e90a..05a6893 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -9,7 +9,6 @@
#include "net/quic/quic_fec_group.h"
#include "net/quic/quic_utils.h"
-
using base::StringPiece;
using std::make_pair;
using std::min;
@@ -20,14 +19,16 @@ namespace net {
QuicPacketCreator::QuicPacketCreator(QuicGuid guid,
QuicFramer* framer,
- QuicRandom* random_generator)
+ QuicRandom* random_generator,
+ bool is_server)
: guid_(guid),
framer_(framer),
random_generator_(random_generator),
sequence_number_(0),
fec_group_number_(0),
- // TODO(satyashekhar): Fix this when versioning is implemented.
- packet_size_(GetPacketHeaderSize(!kIncludeVersion)) {
+ is_server_(is_server),
+ send_version_in_packet_(!is_server),
+ packet_size_(GetPacketHeaderSize(send_version_in_packet_)) {
framer_->set_fec_builder(this);
}
@@ -55,6 +56,18 @@ void QuicPacketCreator::MaybeStartFEC() {
}
}
+// Stops serializing version of the protocol in packets sent after this call.
+// A packet that is already open might send kQuicVersionSize bytes less than the
+// maximum packet size if we stop sending version before it is serialized.
+void QuicPacketCreator::StopSendingVersion() {
+ DCHECK(send_version_in_packet_);
+ send_version_in_packet_ = false;
+ if (packet_size_ > 0) {
+ DCHECK_LT(kQuicVersionSize, packet_size_);
+ packet_size_ -= kQuicVersionSize;
+ }
+}
+
bool QuicPacketCreator::HasRoomForStreamFrame() const {
return BytesFree() > QuicFramer::GetMinStreamFrameSize();
}
@@ -134,8 +147,7 @@ SerializedPacket QuicPacketCreator::SerializePacket() {
SerializedPacket serialized = framer_->ConstructFrameDataPacket(
header, queued_frames_, packet_size_);
queued_frames_.clear();
- // TODO(satyamshekhar) Fix this versioning is implemented.
- packet_size_ = GetPacketHeaderSize(false);
+ packet_size_ = GetPacketHeaderSize(send_version_in_packet_);
serialized.retransmittable_frames = queued_retransmittable_frames_.release();
return serialized;
}
@@ -164,13 +176,28 @@ SerializedPacket QuicPacketCreator::SerializeConnectionClose(
return SerializeAllFrames(frames);
}
+QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
+ const QuicVersionTagList& supported_versions) {
+ DCHECK(!is_server_);
+ QuicPacketPublicHeader header;
+ header.guid = guid_;
+ header.reset_flag = false;
+ header.version_flag = true;
+ header.versions = supported_versions;
+ QuicEncryptedPacket* encrypted =
+ framer_->ConstructVersionNegotiationPacket(header, supported_versions);
+ DCHECK(encrypted);
+ DCHECK_GE(options_.max_packet_length, encrypted->length());
+ return encrypted;
+}
+
void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
bool fec_flag,
bool fec_entropy_flag,
QuicPacketHeader* header) {
header->public_header.guid = guid_;
header->public_header.reset_flag = false;
- header->public_header.version_flag = false;
+ header->public_header.version_flag = send_version_in_packet_;
header->fec_flag = fec_flag;
header->fec_entropy_flag = fec_entropy_flag;
header->packet_sequence_number = ++sequence_number_;
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index e3fdc2b..60f9fb4 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -19,6 +19,9 @@
#include "net/quic/quic_protocol.h"
namespace net {
+namespace test {
+class QuicPacketCreatorPeer;
+}
class QuicRandom;
@@ -41,7 +44,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// QuicRandom* required for packet entropy.
QuicPacketCreator(QuicGuid guid,
QuicFramer* framer,
- QuicRandom* random_generator);
+ QuicRandom* random_generator,
+ bool is_server);
virtual ~QuicPacketCreator();
@@ -57,6 +61,9 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// and there is not already an FEC group open.
void MaybeStartFEC();
+ // Makes the framer not serialize the protocol version in sent packets.
+ void StopSendingVersion();
+
// The overhead the framing will add for a packet with num_frames frames.
static size_t StreamFramePacketOverhead(int num_frames, bool include_version);
@@ -108,6 +115,13 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
SerializedPacket SerializeConnectionClose(
QuicConnectionCloseFrame* close_frame);
+ // Creates a version negotiation packet which supports |supported_versions|.
+ // Caller owns the created packet. Also, sets the entropy hash of the
+ // serialized packet to a random bool and returns that value as a member of
+ // SerializedPacket.
+ QuicEncryptedPacket* SerializeVersionNegotiationPacket(
+ const QuicVersionTagList& supported_versions);
+
QuicPacketSequenceNumber sequence_number() const {
return sequence_number_;
}
@@ -121,6 +135,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
}
private:
+ friend class test::QuicPacketCreatorPeer;
+
static bool ShouldRetransmit(const QuicFrame& frame);
void FillPacketHeader(QuicFecGroupNumber fec_group,
@@ -139,6 +155,11 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
QuicPacketSequenceNumber sequence_number_;
QuicFecGroupNumber fec_group_number_;
scoped_ptr<QuicFecGroup> fec_group_;
+ // bool to keep track if this packet creator is being used the server.
+ bool is_server_;
+ // Controls whether protocol version should be included while serializing the
+ // packet.
+ bool send_version_in_packet_;
size_t packet_size_;
QuicFrames queued_frames_;
scoped_ptr<RetransmittableFrames> queued_retransmittable_frames_;
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 752da91..423028a 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -10,39 +10,49 @@
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
using base::StringPiece;
using std::string;
using std::vector;
+using testing::DoAll;
using testing::InSequence;
+using testing::Return;
+using testing::SaveArg;
using testing::_;
namespace net {
namespace test {
namespace {
-class QuicPacketCreatorTest : public ::testing::Test {
+class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> {
protected:
QuicPacketCreatorTest()
- : framer_(kQuicVersion1,
- QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)),
+ : server_framer_(kQuicVersion1,
+ QuicDecrypter::Create(kNULL),
+ QuicEncrypter::Create(kNULL),
+ true),
+ client_framer_(kQuicVersion1,
+ QuicDecrypter::Create(kNULL),
+ QuicEncrypter::Create(kNULL),
+ false),
id_(1),
sequence_number_(0),
guid_(2),
data_("foo"),
- creator_(guid_, &framer_, QuicRandom::GetInstance()) {
- framer_.set_visitor(&framer_visitor_);
+ creator_(guid_, &client_framer_, QuicRandom::GetInstance(), false) {
+ client_framer_.set_visitor(&framer_visitor_);
+ server_framer_.set_visitor(&framer_visitor_);
}
~QuicPacketCreatorTest() {
}
void ProcessPacket(QuicPacket* packet) {
scoped_ptr<QuicEncryptedPacket> encrypted(
- framer_.EncryptPacket(sequence_number_, *packet));
- framer_.ProcessPacket(*encrypted);
+ server_framer_.EncryptPacket(sequence_number_, *packet));
+ server_framer_.ProcessPacket(*encrypted);
}
void CheckStreamFrame(const QuicFrame& frame, QuicStreamId stream_id,
@@ -56,7 +66,8 @@ class QuicPacketCreatorTest : public ::testing::Test {
}
QuicFrames frames_;
- QuicFramer framer_;
+ QuicFramer server_framer_;
+ QuicFramer client_framer_;
testing::StrictMock<MockFramerVisitor> framer_visitor_;
QuicStreamId id_;
QuicPacketSequenceNumber sequence_number_;
@@ -65,25 +76,8 @@ class QuicPacketCreatorTest : public ::testing::Test {
QuicPacketCreator creator_;
};
-TEST_F(QuicPacketCreatorTest, SerializeFrame) {
- frames_.push_back(QuicFrame(new QuicStreamFrame(
- 0u, false, 0u, StringPiece(""))));
- SerializedPacket serialized = creator_.SerializeAllFrames(frames_);
- delete frames_[0].stream_frame;
-
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized.packet);
- delete serialized.packet;
-}
-
TEST_F(QuicPacketCreatorTest, SerializeFrames) {
- frames_.push_back(QuicFrame(new QuicAckFrame(0u, 0u)));
+ frames_.push_back(QuicFrame(new QuicAckFrame(0u, QuicTime::Zero(), 0u)));
frames_.push_back(QuicFrame(new QuicStreamFrame(
0u, false, 0u, StringPiece(""))));
frames_.push_back(QuicFrame(new QuicStreamFrame(
@@ -147,7 +141,7 @@ TEST_F(QuicPacketCreatorTest, SerializeWithFEC) {
TEST_F(QuicPacketCreatorTest, SerializeConnectionClose) {
QuicConnectionCloseFrame frame;
frame.error_code = QUIC_NO_ERROR;
- frame.ack_frame = QuicAckFrame(0u, 0u);
+ frame.ack_frame = QuicAckFrame(0u, QuicTime::Zero(), 0u);
SerializedPacket serialized = creator_.SerializeConnectionClose(&frame);
ASSERT_EQ(1u, serialized.sequence_number);
@@ -188,11 +182,54 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) {
delete frame.stream_frame;
}
-TEST_F(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
+TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
+ QuicVersionTagList versions;
+ versions.push_back(kQuicVersion1);
+ scoped_ptr<QuicEncryptedPacket> encrypted(
+ creator_.SerializeVersionNegotiationPacket(versions));
+
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnVersionNegotiationPacket(_));
+ }
+ client_framer_.ProcessPacket(*encrypted.get());
+}
+
+INSTANTIATE_TEST_CASE_P(ToggleVersionSerialization,
+ QuicPacketCreatorTest,
+ ::testing::Values(false, true));
+
+TEST_P(QuicPacketCreatorTest, SerializeFrame) {
+ if (!GetParam()) {
+ creator_.StopSendingVersion();
+ }
+ frames_.push_back(QuicFrame(new QuicStreamFrame(
+ 0u, false, 0u, StringPiece(""))));
+ SerializedPacket serialized = creator_.SerializeAllFrames(frames_);
+ delete frames_[0].stream_frame;
+
+ QuicPacketHeader header;
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_)).WillOnce(
+ DoAll(SaveArg<0>(&header), Return(true)));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized.packet);
+ EXPECT_EQ(GetParam(), header.public_header.version_flag);
+ delete serialized.packet;
+}
+
+TEST_P(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
+ if (!GetParam()) {
+ creator_.StopSendingVersion();
+ }
// A string larger than fits into a frame.
- size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1);
- creator_.options()->max_packet_length = ciphertext_size +
- QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion);
+ creator_.options()->max_packet_length = GetPacketLengthForOneStream(
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_), 1);
QuicFrame frame;
size_t consumed = creator_.CreateStreamFrame(1u, "test", 0u, true, &frame);
EXPECT_EQ(1u, consumed);
@@ -200,11 +237,16 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
delete frame.stream_frame;
}
-TEST_F(QuicPacketCreatorTest, AddFrameAndSerialize) {
+TEST_P(QuicPacketCreatorTest, AddFrameAndSerialize) {
+ if (!GetParam()) {
+ creator_.StopSendingVersion();
+ }
const size_t max_plaintext_size =
- framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+ client_framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize(!kIncludeVersion),
+ EXPECT_EQ(max_plaintext_size -
+ GetPacketHeaderSize(
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_)),
creator_.BytesFree());
// Add a variety of frame types and then a padding frame.
@@ -243,7 +285,9 @@ TEST_F(QuicPacketCreatorTest, AddFrameAndSerialize) {
delete serialized.retransmittable_frames;
EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize(!kIncludeVersion),
+ EXPECT_EQ(max_plaintext_size -
+ GetPacketHeaderSize(
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_)),
creator_.BytesFree());
}
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index d3de9b55..87464f7 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -72,8 +72,9 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
size_t total_bytes_consumed = 0;
bool fin_consumed = false;
+ bool has_retransmittable_data = true;
- while (delegate_->CanWrite(false)) {
+ while (delegate_->CanWrite(false, has_retransmittable_data)) {
// TODO(rch) figure out FEC.
// packet_creator_.MaybeStartFEC();
QuicFrame frame;
@@ -113,7 +114,8 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
}
void QuicPacketGenerator::SendQueuedData() {
- while (HasPendingData() && delegate_->CanWrite(false)) {
+ while (HasPendingData() &&
+ delegate_->CanWrite(false, packet_creator_->HasPendingFrames())) {
if (!AddNextPendingFrame()) {
// Packet was full, so serialize and send it.
SerializeAndSendPacket();
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 254a4fe..99f6098 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -62,7 +62,8 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
class NET_EXPORT_PRIVATE DelegateInterface {
public:
virtual ~DelegateInterface() {}
- virtual bool CanWrite(bool is_retransmission) = 0;
+ virtual bool CanWrite(bool is_retransmission,
+ bool has_retransmittable_data) = 0;
virtual QuicAckFrame* CreateAckFrame() = 0;
virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() = 0;
// Takes ownership of |packet.packet| and |packet.retransmittable_frames|.
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 3b97472..5ed1df5 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -31,14 +31,15 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface {
MockDelegate() {}
virtual ~MockDelegate() {}
- MOCK_METHOD1(CanWrite, bool(bool is_retransmission));
+ MOCK_METHOD2(CanWrite, bool(bool is_retransmission,
+ bool has_retransmittable_data));
MOCK_METHOD0(CreateAckFrame, QuicAckFrame*());
MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*());
MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet));
void SetCanWrite(bool can_write) {
- EXPECT_CALL(*this, CanWrite(false)).WillRepeatedly(Return(can_write));
+ EXPECT_CALL(*this, CanWrite(false, _)).WillRepeatedly(Return(can_write));
}
private:
@@ -76,8 +77,9 @@ class QuicPacketGeneratorTest : public ::testing::Test {
QuicPacketGeneratorTest()
: framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)),
- creator_(42, &framer_, &random_),
+ QuicEncrypter::Create(kNULL),
+ false),
+ creator_(42, &framer_, &random_, false),
generator_(&delegate_, &creator_),
packet_(0, NULL, 0, NULL),
packet2_(0, NULL, 0, NULL),
@@ -101,7 +103,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
QuicAckFrame* CreateAckFrame() {
// TODO(rch): Initialize this so it can be verified later.
- return new QuicAckFrame(0, 0);
+ return new QuicAckFrame(0, QuicTime::Zero(), 0);
}
QuicCongestionFeedbackFrame* CreateFeedbackFrame() {
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 0a7239a..6fca452 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -33,6 +33,29 @@ size_t GetStartOfEncryptedData(bool include_version) {
kFecGroupSize;
}
+QuicPacketPublicHeader::QuicPacketPublicHeader() {}
+
+QuicPacketPublicHeader::QuicPacketPublicHeader(
+ const QuicPacketPublicHeader& other)
+ : guid(other.guid),
+ reset_flag(other.reset_flag),
+ version_flag(other.version_flag),
+ versions(other.versions) {
+}
+
+QuicPacketPublicHeader::~QuicPacketPublicHeader() {}
+
+QuicPacketPublicHeader& QuicPacketPublicHeader::operator=(
+ const QuicPacketPublicHeader& other) {
+ guid = other.guid;
+ reset_flag = other.reset_flag;
+ version_flag = other.version_flag;
+ // Window's STL crashes when empty std::vectors are copied.
+ if (other.versions.size() > 0)
+ versions = other.versions;
+ return *this;
+}
+
QuicStreamFrame::QuicStreamFrame() {}
QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
@@ -48,8 +71,14 @@ QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
os << "{ guid: " << header.public_header.guid
<< ", reset_flag: " << header.public_header.reset_flag
- << ", version_flag: " << header.public_header.version_flag
- << ", fec_flag: " << header.fec_flag
+ << ", version_flag: " << header.public_header.version_flag;
+ if (header.public_header.version_flag) {
+ os << " version: ";
+ for (size_t i = 0; i < header.public_header.versions.size(); ++i) {
+ os << header.public_header.versions[0] << " ";
+ }
+ }
+ os << ", fec_flag: " << header.fec_flag
<< ", entropy_flag: " << header.entropy_flag
<< ", entropy hash: " << static_cast<int>(header.entropy_hash)
<< ", sequence_number: " << header.packet_sequence_number
@@ -59,7 +88,8 @@ ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
// TODO(ianswett): Initializing largest_observed to 0 should not be necessary.
ReceivedPacketInfo::ReceivedPacketInfo()
- : largest_observed(0) {
+ : largest_observed(0),
+ delta_time_largest_observed(QuicTime::Delta::Infinite()) {
}
ReceivedPacketInfo::~ReceivedPacketInfo() {}
@@ -84,6 +114,7 @@ SentPacketInfo::~SentPacketInfo() {}
// Testing convenience method.
QuicAckFrame::QuicAckFrame(QuicPacketSequenceNumber largest_observed,
+ QuicTime largest_observed_receive_time,
QuicPacketSequenceNumber least_unacked) {
received_info.largest_observed = largest_observed;
received_info.entropy_hash = 0;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 9a1e128..2a297ba 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -37,6 +37,7 @@ typedef QuicPacketSequenceNumber QuicFecGroupNumber;
typedef uint64 QuicPublicResetNonceProof;
typedef uint8 QuicPacketEntropyHash;
typedef uint32 QuicVersionTag;
+typedef std::vector<QuicVersionTag> QuicVersionTagList;
// TODO(rch): Consider Quic specific names for these constants.
// Maximum size in bytes of a QUIC packet.
@@ -72,6 +73,8 @@ NET_EXPORT_PRIVATE size_t GetPublicResetPacketSize();
NET_EXPORT_PRIVATE size_t GetStartOfFecProtectedData(bool include_version);
// Index of the first byte in a QUIC packet of encrypted data.
NET_EXPORT_PRIVATE size_t GetStartOfEncryptedData(bool include_version);
+// Returns true if |version| is a supported protocol version.
+NET_EXPORT_PRIVATE bool IsSupportedVersion(QuicVersionTag version);
// Index of the first byte in a QUIC packet which is used in hash calculation.
const size_t kStartOfHashData = 0;
@@ -118,6 +121,9 @@ enum QuicErrorCode {
// Stream errors.
QUIC_NO_ERROR = 0,
+ // Connection has reached an invalid state.
+ QUIC_INTERNAL_ERROR,
+
// There were data frames after the a fin or reset.
QUIC_STREAM_DATA_AFTER_TERMINATION,
// There was some server error which halted stream processing.
@@ -143,6 +149,8 @@ enum QuicErrorCode {
QUIC_INVALID_GOAWAY_DATA,
// Ack data is malformed.
QUIC_INVALID_ACK_DATA,
+ // Version negotiation packet is malformed.
+ QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
// There was an error decrypting.
QUIC_DECRYPTION_FAILURE,
// There was an error encrypting.
@@ -159,6 +167,8 @@ enum QuicErrorCode {
QUIC_TOO_MANY_OPEN_STREAMS,
// Received public reset for this connection.
QUIC_PUBLIC_RESET,
+ // Invalid protocol version
+ QUIC_INVALID_VERSION,
// We hit our prenegotiated (or default) timeout
QUIC_CONNECTION_TIMED_OUT,
@@ -195,14 +205,21 @@ enum QuicErrorCode {
// to reverse the order of the bytes.
#define MAKE_TAG(a, b, c, d) ((d << 24) + (c << 16) + (b << 8) + a)
+const QuicVersionTag kUnsupportedVersion = -1;
const QuicVersionTag kQuicVersion1 = MAKE_TAG('Q', '1', '.', '0');
struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
+ QuicPacketPublicHeader();
+ explicit QuicPacketPublicHeader(const QuicPacketPublicHeader& other);
+ ~QuicPacketPublicHeader();
+
+ QuicPacketPublicHeader& operator=(const QuicPacketPublicHeader& other);
+
// Universal header. All QuicPacket headers will have a guid and public flags.
QuicGuid guid;
bool reset_flag;
bool version_flag;
- QuicVersionTag version;
+ QuicVersionTagList versions;
};
// Header for Data or FEC packets.
@@ -232,6 +249,14 @@ struct QuicPublicResetPacket {
QuicPublicResetNonceProof nonce_proof;
};
+enum QuicVersionNegotiationState {
+ START_NEGOTIATION = 0,
+ SENT_NEGOTIATION_PACKET,
+ NEGOTIATED_VERSION
+};
+
+typedef QuicPacketPublicHeader QuicVersionNegotiationPacket;
+
// A padding frame contains no payload.
struct NET_EXPORT_PRIVATE QuicPaddingFrame {
};
@@ -275,6 +300,10 @@ struct NET_EXPORT_PRIVATE ReceivedPacketInfo {
// list.
QuicPacketSequenceNumber largest_observed;
+ // Time elapsed since largest_observed was received until this Ack frame was
+ // sent.
+ QuicTime::Delta delta_time_largest_observed;
+
// TODO(satyamshekhar): Can be optimized using an interval set like data
// structure.
// The set of packets which we're expecting and have not received.
@@ -312,6 +341,7 @@ struct NET_EXPORT_PRIVATE QuicAckFrame {
// Testing convenience method to construct a QuicAckFrame with all packets
// from least_unacked to largest_observed acked.
QuicAckFrame(QuicPacketSequenceNumber largest_observed,
+ QuicTime largest_observed_receive_time,
QuicPacketSequenceNumber least_unacked);
NET_EXPORT_PRIVATE friend std::ostream& operator<<(
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index 7990f16..3da022b 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -34,7 +34,7 @@ class MockDelegate : public QuicReliableClientStream::Delegate {
class QuicReliableClientStreamTest : public ::testing::Test {
public:
QuicReliableClientStreamTest()
- : session_(new MockConnection(1, IPEndPoint()), false),
+ : session_(new MockConnection(1, IPEndPoint(), false), false),
stream_(1, &session_, BoundNetLog()) {
stream_.SetDelegate(&delegate_);
}
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index b97a021..a629f20 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -8,6 +8,7 @@
#include <set>
#include "base/hash_tables.h"
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -87,7 +88,7 @@ class QuicSessionTest : public ::testing::Test {
protected:
QuicSessionTest()
: guid_(1),
- connection_(new MockConnection(guid_, IPEndPoint())),
+ connection_(new MockConnection(guid_, IPEndPoint(), false)),
session_(connection_, true) {
}
diff --git a/net/quic/quic_stats.cc b/net/quic/quic_stats.cc
new file mode 100644
index 0000000..162e093
--- /dev/null
+++ b/net/quic/quic_stats.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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_stats.h"
+
+namespace net {
+
+QuicConnectionStats::QuicConnectionStats() {
+ bytes_sent = 0;
+ packets_sent = 0;
+
+ bytes_received = 0;
+ packets_received = 0;
+
+ bytes_retransmitted = 0;
+ packets_retransmitted = 0;
+
+ packets_revived = 0;
+ packets_dropped = 0;
+ rto_count = 0;
+
+ rtt = 0;
+ estimated_bandwidth = 0;
+}
+
+QuicConnectionStats::~QuicConnectionStats() {}
+
+} // namespace net
diff --git a/net/quic/quic_stats.h b/net/quic/quic_stats.h
new file mode 100644
index 0000000..252791e
--- /dev/null
+++ b/net/quic/quic_stats.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 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_STATS_H_
+#define NET_QUIC_QUIC_STATS_H_
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+
+namespace net {
+// TODO(satyamshekhar): Add more interesting stats:
+// 1. (C/S)HLO retransmission count.
+// 2. SHLO received to first stream packet processed time.
+// 3. CHLO sent to SHLO received time.
+// 4. Number of migrations.
+// 5. Number of out of order packets.
+// 6. Avg packet size.
+// 7. Number of connections that require more that 1-RTT.
+// 8. Avg number of streams / session.
+// 9. Number of duplicates received.
+// 10. Fraction of traffic sent/received that was not data (protocol overhead).
+// 11. Fraction of data transferred that was padding.
+
+// Structure to hold stats for a QuicConnection.
+struct NET_EXPORT_PRIVATE QuicConnectionStats {
+ QuicConnectionStats();
+ ~QuicConnectionStats();
+
+ uint64 bytes_sent; // includes retransmissions, fec.
+ uint32 packets_sent;
+
+ uint64 bytes_received; // includes duplicate data for a stream, fec.
+ uint32 packets_received; // includes dropped packets
+
+ uint64 bytes_retransmitted;
+ uint32 packets_retransmitted;
+
+ uint32 packets_revived;
+ uint32 packets_dropped; // duplicate or less than least unacked.
+ uint32 rto_count;
+
+ uint32 rtt;
+ uint64 estimated_bandwidth;
+ // TODO(satyamshekhar): Add window_size, mss and mtu.
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_STATS_H_
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 9f9d96a..c5a5026 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -373,7 +373,7 @@ QuicClientSession* QuicStreamFactory::CreateSession(
MessageLoop::current()->message_loop_proxy(),
clock_.get(), random_generator_, socket);
- QuicConnection* connection = new QuicConnection(guid, addr, helper);
+ QuicConnection* connection = new QuicConnection(guid, addr, helper, false);
QuicClientSession* session = new QuicClientSession(connection, helper, this,
host, net_log.net_log());
all_sessions_.insert(session); // owning pointer
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 5ddae7c..34b06b8 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -37,10 +37,12 @@ class QuicStreamFactoryTest : public ::testing::Test {
scoped_ptr<QuicPacket> chlo(ConstructClientHelloPacket(0xDEADBEEF,
clock_,
&random_generator_,
- host));
+ host,
+ true));
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo));
}
@@ -52,7 +54,8 @@ class QuicStreamFactoryTest : public ::testing::Test {
host));
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo));
}
@@ -87,7 +90,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
header.fec_flag = false;
header.fec_group = 0;
- QuicAckFrame ack(largest_received, least_unacked);
+ QuicAckFrame ack(largest_received, QuicTime::Zero(), least_unacked);
QuicCongestionFeedbackFrame feedback;
feedback.type = kTCP;
feedback.tcp.accumulated_number_of_lost_packets = 0;
@@ -95,7 +98,8 @@ class QuicStreamFactoryTest : public ::testing::Test {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
@@ -132,7 +136,8 @@ class QuicStreamFactoryTest : public ::testing::Test {
const QuicFrame& frame) {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc
index a2c6901..dac6231 100644
--- a/net/quic/quic_time.cc
+++ b/net/quic/quic_time.cc
@@ -121,4 +121,4 @@ QuicTime::Delta QuicTime::Subtract(const QuicTime& other) const {
return QuicTime::Delta(ticks_ - other.ticks_);
}
-} // namespace gfe_quic
+} // namespace net
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index bf6f61b..0f6750b 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -39,6 +39,7 @@ return #x;
const char* QuicUtils::ErrorToString(QuicErrorCode error) {
switch (error) {
RETURN_STRING_LITERAL(QUIC_NO_ERROR);
+ RETURN_STRING_LITERAL(QUIC_INTERNAL_ERROR);
RETURN_STRING_LITERAL(QUIC_STREAM_DATA_AFTER_TERMINATION);
RETURN_STRING_LITERAL(QUIC_SERVER_ERROR_PROCESSING_STREAM);
RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS);
@@ -50,6 +51,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_CONNECTION_CLOSE_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
RETURN_STRING_LITERAL(QUIC_DECRYPTION_FAILURE);
RETURN_STRING_LITERAL(QUIC_ENCRYPTION_FAILURE);
RETURN_STRING_LITERAL(QUIC_PACKET_TOO_LARGE);
@@ -67,6 +69,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID);
RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS);
RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET);
+ RETURN_STRING_LITERAL(QUIC_INVALID_VERSION);
RETURN_STRING_LITERAL(QUIC_CONNECTION_TIMED_OUT);
// Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here.
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 0800dc8..c941e44 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -37,7 +37,7 @@ class QuicReliableTestStream : public ReliableQuicStream {
class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
public:
ReliableQuicStreamTest()
- : connection_(new MockConnection(1, IPEndPoint())),
+ : connection_(new MockConnection(1, IPEndPoint(), false)),
session_(connection_, true),
stream_(1, &session_) {
}
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index a9c5e0d..71f3234 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -4,12 +4,17 @@
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "base/string_piece.h"
+#include "net/quic/crypto/quic_decrypter.h"
+#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/quic_crypto_server_stream.h"
#include "net/quic/quic_crypto_stream.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
+using base::StringPiece;
+
namespace net {
namespace test {
@@ -61,13 +66,13 @@ void CommunicateHandshakeMessages(
// static
void CryptoTestUtils::HandshakeWithFakeServer(
PacketSavingConnection* client_conn,
- QuicCryptoStream* client) {
+ QuicCryptoClientStream* client) {
QuicGuid guid(1);
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
IPEndPoint addr = IPEndPoint(ip, 1);
PacketSavingConnection* server_conn =
- new PacketSavingConnection(guid, addr);
+ new PacketSavingConnection(guid, addr, true);
TestSession server_session(server_conn, true);
QuicCryptoServerStream server(&server_session);
@@ -75,18 +80,20 @@ void CryptoTestUtils::HandshakeWithFakeServer(
CHECK_NE(0u, client_conn->packets_.size());
CommunicateHandshakeMessages(client_conn, client, server_conn, &server);
+
+ CompareClientAndServerKeys(client, &server);
}
// static
void CryptoTestUtils::HandshakeWithFakeClient(
PacketSavingConnection* server_conn,
- QuicCryptoStream* server) {
+ QuicCryptoServerStream* server) {
QuicGuid guid(1);
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
IPEndPoint addr = IPEndPoint(ip, 1);
PacketSavingConnection* client_conn =
- new PacketSavingConnection(guid, addr);
+ new PacketSavingConnection(guid, addr, false);
TestSession client_session(client_conn, true);
QuicCryptoClientStream client(&client_session, "test.example.com");
@@ -94,6 +101,50 @@ void CryptoTestUtils::HandshakeWithFakeClient(
CHECK_EQ(1u, client_conn->packets_.size());
CommunicateHandshakeMessages(client_conn, &client, server_conn, server);
+
+ CompareClientAndServerKeys(&client, server);
+}
+
+// static
+void CryptoTestUtils::CompareClientAndServerKeys(
+ QuicCryptoClientStream* client,
+ QuicCryptoServerStream* server) {
+ StringPiece client_encrypter_key =
+ client->crypto_negotiated_params_.encrypter->GetKey();
+ StringPiece client_encrypter_iv =
+ client->crypto_negotiated_params_.encrypter->GetNoncePrefix();
+ StringPiece client_decrypter_key =
+ client->crypto_negotiated_params_.decrypter->GetKey();
+ StringPiece client_decrypter_iv =
+ client->crypto_negotiated_params_.decrypter->GetNoncePrefix();
+ StringPiece server_encrypter_key =
+ server->crypto_negotiated_params_.encrypter->GetKey();
+ StringPiece server_encrypter_iv =
+ server->crypto_negotiated_params_.encrypter->GetNoncePrefix();
+ StringPiece server_decrypter_key =
+ server->crypto_negotiated_params_.decrypter->GetKey();
+ StringPiece server_decrypter_iv =
+ server->crypto_negotiated_params_.decrypter->GetNoncePrefix();
+ CompareCharArraysWithHexError("client write key",
+ client_encrypter_key.data(),
+ client_encrypter_key.length(),
+ server_decrypter_key.data(),
+ server_decrypter_key.length());
+ CompareCharArraysWithHexError("client write IV",
+ client_encrypter_iv.data(),
+ client_encrypter_iv.length(),
+ server_decrypter_iv.data(),
+ server_decrypter_iv.length());
+ CompareCharArraysWithHexError("server write key",
+ server_encrypter_key.data(),
+ server_encrypter_key.length(),
+ client_decrypter_key.data(),
+ client_decrypter_key.length());
+ CompareCharArraysWithHexError("server write IV",
+ server_encrypter_iv.data(),
+ server_encrypter_iv.length(),
+ client_decrypter_iv.data(),
+ client_decrypter_iv.length());
}
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h
index 6251396..a205074 100644
--- a/net/quic/test_tools/crypto_test_utils.h
+++ b/net/quic/test_tools/crypto_test_utils.h
@@ -14,7 +14,8 @@
namespace net {
-class QuicCryptoStream;
+class QuicCryptoClientStream;
+class QuicCryptoServerStream;
namespace test {
@@ -23,10 +24,14 @@ class PacketSavingConnection;
class CryptoTestUtils {
public:
static void HandshakeWithFakeServer(PacketSavingConnection* client_conn,
- QuicCryptoStream* client);
+ QuicCryptoClientStream* client);
static void HandshakeWithFakeClient(PacketSavingConnection* server_conn,
- QuicCryptoStream* server);
+ QuicCryptoServerStream* server);
+
+ private:
+ static void CompareClientAndServerKeys(QuicCryptoClientStream* client,
+ QuicCryptoServerStream* server);
};
} // namespace test
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index d834d5e..102b2d7 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -9,6 +9,7 @@
#include "net/quic/congestion_control/receive_algorithm_interface.h"
#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/quic_connection.h"
+#include "net/quic/test_tools/quic_framer_peer.h"
namespace net {
namespace test {
@@ -102,5 +103,17 @@ QuicPacketEntropyHash QuicConnectionPeer::ReceivedEntropyHash(
return connection->entropy_manager_.ReceivedEntropyHash(sequence_number);
}
+// static
+bool QuicConnectionPeer::IsServer(QuicConnection* connection) {
+ return connection->is_server_;
+}
+
+// static
+void QuicConnectionPeer::SetIsServer(QuicConnection* connection,
+ bool is_server) {
+ connection->is_server_ = is_server;
+ QuicFramerPeer::SetIsServer(&connection->framer_, is_server);
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 8c3ff67..97f7afa 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_stats.h"
namespace net {
@@ -62,6 +63,10 @@ class QuicConnectionPeer {
QuicConnection* connection,
QuicPacketSequenceNumber sequence_number);
+ static bool IsServer(QuicConnection* connection);
+
+ static void SetIsServer(QuicConnection* connection, bool is_server);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
};
diff --git a/net/quic/test_tools/quic_framer_peer.cc b/net/quic/test_tools/quic_framer_peer.cc
new file mode 100644
index 0000000..15a8067
--- /dev/null
+++ b/net/quic/test_tools/quic_framer_peer.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 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/test_tools/quic_framer_peer.h"
+
+#include "net/quic/quic_framer.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+namespace test {
+
+// static
+QuicPacketSequenceNumber QuicFramerPeer::CalculatePacketSequenceNumberFromWire(
+ QuicFramer* framer,
+ QuicPacketSequenceNumber packet_sequence_number) {
+ return framer->CalculatePacketSequenceNumberFromWire(packet_sequence_number);
+}
+
+// static
+void QuicFramerPeer::SetLastSequenceNumber(
+ QuicFramer* framer,
+ QuicPacketSequenceNumber packet_sequence_number) {
+ framer->last_sequence_number_ = packet_sequence_number;
+}
+
+void QuicFramerPeer::SetIsServer(QuicFramer* framer, bool is_server) {
+ framer->is_server_ = is_server;
+}
+
+void QuicFramerPeer::SetVersion(QuicFramer* framer, QuicVersionTag version) {
+ framer->quic_version_ = version;
+}
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/test_tools/quic_framer_peer.h b/net/quic/test_tools/quic_framer_peer.h
new file mode 100644
index 0000000..3880412
--- /dev/null
+++ b/net/quic/test_tools/quic_framer_peer.h
@@ -0,0 +1,35 @@
+// Copyright (c) 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_TEST_TOOLS_QUIC_FRAMER_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
+
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class QuicFramer;
+
+namespace test {
+
+class QuicFramerPeer {
+ public:
+ static QuicPacketSequenceNumber CalculatePacketSequenceNumberFromWire(
+ QuicFramer* framer,
+ QuicPacketSequenceNumber packet_sequence_number);
+ static void SetLastSequenceNumber(
+ QuicFramer* framer,
+ QuicPacketSequenceNumber packet_sequence_number);
+ static void SetIsServer(QuicFramer* framer, bool is_server);
+ static void SetVersion(QuicFramer* framer, QuicVersionTag version);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicFramerPeer);
+};
+
+} // namespace test
+
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
diff --git a/net/quic/test_tools/quic_packet_creator_peer.cc b/net/quic/test_tools/quic_packet_creator_peer.cc
new file mode 100644
index 0000000..4451f02
--- /dev/null
+++ b/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 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/test_tools/quic_packet_creator_peer.h"
+
+#include "net/quic/quic_packet_creator.h"
+
+namespace net {
+namespace test {
+
+// static
+bool QuicPacketCreatorPeer::SendVersionInPacket(QuicPacketCreator* creator) {
+ return creator->send_version_in_packet_;
+}
+
+// static
+void QuicPacketCreatorPeer::SetSendVersionInPacket(
+ QuicPacketCreator* creator, bool send_version_in_packet) {
+ creator->send_version_in_packet_ = send_version_in_packet;
+}
+
+// static
+void QuicPacketCreatorPeer::SetIsServer(QuicPacketCreator* creator,
+ bool is_server) {
+ creator->is_server_ = is_server;
+}
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/test_tools/quic_packet_creator_peer.h b/net/quic/test_tools/quic_packet_creator_peer.h
new file mode 100644
index 0000000..816afa9
--- /dev/null
+++ b/net/quic/test_tools/quic_packet_creator_peer.h
@@ -0,0 +1,32 @@
+// Copyright (c) 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_TEST_TOOLS_QUIC_PACKET_CREATOR_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_PACKET_CREATOR_PEER_H_
+
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+class QuicPacketCreator;
+
+namespace test {
+
+class QuicPacketCreatorPeer {
+ public:
+ static bool SendVersionInPacket(QuicPacketCreator* creator);
+
+ static void SetSendVersionInPacket(QuicPacketCreator* creator,
+ bool send_version_in_packet);
+
+ static void SetIsServer(QuicPacketCreator* creator, bool is_server);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicPacketCreatorPeer);
+};
+
+} // namespace test
+
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_PACKET_CREATOR_PEER_H_
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index b1c2657..6eef75c 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -23,6 +23,10 @@ namespace test {
MockFramerVisitor::MockFramerVisitor() {
// By default, we want to accept packets.
+ ON_CALL(*this, OnProtocolVersionMismatch(_))
+ .WillByDefault(testing::Return(false));
+
+ // By default, we want to accept packets.
ON_CALL(*this, OnPacketHeader(_))
.WillByDefault(testing::Return(true));
}
@@ -30,6 +34,10 @@ MockFramerVisitor::MockFramerVisitor() {
MockFramerVisitor::~MockFramerVisitor() {
}
+bool NoOpFramerVisitor::OnProtocolVersionMismatch(QuicVersionTag version) {
+ return false;
+}
+
bool NoOpFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) {
return true;
}
@@ -82,6 +90,12 @@ void FramerVisitorCapturingFrames::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
++frame_count_;
}
+void FramerVisitorCapturingFrames::OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {
+ version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet));
+ frame_count_ = 0;
+}
+
FramerVisitorCapturingPublicReset::FramerVisitorCapturingPublicReset() {
}
@@ -113,15 +127,18 @@ QuicRandom* MockHelper::GetRandomGenerator() {
return &random_generator_;
}
-MockConnection::MockConnection(QuicGuid guid, IPEndPoint address)
- : QuicConnection(guid, address, new MockHelper()),
+MockConnection::MockConnection(QuicGuid guid,
+ IPEndPoint address,
+ bool is_server)
+ : QuicConnection(guid, address, new MockHelper(), is_server),
helper_(helper()) {
}
MockConnection::MockConnection(QuicGuid guid,
IPEndPoint address,
- QuicConnectionHelperInterface* helper)
- : QuicConnection(guid, address, helper),
+ QuicConnectionHelperInterface* helper,
+ bool is_server)
+ : QuicConnection(guid, address, helper, is_server),
helper_(helper) {
}
@@ -129,8 +146,9 @@ MockConnection::~MockConnection() {
}
PacketSavingConnection::PacketSavingConnection(QuicGuid guid,
- IPEndPoint address)
- : MockConnection(guid, address) {
+ IPEndPoint address,
+ bool is_server)
+ : MockConnection(guid, address, is_server) {
}
PacketSavingConnection::~PacketSavingConnection() {
@@ -245,17 +263,19 @@ void CompareQuicDataWithHexError(
static QuicPacket* ConstructPacketFromHandshakeMessage(
QuicGuid guid,
- const CryptoHandshakeMessage& message) {
+ const CryptoHandshakeMessage& message,
+ bool should_include_version) {
CryptoFramer crypto_framer;
scoped_ptr<QuicData> data(crypto_framer.ConstructHandshakeMessage(message));
QuicFramer quic_framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL));
+ QuicEncrypter::Create(kNULL),
+ false);
QuicPacketHeader header;
header.public_header.guid = guid;
header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
+ header.public_header.version_flag = should_include_version;
header.packet_sequence_number = 1;
header.entropy_flag = false;
header.entropy_hash = 0;
@@ -275,7 +295,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage(
QuicPacket* ConstructHandshakePacket(QuicGuid guid, CryptoTag tag) {
CryptoHandshakeMessage message;
message.tag = tag;
- return ConstructPacketFromHandshakeMessage(guid, message);
+ return ConstructPacketFromHandshakeMessage(guid, message, false);
}
CryptoHandshakeMessage CreateChloMessage(const QuicClock* clock,
@@ -298,10 +318,12 @@ CryptoHandshakeMessage CreateChloMessage(const QuicClock* clock,
QuicPacket* ConstructClientHelloPacket(QuicGuid guid,
const QuicClock* clock,
QuicRandom* random_generator,
- const string& server_hostname) {
+ const string& server_hostname,
+ bool should_include_version) {
CryptoHandshakeMessage chlo = CreateChloMessage(clock, random_generator,
server_hostname);
- return ConstructPacketFromHandshakeMessage(guid, chlo);
+ return ConstructPacketFromHandshakeMessage(
+ guid, chlo, should_include_version);
}
CryptoHandshakeMessage CreateShloMessage(const QuicClock* clock,
@@ -344,10 +366,11 @@ QuicPacket* ConstructServerHelloPacket(QuicGuid guid,
const string& server_hostname) {
CryptoHandshakeMessage shlo =
CreateShloMessage(clock, random_generator, server_hostname);
- return ConstructPacketFromHandshakeMessage(guid, shlo);
+ return ConstructPacketFromHandshakeMessage(guid, shlo, false);
}
size_t GetPacketLengthForOneStream(bool include_version, size_t payload) {
+ // TODO(wtc): the hardcoded use of NullEncrypter here seems wrong.
return NullEncrypter().GetCiphertextSize(payload) +
QuicPacketCreator::StreamFramePacketOverhead(1, include_version);
}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 33a5c56..f1d8cbf 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -39,7 +39,8 @@ CryptoHandshakeMessage CreateChloMessage(const QuicClock* clock,
QuicPacket* ConstructClientHelloPacket(QuicGuid guid,
const QuicClock* clock,
QuicRandom* random_generator,
- const std::string& server_hostname);
+ const std::string& server_hostname,
+ bool should_include_version);
CryptoHandshakeMessage CreateShloMessage(const QuicClock* clock,
QuicRandom* random_generator,
@@ -61,10 +62,14 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
~MockFramerVisitor();
MOCK_METHOD1(OnError, void(QuicFramer* framer));
+ // The constructor sets this up to return false by default.
+ MOCK_METHOD1(OnProtocolVersionMismatch, bool(QuicVersionTag version));
MOCK_METHOD0(OnPacket, void());
MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header));
+ MOCK_METHOD1(OnVersionNegotiationPacket,
+ void(const QuicVersionNegotiationPacket& packet));
MOCK_METHOD0(OnRevivedPacket, void());
- // The constructor set this up to return true by default.
+ // The constructor sets this up to return true by default.
MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header));
MOCK_METHOD1(OnFecProtectedPayload, void(base::StringPiece payload));
MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame& frame));
@@ -90,7 +95,10 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface {
virtual void OnPacket() OVERRIDE {}
virtual void OnPublicResetPacket(
const QuicPublicResetPacket& packet) OVERRIDE {}
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) OVERRIDE {}
virtual void OnRevivedPacket() OVERRIDE {}
+ virtual bool OnProtocolVersionMismatch(QuicVersionTag version) OVERRIDE;
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
virtual void OnFecProtectedPayload(base::StringPiece payload) OVERRIDE {}
virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {}
@@ -130,7 +138,8 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor {
virtual ~FramerVisitorCapturingFrames();
// NoOpFramerVisitor
-
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) OVERRIDE;
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE;
virtual void OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
@@ -151,6 +160,9 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor {
QuicRstStreamFrame* rst() { return rst_.get(); }
QuicConnectionCloseFrame* close() { return close_.get(); }
QuicGoAwayFrame* goaway() { return goaway_.get(); }
+ QuicVersionNegotiationPacket* version_negotiation_packet() {
+ return version_negotiation_packet_.get();
+ }
private:
size_t frame_count_;
@@ -161,6 +173,7 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor {
scoped_ptr<QuicRstStreamFrame> rst_;
scoped_ptr<QuicConnectionCloseFrame> close_;
scoped_ptr<QuicGoAwayFrame> goaway_;
+ scoped_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
DISALLOW_COPY_AND_ASSIGN(FramerVisitorCapturingFrames);
};
@@ -209,10 +222,11 @@ class MockHelper : public QuicConnectionHelperInterface {
class MockConnection : public QuicConnection {
public:
// Uses a MockHelper.
- MockConnection(QuicGuid guid, IPEndPoint address);
+ MockConnection(QuicGuid guid, IPEndPoint address, bool is_server);
MockConnection(QuicGuid guid,
IPEndPoint address,
- QuicConnectionHelperInterface* helper);
+ QuicConnectionHelperInterface* helper,
+ bool is_server);
virtual ~MockConnection();
MOCK_METHOD3(ProcessUdpPacket, void(const IPEndPoint& self_address,
@@ -233,6 +247,10 @@ class MockConnection : public QuicConnection {
QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
}
+ virtual bool OnProtocolVersionMismatch(QuicVersionTag version) OVERRIDE {
+ return false;
+ }
+
private:
scoped_ptr<QuicConnectionHelperInterface> helper_;
DISALLOW_COPY_AND_ASSIGN(MockConnection);
@@ -240,7 +258,7 @@ class MockConnection : public QuicConnection {
class PacketSavingConnection : public MockConnection {
public:
- PacketSavingConnection(QuicGuid guid, IPEndPoint address);
+ PacketSavingConnection(QuicGuid guid, IPEndPoint address, bool is_server);
virtual ~PacketSavingConnection();
virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
@@ -291,10 +309,13 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
MOCK_METHOD3(OnIncomingAck,
void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta));
MOCK_METHOD1(OnIncomingLoss, void(QuicTime));
- MOCK_METHOD5(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber,
- QuicByteCount, bool, bool));
- MOCK_METHOD2(TimeUntilSend, QuicTime::Delta(QuicTime now, bool));
+ MOCK_METHOD4(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber,
+ QuicByteCount, bool));
+ MOCK_METHOD2(AbandoningPacket, void(QuicPacketSequenceNumber sequence_number,
+ QuicByteCount abandoned_bytes));
+ MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now, bool, bool));
MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void));
+ MOCK_METHOD0(SmoothedRtt, QuicTime::Delta(void));
private:
DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 5dec9d0..d529ac7 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -25,9 +25,16 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
error_ = framer->error();
}
+ virtual bool OnProtocolVersionMismatch(QuicVersionTag version) {
+ return false;
+ }
+
virtual void OnPacket() {}
virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {}
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {}
virtual void OnRevivedPacket() {}
+
virtual bool OnPacketHeader(const QuicPacketHeader& header) {
has_header_ = true;
header_ = header;
@@ -116,7 +123,9 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
SimpleQuicFramer::SimpleQuicFramer()
: framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
- QuicEncrypter::Create(kNULL)) {
+ QuicEncrypter::Create(kNULL),
+ true),
+ visitor_(NULL) {
}
SimpleQuicFramer::~SimpleQuicFramer() {