summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/net.gyp1
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc6
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h9
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc46
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.cc11
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.h6
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h11
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc9
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h9
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc35
-rw-r--r--net/quic/crypto/aes_128_gcm_decrypter.h20
-rw-r--r--net/quic/crypto/aes_128_gcm_decrypter_nss.cc83
-rw-r--r--net/quic/crypto/aes_128_gcm_decrypter_openssl.cc112
-rw-r--r--net/quic/crypto/aes_128_gcm_decrypter_test.cc25
-rw-r--r--net/quic/crypto/aes_128_gcm_encrypter.h19
-rw-r--r--net/quic/crypto/aes_128_gcm_encrypter_nss.cc106
-rw-r--r--net/quic/crypto/aes_128_gcm_encrypter_openssl.cc112
-rw-r--r--net/quic/crypto/aes_128_gcm_encrypter_test.cc26
-rw-r--r--net/quic/crypto/crypto_handshake.cc227
-rw-r--r--net/quic/crypto/crypto_handshake.h88
-rw-r--r--net/quic/crypto/crypto_handshake_test.cc72
-rw-r--r--net/quic/crypto/null_decrypter.cc34
-rw-r--r--net/quic/crypto/null_decrypter.h11
-rw-r--r--net/quic/crypto/null_decrypter_test.cc21
-rw-r--r--net/quic/crypto/null_encrypter.cc27
-rw-r--r--net/quic/crypto/null_encrypter.h10
-rw-r--r--net/quic/crypto/null_encrypter_test.cc4
-rw-r--r--net/quic/crypto/p256_key_exchange_nss.cc70
-rw-r--r--net/quic/crypto/p256_key_exchange_openssl.cc51
-rw-r--r--net/quic/crypto/p256_key_exchange_test.cc6
-rw-r--r--net/quic/crypto/quic_decrypter.h20
-rw-r--r--net/quic/crypto/quic_encrypter.h16
-rw-r--r--net/quic/quic_client_session_test.cc21
-rw-r--r--net/quic/quic_connection.cc155
-rw-r--r--net/quic/quic_connection.h52
-rw-r--r--net/quic/quic_connection_helper_test.cc42
-rw-r--r--net/quic/quic_connection_logger.cc2
-rw-r--r--net/quic/quic_connection_test.cc113
-rw-r--r--net/quic/quic_crypto_client_stream.cc18
-rw-r--r--net/quic/quic_crypto_client_stream.h2
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc26
-rw-r--r--net/quic/quic_crypto_server_stream.cc22
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc25
-rw-r--r--net/quic/quic_framer.cc75
-rw-r--r--net/quic/quic_framer.h15
-rw-r--r--net/quic/quic_framer_test.cc78
-rw-r--r--net/quic/quic_http_stream.cc2
-rw-r--r--net/quic/quic_http_stream_test.cc3
-rw-r--r--net/quic/quic_network_transaction_unittest.cc4
-rw-r--r--net/quic/quic_packet_creator.cc2
-rw-r--r--net/quic/quic_packet_creator_test.cc3
-rw-r--r--net/quic/quic_packet_generator.cc8
-rw-r--r--net/quic/quic_packet_generator.h4
-rw-r--r--net/quic/quic_packet_generator_test.cc10
-rw-r--r--net/quic/quic_protocol.cc37
-rw-r--r--net/quic/quic_protocol.h50
-rw-r--r--net/quic/quic_reliable_client_stream.cc4
-rw-r--r--net/quic/quic_reliable_client_stream_test.cc2
-rw-r--r--net/quic/quic_session.cc4
-rw-r--r--net/quic/quic_session.h3
-rw-r--r--net/quic/quic_session_test.cc2
-rw-r--r--net/quic/quic_stream_factory_test.cc4
-rw-r--r--net/quic/quic_stream_sequencer_test.cc2
-rw-r--r--net/quic/quic_time.cc26
-rw-r--r--net/quic/quic_time.h23
-rw-r--r--net/quic/quic_time_test.cc31
-rw-r--r--net/quic/quic_utils.cc25
-rw-r--r--net/quic/quic_utils.h5
-rw-r--r--net/quic/quic_utils_test.cc25
-rw-r--r--net/quic/reliable_quic_stream.cc17
-rw-r--r--net/quic/reliable_quic_stream.h17
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc16
-rw-r--r--net/quic/test_tools/quic_test_utils.cc3
-rw-r--r--net/quic/test_tools/quic_test_utils.h16
-rw-r--r--net/quic/test_tools/simple_quic_framer.cc1
-rw-r--r--net/tools/quic/end_to_end_test.cc87
-rw-r--r--net/tools/quic/quic_time_wait_list_manager.cc1
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc8
-rw-r--r--net/tools/quic/test_tools/quic_test_client.h4
79 files changed, 1662 insertions, 736 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 9b94caa..743507c 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -1602,6 +1602,7 @@
'quic/quic_stream_factory_test.cc',
'quic/quic_stream_sequencer_test.cc',
'quic/quic_time_test.cc',
+ 'quic/quic_utils_test.cc',
'quic/reliable_quic_stream_test.cc',
'socket/buffered_write_stream_socket_unittest.cc',
'socket/client_socket_pool_base_unittest.cc',
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 19549a47..2ccbc8b 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -58,7 +58,7 @@ void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
void FixRateSender::SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber /*sequence_number*/,
QuicByteCount bytes,
- bool is_retransmission) {
+ Retransmission is_retransmission) {
fix_rate_leaky_bucket_.Add(sent_time, bytes);
paced_sender_.SentPacket(sent_time, bytes);
if (!is_retransmission) {
@@ -73,8 +73,8 @@ void FixRateSender::AbandoningPacket(
QuicTime::Delta FixRateSender::TimeUntilSend(
QuicTime now,
- bool /*is_retransmission*/,
- bool /*has_retransmittable_data*/) {
+ Retransmission /*is_retransmission*/,
+ HasRetransmittableData /*has_retransmittable_data*/) {
if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) {
if (CongestionWindow() <= data_in_flight_) {
// We need an ack before we send more.
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index e81981a..42915e1 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -36,12 +36,13 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
virtual void SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber equence_number,
QuicByteCount bytes,
- bool is_retransmission) OVERRIDE;
+ Retransmission is_retransmission) OVERRIDE;
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes) OVERRIDE;
- virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- bool is_retransmission,
- bool has_retransmittable_data) OVERRIDE;
+ virtual QuicTime::Delta TimeUntilSend(
+ QuicTime now,
+ Retransmission is_retransmission,
+ HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
// End implementation of SendAlgorithmInterface.
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index bbbb3cd..4969966 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -32,7 +32,8 @@ class FixRateTest : public ::testing::Test {
: rtt_(QuicTime::Delta::FromMilliseconds(30)),
unused_bandwidth_(QuicBandwidth::Zero()),
sender_(new FixRateSender(&clock_)),
- receiver_(new FixRateReceiverPeer()) {
+ receiver_(new FixRateReceiverPeer()),
+ start_(clock_.Now()) {
// Make sure clock does not start at 0.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
}
@@ -42,6 +43,7 @@ class FixRateTest : public ::testing::Test {
SendAlgorithmInterface::SentPacketsMap unused_packet_map_;
scoped_ptr<FixRateSender> sender_;
scoped_ptr<FixRateReceiverPeer> receiver_;
+ const QuicTime start_;
};
TEST_F(FixRateTest, ReceiverAPI) {
@@ -61,21 +63,24 @@ 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, 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, true));
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
+ sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION);
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
+ sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, NOT_RETRANSMISSION);
+ sender_->SentPacket(clock_.Now(), 3, 600, NOT_RETRANSMISSION);
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- sender_->TimeUntilSend(clock_.Now(), false, true));
+ EXPECT_EQ(QuicTime::Delta::Infinite(), sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA));
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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
}
TEST_F(FixRateTest, FixRatePacing) {
@@ -90,19 +95,24 @@ 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, 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);
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
+ sender_->SentPacket(clock_.Now(), sequence_number++, packet_size,
+ NOT_RETRANSMISSION);
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
+ sender_->SentPacket(clock_.Now(), sequence_number++, packet_size,
+ NOT_RETRANSMISSION);
+ QuicTime::Delta advance_time = sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(advance_time);
sender_->OnIncomingAck(sequence_number - 1, packet_size, rtt_);
sender_->OnIncomingAck(sequence_number - 2, packet_size, rtt_);
acc_advance_time = acc_advance_time.Add(advance_time);
}
EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(),
- static_cast<uint64>(acc_advance_time.ToMicroseconds()));
+ static_cast<uint64>(acc_advance_time.Subtract(start_)
+ .ToMicroseconds()));
}
} // namespace test
diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc
index d4dcdb3..48091c3 100644
--- a/net/quic/congestion_control/quic_congestion_manager.cc
+++ b/net/quic/congestion_control/quic_congestion_manager.cc
@@ -46,10 +46,10 @@ QuicCongestionManager::~QuicCongestionManager() {
void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes,
- bool is_retransmission) {
+ Retransmission retransmission) {
DCHECK(!ContainsKey(pending_packets_, sequence_number));
send_algorithm_->SentPacket(sent_time, sequence_number, bytes,
- is_retransmission);
+ retransmission);
packet_history_map_[sequence_number] =
new class SendAlgorithmInterface::SentPacket(bytes, sent_time);
@@ -122,10 +122,9 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame,
QuicTime::Delta QuicCongestionManager::TimeUntilSend(
QuicTime now,
- bool is_retransmission,
- bool has_retransmittable_data) {
- return send_algorithm_->TimeUntilSend(now, is_retransmission,
- has_retransmittable_data);
+ Retransmission retransmission,
+ HasRetransmittableData retransmittable) {
+ return send_algorithm_->TimeUntilSend(now, retransmission, retransmittable);
}
bool QuicCongestionManager::GenerateCongestionFeedback(
diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h
index 4560957..5840444 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -46,7 +46,7 @@ class QuicCongestionManager {
virtual void SentPacket(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes,
- bool is_retransmission);
+ Retransmission retransmission);
// Called when a packet is timed out.
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number);
@@ -57,8 +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 has_retransmittable_data);
+ Retransmission retransmission,
+ HasRetransmittableData retransmittable);
// Should be called before sending an ACK packet, to decide if we need
// to attach a QuicCongestionFeedbackFrame block.
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index effa671..fd8ec3e 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -7,6 +7,8 @@
#ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
#define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
+#include <map>
+
#include "base/basictypes.h"
#include "net/base/net_export.h"
#include "net/quic/quic_bandwidth.h"
@@ -58,16 +60,17 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
virtual void SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- bool is_retransmission) = 0;
+ Retransmission 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,
- bool has_retransmittable_data) = 0;
+ virtual QuicTime::Delta TimeUntilSend(
+ QuicTime now,
+ Retransmission is_retransmission,
+ HasRetransmittableData has_retransmittable_data) = 0;
// What's the current estimated bandwidth in bytes per second.
// Returns 0 when it does not have an estimate.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 70367ff..4bed7ed 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -85,7 +85,7 @@ void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
void TcpCubicSender::SentPacket(QuicTime /*sent_time*/,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- bool is_retransmission) {
+ Retransmission is_retransmission) {
bytes_in_flight_ += bytes;
if (!is_retransmission && update_end_sequence_number_) {
end_sequence_number_ = sequence_number;
@@ -101,9 +101,10 @@ void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number,
bytes_in_flight_ -= abandoned_bytes;
}
-QuicTime::Delta TcpCubicSender::TimeUntilSend(QuicTime now,
- bool is_retransmission,
- bool has_retransmittable_data) {
+QuicTime::Delta TcpCubicSender::TimeUntilSend(
+ QuicTime now,
+ Retransmission is_retransmission,
+ HasRetransmittableData 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();
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 6943044..2a1066d 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -42,12 +42,13 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
virtual void SentPacket(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
- bool is_retransmission) OVERRIDE;
+ Retransmission is_retransmission) OVERRIDE;
virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes) OVERRIDE;
- virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- bool is_retransmission,
- bool has_retransmittable_data) OVERRIDE;
+ virtual QuicTime::Delta TimeUntilSend(
+ QuicTime now,
+ Retransmission is_retransmission,
+ HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
// End implementation of SendAlgorithmInterface.
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 2aab55a..0cd51fd 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -40,10 +40,11 @@ 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);
+ NOT_RETRANSMISSION);
bytes_to_send -= bytes_in_packet;
if (bytes_to_send > 0) {
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION,
+ NO_RETRANSMITTABLE_DATA).IsZero());
}
}
}
@@ -73,31 +74,36 @@ TEST_F(TcpCubicSenderTest, SimpleSender) {
EXPECT_EQ(kDefaultWindowTCP,
sender_->AvailableCongestionWindow());
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), IS_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
for (int n = 0; n < kNumberOfAck; ++n) {
// Send our full congestion window.
@@ -118,13 +124,15 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
const int kNumberOfAck = 65;
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
for (int n = 0; n < kNumberOfAck; ++n) {
// Send our full congestion window.
@@ -159,13 +167,15 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
const int kNumberOfAck = 10;
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).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, true).IsZero());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsZero());
for (int i = 0; i < kNumberOfAck; ++i) {
// Send our full congestion window.
@@ -180,7 +190,8 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
sender_->OnIncomingLoss(clock_.Now());
// Make sure that we should not send right now.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false, true).IsInfinite());
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA).IsInfinite());
// We should now have fallen out of slow start.
// We expect window to be cut in half.
diff --git a/net/quic/crypto/aes_128_gcm_decrypter.h b/net/quic/crypto/aes_128_gcm_decrypter.h
index 88ce90e..bcd1d25 100644
--- a/net/quic/crypto/aes_128_gcm_decrypter.h
+++ b/net/quic/crypto/aes_128_gcm_decrypter.h
@@ -32,22 +32,18 @@ class NET_EXPORT_PRIVATE Aes128GcmDecrypter : public QuicDecrypter {
// QuicDecrypter implementation
virtual bool SetKey(base::StringPiece key) OVERRIDE;
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE;
- virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number,
- base::StringPiece associated_data,
- base::StringPiece ciphertext) OVERRIDE;
+ virtual bool Decrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) OVERRIDE;
+ virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext) OVERRIDE;
virtual base::StringPiece GetKey() const OVERRIDE;
virtual base::StringPiece GetNoncePrefix() const OVERRIDE;
private:
- friend class test::Aes128GcmDecrypterPeer;
-
- // The same as Decrypt(), except that the supplied |nonce| argument rather
- // than the |nonce_| member is used as the nonce. This method is useful
- // for testing the underlying AES GCM implementation.
- QuicData* DecryptWithNonce(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece ciphertext);
-
// The 128-bit AES key.
unsigned char key_[16];
// The nonce, a concatenation of a four-byte fixed prefix and a 8-byte
diff --git a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_decrypter_nss.cc
index 1d5c485..6c9bf1d 100644
--- a/net/quic/crypto/aes_128_gcm_decrypter_nss.cc
+++ b/net/quic/crypto/aes_128_gcm_decrypter_nss.cc
@@ -52,41 +52,23 @@ bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return true;
}
-QuicData* Aes128GcmDecrypter::Decrypt(QuicPacketSequenceNumber sequence_number,
- StringPiece associated_data,
- StringPiece ciphertext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
- return DecryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_),
- sizeof(nonce_)),
- associated_data, ciphertext);
-}
-
-StringPiece Aes128GcmDecrypter::GetKey() const {
- return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
-}
-
-StringPiece Aes128GcmDecrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
-}
-
-QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce,
- StringPiece associated_data,
- StringPiece ciphertext) {
+bool Aes128GcmDecrypter::Decrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) {
#if defined(USE_NSS)
// See the comment in IsSupported().
- return NULL;
+ return false;
#else
- if (ciphertext.length() < kAuthTagSize) {
- return NULL;
+ if (ciphertext.length() < kAuthTagSize ||
+ nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
+ return false;
}
// NSS 3.14.x incorrectly requires an output buffer at least as long as
- // the ciphertext (NSS bug 853674). So the capacity of the |plaintext|
- // buffer needs to be larger than the plaintext size.
- size_t plaintext_capacity = ciphertext.length();
+ // the ciphertext (NSS bug 853674). Fortunately QuicDecrypter::Decrypt()
+ // specifies that |output| must be as long as |ciphertext| on entry.
size_t plaintext_size = ciphertext.length() - kAuthTagSize;
- scoped_ptr<char[]> plaintext(new char[plaintext_capacity]);
// Import key_ into NSS.
SECItem key_item;
@@ -103,7 +85,7 @@ QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce,
slot = NULL;
if (!aes_key) {
DLOG(INFO) << "PK11_ImportSymKey failed";
- return NULL;
+ return false;
}
CK_GCM_PARAMS gcm_params;
@@ -124,21 +106,50 @@ QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce,
// If an incorrect authentication tag causes a decryption failure, the NSS
// error is SEC_ERROR_BAD_DATA (-8190).
if (PK11_Decrypt(aes_key.get(), CKM_AES_GCM, &param,
- reinterpret_cast<unsigned char*>(plaintext.get()),
- &output_len, plaintext_capacity,
- reinterpret_cast<const unsigned char*>(ciphertext.data()),
- ciphertext.size()) != SECSuccess) {
+ output, &output_len, ciphertext.length(),
+ reinterpret_cast<const unsigned char*>(
+ ciphertext.data()), ciphertext.length()) != SECSuccess) {
DLOG(INFO) << "PK11_Decrypt failed: NSS error " << PORT_GetError();
- return NULL;
+ return false;
}
if (output_len != plaintext_size) {
DLOG(INFO) << "Wrong output length";
+ return false;
+ }
+ *output_length = output_len;
+ return true;
+#endif
+}
+
+QuicData* Aes128GcmDecrypter::DecryptPacket(
+ QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece ciphertext) {
+ COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
+ incorrect_nonce_size);
+ if (ciphertext.length() < kAuthTagSize) {
return NULL;
}
+ size_t plaintext_size;
+ scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
+ memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+ if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ associated_data, ciphertext,
+ reinterpret_cast<unsigned char*>(plaintext.get()),
+ &plaintext_size)) {
+ return NULL;
+ }
return new QuicData(plaintext.release(), plaintext_size, true);
-#endif
+}
+
+StringPiece Aes128GcmDecrypter::GetKey() const {
+ return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
+}
+
+StringPiece Aes128GcmDecrypter::GetNoncePrefix() const {
+ return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
}
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc
index 3b73779..8cf52e6 100644
--- a/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc
+++ b/net/quic/crypto/aes_128_gcm_decrypter_openssl.cc
@@ -44,91 +44,105 @@ bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return true;
}
-QuicData* Aes128GcmDecrypter::Decrypt(QuicPacketSequenceNumber sequence_number,
- StringPiece associated_data,
- StringPiece ciphertext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
- return DecryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_),
- sizeof(nonce_)),
- associated_data, ciphertext);
-}
-
-StringPiece Aes128GcmDecrypter::GetKey() const {
- return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
-}
-
-StringPiece Aes128GcmDecrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
-}
-
-QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce,
- StringPiece associated_data,
- StringPiece ciphertext) {
- if (ciphertext.length() < kAuthTagSize) {
- return NULL;
+bool Aes128GcmDecrypter::Decrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) {
+ if (ciphertext.length() < kAuthTagSize ||
+ nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
+ return false;
}
- size_t plaintext_size = ciphertext.length() - kAuthTagSize;
- scoped_ptr<char[]> plaintext(new char[plaintext_size]);
-
- // |output| points to the position in the |plaintext| buffer to receive
- // the next output.
- unsigned char* output = reinterpret_cast<unsigned char*>(plaintext.get());
- // |output_len| is passed to an OpenSSL function to receive the output
- // length.
- int output_len;
+ const size_t plaintext_size = ciphertext.length() - kAuthTagSize;
+ // |len| is passed to an OpenSSL function to receive the output length.
+ int len;
ScopedEVPCipherCtx ctx;
// Set the cipher type and the key. The IV (nonce) is set below.
if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_,
NULL) == 0) {
- return NULL;
+ return false;
}
// Set the IV (nonce) length.
if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(),
NULL) == 0) {
- return NULL;
+ return false;
}
// Set the IV (nonce).
if (EVP_DecryptInit_ex(ctx.get(), NULL, NULL, NULL,
reinterpret_cast<const unsigned char*>(
nonce.data())) == 0) {
- return NULL;
+ return false;
}
// Set the authentication tag.
if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize,
const_cast<char*>(ciphertext.data()) +
plaintext_size) == 0) {
- return NULL;
+ return false;
}
- // Set the associated data. The second argument (output buffer) must be
- // NULL.
- if (EVP_DecryptUpdate(ctx.get(), NULL, &output_len,
- reinterpret_cast<const unsigned char*>(
- associated_data.data()),
- associated_data.size()) == 0) {
- return NULL;
+ // If we pass a NULL, zero-length associated data to OpenSSL then it breaks.
+ // Thus we only set non-empty associated data.
+ if (!associated_data.empty()) {
+ // Set the associated data. The second argument (output buffer) must be
+ // NULL.
+ if (EVP_DecryptUpdate(ctx.get(), NULL, &len,
+ reinterpret_cast<const unsigned char*>(
+ associated_data.data()),
+ associated_data.size()) == 0) {
+ return false;
+ }
}
- if (EVP_DecryptUpdate(ctx.get(), output, &output_len,
+ if (EVP_DecryptUpdate(ctx.get(), output, &len,
reinterpret_cast<const unsigned char*>(
ciphertext.data()),
plaintext_size) == 0) {
- return NULL;
+ return false;
+ }
+ output += len;
+
+ if (EVP_DecryptFinal_ex(ctx.get(), output, &len) == 0) {
+ return false;
}
- output += output_len;
+ output += len;
- if (EVP_DecryptFinal_ex(ctx.get(), output, &output_len) == 0) {
+ *output_length = plaintext_size;
+
+ return true;
+}
+
+QuicData* Aes128GcmDecrypter::DecryptPacket(
+ QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece ciphertext) {
+ COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
+ incorrect_nonce_size);
+ if (ciphertext.length() < kAuthTagSize) {
return NULL;
}
- output += output_len;
+ size_t plaintext_size;
+ scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
+ memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+ if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ associated_data, ciphertext,
+ reinterpret_cast<unsigned char*>(plaintext.get()),
+ &plaintext_size)) {
+ return NULL;
+ }
return new QuicData(plaintext.release(), plaintext_size, true);
}
+StringPiece Aes128GcmDecrypter::GetKey() const {
+ return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
+}
+
+StringPiece Aes128GcmDecrypter::GetNoncePrefix() const {
+ return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
+}
+
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_decrypter_test.cc
index ac09581..2ab0dd0 100644
--- a/net/quic/crypto/aes_128_gcm_decrypter_test.cc
+++ b/net/quic/crypto/aes_128_gcm_decrypter_test.cc
@@ -291,15 +291,22 @@ bool DecodeHexString(const char* in,
namespace net {
namespace test {
-class Aes128GcmDecrypterPeer {
- public:
- static QuicData* Decrypt(Aes128GcmDecrypter* decrypter,
+// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing
+// in an nonce and also to allocate the buffer needed for the plaintext.
+QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter,
StringPiece nonce,
StringPiece associated_data,
StringPiece ciphertext) {
- return decrypter->DecryptWithNonce(nonce, associated_data, ciphertext);
+ size_t plaintext_size = ciphertext.length();
+ scoped_ptr<char[]> plaintext(new char[plaintext_size]);
+
+ if (!decrypter->Decrypt(nonce, associated_data, ciphertext,
+ reinterpret_cast<unsigned char*>(plaintext.get()),
+ &plaintext_size)) {
+ return NULL;
}
-};
+ return new QuicData(plaintext.release(), plaintext_size, true);
+}
TEST(Aes128GcmDecrypterTest, Decrypt) {
if (!Aes128GcmDecrypter::IsSupported()) {
@@ -321,6 +328,7 @@ TEST(Aes128GcmDecrypterTest, Decrypt) {
size_t pt_len;
for (size_t i = 0; i < arraysize(test_group_array); i++) {
+ SCOPED_TRACE(i);
const TestVector* test_vector = test_group_array[i];
const TestGroupInfo& test_info = test_group_info[i];
for (size_t j = 0; test_vector[j].key != NULL; j++) {
@@ -353,8 +361,11 @@ TEST(Aes128GcmDecrypterTest, Decrypt) {
ASSERT_TRUE(decrypter.SetKey(StringPiece(key, key_len)));
string ciphertext(ct, ct_len);
ciphertext.append(tag, tag_len);
- scoped_ptr<QuicData> decrypted(Aes128GcmDecrypterPeer::Decrypt(
- &decrypter, StringPiece(iv, iv_len), StringPiece(aad, aad_len),
+ scoped_ptr<QuicData> decrypted(DecryptWithNonce(
+ &decrypter, StringPiece(iv, iv_len),
+ // OpenSSL fails if NULL is set as the AAD, as opposed to a
+ // zero-length, non-NULL pointer.
+ StringPiece(aad_len ? aad : NULL, aad_len),
ciphertext));
if (!decrypted.get()) {
EXPECT_EQ((size_t)-1, pt_len);
diff --git a/net/quic/crypto/aes_128_gcm_encrypter.h b/net/quic/crypto/aes_128_gcm_encrypter.h
index 1b1df9e..790c1d17 100644
--- a/net/quic/crypto/aes_128_gcm_encrypter.h
+++ b/net/quic/crypto/aes_128_gcm_encrypter.h
@@ -32,9 +32,13 @@ class NET_EXPORT_PRIVATE Aes128GcmEncrypter : public QuicEncrypter {
// QuicEncrypter implementation
virtual bool SetKey(base::StringPiece key) OVERRIDE;
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE;
- virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number,
- base::StringPiece associated_data,
- base::StringPiece plaintext) OVERRIDE;
+ virtual bool Encrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ unsigned char* output) OVERRIDE;
+ virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext) OVERRIDE;
virtual size_t GetKeySize() const OVERRIDE;
virtual size_t GetNoncePrefixSize() const OVERRIDE;
virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE;
@@ -43,15 +47,6 @@ class NET_EXPORT_PRIVATE Aes128GcmEncrypter : public QuicEncrypter {
virtual base::StringPiece GetNoncePrefix() const OVERRIDE;
private:
- friend class test::Aes128GcmEncrypterPeer;
-
- // The same as Encrypt(), except that the supplied |nonce| argument rather
- // than the |nonce_| member is used as the nonce. This method is useful
- // for testing the underlying AES GCM implementation.
- QuicData* EncryptWithNonce(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece plaintext);
-
// The 128-bit AES key.
unsigned char key_[16];
// The nonce, a concatenation of a four-byte fixed prefix and a 8-byte
diff --git a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_encrypter_nss.cc
index 57d364c..789c16d 100644
--- a/net/quic/crypto/aes_128_gcm_encrypter_nss.cc
+++ b/net/quic/crypto/aes_128_gcm_encrypter_nss.cc
@@ -53,52 +53,19 @@ bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return true;
}
-QuicData* Aes128GcmEncrypter::Encrypt(QuicPacketSequenceNumber sequence_number,
- StringPiece associated_data,
- StringPiece plaintext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
- return EncryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_),
- sizeof(nonce_)),
- associated_data, plaintext);
-}
-
-size_t Aes128GcmEncrypter::GetKeySize() const {
- return kKeySize;
-}
-
-size_t Aes128GcmEncrypter::GetNoncePrefixSize() const {
- return kNoncePrefixSize;
-}
-
-size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
- return ciphertext_size - kAuthTagSize;
-}
-
-// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its
-// corresponding plaintext.
-size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const {
- return plaintext_size + kAuthTagSize;
-}
-
-StringPiece Aes128GcmEncrypter::GetKey() const {
- return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
-}
-
-StringPiece Aes128GcmEncrypter::GetNoncePrefix() const {
- return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
-}
-
-QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext) {
+bool Aes128GcmEncrypter::Encrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ unsigned char* output) {
#if defined(USE_NSS)
// See the comment in IsSupported().
- return NULL;
+ return false;
#else
+ if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
+ return false;
+ }
+
size_t ciphertext_size = GetCiphertextSize(plaintext.length());
- scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
// Import key_ into NSS.
SECItem key_item;
@@ -115,7 +82,7 @@ QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce,
slot = NULL;
if (!aes_key) {
DLOG(INFO) << "PK11_ImportSymKey failed";
- return NULL;
+ return false;
}
CK_GCM_PARAMS gcm_params;
@@ -134,21 +101,66 @@ QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce,
unsigned int output_len;
if (PK11_Encrypt(aes_key.get(), CKM_AES_GCM, &param,
- reinterpret_cast<unsigned char*>(ciphertext.get()),
- &output_len, ciphertext_size,
+ output, &output_len, ciphertext_size,
reinterpret_cast<const unsigned char*>(plaintext.data()),
plaintext.size()) != SECSuccess) {
DLOG(INFO) << "PK11_Encrypt failed";
- return NULL;
+ return false;
}
if (output_len != ciphertext_size) {
DLOG(INFO) << "Wrong output length";
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+QuicData* Aes128GcmEncrypter::EncryptPacket(
+ QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece plaintext) {
+ COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
+ incorrect_nonce_size);
+ memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+
+ size_t ciphertext_size = GetCiphertextSize(plaintext.length());
+ scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
+
+ if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ associated_data, plaintext,
+ reinterpret_cast<unsigned char*>(ciphertext.get()))) {
return NULL;
}
return new QuicData(ciphertext.release(), ciphertext_size, true);
-#endif
+}
+
+size_t Aes128GcmEncrypter::GetKeySize() const {
+ return kKeySize;
+}
+
+size_t Aes128GcmEncrypter::GetNoncePrefixSize() const {
+ return kNoncePrefixSize;
+}
+
+size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
+ return ciphertext_size - kAuthTagSize;
+}
+
+// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its
+// corresponding plaintext.
+size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const {
+ return plaintext_size + kAuthTagSize;
+}
+
+StringPiece Aes128GcmEncrypter::GetKey() const {
+ return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
+}
+
+StringPiece Aes128GcmEncrypter::GetNoncePrefix() const {
+ return StringPiece(reinterpret_cast<const char*>(nonce_), kNoncePrefixSize);
}
} // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc
index 41d9177..87b8f53 100644
--- a/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc
+++ b/net/quic/crypto/aes_128_gcm_encrypter_openssl.cc
@@ -45,98 +45,110 @@ bool Aes128GcmEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return true;
}
-QuicData* Aes128GcmEncrypter::Encrypt(QuicPacketSequenceNumber sequence_number,
- StringPiece associated_data,
- StringPiece plaintext) {
- COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
- incorrect_nonce_size);
- memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
- return EncryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_),
- sizeof(nonce_)),
- associated_data, plaintext);
-}
-
-size_t Aes128GcmEncrypter::GetKeySize() const {
- return kKeySize;
-}
-
-size_t Aes128GcmEncrypter::GetNoncePrefixSize() const {
- return kNoncePrefixSize;
-}
-
-size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
- return ciphertext_size - kAuthTagSize;
-}
-
-// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its
-// corresponding plaintext.
-size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const {
- return plaintext_size + kAuthTagSize;
-}
-
-QuicData* Aes128GcmEncrypter::EncryptWithNonce(StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext) {
- size_t ciphertext_size = GetCiphertextSize(plaintext.length());
- scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
-
- // |output| points to the position in the |ciphertext| buffer to receive
- // the next output.
- unsigned char* output = reinterpret_cast<unsigned char*>(ciphertext.get());
+bool Aes128GcmEncrypter::Encrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ unsigned char* output) {
// |output_len| is passed to an OpenSSL function to receive the output
// length.
int output_len;
+ if (nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
+ return false;
+ }
+
ScopedEVPCipherCtx ctx;
// Set the cipher type and the key. The IV (nonce) is set below.
if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_,
NULL) == 0) {
- return NULL;
+ return false;
}
// Set the IV (nonce) length.
if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(),
NULL) == 0) {
- return NULL;
+ return false;
}
// Set the IV (nonce).
if (EVP_EncryptInit_ex(ctx.get(), NULL, NULL, NULL,
reinterpret_cast<const unsigned char*>(
nonce.data())) == 0) {
- return NULL;
+ return false;
}
- // Set the associated data. The second argument (output buffer) must be
- // NULL.
- if (EVP_EncryptUpdate(ctx.get(), NULL, &output_len,
- reinterpret_cast<const unsigned char*>(
- associated_data.data()),
- associated_data.size()) == 0) {
- return NULL;
+ // If we pass a NULL, zero-length associated data to OpenSSL then it breaks.
+ // Thus we only set non-empty associated data.
+ if (!associated_data.empty()) {
+ // Set the associated data. The second argument (output buffer) must be
+ // NULL.
+ if (EVP_EncryptUpdate(ctx.get(), NULL, &output_len,
+ reinterpret_cast<const unsigned char*>(
+ associated_data.data()),
+ associated_data.size()) == 0) {
+ return false;
+ }
}
if (EVP_EncryptUpdate(ctx.get(), output, &output_len,
reinterpret_cast<const unsigned char*>(
plaintext.data()),
plaintext.size()) == 0) {
- return NULL;
+ return false;
}
output += output_len;
if (EVP_EncryptFinal_ex(ctx.get(), output, &output_len) == 0) {
- return NULL;
+ return false;
}
output += output_len;
if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kAuthTagSize,
output) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+QuicData* Aes128GcmEncrypter::EncryptPacket(
+ QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece plaintext) {
+ COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number),
+ incorrect_nonce_size);
+ memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
+
+ size_t ciphertext_size = GetCiphertextSize(plaintext.length());
+ scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
+
+ if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce_), sizeof(nonce_)),
+ associated_data, plaintext,
+ reinterpret_cast<unsigned char*>(ciphertext.get()))) {
return NULL;
}
return new QuicData(ciphertext.release(), ciphertext_size, true);
}
+size_t Aes128GcmEncrypter::GetKeySize() const {
+ return kKeySize;
+}
+
+size_t Aes128GcmEncrypter::GetNoncePrefixSize() const {
+ return kNoncePrefixSize;
+}
+
+size_t Aes128GcmEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
+ return ciphertext_size - kAuthTagSize;
+}
+
+// An AEAD_AES_128_GCM ciphertext is exactly 16 bytes longer than its
+// corresponding plaintext.
+size_t Aes128GcmEncrypter::GetCiphertextSize(size_t plaintext_size) const {
+ return plaintext_size + kAuthTagSize;
+}
+
StringPiece Aes128GcmEncrypter::GetKey() const {
return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
}
diff --git a/net/quic/crypto/aes_128_gcm_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_encrypter_test.cc
index 4dd38b4..0da7a8f 100644
--- a/net/quic/crypto/aes_128_gcm_encrypter_test.cc
+++ b/net/quic/crypto/aes_128_gcm_encrypter_test.cc
@@ -243,15 +243,22 @@ bool DecodeHexString(const char* in,
namespace net {
namespace test {
-class Aes128GcmEncrypterPeer {
- public:
- static QuicData* Encrypt(Aes128GcmEncrypter* encrypter,
+// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing
+// in an nonce and also to allocate the buffer needed for the ciphertext.
+QuicData* EncryptWithNonce(Aes128GcmEncrypter* encrypter,
StringPiece nonce,
StringPiece associated_data,
StringPiece plaintext) {
- return encrypter->EncryptWithNonce(nonce, associated_data, plaintext);
+ size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
+ scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
+
+ if (!encrypter->Encrypt(nonce, associated_data, plaintext,
+ reinterpret_cast<unsigned char*>(ciphertext.get()))) {
+ return NULL;
}
-};
+
+ return new QuicData(ciphertext.release(), ciphertext_size, true);
+}
TEST(Aes128GcmEncrypterTest, Encrypt) {
if (!Aes128GcmEncrypter::IsSupported()) {
@@ -273,6 +280,7 @@ TEST(Aes128GcmEncrypterTest, Encrypt) {
size_t tag_len;
for (size_t i = 0; i < arraysize(test_group_array); i++) {
+ SCOPED_TRACE(i);
const TestVector* test_vector = test_group_array[i];
const TestGroupInfo& test_info = test_group_info[i];
for (size_t j = 0; test_vector[j].key != NULL; j++) {
@@ -301,8 +309,12 @@ TEST(Aes128GcmEncrypterTest, Encrypt) {
Aes128GcmEncrypter encrypter;
ASSERT_TRUE(encrypter.SetKey(StringPiece(key, key_len)));
- scoped_ptr<QuicData> encrypted(Aes128GcmEncrypterPeer::Encrypt(
- &encrypter, StringPiece(iv, iv_len), StringPiece(aad, aad_len),
+ scoped_ptr<QuicData> encrypted(EncryptWithNonce(
+ &encrypter, StringPiece(iv, iv_len),
+ // OpenSSL fails if NULL is set as the AAD, as opposed to a
+ // zero-length, non-NULL pointer. This deliberately tests that we
+ // handle this case.
+ StringPiece(aad_len ? aad : NULL, aad_len),
StringPiece(pt, pt_len)));
ASSERT_TRUE(encrypted.get());
ASSERT_EQ(ct_len + tag_len, encrypted->length());
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index f25133d..5956e45 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -9,9 +9,12 @@
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "crypto/hkdf.h"
#include "crypto/secure_hash.h"
#include "net/base/net_util.h"
+#include "net/quic/crypto/aes_128_gcm_decrypter.h"
+#include "net/quic/crypto/aes_128_gcm_encrypter.h"
#include "net/quic/crypto/crypto_framer.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/curve25519_key_exchange.h"
@@ -319,6 +322,34 @@ string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
return ret;
}
+SourceAddressToken::SourceAddressToken() {
+}
+
+SourceAddressToken::~SourceAddressToken() {
+}
+
+string SourceAddressToken::SerializeAsString() const {
+ return ip_ + " " + base::Int64ToString(timestamp_);
+}
+
+bool SourceAddressToken::ParseFromArray(unsigned char* plaintext,
+ size_t plaintext_length) {
+ string data(reinterpret_cast<const char*>(plaintext), plaintext_length);
+ std::vector<std::string> results;
+ base::SplitString(data, ' ', &results);
+ if (results.size() < 2) {
+ return false;
+ }
+
+ int64 timestamp;
+ if (!base::StringToInt64(results[1], &timestamp)) {
+ return false;
+ }
+
+ ip_ = results[0];
+ timestamp_ = timestamp;
+ return true;
+}
QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
: version(0),
@@ -392,13 +423,19 @@ const string& QuicCryptoClientConfig::CachedState::orbit() const {
return orbit_;
}
+void QuicCryptoClientConfig::CachedState::set_source_address_token(
+ StringPiece token) {
+ source_address_token_ = token.as_string();
+}
+
void QuicCryptoClientConfig::SetDefaults() {
// Version must be 0.
version = kVersion;
// Key exchange methods.
- kexs.resize(1);
+ kexs.resize(2);
kexs[0] = kC255;
+ kexs[1] = kP256;
// Authenticated encryption algorithms.
aead.resize(1);
@@ -431,7 +468,7 @@ void QuicCryptoClientConfig::FillInchoateClientHello(
out->SetValue(kVERS, version);
if (cached && !cached->source_address_token().empty()) {
- out->SetValue(kSRCT, cached->source_address_token());
+ out->SetStringPiece(kSRCT, cached->source_address_token());
}
}
@@ -527,7 +564,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
break;
case kP256:
key_exchange.reset(P256KeyExchange::New(
- Curve25519KeyExchange::NewPrivateKey(rand)));
+ P256KeyExchange::NewPrivateKey()));
break;
default:
DCHECK(false);
@@ -589,6 +626,11 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
+ StringPiece token;
+ if (rej.GetStringPiece(kSRCT, &token)) {
+ cached->set_source_address_token(token);
+ }
+
return QUIC_NO_ERROR;
}
@@ -610,7 +652,26 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
}
-QuicCryptoServerConfig::QuicCryptoServerConfig() {
+QuicCryptoServerConfig::QuicCryptoServerConfig(
+ StringPiece source_address_token_secret)
+ // AES-GCM is used to encrypt and authenticate source address tokens. The
+ // full, 96-bit nonce is used but we must ensure that an attacker cannot
+ // obtain two source address tokens with the same nonce. This occurs with
+ // probability 0.5 after 2**48 values. We assume that obtaining 2**48
+ // source address tokens is not possible: at a rate of 10M packets per
+ // second, it would still take the attacker a year to obtain the needed
+ // number of packets.
+ //
+ // TODO(agl): switch to an encrypter with a larger nonce space (i.e.
+ // Salsa20+Poly1305).
+ : source_address_token_encrypter_(new Aes128GcmEncrypter),
+ source_address_token_decrypter_(new Aes128GcmDecrypter) {
+ crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
+ "QUIC source address token key",
+ source_address_token_encrypter_->GetKeySize(),
+ 0 /* no fixed IV needed */);
+ source_address_token_encrypter_->SetKey(hkdf.server_write_key());
+ source_address_token_decrypter_->SetKey(hkdf.server_write_key());
}
QuicCryptoServerConfig::~QuicCryptoServerConfig() {
@@ -624,21 +685,34 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting(
const CryptoHandshakeMessage& extra_tags) {
CryptoHandshakeMessage msg;
- const string private_key = Curve25519KeyExchange::NewPrivateKey(rand);
+ const string curve25519_private_key =
+ Curve25519KeyExchange::NewPrivateKey(rand);
scoped_ptr<Curve25519KeyExchange> curve25519(
- Curve25519KeyExchange::New(private_key));
- StringPiece public_value = curve25519->public_value();
- string encoded_public_value;
+ Curve25519KeyExchange::New(curve25519_private_key));
+ StringPiece curve25519_public_value = curve25519->public_value();
+
+ const string p256_private_key =
+ P256KeyExchange::NewPrivateKey();
+ scoped_ptr<P256KeyExchange> p256(
+ P256KeyExchange::New(p256_private_key));
+ StringPiece p256_public_value = p256->public_value();
+
+ string encoded_public_values;
// First two bytes encode the length of the public value.
- encoded_public_value.push_back(public_value.size());
- encoded_public_value.push_back(public_value.size() >> 8);
- encoded_public_value.append(public_value.data(), public_value.size());
+ encoded_public_values.push_back(curve25519_public_value.size());
+ encoded_public_values.push_back(curve25519_public_value.size() >> 8);
+ encoded_public_values.append(curve25519_public_value.data(),
+ curve25519_public_value.size());
+ encoded_public_values.push_back(p256_public_value.size());
+ encoded_public_values.push_back(p256_public_value.size() >> 8);
+ encoded_public_values.append(p256_public_value.data(),
+ p256_public_value.size());
msg.set_tag(kSCFG);
- msg.SetTaglist(kKEXS, kC255, 0);
+ msg.SetTaglist(kKEXS, kC255, kP256, 0);
msg.SetTaglist(kAEAD, kAESG, 0);
msg.SetValue(kVERS, static_cast<uint16>(0));
- msg.SetStringPiece(kPUBS, encoded_public_value);
+ msg.SetStringPiece(kPUBS, encoded_public_values);
msg.Insert(extra_tags.tag_value_map().begin(),
extra_tags.tag_value_map().end());
@@ -651,9 +725,12 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting(
scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf);
config->set_config(serialized->AsStringPiece());
- QuicServerConfigProtobuf::PrivateKey* key = config->add_key();
- key->set_tag(kC255);
- key->set_private_key(private_key);
+ QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key();
+ curve25519_key->set_tag(kC255);
+ curve25519_key->set_private_key(curve25519_private_key);
+ QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key();
+ p256_key->set_tag(kP256);
+ p256_key->set_private_key(p256_private_key);
return config.release();
}
@@ -739,6 +816,14 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
return NULL;
}
break;
+ case kP256:
+ ka.reset(P256KeyExchange::New(private_key));
+ if (!ka.get()) {
+ LOG(WARNING) << "Server config contained an invalid P-256"
+ " private key.";
+ return NULL;
+ }
+ break;
default:
LOG(WARNING) << "Server config message contains unknown key exchange "
"method: "
@@ -791,6 +876,9 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddTestingConfig(
QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
const CryptoHandshakeMessage& client_hello,
QuicGuid guid,
+ const IPEndPoint& client_ip,
+ QuicTime::Delta now_since_unix_epoch,
+ QuicRandom* rand,
CryptoHandshakeMessage* out,
QuicCryptoNegotiatedParameters *out_params,
string* error_details) {
@@ -798,15 +886,27 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
// FIXME(agl): we should use the client's SCID, not just the active config.
const Config* config(configs_[active_config_]);
+ bool valid_source_address_token = false;
+ StringPiece srct;
+ if (client_hello.GetStringPiece(kSRCT, &srct) &&
+ ValidateSourceAddressToken(srct, client_ip, now_since_unix_epoch)) {
+ valid_source_address_token = true;
+ }
+
+ const string fresh_source_address_token =
+ NewSourceAddressToken(client_ip, rand, now_since_unix_epoch);
+
StringPiece scid;
if (!client_hello.GetStringPiece(kSCID, &scid) ||
- scid.as_string() != config->id) {
+ scid.as_string() != config->id ||
+ !valid_source_address_token) {
// If the client didn't provide a server config ID, or gave the wrong one,
// then the handshake cannot possibly complete. We reject the handshake and
// give the client enough information to do better next time.
out->Clear();
out->set_tag(kREJ);
out->SetStringPiece(kSCFG, config->serialized);
+ out->SetStringPiece(kSRCT, fresh_source_address_token);
return QUIC_NO_ERROR;
}
@@ -880,9 +980,102 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
CryptoUtils::SERVER);
out->set_tag(kSHLO);
+ out->SetStringPiece(kSRCT, fresh_source_address_token);
return QUIC_NO_ERROR;
}
+string QuicCryptoServerConfig::NewSourceAddressToken(
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicTime::Delta now_since_epoch) {
+ SourceAddressToken source_address_token;
+ source_address_token.set_ip(ip.ToString());
+ source_address_token.set_timestamp(now_since_epoch.ToSeconds());
+
+ string plaintext = source_address_token.SerializeAsString();
+ char nonce[12];
+ DCHECK_EQ(sizeof(nonce),
+ source_address_token_encrypter_->GetNoncePrefixSize() +
+ sizeof(QuicPacketSequenceNumber));
+ rand->RandBytes(nonce, sizeof(nonce));
+
+ size_t ciphertext_size =
+ source_address_token_encrypter_->GetCiphertextSize(plaintext.size());
+ string result;
+ result.resize(sizeof(nonce) + ciphertext_size);
+ memcpy(&result[0], &nonce, sizeof(nonce));
+
+ if (!source_address_token_encrypter_->Encrypt(
+ StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext,
+ reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) {
+ DCHECK(false);
+ return string();
+ }
+
+ return result;
+}
+
+bool QuicCryptoServerConfig::ValidateSourceAddressToken(
+ StringPiece token,
+ const IPEndPoint& ip,
+ QuicTime::Delta now_since_epoch) {
+ char nonce[12];
+ DCHECK_EQ(sizeof(nonce),
+ source_address_token_encrypter_->GetNoncePrefixSize() +
+ sizeof(QuicPacketSequenceNumber));
+
+ if (token.size() <= sizeof(nonce)) {
+ return false;
+ }
+ memcpy(&nonce, token.data(), sizeof(nonce));
+ token.remove_prefix(sizeof(nonce));
+
+ unsigned char plaintext_stack[128];
+ scoped_ptr<unsigned char[]> plaintext_heap;
+ unsigned char* plaintext;
+ if (token.size() <= sizeof(plaintext_stack)) {
+ plaintext = plaintext_stack;
+ } else {
+ plaintext_heap.reset(new unsigned char[token.size()]);
+ plaintext = plaintext_heap.get();
+ }
+ size_t plaintext_length;
+
+ if (!source_address_token_decrypter_->Decrypt(
+ StringPiece(nonce, sizeof(nonce)), StringPiece(), token,
+ plaintext, &plaintext_length)) {
+ return false;
+ }
+
+ SourceAddressToken source_address_token;
+ if (!source_address_token.ParseFromArray(plaintext, plaintext_length)) {
+ return false;
+ }
+
+ if (source_address_token.ip() != ip.ToString()) {
+ // It's for a different IP address.
+ return false;
+ }
+
+ const QuicTime::Delta delta(now_since_epoch.Subtract(
+ QuicTime::Delta::FromSeconds(source_address_token.timestamp())));
+ const int64 delta_secs = delta.ToSeconds();
+
+ // TODO(agl): consider whether and how these magic values should be moved to
+ // a config.
+ if (delta_secs < -3600) {
+ // We only allow timestamps to be from an hour in the future.
+ return false;
+ }
+
+ if (delta_secs > 86400) {
+ // We allow one day into the past.
+ return false;
+ }
+
+ return true;
+}
+
QuicCryptoServerConfig::Config::Config() {
}
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index fe2565e..e433d15 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -11,16 +11,23 @@
#include "base/memory/scoped_ptr.h"
#include "base/string_piece.h"
+#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_time.h"
namespace net {
class KeyExchange;
+class QuicClock;
class QuicDecrypter;
class QuicEncrypter;
class QuicRandom;
-class QuicClock;
+class QuicServerConfigProtobuf;
+
+namespace test {
+class QuicCryptoServerConfigPeer;
+} // namespace test
// An intermediate format of a handshake message that's convenient for a
// CryptoFramer to serialize from or parse into.
@@ -170,6 +177,37 @@ class NET_EXPORT_PRIVATE QuicServerConfigProtobuf {
std::string config_;
};
+// TODO(rtenneti): sync with server more rationally.
+class NET_EXPORT_PRIVATE SourceAddressToken {
+ public:
+ SourceAddressToken();
+ ~SourceAddressToken();
+
+ std::string SerializeAsString() const;
+
+ bool ParseFromArray(unsigned char* plaintext, size_t plaintext_length);
+
+ std::string ip() const {
+ return ip_;
+ }
+
+ int64 timestamp() const {
+ return timestamp_;
+ }
+
+ void set_ip(base::StringPiece ip) {
+ ip_ = ip.as_string();
+ }
+
+ void set_timestamp(int64 timestamp) {
+ timestamp_ = timestamp;
+ }
+
+ private:
+ std::string ip_;
+ int64 timestamp_;
+};
+
// Parameters negotiated by the crypto handshake.
struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters {
// Initializes the members to 0 or empty values.
@@ -233,6 +271,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
const std::string& source_address_token() const;
const std::string& orbit() const;
+ void set_source_address_token(base::StringPiece token);
+
private:
std::string server_config_id_; // An opaque id from the server.
std::string server_config_; // A serialized handshake message.
@@ -306,7 +346,11 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// need to consider locking.
class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
public:
- QuicCryptoServerConfig();
+ // |source_address_token_secret|: secret key material used for encrypting and
+ // decrypting source address tokens. It can be of any length as it is fed
+ // into a KDF before use.
+ explicit QuicCryptoServerConfig(
+ base::StringPiece source_address_token_secret);
~QuicCryptoServerConfig();
// ConfigForTesting generates a QuicServerConfigProtobuf protobuf suitable
@@ -332,15 +376,31 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// ProcessClientHello processes |client_hello| and decides whether to accept
// or reject the connection. If the connection is to be accepted, |out| is
// set to the contents of the ServerHello, |out_params| is completed and
- // QUIC_NO_ERROR is returned. |nonce| is used as the server's nonce.
- // Otherwise |out| is set to be a REJ message and an error code is returned.
+ // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ message and
+ // an error code is returned.
+ //
+ // client_hello: the incoming client hello message.
+ // guid: the GUID for the connection, which is used in key derivation.
+ // client_ip: the IP address of the client, which is used to generate and
+ // validate source-address tokens.
+ // now_since_epoch: the current time, as a delta since the unix epoch,
+ // which is used to validate client nonces.
+ // rand: an entropy source
+ // out: the resulting handshake message (either REJ or SHLO)
+ // out_params: the state of the handshake
+ // error_details: used to store a string describing any error.
QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello,
QuicGuid guid,
+ const IPEndPoint& client_ip,
+ QuicTime::Delta now_since_epoch,
+ QuicRandom* rand,
CryptoHandshakeMessage* out,
QuicCryptoNegotiatedParameters* out_params,
std::string* error_details);
private:
+ friend class test::QuicCryptoServerConfigPeer;
+
// Config represents a server config: a collection of preferences and
// Diffie-Hellman public values.
struct Config : public QuicCryptoConfig {
@@ -365,9 +425,27 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
DISALLOW_COPY_AND_ASSIGN(Config);
};
+ // NewSourceAddressToken returns a fresh source address token for the given
+ // IP address.
+ std::string NewSourceAddressToken(const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicTime::Delta now_since_epoch);
+
+ // ValidateSourceAddressToken returns true if the source address token in
+ // |token| is a valid and timely token for the IP address |ip| given that the
+ // current time is |now|.
+ bool ValidateSourceAddressToken(base::StringPiece token,
+ const IPEndPoint& ip,
+ QuicTime::Delta now_since_epoch);
+
std::map<ServerConfigID, Config*> configs_;
- std::string active_config_;
+ ServerConfigID active_config_;
+
+ // These members are used to encrypt and decrypt the source address tokens
+ // that we receive from and send to clients.
+ scoped_ptr<QuicEncrypter> source_address_token_encrypter_;
+ scoped_ptr<QuicDecrypter> source_address_token_decrypter_;
};
} // namespace net
diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc
index 0ce2ed4..911bc29 100644
--- a/net/quic/crypto/crypto_handshake_test.cc
+++ b/net/quic/crypto/crypto_handshake_test.cc
@@ -4,11 +4,83 @@
#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/crypto/aes_128_gcm_encrypter.h"
+#include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_time.h"
+#include "net/quic/test_tools/mock_clock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::StringPiece;
+using std::string;
+
namespace net {
namespace test {
+class QuicCryptoServerConfigPeer {
+ public:
+ explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config)
+ : server_config_(server_config) {
+ }
+
+ string NewSourceAddressToken(IPEndPoint ip,
+ QuicRandom* rand,
+ QuicTime::Delta now) {
+ return server_config_->NewSourceAddressToken(ip, rand, now);
+ }
+
+ bool ValidateSourceAddressToken(StringPiece srct,
+ IPEndPoint ip,
+ QuicTime::Delta now) {
+ return server_config_->ValidateSourceAddressToken(srct, ip, now);
+ }
+
+ private:
+ QuicCryptoServerConfig* const server_config_;
+};
+
+TEST(QuicCryptoServerConfigTest, ServerConfig) {
+ QuicCryptoServerConfig server("source address token secret");
+ MockClock clock;
+ CryptoHandshakeMessage extra_tags;
+
+ scoped_ptr<CryptoHandshakeMessage>(
+ server.AddTestingConfig(QuicRandom::GetInstance(), &clock, extra_tags));
+}
+
+TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
+ QuicCryptoServerConfig server("source address token secret");
+ IPAddressNumber ip;
+ CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
+ IPEndPoint ip4 = IPEndPoint(ip, 1);
+ CHECK(ParseIPLiteralToNumber("2001:db8:0::42", &ip));
+ IPEndPoint ip6 = IPEndPoint(ip, 2);
+ QuicRandom* rand = QuicRandom::GetInstance();
+ MockClock clock;
+ QuicCryptoServerConfigPeer peer(&server);
+
+ QuicTime::Delta now = clock.NowAsDeltaSinceUnixEpoch();
+ const QuicTime::Delta original_time = now;
+
+ const string token4 = peer.NewSourceAddressToken(ip4, rand, now);
+ LOG(INFO) << __LINE__ << token4;
+ const string token6 = peer.NewSourceAddressToken(ip6, rand, now);
+ LOG(INFO) << __LINE__ << token6;
+ EXPECT_TRUE(peer.ValidateSourceAddressToken(token4, ip4, now));
+ EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip6, now));
+ EXPECT_TRUE(peer.ValidateSourceAddressToken(token6, ip6, now));
+
+ now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7));
+ EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now));
+
+ now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
+ EXPECT_FALSE(peer.ValidateSourceAddressToken(token4, ip4, now));
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc
index 05d6bda..0875558 100644
--- a/net/quic/crypto/null_decrypter.cc
+++ b/net/quic/crypto/null_decrypter.cc
@@ -19,9 +19,37 @@ bool NullDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return nonce_prefix.empty();
}
-QuicData* NullDecrypter::Decrypt(QuicPacketSequenceNumber /*sequence_number*/,
- StringPiece associated_data,
- StringPiece ciphertext) {
+bool NullDecrypter::Decrypt(StringPiece /*nonce*/,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) {
+ QuicDataReader reader(ciphertext.data(), ciphertext.length());
+
+ uint128 hash;
+ if (!reader.ReadUInt128(&hash)) {
+ return false;
+ }
+
+ StringPiece plaintext = reader.ReadRemainingPayload();
+
+ // TODO(rch): avoid buffer copy here
+ string buffer = associated_data.as_string();
+ plaintext.AppendToString(&buffer);
+
+ if (hash != QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length())) {
+ return false;
+ }
+ memcpy(output, plaintext.data(), plaintext.length());
+ *output_length = plaintext.length();
+ return true;
+}
+
+QuicData* NullDecrypter::DecryptPacket(QuicPacketSequenceNumber /*seq_number*/,
+ StringPiece associated_data,
+ StringPiece ciphertext) {
+ // It's worth duplicating |Decrypt|, above, in order to save a copy by using
+ // the shared-data QuicData constructor directly.
QuicDataReader reader(ciphertext.data(), ciphertext.length());
uint128 hash;
diff --git a/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h
index bd4a7ea..01beb2d 100644
--- a/net/quic/crypto/null_decrypter.h
+++ b/net/quic/crypto/null_decrypter.h
@@ -21,9 +21,14 @@ class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter {
// QuicDecrypter implementation
virtual bool SetKey(base::StringPiece key) OVERRIDE;
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE;
- virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number,
- base::StringPiece associated_data,
- base::StringPiece ciphertext) OVERRIDE;
+ virtual bool Decrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) OVERRIDE;
+ virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext) OVERRIDE;
virtual base::StringPiece GetKey() const OVERRIDE;
virtual base::StringPiece GetNoncePrefix() const OVERRIDE;
};
diff --git a/net/quic/crypto/null_decrypter_test.cc b/net/quic/crypto/null_decrypter_test.cc
index 56aa531..7854b04 100644
--- a/net/quic/crypto/null_decrypter_test.cc
+++ b/net/quic/crypto/null_decrypter_test.cc
@@ -23,9 +23,10 @@ TEST(NullDecrypterTest, Decrypt) {
};
NullDecrypter decrypter;
scoped_ptr<QuicData> decrypted(
- decrypter.Decrypt(0, "hello world!",
- StringPiece(reinterpret_cast<const char*>(expected),
- arraysize(expected))));
+ decrypter.DecryptPacket(
+ 0, "hello world!",
+ StringPiece(reinterpret_cast<const char*>(expected),
+ arraysize(expected))));
ASSERT_TRUE(decrypted.get());
EXPECT_EQ("goodbye!", decrypted->AsStringPiece());
}
@@ -43,9 +44,10 @@ TEST(NullDecrypterTest, BadHash) {
};
NullDecrypter decrypter;
scoped_ptr<QuicData> decrypted(
- decrypter.Decrypt(0, "hello world!",
- StringPiece(reinterpret_cast<const char*>(expected),
- arraysize(expected))));
+ decrypter.DecryptPacket(
+ 0, "hello world!",
+ StringPiece(reinterpret_cast<const char*>(expected),
+ arraysize(expected))));
ASSERT_FALSE(decrypted.get());
}
@@ -59,9 +61,10 @@ TEST(NullDecrypterTest, ShortInput) {
};
NullDecrypter decrypter;
scoped_ptr<QuicData> decrypted(
- decrypter.Decrypt(0, "hello world!",
- StringPiece(reinterpret_cast<const char*>(expected),
- arraysize(expected))));
+ decrypter.DecryptPacket(
+ 0, "hello world!",
+ StringPiece(reinterpret_cast<const char*>(expected),
+ arraysize(expected))));
ASSERT_FALSE(decrypted.get());
}
diff --git a/net/quic/crypto/null_encrypter.cc b/net/quic/crypto/null_encrypter.cc
index b563107..22370ba 100644
--- a/net/quic/crypto/null_encrypter.cc
+++ b/net/quic/crypto/null_encrypter.cc
@@ -21,18 +21,27 @@ bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
return nonce_prefix.empty();
}
-QuicData* NullEncrypter::Encrypt(QuicPacketSequenceNumber /*sequence_number*/,
- StringPiece associated_data,
- StringPiece plaintext) {
- // TODO(rch): avoid buffer copy here
+bool NullEncrypter::Encrypt(
+ StringPiece /*nonce*/,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ unsigned char* output) {
string buffer = associated_data.as_string();
plaintext.AppendToString(&buffer);
uint128 hash = QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length());
- QuicDataWriter writer(plaintext.length() + kHashSize);
- writer.WriteUInt128(hash);
- writer.WriteBytes(plaintext.data(), plaintext.length());
- size_t len = writer.length();
- return new QuicData(writer.take(), len, true);
+ memcpy(output, &hash, sizeof(hash));
+ memcpy(output + sizeof(hash), plaintext.data(), plaintext.size());
+ return true;
+}
+
+QuicData* NullEncrypter::EncryptPacket(
+ QuicPacketSequenceNumber /*sequence_number*/,
+ StringPiece associated_data,
+ StringPiece plaintext) {
+ const size_t len = plaintext.size() + sizeof(uint128);
+ uint8* buffer = new uint8[len];
+ Encrypt(StringPiece(), associated_data, plaintext, buffer);
+ return new QuicData(reinterpret_cast<char*>(buffer), len, true);
}
size_t NullEncrypter::GetKeySize() const {
diff --git a/net/quic/crypto/null_encrypter.h b/net/quic/crypto/null_encrypter.h
index c452348..ed05e1f 100644
--- a/net/quic/crypto/null_encrypter.h
+++ b/net/quic/crypto/null_encrypter.h
@@ -21,9 +21,13 @@ class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter {
// QuicEncrypter implementation
virtual bool SetKey(base::StringPiece key) OVERRIDE;
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE;
- virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number,
- base::StringPiece associated_data,
- base::StringPiece plaintext) OVERRIDE;
+ virtual bool Encrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ unsigned char* output) OVERRIDE;
+ virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext) OVERRIDE;
virtual size_t GetKeySize() const OVERRIDE;
virtual size_t GetNoncePrefixSize() const OVERRIDE;
virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE;
diff --git a/net/quic/crypto/null_encrypter_test.cc b/net/quic/crypto/null_encrypter_test.cc
index df9bcdc..e1e6834 100644
--- a/net/quic/crypto/null_encrypter_test.cc
+++ b/net/quic/crypto/null_encrypter_test.cc
@@ -22,8 +22,8 @@ TEST(NullEncrypterTest, Encrypt) {
'b', 'y', 'e', '!',
};
NullEncrypter encrypter;
- scoped_ptr<QuicData> encrypted(encrypter.Encrypt(0, "hello world!",
- "goodbye!"));
+ scoped_ptr<QuicData> encrypted(encrypter.EncryptPacket(0, "hello world!",
+ "goodbye!"));
ASSERT_TRUE(encrypted.get());
test::CompareCharArraysWithHexError(
"encrypted data", encrypted->data(), encrypted->length(),
diff --git a/net/quic/crypto/p256_key_exchange_nss.cc b/net/quic/crypto/p256_key_exchange_nss.cc
index eff2028..c1de42e 100644
--- a/net/quic/crypto/p256_key_exchange_nss.cc
+++ b/net/quic/crypto/p256_key_exchange_nss.cc
@@ -7,6 +7,10 @@
#include "base/logging.h"
#include "base/sys_byteorder.h"
+using base::StringPiece;
+using std::string;
+using std::vector;
+
namespace net {
namespace {
@@ -17,9 +21,9 @@ namespace {
// use the same approach.
const char kExportPassword[] = "";
-// Convert StringPiece to vector of uint8
-static std::vector<uint8> StringPieceToVector(base::StringPiece piece) {
- return std::vector<uint8>(piece.data(), piece.data() + piece.length());
+// Convert StringPiece to vector of uint8.
+static vector<uint8> StringPieceToVector(StringPiece piece) {
+ return vector<uint8>(piece.data(), piece.data() + piece.length());
}
} // namespace
@@ -34,9 +38,9 @@ P256KeyExchange::~P256KeyExchange() {
}
// static
-P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
+P256KeyExchange* P256KeyExchange::New(StringPiece key) {
if (key.size() < 2) {
- DLOG(INFO) << "Key pair is too small";
+ DLOG(INFO) << "Key pair is too small.";
return NULL;
}
@@ -45,18 +49,18 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
(static_cast<size_t>(data[1]) << 8);
key.remove_prefix(2);
if (key.size() < size) {
- DLOG(INFO) << "Key pair does not contain key material";
+ DLOG(INFO) << "Key pair does not contain key material.";
return NULL;
}
- base::StringPiece private_piece(key.data(), size);
+ StringPiece private_piece(key.data(), size);
key.remove_prefix(size);
if (key.empty()) {
- DLOG(INFO) << "Key pair does not contain public key";
+ DLOG(INFO) << "Key pair does not contain public key.";
return NULL;
}
- base::StringPiece public_piece(key);
+ StringPiece public_piece(key);
scoped_ptr<crypto::ECPrivateKey> key_pair(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
@@ -66,7 +70,7 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
StringPieceToVector(public_piece)));
if (!key_pair.get()) {
- DLOG(INFO) << "Can't decrypt private key";
+ DLOG(INFO) << "Can't decrypt private key.";
return NULL;
}
@@ -76,14 +80,14 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
public_key->u.ec.publicValue.len != kUncompressedP256PointBytes ||
!public_key->u.ec.publicValue.data ||
public_key->u.ec.publicValue.data[0] != kUncompressedECPointForm) {
- DLOG(INFO) << "Key is invalid";
+ DLOG(INFO) << "Key is invalid.";
return NULL;
}
// Ensure that the key is using the correct curve, i.e., NIST P-256.
const SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
if (!oid_data) {
- DLOG(INFO) << "Can't get P-256's OID";
+ DLOG(INFO) << "Can't get P-256's OID.";
return NULL;
}
@@ -93,7 +97,7 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
public_key->u.ec.DEREncodedParams.data[1] != oid_data->oid.len ||
memcmp(public_key->u.ec.DEREncodedParams.data + 2,
oid_data->oid.data, oid_data->oid.len) != 0) {
- DLOG(INFO) << "Key is invalid";
+ DLOG(INFO) << "Key is invalid.";
}
return new P256KeyExchange(key_pair.release(),
@@ -101,29 +105,29 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
}
// static
-std::string P256KeyExchange::NewPrivateKey() {
+string P256KeyExchange::NewPrivateKey() {
scoped_ptr<crypto::ECPrivateKey> key_pair(crypto::ECPrivateKey::Create());
if (!key_pair.get()) {
- DLOG(INFO) << "Can't generate new key pair";
- return std::string();
+ DLOG(INFO) << "Can't generate new key pair.";
+ return string();
}
- std::vector<uint8> private_key;
+ vector<uint8> private_key;
if (!key_pair->ExportEncryptedPrivateKey(kExportPassword,
1 /* iteration */,
&private_key)) {
- DLOG(INFO) << "Can't export private key";
- return std::string();
+ DLOG(INFO) << "Can't export private key.";
+ return string();
}
// NSS lacks the ability to import an ECC private key without
// also importing the public key, so it is necessary to also
// store the public key.
- std::vector<uint8> public_key;
+ vector<uint8> public_key;
if (!key_pair->ExportPublicKey(&public_key)) {
- DLOG(INFO) << "Can't export public key";
- return std::string();
+ DLOG(INFO) << "Can't export public key.";
+ return string();
}
// TODO(thaidn): determine how large encrypted private key can be
@@ -131,7 +135,7 @@ std::string P256KeyExchange::NewPrivateKey() {
const size_t result_size = sizeof(private_key_size) +
private_key_size +
public_key.size();
- std::vector<char> result(result_size);
+ vector<char> result(result_size);
char* resultp = &result[0];
// Export the key string.
// The first two bytes are the private key's size in little endian.
@@ -142,15 +146,15 @@ std::string P256KeyExchange::NewPrivateKey() {
resultp += private_key.size();
memcpy(resultp, &public_key[0], public_key.size());
- return std::string(&result[0], result_size);
+ return string(&result[0], result_size);
}
bool P256KeyExchange::CalculateSharedKey(
- const base::StringPiece& peer_public_value,
- std::string* out_result) const {
+ const StringPiece& peer_public_value,
+ string* out_result) const {
if (peer_public_value.size() != kUncompressedP256PointBytes ||
peer_public_value[0] != kUncompressedECPointForm) {
- DLOG(INFO) << "Peer public value is invalid";
+ DLOG(INFO) << "Peer public value is invalid.";
return false;
}
@@ -194,18 +198,18 @@ bool P256KeyExchange::CalculateSharedKey(
NULL));
if (!premaster_secret.get()) {
- DLOG(INFO) << "Can't derive ECDH shared key";
+ DLOG(INFO) << "Can't derive ECDH shared key.";
return false;
}
if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) {
- DLOG(INFO) << "Can't extract raw ECDH shared key";
+ DLOG(INFO) << "Can't extract raw ECDH shared key.";
return false;
}
SECItem* key_data = PK11_GetKeyData(premaster_secret.get());
if (!key_data || !key_data->data || key_data->len != kP256FieldBytes) {
- DLOG(INFO) << "ECDH shared key is invalid";
+ DLOG(INFO) << "ECDH shared key is invalid.";
return false;
}
@@ -213,9 +217,9 @@ bool P256KeyExchange::CalculateSharedKey(
return true;
}
-base::StringPiece P256KeyExchange::public_value() const {
- return base::StringPiece(reinterpret_cast<const char*>(public_key_),
- sizeof(public_key_));
+StringPiece P256KeyExchange::public_value() const {
+ return StringPiece(reinterpret_cast<const char*>(public_key_),
+ sizeof(public_key_));
}
CryptoTag P256KeyExchange::tag() const {
diff --git a/net/quic/crypto/p256_key_exchange_openssl.cc b/net/quic/crypto/p256_key_exchange_openssl.cc
index ae7f30e..051adcf 100644
--- a/net/quic/crypto/p256_key_exchange_openssl.cc
+++ b/net/quic/crypto/p256_key_exchange_openssl.cc
@@ -10,6 +10,9 @@
#include "base/logging.h"
+using base::StringPiece;
+using std::string;
+
namespace net {
P256KeyExchange::P256KeyExchange(EC_KEY* private_key, const uint8* public_key)
@@ -21,7 +24,7 @@ P256KeyExchange::~P256KeyExchange() {
}
// static
-P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
+P256KeyExchange* P256KeyExchange::New(StringPiece key) {
if (key.empty()) {
DLOG(INFO) << "Private key is empty";
return NULL;
@@ -31,19 +34,19 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> private_key(
d2i_ECPrivateKey(NULL, &keyp, key.size()));
if (!private_key.get() || !EC_KEY_check_key(private_key.get())) {
- DLOG(INFO) << "Private key is invalid";
+ DLOG(INFO) << "Private key is invalid.";
return NULL;
}
uint8 public_key[kUncompressedP256PointBytes];
if (EC_POINT_point2oct(
- EC_KEY_get0_group(private_key.get()),
- EC_KEY_get0_public_key(private_key.get()),
- POINT_CONVERSION_UNCOMPRESSED,
- public_key,
- sizeof(public_key),
- NULL) != sizeof(public_key)) {
- DLOG(INFO) << "Can't get public key";
+ EC_KEY_get0_group(private_key.get()),
+ EC_KEY_get0_public_key(private_key.get()),
+ POINT_CONVERSION_UNCOMPRESSED,
+ public_key,
+ sizeof(public_key),
+ NULL) != sizeof(public_key)) {
+ DLOG(INFO) << "Can't get public key.";
return NULL;
}
@@ -51,38 +54,38 @@ P256KeyExchange* P256KeyExchange::New(base::StringPiece key) {
}
// static
-std::string P256KeyExchange::NewPrivateKey() {
+string P256KeyExchange::NewPrivateKey() {
crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> key(
EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
if (!key.get() || !EC_KEY_generate_key(key.get())) {
- DLOG(INFO) << "Can't generate a new private key";
- return std::string();
+ DLOG(INFO) << "Can't generate a new private key.";
+ return string();
}
int key_len = i2d_ECPrivateKey(key.get(), NULL);
if (key_len <= 0) {
DLOG(INFO) << "Can't convert private key to string";
- return std::string();
+ return string();
}
scoped_ptr<uint8[]> private_key(new uint8[key_len]);
uint8* keyp = private_key.get();
if (!i2d_ECPrivateKey(key.get(), &keyp)) {
- DLOG(INFO) << "Can't convert private key to string";
- return std::string();
+ DLOG(INFO) << "Can't convert private key to string.";
+ return string();
}
- return std::string(reinterpret_cast<char*>(private_key.get()), key_len);
+ return string(reinterpret_cast<char*>(private_key.get()), key_len);
}
bool P256KeyExchange::CalculateSharedKey(
- const base::StringPiece& peer_public_value,
- std::string* out_result) const {
+ const StringPiece& peer_public_value,
+ string* out_result) const {
if (peer_public_value.size() != kUncompressedP256PointBytes) {
DLOG(INFO) << "Peer public value is invalid";
return false;
}
crypto::ScopedOpenSSL<EC_POINT, EC_POINT_free> point(
- EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
+ EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
if (!point.get() ||
!EC_POINT_oct2point( /* also test if point is on curve */
EC_KEY_get0_group(private_key_.get()),
@@ -90,7 +93,7 @@ bool P256KeyExchange::CalculateSharedKey(
reinterpret_cast<const uint8*>(peer_public_value.data()),
peer_public_value.size(),
NULL)) {
- DLOG(INFO) << "Can't convert peer public value to curve point";
+ DLOG(INFO) << "Can't convert peer public value to curve point.";
return false;
}
@@ -101,7 +104,7 @@ bool P256KeyExchange::CalculateSharedKey(
point.get(),
private_key_.get(),
NULL) != sizeof(result)) {
- DLOG(INFO) << "Can't compute ECDH shared key";
+ DLOG(INFO) << "Can't compute ECDH shared key.";
return false;
}
@@ -109,9 +112,9 @@ bool P256KeyExchange::CalculateSharedKey(
return true;
}
-base::StringPiece P256KeyExchange::public_value() const {
- return base::StringPiece(reinterpret_cast<const char*>(public_key_),
- sizeof(public_key_));
+StringPiece P256KeyExchange::public_value() const {
+ return StringPiece(reinterpret_cast<const char*>(public_key_),
+ sizeof(public_key_));
}
CryptoTag P256KeyExchange::tag() const {
diff --git a/net/quic/crypto/p256_key_exchange_test.cc b/net/quic/crypto/p256_key_exchange_test.cc
index 799c853..8ea59da 100644
--- a/net/quic/crypto/p256_key_exchange_test.cc
+++ b/net/quic/crypto/p256_key_exchange_test.cc
@@ -7,6 +7,8 @@
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
+using std::string;
+
namespace net {
namespace test {
@@ -14,8 +16,8 @@ namespace test {
// parties end up with the same key.
TEST(P256KeyExchange, SharedKey) {
for (int i = 0; i < 5; i++) {
- std::string alice_private(P256KeyExchange::NewPrivateKey());
- std::string bob_private(P256KeyExchange::NewPrivateKey());
+ string alice_private(P256KeyExchange::NewPrivateKey());
+ string bob_private(P256KeyExchange::NewPrivateKey());
ASSERT_FALSE(alice_private.empty());
ASSERT_FALSE(bob_private.empty());
diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h
index c648668..349425a 100644
--- a/net/quic/crypto/quic_decrypter.h
+++ b/net/quic/crypto/quic_decrypter.h
@@ -40,15 +40,27 @@ class NET_EXPORT_PRIVATE QuicDecrypter {
// packet sequence number, even when retransmitting a lost packet.
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
+ // Decrypt authenticates |associated_data| and |ciphertext| and then decrypts
+ // |ciphertext| into |output|, using |nonce|. |nonce| must be 8 bytes longer
+ // than the nonce prefix length returned by GetNoncePrefixSize() (of the
+ // encrypter). |output| must be as long as |ciphertext| on entry and, on
+ // successful return, the true length of the plaintext will be written to
+ // |*output_length|.
+ virtual bool Decrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) = 0;
+
// Returns a newly created QuicData object containing the decrypted
// |ciphertext| or NULL if there is an error. |sequence_number| is
// appended to the |nonce_prefix| value provided in SetNoncePrefix()
// to form the nonce.
- // TODO(wtc): add a way for Decrypt to report decryption failure due
+ // TODO(wtc): add a way for DecryptPacket to report decryption failure due
// to non-authentic inputs, as opposed to other reasons for failure.
- virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number,
- base::StringPiece associated_data,
- base::StringPiece ciphertext) = 0;
+ virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext) = 0;
// For use by unit tests only.
virtual base::StringPiece GetKey() const = 0;
diff --git a/net/quic/crypto/quic_encrypter.h b/net/quic/crypto/quic_encrypter.h
index 013aff1..86d0e3a 100644
--- a/net/quic/crypto/quic_encrypter.h
+++ b/net/quic/crypto/quic_encrypter.h
@@ -40,13 +40,23 @@ class NET_EXPORT_PRIVATE QuicEncrypter {
// packet sequence number, even when retransmitting a lost packet.
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
+ // Encrypt encrypts |plaintext| and writes the ciphertext, plus a MAC over
+ // both |associated_data| and |plaintext| to |output|, using |nonce| as the
+ // nonce. |nonce| must be |8+GetNoncePrefixSize()| bytes long and |output|
+ // must point to a buffer that is at least
+ // |GetCiphertextSize(plaintext.size()| bytes long.
+ virtual bool Encrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ unsigned char* output) = 0;
+
// Returns a newly created QuicData object containing the encrypted
// |plaintext| as well as a MAC over both |plaintext| and |associated_data|,
// or NULL if there is an error. |sequence_number| is appended to the
// |nonce_prefix| value provided in SetNoncePrefix() to form the nonce.
- virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number,
- base::StringPiece associated_data,
- base::StringPiece plaintext) = 0;
+ virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext) = 0;
// GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes
// of key material needs to be derived from the master secret.
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index d87f903..1ca0080 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -10,6 +10,7 @@
#include "net/base/capturing_net_log.h"
#include "net/base/net_log_unittest.h"
#include "net/base/test_completion_callback.h"
+#include "net/quic/crypto/aes_128_gcm_encrypter.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
@@ -51,10 +52,20 @@ class QuicClientSessionTest : public ::testing::Test {
};
TEST_F(QuicClientSessionTest, CryptoConnect) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
}
TEST_F(QuicClientSessionTest, MaxNumConnections) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
std::vector<QuicReliableClientStream*> streams;
@@ -85,6 +96,11 @@ TEST_F(QuicClientSessionTest, GoAwayReceived) {
}
TEST_F(QuicClientSessionTest, Logging) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
// TODO(rch): Add some helper methods to simplify packet creation in tests.
@@ -92,10 +108,11 @@ TEST_F(QuicClientSessionTest, Logging) {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false);
QuicRstStreamFrame frame;
frame.stream_id = 2;
- frame.error_code = QUIC_CONNECTION_TIMED_OUT;
+ frame.error_code = QUIC_STREAM_CONNECTION_ERROR;
frame.error_details = "doh!";
QuicFrames frames;
@@ -143,7 +160,7 @@ TEST_F(QuicClientSessionTest, Logging) {
EXPECT_EQ(frame.stream_id, static_cast<QuicStreamId>(stream_id));
int error_code;
ASSERT_TRUE(entries[pos].GetIntegerValue("error_code", &error_code));
- EXPECT_EQ(frame.error_code, static_cast<QuicErrorCode>(error_code));
+ EXPECT_EQ(frame.error_code, static_cast<QuicRstStreamErrorCode>(error_code));
std::string details;
ASSERT_TRUE(entries[pos].GetStringValue("details", &details));
EXPECT_EQ(frame.error_details, details);
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 5bb15c6..6449ee1 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -64,13 +64,6 @@ const int kMaxPacketsToSerializeAtOnce = 6;
// eventually cede. 10 is arbitrary.
const int kMaxPacketsPerRetransmissionAlarm = 10;
-// Named constant for WritePacket()
-const bool kForce = true;
-// Named constant for CanWrite().
-const bool kIsRetransmission = true;
-// Named constant for WritePacket.
-const bool kHasRetransmittableData = true;
-
bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a;
return delta <= kMaxPacketGap;
@@ -78,6 +71,8 @@ bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
} // namespace
+#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
+
QuicConnection::QuicConnection(QuicGuid guid,
IPEndPoint address,
QuicConnectionHelperInterface* helper,
@@ -86,6 +81,7 @@ QuicConnection::QuicConnection(QuicGuid guid,
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ helper->GetClock()->ApproximateNow(),
is_server),
clock_(helper->GetClock()),
random_generator_(helper->GetRandomGenerator()),
@@ -116,7 +112,6 @@ QuicConnection::QuicConnection(QuicGuid guid,
helper_->SetTimeoutAlarm(timeout_);
framer_.set_visitor(this);
framer_.set_entropy_calculator(&entropy_manager_);
- memset(&last_header_, 0, sizeof(last_header_));
outgoing_ack_.sent_info.least_unacked = 0;
outgoing_ack_.sent_info.entropy_hash = 0;
outgoing_ack_.received_info.largest_observed = 0;
@@ -125,7 +120,7 @@ QuicConnection::QuicConnection(QuicGuid guid,
/*
if (FLAGS_fake_packet_loss_percentage > 0) {
int32 seed = RandomBase::WeakSeed32();
- LOG(INFO) << "Seeding packet loss with " << seed;
+ LOG(INFO) << ENDPOINT << "Seeding packet loss with " << seed;
random_.reset(new MTRandom(seed));
}
*/
@@ -163,7 +158,7 @@ void QuicConnection::OnPacket() {
// 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();
+ << time_of_last_received_packet_.ToDebuggingValue();
// TODO(alyssar, rch) handle migration!
self_address_ = last_self_address_;
@@ -275,14 +270,14 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
++stats_.packets_dropped;
if (header.public_header.guid != guid_) {
- DLOG(INFO) << "Ignoring packet from unexpected GUID: "
+ DLOG(INFO) << ENDPOINT << "Ignoring packet from unexpected GUID: "
<< header.public_header.guid << " instead of " << guid_;
return false;
}
if (!Near(header.packet_sequence_number,
last_header_.packet_sequence_number)) {
- DLOG(INFO) << "Packet " << header.packet_sequence_number
+ DLOG(INFO) << ENDPOINT << "Packet " << header.packet_sequence_number
<< " out of bounds. Discarding";
// TODO(alyssar) close the connection entirely.
return false;
@@ -298,8 +293,8 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
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.";
+ DLOG(WARNING) << ENDPOINT << "Got packet without version flag before "
+ << "version negotiated.";
// Packets should have the version flag till version negotiation is
// done.
CloseConnection(QUIC_INVALID_VERSION, false);
@@ -346,7 +341,7 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
DVLOG(1) << "OnAckFrame: " << incoming_ack;
if (last_header_.packet_sequence_number <= largest_seen_packet_with_ack_) {
- DLOG(INFO) << "Received an old ack frame: ignoring";
+ DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
return;
}
largest_seen_packet_with_ack_ = last_header_.packet_sequence_number;
@@ -376,10 +371,9 @@ 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, has_retransmittable_data);
+ time_of_last_received_packet_, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA);
if (delay.IsZero()) {
helper_->UnregisterSendAlarmIfRegistered();
if (!write_blocked_) {
@@ -402,7 +396,7 @@ void QuicConnection::OnCongestionFeedbackFrame(
bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (incoming_ack.received_info.largest_observed >
packet_creator_.sequence_number()) {
- DLOG(ERROR) << "Client observed unsent packet:"
+ DLOG(ERROR) << ENDPOINT << "Peer's observed unsent packet:"
<< incoming_ack.received_info.largest_observed << " vs "
<< packet_creator_.sequence_number();
// We got an error for data we have not sent. Error out.
@@ -411,7 +405,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (incoming_ack.received_info.largest_observed <
peer_largest_observed_packet_) {
- DLOG(ERROR) << "Client's largest_observed packet decreased:"
+ DLOG(ERROR) << ENDPOINT << "Peer's largest_observed packet decreased:"
<< incoming_ack.received_info.largest_observed << " vs "
<< peer_largest_observed_packet_;
// We got an error for data we have not sent. Error out.
@@ -424,7 +418,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
GetMaxUnackedPackets(last_header_.public_header.version_flag));
if (incoming_ack.sent_info.least_unacked < peer_least_packet_awaiting_ack_) {
- DLOG(ERROR) << "Client sent low least_unacked: "
+ DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
<< incoming_ack.sent_info.least_unacked
<< " vs " << peer_least_packet_awaiting_ack_;
// We never process old ack frames, so this number should only increase.
@@ -433,7 +427,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (incoming_ack.sent_info.least_unacked >
last_header_.packet_sequence_number) {
- DLOG(ERROR) << "Client sent least_unacked:"
+ DLOG(ERROR) << ENDPOINT << "Peer sent least_unacked:"
<< incoming_ack.sent_info.least_unacked
<< " greater than the enclosing packet sequence number:"
<< last_header_.packet_sequence_number;
@@ -443,7 +437,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (!incoming_ack.received_info.missing_packets.empty() &&
*incoming_ack.received_info.missing_packets.rbegin() >
incoming_ack.received_info.largest_observed) {
- DLOG(ERROR) << "Client sent missing packet: "
+ DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
<< *incoming_ack.received_info.missing_packets.rbegin()
<< " greater than largest observed: "
<< incoming_ack.received_info.largest_observed;
@@ -453,7 +447,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (!incoming_ack.received_info.missing_packets.empty() &&
*incoming_ack.received_info.missing_packets.begin() <
least_packet_awaited_by_peer_) {
- DLOG(ERROR) << "Client sent missing packet: "
+ DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
<< *incoming_ack.received_info.missing_packets.begin()
<< "smaller than least_packet_awaited_by_peer_: "
<< least_packet_awaited_by_peer_;
@@ -464,7 +458,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
incoming_ack.received_info.largest_observed,
incoming_ack.received_info.missing_packets,
incoming_ack.received_info.entropy_hash)) {
- DLOG(ERROR) << "Client sent invalid entropy.";
+ DLOG(ERROR) << ENDPOINT << "Peer sent invalid entropy.";
return false;
}
@@ -589,7 +583,7 @@ void QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
debug_visitor_->OnRstStreamFrame(frame);
}
DLOG(INFO) << "Stream reset with error "
- << QuicUtils::ErrorToString(frame.error_code);
+ << QuicUtils::StreamErrorToString(frame.error_code);
visitor_->OnRstStream(frame);
}
@@ -598,13 +592,13 @@ void QuicConnection::OnConnectionCloseFrame(
if (debug_visitor_) {
debug_visitor_->OnConnectionCloseFrame(frame);
}
- DLOG(INFO) << "Connection closed with error "
+ DLOG(INFO) << ENDPOINT << "Connection closed with error "
<< QuicUtils::ErrorToString(frame.error_code);
CloseConnection(frame.error_code, true);
}
void QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
- DLOG(INFO) << "Go away received with error "
+ DLOG(INFO) << ENDPOINT << "Go away received with error "
<< QuicUtils::ErrorToString(frame.error_code)
<< " and reason:" << frame.reason_phrase;
visitor_->OnGoAway(frame);
@@ -614,15 +608,16 @@ void QuicConnection::OnPacketComplete() {
// TODO(satyamshekhar): Don't do anything if this packet closed the
// connection.
if (!last_packet_revived_) {
- DLOG(INFO) << "Got packet " << last_header_.packet_sequence_number
+ DLOG(INFO) << ENDPOINT << "Got packet "
+ << last_header_.packet_sequence_number
<< " with " << last_stream_frames_.size()
<< " stream frames for " << last_header_.public_header.guid;
congestion_manager_.RecordIncomingPacket(
last_size_, last_header_.packet_sequence_number,
time_of_last_received_packet_, last_packet_revived_);
} else {
- DLOG(INFO) << "Got revived packet with " << last_stream_frames_.size()
- << " frames.";
+ DLOG(INFO) << ENDPOINT << "Got revived packet with "
+ << last_stream_frames_.size() << " frames.";
}
if ((last_stream_frames_.empty() ||
@@ -673,7 +668,7 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
}
void QuicConnection::SendRstStream(QuicStreamId id,
- QuicErrorCode error) {
+ QuicRstStreamErrorCode error) {
packet_generator_.AddControlFrame(
QuicFrame(new QuicRstStreamFrame(id, error)));
}
@@ -716,14 +711,15 @@ 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.
- if (CanWrite(false, true)) {
+ if (CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) {
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 && CanWrite(false, true)) {
+ if (!write_blocked_ && !all_bytes_written &&
+ CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) {
// 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.
@@ -747,8 +743,8 @@ bool QuicConnection::WriteQueuedPackets() {
num_queued_packets = queued_packets_.size();
if (WritePacket(packet_iterator->sequence_number,
packet_iterator->packet,
- packet_iterator->has_retransmittable_data,
- !kForce)) {
+ packet_iterator->retransmittable,
+ NO_FORCE)) {
packet_iterator = queued_packets_.erase(packet_iterator);
} else {
// Continue, because some queued packets may still be writable.
@@ -761,7 +757,8 @@ bool QuicConnection::WriteQueuedPackets() {
}
void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) {
- DLOG(INFO) << "Recording received packet: " << header.packet_sequence_number;
+ DLOG(INFO) << ENDPOINT << "Recording received packet: "
+ << header.packet_sequence_number;
QuicPacketSequenceNumber sequence_number = header.packet_sequence_number;
DCHECK(IsAwaitingPacket(outgoing_ack_.received_info, sequence_number));
@@ -858,11 +855,11 @@ void QuicConnection::RetransmitPacket(
SendOrQueuePacket(serialized_packet.sequence_number,
serialized_packet.packet,
serialized_packet.entropy_hash,
- true);
+ HAS_RETRANSMITTABLE_DATA);
}
-bool QuicConnection::CanWrite(bool is_retransmission,
- bool has_retransmittable_data) {
+bool QuicConnection::CanWrite(Retransmission retransmission,
+ HasRetransmittableData retransmittable) {
// TODO(ianswett): If the packet is a retransmit, the current send alarm may
// be too long.
if (write_blocked_ || helper_->IsSendAlarmSet()) {
@@ -871,7 +868,7 @@ bool QuicConnection::CanWrite(bool is_retransmission,
QuicTime now = clock_->Now();
QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
- now, is_retransmission, has_retransmittable_data);
+ now, retransmission, retransmittable);
if (delay.IsInfinite()) {
// TODO(pwestin): should be false but trigger other bugs see b/8350327.
return true;
@@ -915,40 +912,42 @@ void QuicConnection::MaybeSetupRetransmission(
if (!handling_retransmission_timeout_) {
helper_->SetRetransmissionAlarm(retransmission_delay);
}
- // TODO(satyamshekhar): restore pacekt reordering with Ian's TODO in
+ // TODO(satyamshekhar): restore packet reordering with Ian's TODO in
// SendStreamData().
}
bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
- bool has_retransmittable_data,
- bool forced) {
+ HasRetransmittableData retransmittable,
+ Force forced) {
if (!connected_) {
- DLOG(INFO)
- << "Dropping packet to be sent since connection is disconnected.";
+ DLOG(INFO) << ENDPOINT
+ << "Not sending packet as connection is disconnected.";
delete packet;
// Returning true because we deleted the packet and the caller shouldn't
// delete it again.
return true;
}
- bool is_retransmission = IsRetransmission(sequence_number);
+ Retransmission retransmission = IsRetransmission(sequence_number) ?
+ IS_RETRANSMISSION : NOT_RETRANSMISSION;
// If we are not forced and we can't write, then simply return false;
- if (!forced && !CanWrite(is_retransmission, has_retransmittable_data)) {
+ if (forced == NO_FORCE && !CanWrite(retransmission, retransmittable)) {
return false;
}
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(sequence_number, *packet));
- DLOG(INFO) << "Sending packet number " << sequence_number << " : "
- << (packet->is_fec_packet() ? "FEC " :
- (has_retransmittable_data ? "data bearing " : " ack only "))
+ DLOG(INFO) << ENDPOINT << "Sending packet number " << sequence_number
+ << " : " << (packet->is_fec_packet() ? "FEC " :
+ (retransmittable == 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_ << " forced: " << (forced ? "yes" : "no");
+ << outgoing_ack_ << " forced: " << (forced == FORCE ? "yes" : "no");
int error;
QuicTime now = clock_->Now();
@@ -964,7 +963,7 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
return helper_->IsWriteBlockedDataBuffered();
}
time_of_last_sent_packet_ = now;
- DVLOG(1) << "time of last sent packet: " << now.ToMicroseconds();
+ DVLOG(1) << "time of last sent packet: " << now.ToDebuggingValue();
// TODO(wtc): Is it correct to continue if the write failed.
// Set the retransmit alarm only when we have sent the packet to the client
@@ -973,12 +972,12 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
MaybeSetupRetransmission(sequence_number);
congestion_manager_.SentPacket(sequence_number, now, packet->length(),
- is_retransmission);
+ retransmission);
stats_.bytes_sent += encrypted->length();
++stats_.packets_sent;
- if (is_retransmission) {
+ if (retransmission == IS_RETRANSMISSION) {
stats_.bytes_retransmitted += encrypted->length();
++stats_.packets_retransmitted;
}
@@ -1004,19 +1003,19 @@ bool QuicConnection::OnSerializedPacket(
return SendOrQueuePacket(serialized_packet.sequence_number,
serialized_packet.packet,
serialized_packet.entropy_hash,
- serialized_packet.retransmittable_frames != NULL);
+ serialized_packet.retransmittable_frames != NULL ?
+ HAS_RETRANSMITTABLE_DATA :
+ NO_RETRANSMITTABLE_DATA);
}
bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
- bool has_retransmittable_data) {
- entropy_manager_.RecordSentPacketEntropyHash(sequence_number,
- entropy_hash);
- if (!WritePacket(sequence_number, packet, has_retransmittable_data,
- !kForce)) {
+ HasRetransmittableData retransmittable) {
+ entropy_manager_.RecordSentPacketEntropyHash(sequence_number, entropy_hash);
+ if (!WritePacket(sequence_number, packet, retransmittable, NO_FORCE)) {
queued_packets_.push_back(QueuedPacket(sequence_number, packet,
- has_retransmittable_data));
+ retransmittable));
return false;
}
return true;
@@ -1085,7 +1084,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
}
retransmission_timeouts_.pop();
if (!MaybeRetransmitPacketForRTO(retransmission_info.sequence_number)) {
- DLOG(INFO) << "MaybeRetransmitPacketForRTO failed: "
+ DLOG(INFO) << ENDPOINT << "MaybeRetransmitPacketForRTO failed: "
<< "adding an extra delay for "
<< retransmission_info.sequence_number;
retransmission_info.scheduled_time = clock_->ApproximateNow().Add(
@@ -1097,7 +1096,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
handling_retransmission_timeout_ = false;
if (retransmission_timeouts_.empty()) {
- return QuicTime::FromMilliseconds(0);
+ return QuicTime::Zero();
}
// We have packets remaining. Return the absolute RTO of the oldest packet
@@ -1105,6 +1104,18 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
return retransmission_timeouts_.top().scheduled_time;
}
+void QuicConnection::ChangeEncrypter(QuicEncrypter* encrypter) {
+ framer_.set_encrypter(encrypter);
+}
+
+void QuicConnection::PushDecrypter(QuicDecrypter* decrypter) {
+ framer_.push_decrypter(decrypter);
+}
+
+void QuicConnection::PopDecrypter() {
+ framer_.pop_decrypter();
+}
+
void QuicConnection::MaybeProcessRevivedPacket() {
QuicFecGroup* group = GetFecGroup();
if (group == NULL || !group->CanRevive()) {
@@ -1150,8 +1161,8 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) {
void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
const string& details) {
- DLOG(INFO) << "Force closing with error " << QuicUtils::ErrorToString(error)
- << " (" << error << ")";
+ DLOG(INFO) << ENDPOINT << "Force closing with error "
+ << QuicUtils::ErrorToString(error) << " (" << error << ")";
QuicConnectionCloseFrame frame;
frame.error_code = error;
frame.error_details = details;
@@ -1168,8 +1179,9 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
WritePacket(serialized_packet.sequence_number,
serialized_packet.packet,
- serialized_packet.retransmittable_frames != NULL,
- kForce);
+ serialized_packet.retransmittable_frames != NULL ?
+ HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA,
+ FORCE);
}
void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error,
@@ -1186,7 +1198,8 @@ void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
void QuicConnection::SendGoAway(QuicErrorCode error,
QuicStreamId last_good_stream_id,
const string& reason) {
- DLOG(INFO) << "Going away with error " << QuicUtils::ErrorToString(error)
+ DLOG(INFO) << ENDPOINT << "Going away with error "
+ << QuicUtils::ErrorToString(error)
<< " (" << error << ")";
packet_generator_.AddControlFrame(
QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason)));
@@ -1223,8 +1236,8 @@ bool QuicConnection::CheckForTimeout() {
time_of_last_sent_packet_);
QuicTime::Delta delta = now.Subtract(time_of_last_packet);
- DVLOG(1) << "last packet " << time_of_last_packet.ToMicroseconds()
- << " now:" << now.ToMicroseconds()
+ DVLOG(1) << "last packet " << time_of_last_packet.ToDebuggingValue()
+ << " now:" << now.ToDebuggingValue()
<< " delta:" << delta.ToMicroseconds();
if (delta >= timeout_) {
SendConnectionClose(QUIC_CONNECTION_TIMED_OUT);
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 3c3c00d..d097acb 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -66,7 +66,8 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// Called when the connection is closed either locally by the framer, or
// remotely by the peer.
- virtual void ConnectionClose(QuicErrorCode error, bool from_peer) = 0;
+ virtual void ConnectionClose(QuicErrorCode error,
+ bool from_peer) = 0;
// Called when packets are acked by the peer.
virtual void OnAck(const SequenceNumberSet& acked_packets) = 0;
@@ -197,6 +198,11 @@ class NET_EXPORT_PRIVATE QuicConnection
public QuicBlockedWriterInterface,
public QuicPacketGenerator::DelegateInterface {
public:
+ enum Force {
+ NO_FORCE,
+ FORCE
+ };
+
// Constructs a new QuicConnection for the specified |guid| and |address|.
// |helper| will be owned by this connection.
QuicConnection(QuicGuid guid,
@@ -218,7 +224,7 @@ class NET_EXPORT_PRIVATE QuicConnection
bool fin);
// Send a stream reset frame to the peer.
virtual void SendRstStream(QuicStreamId id,
- QuicErrorCode error);
+ QuicRstStreamErrorCode error);
// Sends the connection close packet without affecting the state of the
// connection. This should only be called if the session is actively being
@@ -280,6 +286,9 @@ class NET_EXPORT_PRIVATE QuicConnection
virtual void OnPacketComplete() OVERRIDE;
// QuicPacketGenerator::DelegateInterface
+ virtual bool CanWrite(
+ Retransmission is_retransmission,
+ HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual QuicAckFrame* CreateAckFrame() OVERRIDE;
virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() OVERRIDE;
virtual bool OnSerializedPacket(const SerializedPacket& packet) OVERRIDE;
@@ -336,6 +345,27 @@ class NET_EXPORT_PRIVATE QuicConnection
// should next fire, or 0 if no retransmission alarm should be set.
QuicTime OnRetransmissionTimeout();
+ // Changes the encrypter used by |framer_| to |encrypter|. The function
+ // takes ownership of |encrypter|.
+ void ChangeEncrypter(QuicEncrypter* encrypter);
+
+ // Sets the primary decrypter used by |framer_| to |decrypter|. The current
+ // primary decrypter becomes the backup decrypter. The function takes
+ // ownership of |decrypter|.
+ //
+ // After the function is called, |framer_| starts to decrypt packets using
+ // |decrypter|. If the decryption fails, |framer_| falls back on the backup
+ // decrypter. Eventually |framer_| determines that the backup decrypter is
+ // no longer needed and deletes it.
+ void PushDecrypter(QuicDecrypter* decrypter);
+
+ // Deletes the current primary decrypter and promotes the backup decrypter
+ // to be the primary decrypter.
+ void PopDecrypter();
+
+ QuicDecrypter* decrypter() const { return framer_.decrypter(); }
+ QuicEncrypter* encrypter() const { return framer_.encrypter(); }
+
protected:
// Deletes all missing packets before least unacked. The connection won't
// process any packets with sequence number before |least_unacked| that it
@@ -353,7 +383,7 @@ class NET_EXPORT_PRIVATE QuicConnection
virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
- bool has_retransmittable_data);
+ HasRetransmittableData retransmittable);
// Writes the given packet to socket with the help of helper. Returns true on
// successful write, false otherwise. However, behavior is undefined if
@@ -361,12 +391,12 @@ class NET_EXPORT_PRIVATE QuicConnection
// value of true implies that |packet| has been deleted and should not be
// accessed. If |sequence_number| is present in |retransmission_map_| it also
// sets up retransmission of the given packet in case of successful write. If
- // |force| is true, then the packet will be sent immediately and the send
+ // |force| is FORCE, then the packet will be sent immediately and the send
// scheduler will not be consulted.
bool WritePacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
- bool has_retransmittable_data,
- bool force);
+ HasRetransmittableData retransmittable,
+ Force force);
// Make sure an ack we got from our peer is sane.
bool ValidateAckFrame(const QuicAckFrame& incoming_ack);
@@ -390,15 +420,15 @@ class NET_EXPORT_PRIVATE QuicConnection
struct QueuedPacket {
QueuedPacket(QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
- bool has_retransmittable_data)
+ HasRetransmittableData retransmittable)
: sequence_number(sequence_number),
packet(packet),
- has_retransmittable_data(has_retransmittable_data) {
+ retransmittable(retransmittable) {
}
QuicPacketSequenceNumber sequence_number;
QuicPacket* packet;
- bool has_retransmittable_data;
+ HasRetransmittableData retransmittable;
};
struct RetransmissionInfo {
@@ -444,10 +474,6 @@ class NET_EXPORT_PRIVATE QuicConnection
// 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,
- bool has_retransmittable_data) OVERRIDE;
-
void MaybeSetupRetransmission(QuicPacketSequenceNumber sequence_number);
bool IsRetransmission(QuicPacketSequenceNumber sequence_number);
void RetransmitAllUnackedPackets();
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 08743d05..2b2c633 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -62,6 +62,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false),
net_log_(BoundNetLog()),
frame_(1, false, 0, kData) {
@@ -251,7 +252,7 @@ TEST_F(QuicConnectionHelperTest, SetAckAlarm) {
EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
runner_->GetPostedTasks()[1].delay);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
runner_->RunNextTask();
EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.ApproximateNow());
}
@@ -295,7 +296,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));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
runner_->RunNextTask();
EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.ApproximateNow());
}
@@ -309,11 +310,11 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) {
QuicTime::Delta::FromMilliseconds(500);
QuicTime start = clock_.ApproximateNow();
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _));
// Send a packet.
connection_->SendStreamData(1, kData, 0, false);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, true));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION));
// Since no ack was received, the retransmission alarm will fire and
// retransmit it.
runner_->RunNextTask();
@@ -332,12 +333,13 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
EXPECT_EQ(base::TimeDelta::FromMicroseconds(kDefaultTimeoutUs),
runner_->GetPostedTasks().front().delay);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
// After we run the next task, we should close the connection.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
runner_->RunNextTask();
- EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs),
+ EXPECT_EQ(QuicTime::Zero().Add(
+ QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)),
clock_.ApproximateNow());
EXPECT_FALSE(connection_->connected());
EXPECT_TRUE(AtEof());
@@ -372,12 +374,12 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
Initialize();
EXPECT_TRUE(connection_->connected());
- EXPECT_EQ(0u, clock_.ApproximateNow().ToMicroseconds());
+ EXPECT_EQ(0u, clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds());
// 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));
+ EXPECT_EQ(5000u, clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
// Send an ack so we don't set the retransmission alarm.
connection_->SendAck();
@@ -386,15 +388,17 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// network event at t=5000. The alarm will reregister.
runner_->RunNextTask();
- EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs),
+ EXPECT_EQ(QuicTime::Zero().Add(
+ QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)),
clock_.ApproximateNow());
EXPECT_TRUE(connection_->connected());
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION));
runner_->RunNextTask();
- EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.ApproximateNow().ToMicroseconds());
+ EXPECT_EQ(kDefaultTimeoutUs + 5000,
+ clock_.NowAsDeltaSinceUnixEpoch().ToMicroseconds());
EXPECT_FALSE(connection_->connected());
EXPECT_TRUE(AtEof());
}
@@ -404,18 +408,20 @@ 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(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ EXPECT_CALL(
+ *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
+ testing::Return(QuicTime::Delta::FromMicroseconds(1)));
QuicPacket* packet = ConstructRawDataPacket(1);
- connection_->SendOrQueuePacket(1, packet, 0, kHasData);
- EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false));
+ connection_->SendOrQueuePacket(1, packet, 0, HAS_RETRANSMITTABLE_DATA);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
EXPECT_EQ(1u, connection_->NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false, _)).WillRepeatedly(
- testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(
+ *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly(
+ testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true));
runner_->RunNextTask();
EXPECT_EQ(0u, connection_->NumQueuedPackets());
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 3679d1ce3..5b13c92 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -89,7 +89,7 @@ Value* NetLogQuicCongestionFeedbackFrameCallback(
frame->inter_arrival.received_packet_times.begin();
it != frame->inter_arrival.received_packet_times.end(); ++it) {
std::string value = base::Uint64ToString(it->first) + "@" +
- base::Uint64ToString(it->second.ToMilliseconds());
+ base::Uint64ToString(it->second.ToDebuggingValue());
received->Append(new base::StringValue(value));
}
break;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 72322ff..f2811f3 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -44,9 +44,6 @@ const char data1[] = "foo";
const char data2[] = "bar";
const bool kFin = true;
-const bool kForce = true;
-const bool kIsRetransmission = true;
-const bool kHasData = true;
const bool kEntropyFlag = true;
const bool kFecEntropyFlag = true;
const QuicPacketEntropyHash kTestEntropyHash = 76;
@@ -81,7 +78,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
: clock_(clock),
random_generator_(random_generator),
retransmission_alarm_(QuicTime::Zero()),
- send_alarm_(QuicTime::FromMilliseconds(-1)),
+ send_alarm_(QuicTime::Zero().Subtract(
+ QuicTime::Delta::FromMilliseconds(1))),
timeout_alarm_(QuicTime::Zero()),
blocked_(false),
is_server_(true) {
@@ -103,6 +101,7 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
is_server_);
FramerVisitorCapturingFrames visitor;
framer.set_visitor(&visitor);
@@ -156,7 +155,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
}
virtual void UnregisterSendAlarmIfRegistered() OVERRIDE {
- send_alarm_ = QuicTime::FromMilliseconds(-1);
+ send_alarm_ =
+ QuicTime::Zero().Subtract(QuicTime::Delta::FromMilliseconds(1));
}
virtual void SetAckAlarm(QuicTime::Delta delay) OVERRIDE {}
@@ -248,6 +248,8 @@ class TestConnection : public QuicConnection {
void set_is_server(bool is_server) {
helper_->set_is_server(!is_server);
+ QuicPacketCreatorPeer::SetIsServer(
+ QuicConnectionPeer::GetPacketCreator(this), is_server);
QuicConnectionPeer::SetIsServer(this, is_server);
}
@@ -267,6 +269,7 @@ class QuicConnectionTest : public ::testing::Test {
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false),
creator_(guid_, &framer_, QuicRandom::GetInstance(), false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
@@ -832,7 +835,7 @@ TEST_F(QuicConnectionTest, FramePacking) {
// Unblock the connection.
helper_->UnregisterSendAlarmIfRegistered();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission))
+ SentPacket(_, _, _, NOT_RETRANSMISSION))
.Times(1);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -866,7 +869,7 @@ TEST_F(QuicConnectionTest, FramePackingFEC) {
// Unblock the connection.
helper_->UnregisterSendAlarmIfRegistered();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission)).Times(2);
+ SentPacket(_, _, _, NOT_RETRANSMISSION)).Times(2);
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -886,7 +889,7 @@ TEST_F(QuicConnectionTest, OnCanWrite) {
Return(false)));
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
// Unblock the connection.
@@ -941,7 +944,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
// The third nack should trigger a retransimission.
EXPECT_CALL(*send_algorithm_,
SentPacket(_, _, second_packet_size - kQuicVersionSize,
- kIsRetransmission)).Times(1);
+ IS_RETRANSMISSION)).Times(1);
ProcessAckPacket(&nack_two);
}
@@ -949,7 +952,7 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
QuicPacketSequenceNumber largest_observed;
QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission))
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION))
.WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size)));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
connection_.SendStreamData(1, "foo", 0, !kFin);
@@ -960,11 +963,11 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
ProcessAckPacket(&frame);
// Second udp packet will force an ack frame.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission));
+ SentPacket(_, _, _, NOT_RETRANSMISSION));
ProcessAckPacket(&frame);
// Third nack should retransmit the largest observed packet.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize,
- kIsRetransmission));
+ IS_RETRANSMISSION));
ProcessAckPacket(&frame);
}
@@ -1176,7 +1179,7 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
QuicPacketSequenceNumber original_sequence_number;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission))
+ SentPacket(_, _, _, NOT_RETRANSMISSION))
.WillOnce(SaveArg<1>(&original_sequence_number));
connection_.SendStreamData(1, "foo", 0, !kFin);
EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
@@ -1187,7 +1190,7 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
QuicPacketSequenceNumber rto_sequence_number;
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, kIsRetransmission))
+ SentPacket(_, _, _, IS_RETRANSMISSION))
.WillOnce(SaveArg<1>(&rto_sequence_number));
connection_.OnRetransmissionTimeout();
EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission(
@@ -1200,9 +1203,9 @@ 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(_, _, _, NOT_RETRANSMISSION))
.Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission))
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION))
.WillOnce(SaveArg<1>(&nack_sequence_number));
QuicAckFrame ack(rto_sequence_number, QuicTime::Zero(), 0);
// Ack the retransmitted packet.
@@ -1348,10 +1351,11 @@ 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(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
@@ -1359,10 +1363,11 @@ 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(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
@@ -1370,9 +1375,10 @@ 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);
+ TimeUntilSend(_, IS_RETRANSMISSION, _)).Times(0);
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
// XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
@@ -1381,10 +1387,11 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
helper_->set_blocked(true);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
@@ -1392,15 +1399,16 @@ 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(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
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, _)).WillRepeatedly(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
helper_->UnregisterSendAlarmIfRegistered();
@@ -1411,18 +1419,18 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission, _))
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _))
.WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, 1, _, !kIsRetransmission));
+ SentPacket(_, 1, _, NOT_RETRANSMISSION));
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(
+ TimeUntilSend(_, IS_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.OnRetransmissionTimeout();
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1430,12 +1438,12 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
// 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(
+ TimeUntilSend(_, IS_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
// Ensure the scheduler is notified this is a retransmit.
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, kIsRetransmission));
+ SentPacket(_, _, _, IS_RETRANSMISSION));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
helper_->UnregisterSendAlarmIfRegistered();
EXPECT_CALL(visitor_, OnCanWrite());
@@ -1446,30 +1454,33 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Attempt to send another packet and make sure that it gets queued.
packet = ConstructDataPacket(2, 0, !kEntropyFlag);
- connection_.SendOrQueuePacket(2, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 2, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, true);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
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, QuicTime::Zero(), 1);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillRepeatedly(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_,
SentPacket(_, _, _, _));
@@ -1484,16 +1495,17 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
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, QuicTime::Zero(), 1);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
ProcessAckPacket(&frame);
@@ -1503,9 +1515,10 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// OnCanWrite should not send the packet (because of the delay)
@@ -1522,7 +1535,7 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// Queue the first packet.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, !kIsRetransmission, _)).WillOnce(
+ TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
EXPECT_EQ(0u, connection_.SendStreamData(
1, "EnoughDataToQueue", 0, !kFin).bytes_consumed);
@@ -1556,7 +1569,8 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) {
EXPECT_FALSE(connection_.connected());
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0);
- connection_.SendOrQueuePacket(1, packet, kTestEntropyHash, kHasData);
+ connection_.SendOrQueuePacket(
+ 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
}
TEST_F(QuicConnectionTest, PublicReset) {
@@ -1674,7 +1688,8 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) {
packet_entropy_hash = 1 << (i % 8);
}
QuicPacket* packet = ConstructDataPacket(i, 0, entropy_flag);
- connection_.SendOrQueuePacket(i, packet, packet_entropy_hash, true);
+ connection_.SendOrQueuePacket(
+ i, packet, packet_entropy_hash, HAS_RETRANSMITTABLE_DATA);
if (is_missing) {
missing_packets.insert(i);
@@ -1723,18 +1738,18 @@ TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) {
TEST_F(QuicConnectionTest, CheckSendStats) {
EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3);
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission));
+ SentPacket(_, _, _, NOT_RETRANSMISSION));
connection_.SendStreamData(1u, "first", 0, !kFin);
size_t first_packet_size = last_sent_packet_size();
EXPECT_CALL(*send_algorithm_,
- SentPacket(_, _, _, !kIsRetransmission)).Times(2);
+ SentPacket(_, _, _, NOT_RETRANSMISSION)).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);
+ SentPacket(_, _, _, IS_RETRANSMISSION)).Times(3);
// Retransmit due to RTO.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index badddce..63a4f44 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -15,6 +15,7 @@ QuicCryptoClientStream::QuicCryptoClientStream(QuicSession* session,
const string& server_hostname)
: QuicCryptoStream(session),
next_state_(STATE_IDLE),
+ decrypter_pushed_(false),
server_hostname_(server_hostname) {
config_.SetDefaults();
crypto_config_.SetDefaults();
@@ -94,6 +95,10 @@ void QuicCryptoClientStream::DoHandshakeLoop(
next_state_ = STATE_RECV_SHLO;
DLOG(INFO) << "Client Sending: " << out.DebugString();
SendHandshakeMessage(out);
+ // Be prepared to decrypt with the new server write key.
+ session()->connection()->PushDecrypter(
+ crypto_negotiated_params_.decrypter.release());
+ decrypter_pushed_ = true;
return;
}
case STATE_RECV_REJ:
@@ -111,6 +116,11 @@ void QuicCryptoClientStream::DoHandshakeLoop(
CloseConnectionWithDetails(error, error_details);
return;
}
+ // Clear any new server write key that we may have set before.
+ if (decrypter_pushed_) {
+ session()->connection()->PopDecrypter();
+ decrypter_pushed_ = false;
+ }
next_state_ = STATE_SEND_CHLO;
break;
case STATE_RECV_SHLO:
@@ -122,6 +132,14 @@ void QuicCryptoClientStream::DoHandshakeLoop(
"Expected SHLO");
return;
}
+ // Receiving SHLO implies the server must have processed our full
+ // CHLO and is ready to decrypt with the new client write key. We
+ // can start to encrypt with the new client write key.
+ // TODO(wtc): when we support 0-RTT, we will need to change the
+ // encrypter when we send a full CHLO because we will be sending
+ // application data immediately after.
+ session()->connection()->ChangeEncrypter(
+ crypto_negotiated_params_.encrypter.release());
SetHandshakeComplete(QUIC_NO_ERROR);
return;
case STATE_IDLE:
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index 463994e..fb67ee4 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -57,6 +57,8 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
QuicNegotiatedParameters negotiated_params_;
QuicCryptoNegotiatedParameters crypto_negotiated_params_;
+ bool decrypter_pushed_;
+
// Client's connection nonce (4-byte timestamp + 28 random bytes)
std::string nonce_;
// Server's hostname
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 9c33d5b..251a8ef 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -5,6 +5,7 @@
#include "net/quic/quic_crypto_client_stream.h"
#include "base/memory/scoped_ptr.h"
+#include "net/quic/crypto/aes_128_gcm_encrypter.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/test_tools/crypto_test_utils.h"
@@ -87,15 +88,30 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
};
TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
EXPECT_FALSE(stream_.handshake_complete());
}
TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
EXPECT_TRUE(stream_.handshake_complete());
}
TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
EXPECT_CALL(*connection_, SendConnectionClose(
@@ -106,6 +122,11 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
}
TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
EXPECT_TRUE(stream_.CryptoConnect());
message_.set_tag(kCHLO);
@@ -117,6 +138,11 @@ TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
}
TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
const QuicNegotiatedParameters& params(stream_.negotiated_params());
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 6fc508d..d1c21ff 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -12,7 +12,9 @@
namespace net {
QuicCryptoServerStream::QuicCryptoServerStream(QuicSession* session)
- : QuicCryptoStream(session) {
+ : QuicCryptoStream(session),
+ // TODO(agl): use real secret.
+ crypto_config_("secret") {
config_.SetDefaults();
// Use hardcoded crypto parameters for now.
CryptoHandshakeMessage extra_tags;
@@ -56,8 +58,11 @@ void QuicCryptoServerStream::OnHandshakeMessage(
string error_details;
CryptoHandshakeMessage reply;
crypto_config_.ProcessClientHello(
- message, session()->connection()->guid(), &reply,
- &crypto_negotiated_params_, &error_details);
+ message, session()->connection()->guid(),
+ session()->connection()->peer_address(),
+ session()->connection()->clock()->NowAsDeltaSinceUnixEpoch(),
+ session()->connection()->random_generator(),
+ &reply, &crypto_negotiated_params_, &error_details);
if (reply.tag() == kSHLO) {
// If we are returning a SHLO then we accepted the handshake.
@@ -69,6 +74,17 @@ void QuicCryptoServerStream::OnHandshakeMessage(
return;
}
+ // Receiving a full CHLO implies the client is prepared to decrypt with
+ // the new server write key. We can start to encrypt with the new server
+ // write key.
+ //
+ // NOTE: the SHLO will be encrypted with the new server write key.
+ session()->connection()->ChangeEncrypter(
+ crypto_negotiated_params_.encrypter.release());
+ // Be prepared to decrypt with the new client write key, as the client
+ // will start to use it upon receiving the SHLO.
+ session()->connection()->PushDecrypter(
+ crypto_negotiated_params_.decrypter.release());
SetHandshakeComplete(QUIC_NO_ERROR);
}
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 1d2b11d..173122d8 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/memory/scoped_ptr.h"
+#include "net/quic/crypto/aes_128_gcm_encrypter.h"
#include "net/quic/crypto/crypto_framer.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_protocol.h"
@@ -66,7 +67,8 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
public:
QuicCryptoServerStreamTest()
: guid_(1),
- addr_(),
+ addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ?
+ ip_ : IPAddressNumber(), 1),
connection_(new PacketSavingConnection(guid_, addr_, true)),
session_(connection_, true),
stream_(&session_) {
@@ -82,6 +84,7 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
}
protected:
+ IPAddressNumber ip_;
QuicGuid guid_;
IPEndPoint addr_;
PacketSavingConnection* connection_;
@@ -92,15 +95,30 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
};
TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
EXPECT_FALSE(stream_.handshake_complete());
}
TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
EXPECT_TRUE(stream_.handshake_complete());
}
TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
CompleteCryptoHandshake();
EXPECT_CALL(*connection_, SendConnectionClose(
QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
@@ -110,6 +128,11 @@ TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) {
}
TEST_F(QuicCryptoServerStreamTest, BadMessageType) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
message_.set_tag(kSHLO);
ConstructHandshakeMessage();
EXPECT_CALL(*connection_, SendConnectionClose(
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 0b8e27b..c97b857 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -46,6 +46,7 @@ QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target,
QuicFramer::QuicFramer(QuicVersionTag version,
QuicDecrypter* decrypter,
QuicEncrypter* encrypter,
+ QuicTime creation_time,
bool is_server)
: visitor_(NULL),
fec_builder_(NULL),
@@ -54,7 +55,8 @@ QuicFramer::QuicFramer(QuicVersionTag version,
quic_version_(version),
decrypter_(decrypter),
encrypter_(encrypter),
- is_server_(is_server) {
+ is_server_(is_server),
+ creation_time_(creation_time) {
DCHECK(IsSupportedVersion(version));
}
@@ -814,10 +816,11 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
set_detailed_error("Unable to read time received.");
return false;
}
+ QuicTime time_received = creation_time_.Add(
+ QuicTime::Delta::FromMicroseconds(time_received_us));
inter_arrival->received_packet_times.insert(
- make_pair(smallest_received,
- QuicTime::FromMicroseconds(time_received_us)));
+ make_pair(smallest_received, time_received));
for (int i = 0; i < num_received_packets - 1; ++i) {
uint16 sequence_delta;
@@ -835,8 +838,8 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
}
QuicPacketSequenceNumber packet = smallest_received + sequence_delta;
inter_arrival->received_packet_times.insert(
- make_pair(packet, QuicTime::FromMicroseconds(time_received_us +
- time_delta_us)));
+ make_pair(packet, time_received.Add(
+ QuicTime::Delta::FromMicroseconds(time_delta_us))));
}
}
break;
@@ -889,7 +892,14 @@ bool QuicFramer::ProcessRstStreamFrame() {
set_detailed_error("Unable to read rst stream error code.");
return false;
}
- frame.error_code = static_cast<QuicErrorCode>(error_code);
+
+ if (error_code >= QUIC_STREAM_LAST_ERROR ||
+ error_code < QUIC_STREAM_NO_ERROR) {
+ set_detailed_error("Invalid rst stream error code.");
+ return false;
+ }
+
+ frame.error_code = static_cast<QuicRstStreamErrorCode>(error_code);
StringPiece error_details;
if (!reader_->ReadStringPiece16(&error_details)) {
@@ -910,6 +920,13 @@ bool QuicFramer::ProcessConnectionCloseFrame() {
set_detailed_error("Unable to read connection close error code.");
return false;
}
+
+ if (error_code >= QUIC_LAST_ERROR ||
+ error_code < QUIC_NO_ERROR) {
+ set_detailed_error("Invalid error code.");
+ return false;
+ }
+
frame.error_code = static_cast<QuicErrorCode>(error_code);
StringPiece error_details;
@@ -938,12 +955,18 @@ bool QuicFramer::ProcessGoAwayFrame() {
}
frame.error_code = static_cast<QuicErrorCode>(error_code);
+ if (error_code >= QUIC_LAST_ERROR ||
+ error_code < QUIC_NO_ERROR) {
+ set_detailed_error("Invalid error code.");
+ return false;
+ }
+
uint32 stream_id;
if (!reader_->ReadUInt32(&stream_id)) {
set_detailed_error("Unable to read last good stream id.");
return false;
}
- frame.last_good_stream_id = static_cast<QuicErrorCode>(stream_id);
+ frame.last_good_stream_id = static_cast<QuicStreamId>(stream_id);
StringPiece reason_phrase;
if (!reader_->ReadStringPiece16(&reason_phrase)) {
@@ -956,6 +979,7 @@ bool QuicFramer::ProcessGoAwayFrame() {
return true;
}
+// static
StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
const QuicEncryptedPacket& encrypted, bool includes_version) {
return StringPiece(encrypted.data() + kStartOfHashData,
@@ -963,12 +987,27 @@ StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
kStartOfHashData);
}
+void QuicFramer::push_decrypter(QuicDecrypter* decrypter) {
+ DCHECK(backup_decrypter_.get() == NULL);
+ backup_decrypter_.reset(decrypter_.release());
+ decrypter_.reset(decrypter);
+}
+
+void QuicFramer::pop_decrypter() {
+ DCHECK(backup_decrypter_.get() != NULL);
+ decrypter_.reset(backup_decrypter_.release());
+}
+
+void QuicFramer::set_encrypter(QuicEncrypter* encrypter) {
+ encrypter_.reset(encrypter);
+}
+
QuicEncryptedPacket* QuicFramer::EncryptPacket(
QuicPacketSequenceNumber packet_sequence_number,
const QuicPacket& packet) {
- scoped_ptr<QuicData> out(encrypter_->Encrypt(packet_sequence_number,
- packet.AssociatedData(),
- packet.Plaintext()));
+ scoped_ptr<QuicData> out(encrypter_->EncryptPacket(packet_sequence_number,
+ packet.AssociatedData(),
+ packet.Plaintext()));
if (out.get() == NULL) {
RaiseError(QUIC_ENCRYPTION_FAILURE);
return NULL;
@@ -994,10 +1033,19 @@ bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number,
return false;
}
DCHECK(decrypter_.get() != NULL);
- decrypted_.reset(decrypter_->Decrypt(
+ decrypted_.reset(decrypter_->DecryptPacket(
sequence_number,
GetAssociatedDataFromEncryptedPacket(packet, version_flag),
encrypted));
+ if (decrypted_.get() == NULL && backup_decrypter_.get() != NULL) {
+ decrypted_.reset(backup_decrypter_->DecryptPacket(
+ sequence_number,
+ GetAssociatedDataFromEncryptedPacket(packet, version_flag),
+ encrypted));
+ }
+ // TODO(wtc): tell the caller or visitor which decrypter was used, so that
+ // they can verify a packet that should be encrypted is encrypted.
+ // TODO(wtc): figure out when it is safe to delete backup_decrypter_.
if (decrypted_.get() == NULL) {
return false;
}
@@ -1221,9 +1269,8 @@ bool QuicFramer::AppendQuicCongestionFeedbackFramePayload(
}
QuicTime lowest_time = it->second;
- // TODO(ianswett): Use time deltas from the connection's first received
- // packet.
- if (!writer->WriteUInt64(lowest_time.ToMicroseconds())) {
+ if (!writer->WriteUInt64(
+ lowest_time.Subtract(creation_time_).ToMicroseconds())) {
return false;
}
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 7a00aaa..80d7854 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -151,6 +151,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicFramer(QuicVersionTag quic_version,
QuicDecrypter* decrypter,
QuicEncrypter* encrypter,
+ QuicTime creation_time,
bool is_server);
virtual ~QuicFramer();
@@ -269,6 +270,13 @@ class NET_EXPORT_PRIVATE QuicFramer {
const QuicPacketPublicHeader& header,
const QuicVersionTagList& supported_versions);
+ QuicDecrypter* decrypter() const { return decrypter_.get(); }
+ void push_decrypter(QuicDecrypter* decrypter);
+ void pop_decrypter();
+
+ QuicEncrypter* encrypter() const { return encrypter_.get(); }
+ void set_encrypter(QuicEncrypter* encrypter);
+
// Returns a new encrypted packet, owned by the caller.
QuicEncryptedPacket* EncryptPacket(QuicPacketSequenceNumber sequence_number,
const QuicPacket& packet);
@@ -369,13 +377,18 @@ class NET_EXPORT_PRIVATE QuicFramer {
scoped_ptr<QuicData> decrypted_;
// Version of the protocol being used.
QuicVersionTag quic_version_;
- // Decrypter used to decrypt packets during parsing.
+ // Primary decrypter used to decrypt packets during parsing.
scoped_ptr<QuicDecrypter> decrypter_;
+ // Backup decrypter used to decrypt packets during parsing. May be NULL.
+ scoped_ptr<QuicDecrypter> backup_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_;
+ // The time this frames was created. Time written to the wire will be
+ // written as a delta from this value.
+ QuicTime creation_time_;
DISALLOW_COPY_AND_ASSIGN(QuicFramer);
};
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 12d6b2f..8856897 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -73,9 +73,16 @@ class TestEncrypter : public QuicEncrypter {
virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE {
return true;
}
- virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number,
- StringPiece associated_data,
- StringPiece plaintext) OVERRIDE {
+ virtual bool Encrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ unsigned char* output) {
+ CHECK(false) << "Not implemented";
+ return false;
+ }
+ virtual QuicData* EncryptPacket(QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece plaintext) {
sequence_number_ = sequence_number;
associated_data_ = associated_data.as_string();
plaintext_ = plaintext.as_string();
@@ -113,9 +120,17 @@ class TestDecrypter : public QuicDecrypter {
virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE {
return true;
}
- virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number,
- StringPiece associated_data,
- StringPiece ciphertext) OVERRIDE {
+ virtual bool Decrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length) {
+ CHECK(false) << "Not implemented";
+ return false;
+ }
+ virtual QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
+ StringPiece associated_data,
+ StringPiece ciphertext) {
sequence_number_ = sequence_number;
associated_data_ = associated_data.as_string();
ciphertext_ = ciphertext.as_string();
@@ -255,7 +270,8 @@ class QuicFramerTest : public ::testing::Test {
QuicFramerTest()
: encrypter_(new test::TestEncrypter()),
decrypter_(new test::TestDecrypter()),
- framer_(kQuicVersion1, decrypter_, encrypter_, true) {
+ start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))),
+ framer_(kQuicVersion1, decrypter_, encrypter_, start_, true) {
framer_.set_visitor(&visitor_);
framer_.set_entropy_calculator(&entropy_calculator_);
}
@@ -347,6 +363,7 @@ class QuicFramerTest : public ::testing::Test {
test::TestEncrypter* encrypter_;
test::TestDecrypter* decrypter_;
+ QuicTime start_;
QuicFramer framer_;
test::TestQuicVisitor visitor_;
test::TestEntropyCalculator entropy_calculator_;
@@ -1183,10 +1200,10 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
0x02, 0x03,
// num received packets
0x03,
- // smallest ack sequence number
+ // lowest sequence number
0xBA, 0x9A, 0x78, 0x56,
0x34, 0x12,
- // ack time
+ // receive time
0x87, 0x96, 0xA5, 0xB4,
0xC3, 0xD2, 0xE1, 0x07,
// sequence delta
@@ -1217,16 +1234,16 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
TimeMap::const_iterator iter =
frame.inter_arrival.received_packet_times.begin();
EXPECT_EQ(GG_UINT64_C(0x0123456789ABA), iter->first);
- EXPECT_EQ(QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59687)),
- iter->second);
+ EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59687),
+ iter->second.Subtract(start_).ToMicroseconds());
++iter;
EXPECT_EQ(GG_UINT64_C(0x0123456789ABB), iter->first);
- EXPECT_EQ(QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59688)),
- iter->second);
+ EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59688),
+ iter->second.Subtract(start_).ToMicroseconds());
++iter;
EXPECT_EQ(GG_UINT64_C(0x0123456789ABD), iter->first);
- EXPECT_EQ(QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59689)),
- iter->second);
+ EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59689),
+ iter->second.Subtract(start_).ToMicroseconds());
// Now test framing boundaries
for (size_t i = 0; i < 31; ++i) {
@@ -1358,7 +1375,7 @@ TEST_F(QuicFramerTest, RstStreamFrame) {
// stream id
0x04, 0x03, 0x02, 0x01,
// error code
- 0x08, 0x07, 0x06, 0x05,
+ 0x01, 0x00, 0x00, 0x00,
// error details length
0x0d, 0x00,
@@ -1377,7 +1394,7 @@ TEST_F(QuicFramerTest, RstStreamFrame) {
EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
- EXPECT_EQ(0x05060708, visitor_.rst_stream_frame_.error_code);
+ EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details);
// Now test framing boundaries
@@ -1414,7 +1431,7 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
// frame type (connection close frame)
0x05,
// error code
- 0x08, 0x07, 0x06, 0x05,
+ 0x11, 0x00, 0x00, 0x00,
// error details length
0x0d, 0x00,
@@ -1451,7 +1468,7 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
EXPECT_EQ(0u, visitor_.stream_frames_.size());
- EXPECT_EQ(0x05060708, visitor_.connection_close_frame_.error_code);
+ EXPECT_EQ(0x11, visitor_.connection_close_frame_.error_code);
EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
ASSERT_EQ(1u, visitor_.ack_frames_.size());
@@ -1498,7 +1515,7 @@ TEST_F(QuicFramerTest, GoAwayFrame) {
// frame type (go away frame)
0x06,
// error code
- 0x08, 0x07, 0x06, 0x05,
+ 0x09, 0x00, 0x00, 0x00,
// stream id
0x04, 0x03, 0x02, 0x01,
// error details length
@@ -1519,7 +1536,7 @@ TEST_F(QuicFramerTest, GoAwayFrame) {
EXPECT_EQ(GG_UINT64_C(0x01020304),
visitor_.goaway_frame_.last_good_stream_id);
- EXPECT_EQ(0x05060708, visitor_.goaway_frame_.error_code);
+ EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code);
EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
const size_t reason_size = arraysize("because I can") - 1;
@@ -1987,13 +2004,16 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
frame.inter_arrival.accumulated_number_of_lost_packets = 0x0302;
frame.inter_arrival.received_packet_times.insert(
make_pair(GG_UINT64_C(0x0123456789ABA),
- QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59687))));
+ start_.Add(QuicTime::Delta::FromMicroseconds(
+ GG_UINT64_C(0x07E1D2C3B4A59687)))));
frame.inter_arrival.received_packet_times.insert(
make_pair(GG_UINT64_C(0x0123456789ABB),
- QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59688))));
+ start_.Add(QuicTime::Delta::FromMicroseconds(
+ GG_UINT64_C(0x07E1D2C3B4A59688)))));
frame.inter_arrival.received_packet_times.insert(
make_pair(GG_UINT64_C(0x0123456789ABD),
- QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59689))));
+ start_.Add(QuicTime::Delta::FromMicroseconds(
+ GG_UINT64_C(0x07E1D2C3B4A59689)))));
QuicFrames frames;
frames.push_back(QuicFrame(&frame));
@@ -2019,10 +2039,10 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
0x02, 0x03,
// num received packets
0x03,
- // smallest ack sequence number
+ // lowest sequence number
0xBA, 0x9A, 0x78, 0x56,
0x34, 0x12,
- // ack time
+ // receive time
0x87, 0x96, 0xA5, 0xB4,
0xC3, 0xD2, 0xE1, 0x07,
// sequence delta
@@ -2130,7 +2150,7 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) {
QuicRstStreamFrame rst_frame;
rst_frame.stream_id = 0x01020304;
- rst_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
+ rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708);
rst_frame.error_details = "because I can";
unsigned char packet[] = {
@@ -2488,7 +2508,7 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) {
QuicConnectionCloseFrame close_frame;
QuicAckFrame* ack_frame = &close_frame.ack_frame;
- close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
+ close_frame.error_code = static_cast<QuicErrorCode>(0x05);
close_frame.error_details = "because I can";
ack_frame->received_info.largest_observed = 201;
ack_frame->sent_info.least_unacked = 0;
@@ -2543,7 +2563,7 @@ TEST_F(QuicFramerTest, CleanTruncation) {
QuicConnectionCloseFrame close_frame;
QuicAckFrame* ack_frame = &close_frame.ack_frame;
- close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
+ close_frame.error_code = static_cast<QuicErrorCode>(0x05);
close_frame.error_details = "because I can";
ack_frame->received_info.largest_observed = 201;
ack_frame->sent_info.least_unacked = 0;
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 3020610..8aa3723 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -181,7 +181,7 @@ void QuicHttpStream::Close(bool not_reusable) {
// Note: the not_reusable flag has no meaning for SPDY streams.
if (stream_) {
stream_->SetDelegate(NULL);
- stream_->Close(QUIC_NO_ERROR);
+ stream_->Close(QUIC_STREAM_NO_ERROR);
stream_ = NULL;
}
}
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 7f4fef7..34165d6 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -121,6 +121,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false),
creator_(guid_, &framer_, &random_, false) {
IPAddressNumber ip;
@@ -249,7 +250,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
QuicStreamId stream_id) {
InitializeHeader(sequence_number, false);
- QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR);
+ QuicRstStreamFrame rst(stream_id, QUIC_STREAM_NO_ERROR);
return ConstructPacket(header_, QuicFrame(&rst));
}
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index e18f357..82b1075 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -96,7 +96,7 @@ class QuicNetworkTransactionTest : public PlatformTest {
header.fec_entropy_flag = false;
header.fec_group = 0;
- QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR);
+ QuicRstStreamFrame rst(stream_id, QUIC_STREAM_NO_ERROR);
return scoped_ptr<QuicEncryptedPacket>(
ConstructPacket(header, QuicFrame(&rst)));
}
@@ -124,6 +124,7 @@ class QuicNetworkTransactionTest : public PlatformTest {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
@@ -180,6 +181,7 @@ class QuicNetworkTransactionTest : public PlatformTest {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false);
QuicFrames frames;
frames.push_back(frame);
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 05a6893..5339a7f 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -178,7 +178,7 @@ SerializedPacket QuicPacketCreator::SerializeConnectionClose(
QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
const QuicVersionTagList& supported_versions) {
- DCHECK(!is_server_);
+ DCHECK(is_server_);
QuicPacketPublicHeader header;
header.guid = guid_;
header.reset_flag = false;
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 423028a..5e7ed61 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -33,10 +33,12 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> {
: server_framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
true),
client_framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false),
id_(1),
sequence_number_(0),
@@ -183,6 +185,7 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) {
}
TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
+ QuicPacketCreatorPeer::SetIsServer(&creator_, true);
QuicVersionTagList versions;
versions.push_back(kQuicVersion1);
scoped_ptr<QuicEncryptedPacket> encrypted(
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 87464f7..d0e491a 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -72,9 +72,8 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
size_t total_bytes_consumed = 0;
bool fin_consumed = false;
- bool has_retransmittable_data = true;
- while (delegate_->CanWrite(false, has_retransmittable_data)) {
+ while (delegate_->CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) {
// TODO(rch) figure out FEC.
// packet_creator_.MaybeStartFEC();
QuicFrame frame;
@@ -114,8 +113,9 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
}
void QuicPacketGenerator::SendQueuedData() {
- while (HasPendingData() &&
- delegate_->CanWrite(false, packet_creator_->HasPendingFrames())) {
+ while (HasPendingData() && delegate_->CanWrite(NOT_RETRANSMISSION,
+ packet_creator_->HasPendingFrames() ?
+ HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA)) {
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 73e310f..dad1924 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -62,8 +62,8 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
class NET_EXPORT_PRIVATE DelegateInterface {
public:
virtual ~DelegateInterface() {}
- virtual bool CanWrite(bool is_retransmission,
- bool has_retransmittable_data) = 0;
+ virtual bool CanWrite(Retransmission retransmission,
+ HasRetransmittableData retransmittable) = 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 5ed1df5..c7e2918 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -31,15 +31,16 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface {
MockDelegate() {}
virtual ~MockDelegate() {}
- MOCK_METHOD2(CanWrite, bool(bool is_retransmission,
- bool has_retransmittable_data));
+ MOCK_METHOD2(CanWrite, bool(Retransmission retransmission,
+ HasRetransmittableData retransmittable));
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(NOT_RETRANSMISSION, _))
+ .WillRepeatedly(Return(can_write));
}
private:
@@ -78,6 +79,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
: framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false),
creator_(42, &framer_, &random_, false),
generator_(&delegate_, &creator_),
@@ -114,7 +116,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
}
QuicRstStreamFrame* CreateRstStreamFrame() {
- return new QuicRstStreamFrame(1, QUIC_NO_ERROR);
+ return new QuicRstStreamFrame(1, QUIC_STREAM_NO_ERROR);
}
QuicGoAwayFrame* CreateGoAwayFrame() {
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 6fca452..4faec5e 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -15,8 +15,8 @@ namespace net {
size_t GetPacketHeaderSize(bool include_version) {
return kQuicGuidSize + kPublicFlagsSize +
- (include_version ? kQuicVersionSize : 0) + kPrivateFlagsSize +
- kSequenceNumberSize + kFecGroupSize;
+ (include_version ? kQuicVersionSize : 0) + kSequenceNumberSize +
+ kPrivateFlagsSize + kFecGroupSize;
}
size_t GetPublicResetPacketSize() {
@@ -29,11 +29,15 @@ size_t GetStartOfFecProtectedData(bool include_version) {
}
size_t GetStartOfEncryptedData(bool include_version) {
- return GetPacketHeaderSize(include_version) - kPrivateFlagsSize -
+ return GetPacketHeaderSize(include_version) - kPrivateFlagsSize -
kFecGroupSize;
}
-QuicPacketPublicHeader::QuicPacketPublicHeader() {}
+QuicPacketPublicHeader::QuicPacketPublicHeader()
+ : guid(0),
+ reset_flag(false),
+ version_flag(false) {
+}
QuicPacketPublicHeader::QuicPacketPublicHeader(
const QuicPacketPublicHeader& other)
@@ -50,12 +54,29 @@ QuicPacketPublicHeader& QuicPacketPublicHeader::operator=(
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;
+ versions = other.versions;
return *this;
}
+QuicPacketHeader::QuicPacketHeader()
+ : fec_flag(false),
+ fec_entropy_flag(false),
+ entropy_flag(false),
+ entropy_hash(0),
+ packet_sequence_number(0),
+ fec_group(0) {
+}
+
+QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header)
+ : public_header(header),
+ fec_flag(false),
+ fec_entropy_flag(false),
+ entropy_flag(false),
+ entropy_hash(0),
+ packet_sequence_number(0),
+ fec_group(0) {
+}
+
QuicStreamFrame::QuicStreamFrame() {}
QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
@@ -160,7 +181,7 @@ ostream& operator<<(ostream& os,
for (TimeMap::const_iterator it =
inter_arrival.received_packet_times.begin();
it != inter_arrival.received_packet_times.end(); ++it) {
- os << it->first << "@" << it->second.ToMilliseconds() << " ";
+ os << it->first << "@" << it->second.ToDebuggingValue() << " ";
}
os << "]";
break;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index c72c7a7..44aedf9 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -91,6 +91,16 @@ const uint8 kNoFecOffset = 0xFF;
const int64 kDefaultTimeoutUs = 600000000; // 10 minutes.
+enum Retransmission {
+ NOT_RETRANSMISSION = 0,
+ IS_RETRANSMISSION = 1,
+};
+
+enum HasRetransmittableData {
+ HAS_RETRANSMITTABLE_DATA = 0,
+ NO_RETRANSMITTABLE_DATA = 1,
+};
+
enum QuicFrameType {
PADDING_FRAME = 0,
STREAM_FRAME,
@@ -117,24 +127,32 @@ enum QuicPacketPrivateFlags {
PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1 // All bits set.
};
-enum QuicErrorCode {
- // Stream errors.
- QUIC_NO_ERROR = 0,
-
- // Connection has reached an invalid state.
- QUIC_INTERNAL_ERROR,
+enum QuicRstStreamErrorCode {
+ QUIC_STREAM_NO_ERROR = 0,
- // There were data frames after the a fin or reset.
- QUIC_STREAM_DATA_AFTER_TERMINATION,
// There was some server error which halted stream processing.
QUIC_SERVER_ERROR_PROCESSING_STREAM,
// We got two fin or reset offsets which did not match.
QUIC_MULTIPLE_TERMINATION_OFFSETS,
// We got bad payload and can not respond to it at the protocol level.
QUIC_BAD_APPLICATION_PAYLOAD,
+ // Stream closed due to connection error. No reset frame is sent when this
+ // happens.
+ QUIC_STREAM_CONNECTION_ERROR,
+ // GoAway frame sent. No more stream can be created.
+ QUIC_STREAM_PEER_GOING_AWAY,
+
+ // No error. Used as bound while iterating.
+ QUIC_STREAM_LAST_ERROR,
+};
- // Connection errors.
+enum QuicErrorCode {
+ 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,
// Control frame is malformed.
QUIC_INVALID_PACKET_HEADER,
// Frame data is malformed.
@@ -203,6 +221,7 @@ enum QuicErrorCode {
// peer and ourselves.
QUIC_CRYPTO_NO_SUPPORT,
+ // No error. Used as bound while iterating.
QUIC_LAST_ERROR,
};
@@ -232,10 +251,9 @@ struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
};
// Header for Data or FEC packets.
-struct QuicPacketHeader {
- QuicPacketHeader() {}
- explicit QuicPacketHeader(const QuicPacketPublicHeader& header)
- : public_header(header) {}
+struct NET_EXPORT_PRIVATE QuicPacketHeader {
+ QuicPacketHeader();
+ explicit QuicPacketHeader(const QuicPacketPublicHeader& header);
NET_EXPORT_PRIVATE friend std::ostream& operator<<(
std::ostream& os, const QuicPacketHeader& s);
@@ -249,7 +267,7 @@ struct QuicPacketHeader {
QuicFecGroupNumber fec_group;
};
-struct QuicPublicResetPacket {
+struct NET_EXPORT_PRIVATE QuicPublicResetPacket {
QuicPublicResetPacket() {}
explicit QuicPublicResetPacket(const QuicPacketPublicHeader& header)
: public_header(header) {}
@@ -405,13 +423,13 @@ struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame {
struct NET_EXPORT_PRIVATE QuicRstStreamFrame {
QuicRstStreamFrame() {}
- QuicRstStreamFrame(QuicStreamId stream_id, QuicErrorCode error_code)
+ QuicRstStreamFrame(QuicStreamId stream_id, QuicRstStreamErrorCode error_code)
: stream_id(stream_id), error_code(error_code) {
DCHECK_LE(error_code, std::numeric_limits<uint8>::max());
}
QuicStreamId stream_id;
- QuicErrorCode error_code;
+ QuicRstStreamErrorCode error_code;
std::string error_details;
};
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index 676db77..1951ae8 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -19,7 +19,7 @@ QuicReliableClientStream::QuicReliableClientStream(QuicStreamId id,
QuicReliableClientStream::~QuicReliableClientStream() {
if (delegate_)
- delegate_->OnClose(error());
+ delegate_->OnClose(connection_error());
}
uint32 QuicReliableClientStream::ProcessData(const char* data,
@@ -39,7 +39,7 @@ uint32 QuicReliableClientStream::ProcessData(const char* data,
void QuicReliableClientStream::TerminateFromPeer(bool half_close) {
if (delegate_) {
- delegate_->OnClose(error());
+ delegate_->OnClose(connection_error());
delegate_ = NULL;
}
ReliableQuicStream::TerminateFromPeer(half_close);
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index 3da022b..b5f57e5 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -63,7 +63,7 @@ TEST_F(QuicReliableClientStreamTest, ProcessDataWithError) {
EXPECT_CALL(delegate_,
OnDataReceived(StrEq(data),
arraysize(data))).WillOnce(Return(ERR_UNEXPECTED));
- EXPECT_CALL(delegate_, OnClose(QUIC_BAD_APPLICATION_PAYLOAD));
+ EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR));
EXPECT_EQ(0u, stream_.ProcessData(data, arraysize(data)));
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 39abb68..dd90fec 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -166,7 +166,7 @@ QuicConsumedData QuicSession::WriteData(QuicStreamId id,
}
void QuicSession::SendRstStream(QuicStreamId id,
- QuicErrorCode error) {
+ QuicRstStreamErrorCode error) {
connection_->SendRstStream(id, error);
CloseStream(id);
}
@@ -242,7 +242,7 @@ ReliableQuicStream* QuicSession::GetIncomingReliableStream(
if (goaway_sent_) {
// We've already sent a GoAway
- connection()->SendRstStream(stream_id, QUIC_PEER_GOING_AWAY);
+ SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY);
return NULL;
}
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 7152aa0..963a53a 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -57,8 +57,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
QuicStreamOffset offset,
bool fin);
// Called by streams when they want to close the stream in both directions.
- void SendRstStream(QuicStreamId id,
- QuicErrorCode error);
+ virtual void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error);
// Called when the session wants to go away and not accept any new streams.
void SendGoAway(QuicErrorCode error_code, const std::string& reason);
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index a629f20..bd18ec8 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -207,7 +207,7 @@ TEST_F(QuicSessionTest, SendGoAway) {
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
EXPECT_TRUE(session_.goaway_sent());
- EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_PEER_GOING_AWAY));
+ EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_STREAM_PEER_GOING_AWAY));
EXPECT_FALSE(session_.GetIncomingReliableStream(3u));
}
} // namespace
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index e5f74b6..c9c9177 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -47,7 +47,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
header.fec_flag = false;
header.fec_group = 0;
- QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR);
+ QuicRstStreamFrame rst(stream_id, QUIC_STREAM_NO_ERROR);
return scoped_ptr<QuicEncryptedPacket>(
ConstructPacket(header, QuicFrame(&rst)));
}
@@ -74,6 +74,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false);
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
@@ -112,6 +113,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
QuicFramer framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false);
QuicFrames frames;
frames.push_back(frame);
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 74937ae..787d8f5 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -63,7 +63,7 @@ class MockStream : public ReliableQuicStream {
MOCK_METHOD1(TerminateFromPeer, void(bool half_close));
MOCK_METHOD2(ProcessData, uint32(const char* data, uint32 data_len));
- MOCK_METHOD1(Close, void(QuicErrorCode error));
+ MOCK_METHOD1(Close, void(QuicRstStreamErrorCode error));
MOCK_METHOD0(OnCanWrite, void());
};
diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc
index dac6231..c4c80b0 100644
--- a/net/quic/quic_time.cc
+++ b/net/quic/quic_time.cc
@@ -72,36 +72,14 @@ bool QuicTime::Delta::IsInfinite() const {
// static
QuicTime QuicTime::Zero() {
- return QuicTime::FromMilliseconds(0);
-}
-
-// static
-QuicTime QuicTime::FromMilliseconds(int64 time_ms) {
- // DateTime use 100 ns as resolution make sure we don't pass down too high
- // values.
- DCHECK(time_ms < kQuicInfiniteTimeUs / 1000);
- return QuicTime(base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(time_ms));
-}
-
-// static
-QuicTime QuicTime::FromMicroseconds(int64 time_us) {
- // DateTime use 100 ns as resolution make sure we don't pass down too high
- // values.
- DCHECK(time_us < kQuicInfiniteTimeUs);
- return QuicTime(base::TimeTicks() +
- base::TimeDelta::FromMicroseconds(time_us));
+ return QuicTime(base::TimeTicks());
}
QuicTime::QuicTime(base::TimeTicks ticks)
: ticks_(ticks) {
}
-int64 QuicTime::ToMilliseconds() const {
- return (ticks_ - base::TimeTicks()).InMilliseconds();
-}
-
-int64 QuicTime::ToMicroseconds() const {
+int64 QuicTime::ToDebuggingValue() const {
return (ticks_ - base::TimeTicks()).InMicroseconds();
}
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index e780ca5..bfb476d 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -70,15 +70,11 @@ class NET_EXPORT_PRIVATE QuicTime {
// will return false for these times.
static QuicTime Zero();
- // Create a new QuicTime holding the time_ms.
- static QuicTime FromMilliseconds(int64 time_ms);
-
- // Create a new QuicTime holding the time_us.
- static QuicTime FromMicroseconds(int64 time_us);
-
- int64 ToMilliseconds() const;
-
- int64 ToMicroseconds() const;
+ // Produce the internal value to be used when logging. This value
+ // represents the number of microseconds since some epoch. It may
+ // be the UNIX epoch on some platforms. On others, it may
+ // be a CPU ticks based value.
+ int64 ToDebuggingValue() const;
bool IsInitialized() const;
@@ -89,10 +85,13 @@ class NET_EXPORT_PRIVATE QuicTime {
Delta Subtract(const QuicTime& other) const;
private:
- base::TimeTicks ticks_;
+ friend bool operator==(QuicTime lhs, QuicTime rhs);
+ friend bool operator<(QuicTime lhs, QuicTime rhs);
friend class QuicClock;
friend class QuicClockTest;
+
+ base::TimeTicks ticks_;
};
// Non-member relational operators for QuicTime::Delta.
@@ -116,13 +115,13 @@ inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
}
// Non-member relational operators for QuicTime.
inline bool operator==(QuicTime lhs, QuicTime rhs) {
- return lhs.ToMicroseconds() == rhs.ToMicroseconds();
+ return lhs.ticks_ == rhs.ticks_;
}
inline bool operator!=(QuicTime lhs, QuicTime rhs) {
return !(lhs == rhs);
}
inline bool operator<(QuicTime lhs, QuicTime rhs) {
- return lhs.ToMicroseconds() < rhs.ToMicroseconds();
+ return lhs.ticks_ < rhs.ticks_;
}
inline bool operator>(QuicTime lhs, QuicTime rhs) {
return rhs < lhs;
diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc
index a4a6c55..c4ea0e2 100644
--- a/net/quic/quic_time_test.cc
+++ b/net/quic/quic_time_test.cc
@@ -59,21 +59,15 @@ class QuicTimeTest : public ::testing::Test {
TEST_F(QuicTimeTest, Initialized) {
EXPECT_FALSE(QuicTime::Zero().IsInitialized());
- EXPECT_TRUE(QuicTime::FromMilliseconds(1).IsInitialized());
-}
-
-TEST_F(QuicTimeTest, FromTo) {
- EXPECT_EQ(QuicTime::FromMilliseconds(1),
- QuicTime::FromMicroseconds(1000));
- EXPECT_EQ(1u, QuicTime::FromMicroseconds(1000).ToMilliseconds());
- EXPECT_EQ(1000u, QuicTime::FromMilliseconds(1).ToMicroseconds());
+ EXPECT_TRUE(QuicTime::Zero().Add(
+ QuicTime::Delta::FromMicroseconds(1)).IsInitialized());
}
TEST_F(QuicTimeTest, Add) {
- QuicTime time_1 = QuicTime::FromMilliseconds(1);
- QuicTime time_2 = QuicTime::FromMilliseconds(1);
-
- time_1 = time_1.Subtract(QuicTime::Delta::FromMilliseconds(1));
+ QuicTime time_1 = QuicTime::Zero().Add(
+ QuicTime::Delta::FromMilliseconds(1));
+ QuicTime time_2 = QuicTime::Zero().Add(
+ QuicTime::Delta::FromMilliseconds(2));
QuicTime::Delta diff = time_2.Subtract(time_1);
@@ -83,15 +77,18 @@ TEST_F(QuicTimeTest, Add) {
}
TEST_F(QuicTimeTest, Subtract) {
- QuicTime time_1 = QuicTime::FromMilliseconds(1);
- QuicTime time_2 = QuicTime::FromMilliseconds(2);
+ QuicTime time_1 = QuicTime::Zero().Add(
+ QuicTime::Delta::FromMilliseconds(1));
+ QuicTime time_2 = QuicTime::Zero().Add(
+ QuicTime::Delta::FromMilliseconds(2));
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), time_2.Subtract(time_1));
}
TEST_F(QuicTimeTest, SubtractDelta) {
- QuicTime time = QuicTime::FromMilliseconds(2);
- EXPECT_EQ(QuicTime::FromMilliseconds(1),
+ QuicTime time = QuicTime::Zero().Add(
+ QuicTime::Delta::FromMilliseconds(2));
+ EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1)),
time.Subtract(QuicTime::Delta::FromMilliseconds(1)));
}
@@ -99,7 +96,7 @@ TEST_F(QuicTimeTest, MockClock) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
QuicTime now = clock_.ApproximateNow();
- QuicTime time = QuicTime::FromMicroseconds(1000);
+ QuicTime time = QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(1000));
EXPECT_EQ(now, time);
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index d28bc63..616e809 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -36,14 +36,28 @@ case x: \
return #x;
// static
+const char* QuicUtils::StreamErrorToString(QuicRstStreamErrorCode error) {
+ switch (error) {
+ RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR);
+ RETURN_STRING_LITERAL(QUIC_SERVER_ERROR_PROCESSING_STREAM);
+ RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS);
+ RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD);
+ RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY);
+ RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR);
+ }
+ // Return a default value so that we return this when |error| doesn't match
+ // any of the QuicRstStreamErrorCodes. This can happen when the RstStream
+ // frame sent by the peer (attacker) has invalid error code.
+ return "INVALID_RST_STREAM_ERROR_CODE";
+}
+
+// static
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);
- RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD);
RETURN_STRING_LITERAL(QUIC_INVALID_PACKET_HEADER);
RETURN_STRING_LITERAL(QUIC_INVALID_FRAME_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA);
@@ -78,7 +92,10 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
// Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here.
}
- return "";
+ // Return a default value so that we return this when |error| doesn't match
+ // any of the QuicErrorCodes. This can happen when the ConnectionClose
+ // frame sent by the peer (attacker) has invalid error code.
+ return "INVALID_ERROR_CODE";
}
} // namespace net
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index 34f749e..32dc15f 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -19,7 +19,10 @@ class NET_EXPORT_PRIVATE QuicUtils {
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
static uint128 FNV1a_128_Hash(const char* data, int len);
- // Returns the name of the quic error code as a char*
+ // Returns the name of the QuicRstStreamErrorCode as a char*
+ static const char* StreamErrorToString(QuicRstStreamErrorCode error);
+
+ // Returns the name of the QuicErrorCode as a char*
static const char* ErrorToString(QuicErrorCode error);
};
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc
new file mode 100644
index 0000000..a59c1e7
--- /dev/null
+++ b/net/quic/quic_utils_test.cc
@@ -0,0 +1,25 @@
+// 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/quic_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicUtilsTest, StreamErrorToString) {
+ EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD",
+ QuicUtils::StreamErrorToString(QUIC_BAD_APPLICATION_PAYLOAD));
+}
+
+TEST(QuicUtilsTest, ErrorToString) {
+ EXPECT_STREQ("QUIC_NO_ERROR",
+ QuicUtils::ErrorToString(QUIC_NO_ERROR));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 79b060e..3e1b821 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -18,7 +18,8 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id,
visitor_(NULL),
stream_bytes_read_(0),
stream_bytes_written_(0),
- error_(QUIC_NO_ERROR),
+ stream_error_(QUIC_STREAM_NO_ERROR),
+ connection_error_(QUIC_NO_ERROR),
read_side_closed_(false),
write_side_closed_(false),
fin_buffered_(false),
@@ -59,13 +60,17 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
return accepted;
}
-void ReliableQuicStream::OnStreamReset(QuicErrorCode error) {
- error_ = error;
+void ReliableQuicStream::OnStreamReset(QuicRstStreamErrorCode error) {
+ stream_error_ = error;
TerminateFromPeer(false); // Full close.
}
void ReliableQuicStream::ConnectionClose(QuicErrorCode error, bool from_peer) {
- error_ = error;
+ if (error != QUIC_NO_ERROR) {
+ stream_error_ = QUIC_STREAM_CONNECTION_ERROR;
+ connection_error_ = error;
+ }
+
if (from_peer) {
TerminateFromPeer(false);
} else {
@@ -81,8 +86,8 @@ void ReliableQuicStream::TerminateFromPeer(bool half_close) {
CloseReadSide();
}
-void ReliableQuicStream::Close(QuicErrorCode error) {
- error_ = error;
+void ReliableQuicStream::Close(QuicRstStreamErrorCode error) {
+ stream_error_ = error;
session()->SendRstStream(id(), error);
}
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 8249c96..a26595be 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -54,7 +54,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
virtual void OnClose();
// Called when we get a stream reset from the client.
- void OnStreamReset(QuicErrorCode error);
+ virtual void OnStreamReset(QuicRstStreamErrorCode error);
// Called when we get or send a connection close, and should immediately
// close the stream. This is not passed through the sequencer,
@@ -68,7 +68,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
virtual uint32 ProcessData(const char* data, uint32 data_len) = 0;
// Called to close the stream from this end.
- virtual void Close(QuicErrorCode error);
+ virtual void Close(QuicRstStreamErrorCode error);
// This block of functions wraps the sequencer's functions of the same
// name.
@@ -77,7 +77,8 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
QuicStreamId id() const { return id_; }
- QuicErrorCode error() const { return error_; }
+ QuicRstStreamErrorCode stream_error() const { return stream_error_; }
+ QuicErrorCode connection_error() const { return connection_error_; }
bool read_side_closed() const { return read_side_closed_; }
bool write_side_closed() const { return write_side_closed_; }
@@ -134,7 +135,15 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
// framing, encryption overhead etc.
uint64 stream_bytes_read_;
uint64 stream_bytes_written_;
- QuicErrorCode error_;
+
+ // Stream error code received from a RstStreamFrame or error code sent by the
+ // visitor or sequencer in the RstStreamFrame.
+ QuicRstStreamErrorCode stream_error_;
+ // Connection error code due to which the stream was closed. |stream_error_|
+ // is set to |QUIC_STREAM_CONNECTION_ERROR| when this happens and consumers
+ // should check |connection_error_|.
+ QuicErrorCode connection_error_;
+
// True if the read side is closed and further frames should be rejected.
bool read_side_closed_;
// True if the write side is closed, and further writes should fail.
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index fcb04ab..7afad69 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -120,21 +120,21 @@ void CryptoTestUtils::CompareClientAndServerKeys(
QuicCryptoClientStream* client,
QuicCryptoServerStream* server) {
StringPiece client_encrypter_key =
- client->crypto_negotiated_params_.encrypter->GetKey();
+ client->session()->connection()->encrypter()->GetKey();
StringPiece client_encrypter_iv =
- client->crypto_negotiated_params_.encrypter->GetNoncePrefix();
+ client->session()->connection()->encrypter()->GetNoncePrefix();
StringPiece client_decrypter_key =
- client->crypto_negotiated_params_.decrypter->GetKey();
+ client->session()->connection()->decrypter()->GetKey();
StringPiece client_decrypter_iv =
- client->crypto_negotiated_params_.decrypter->GetNoncePrefix();
+ client->session()->connection()->decrypter()->GetNoncePrefix();
StringPiece server_encrypter_key =
- server->crypto_negotiated_params_.encrypter->GetKey();
+ server->session()->connection()->encrypter()->GetKey();
StringPiece server_encrypter_iv =
- server->crypto_negotiated_params_.encrypter->GetNoncePrefix();
+ server->session()->connection()->encrypter()->GetNoncePrefix();
StringPiece server_decrypter_key =
- server->crypto_negotiated_params_.decrypter->GetKey();
+ server->session()->connection()->decrypter()->GetKey();
StringPiece server_decrypter_iv =
- server->crypto_negotiated_params_.decrypter->GetNoncePrefix();
+ server->session()->connection()->decrypter()->GetNoncePrefix();
CompareCharArraysWithHexError("client write key",
client_encrypter_key.data(),
client_encrypter_key.length(),
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index ce726e1..1fb7f4f 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -157,7 +157,7 @@ bool PacketSavingConnection::SendOrQueuePacket(
QuicPacketSequenceNumber sequence_number,
QuicPacket* packet,
QuicPacketEntropyHash entropy_hash,
- bool has_retransmittable_data) {
+ HasRetransmittableData retransmittable) {
packets_.push_back(packet);
return true;
}
@@ -268,6 +268,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage(
QuicFramer quic_framer(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
false);
QuicPacketHeader header;
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 523daaf..2f1f382 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -217,7 +217,7 @@ class MockConnection : public QuicConnection {
MOCK_METHOD2(SendConnectionCloseWithDetails, void(QuicErrorCode error,
const string& details));
MOCK_METHOD2(SendRstStream, void(QuicStreamId id,
- QuicErrorCode error));
+ QuicRstStreamErrorCode error));
MOCK_METHOD3(SendGoAway, void(QuicErrorCode error,
QuicStreamId last_good_stream_id,
const string& reason));
@@ -242,10 +242,11 @@ class PacketSavingConnection : public MockConnection {
PacketSavingConnection(QuicGuid guid, IPEndPoint address, bool is_server);
virtual ~PacketSavingConnection();
- virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
- QuicPacket* packet,
- QuicPacketEntropyHash entropy_hash,
- bool has_retransmittable_data) OVERRIDE;
+ virtual bool SendOrQueuePacket(
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ QuicPacketEntropyHash entropy_hash,
+ HasRetransmittableData has_retransmittable_data) OVERRIDE;
std::vector<QuicPacket*> packets_;
@@ -291,10 +292,11 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta));
MOCK_METHOD1(OnIncomingLoss, void(QuicTime));
MOCK_METHOD4(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber,
- QuicByteCount, bool));
+ QuicByteCount, Retransmission));
MOCK_METHOD2(AbandoningPacket, void(QuicPacketSequenceNumber sequence_number,
QuicByteCount abandoned_bytes));
- MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now, bool, bool));
+ MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now, Retransmission,
+ HasRetransmittableData));
MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void));
MOCK_METHOD0(SmoothedRtt, QuicTime::Delta(void));
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index b9b690d..5d21b73 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -125,6 +125,7 @@ SimpleQuicFramer::SimpleQuicFramer()
: framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
true),
visitor_(NULL) {
}
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 68968ca..70b9a76 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -11,6 +11,8 @@
#include "base/synchronization/waitable_event.h"
#include "base/threading/simple_thread.h"
#include "net/base/ip_endpoint.h"
+// TODO(rtenneti): Delete this when NSS is supported.
+#include "net/quic/crypto/aes_128_gcm_encrypter.h"
#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
@@ -99,7 +101,8 @@ class ServerThread : public base::SimpleThread {
class EndToEndTest : public ::testing::Test {
protected:
EndToEndTest()
- : server_hostname_("localhost") {
+ : server_hostname_("localhost"),
+ server_started_(false) {
net::IPAddressNumber ip;
CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip));
server_address_ = IPEndPoint(ip, 0);
@@ -136,9 +139,12 @@ class EndToEndTest : public ::testing::Test {
server_thread_->listening()->Wait();
server_address_ = IPEndPoint(server_address_.address(),
server_thread_->GetPort());
+ server_started_ = true;
}
void StopServer() {
+ if (!server_started_)
+ return;
server_thread_->quit()->Signal();
server_thread_->Join();
}
@@ -178,9 +184,16 @@ class EndToEndTest : public ::testing::Test {
string server_hostname_;
scoped_ptr<ServerThread> server_thread_;
scoped_ptr<QuicTestClient> client_;
+ bool server_started_;
};
TEST_F(EndToEndTest, SimpleRequestResponse) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -188,6 +201,12 @@ TEST_F(EndToEndTest, SimpleRequestResponse) {
}
TEST_F(EndToEndTest, SimpleRequestResponsev6) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
IPAddressNumber ip;
CHECK(net::ParseIPLiteralToNumber("::", &ip));
server_address_ = IPEndPoint(ip, server_address_.port());
@@ -198,6 +217,12 @@ TEST_F(EndToEndTest, SimpleRequestResponsev6) {
}
TEST_F(EndToEndTest, SeparateFinPacket) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
HTTPMessage request(HttpConstants::HTTP_1_1,
@@ -222,6 +247,12 @@ TEST_F(EndToEndTest, SeparateFinPacket) {
}
TEST_F(EndToEndTest, MultipleRequestResponse) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -231,6 +262,12 @@ TEST_F(EndToEndTest, MultipleRequestResponse) {
}
TEST_F(EndToEndTest, MultipleClients) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
scoped_ptr<QuicTestClient> client2(CreateQuicClient());
@@ -254,6 +291,12 @@ TEST_F(EndToEndTest, MultipleClients) {
}
TEST_F(EndToEndTest, RequestOverMultiplePackets) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
// Set things up so we have a small payload, to guarantee fragmentation.
// A congestion feedback frame can't be split into multiple packets, make sure
@@ -278,6 +321,12 @@ TEST_F(EndToEndTest, RequestOverMultiplePackets) {
}
TEST_F(EndToEndTest, MultipleFramesRandomOrder) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
// Set things up so we have a small payload, to guarantee fragmentation.
// A congestion feedback frame can't be split into multiple packets, make sure
@@ -303,6 +352,12 @@ TEST_F(EndToEndTest, MultipleFramesRandomOrder) {
}
TEST_F(EndToEndTest, PostMissingBytes) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
// Add a content length header with no body.
@@ -319,6 +374,12 @@ TEST_F(EndToEndTest, PostMissingBytes) {
}
TEST_F(EndToEndTest, LargePost) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
// FLAGS_fake_packet_loss_percentage = 30;
ASSERT_TRUE(Initialize());
@@ -333,6 +394,12 @@ TEST_F(EndToEndTest, LargePost) {
}
TEST_F(EndToEndTest, LargePostFEC) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
// FLAGS_fake_packet_loss_percentage = 30;
ASSERT_TRUE(Initialize());
client_->options()->max_packets_per_fec_group = 6;
@@ -365,6 +432,12 @@ TEST_F(EndToEndTest, LargePostFEC) {
}*/
TEST_F(EndToEndTest, InvalidStream) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
string body;
@@ -383,6 +456,12 @@ TEST_F(EndToEndTest, InvalidStream) {
}
TEST_F(EndToEndTest, MultipleTermination) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
scoped_ptr<QuicTestClient> client2(CreateQuicClient());
@@ -424,6 +503,12 @@ TEST_F(EndToEndTest, MultipleTermination) {
}*/
TEST_F(EndToEndTest, ResetConnection) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 04fd922..02dbb63 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -93,6 +93,7 @@ QuicTimeWaitListManager::QuicTimeWaitListManager(
: framer_(kQuicVersion1,
QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL),
+ QuicTime::Zero(),
true),
epoll_server_(epoll_server),
kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 22e3827..43ac914 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -37,7 +37,7 @@ QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname)
: server_address_(address),
client_(address, hostname),
stream_(NULL),
- stream_error_(QUIC_NO_ERROR),
+ stream_error_(QUIC_STREAM_NO_ERROR),
connection_error_(QUIC_NO_ERROR),
bytes_read_(0),
bytes_written_(0),
@@ -135,7 +135,7 @@ IPEndPoint QuicTestClient::LocalSocketAddress() const {
}
void QuicTestClient::ClearPerRequestState() {
- stream_error_ = QUIC_NO_ERROR;
+ stream_error_ = QUIC_STREAM_NO_ERROR;
connection_error_ = QUIC_NO_ERROR;
stream_ = NULL;
response_ = "";
@@ -170,8 +170,8 @@ size_t QuicTestClient::bytes_written() const {
void QuicTestClient::OnClose(ReliableQuicStream* stream) {
response_ = stream_->data();
headers_.CopyFrom(stream_->headers());
- stream_error_ = stream_->error();
- connection_error_ = stream_->error();
+ stream_error_ = stream_->stream_error();
+ connection_error_ = stream_->connection_error();
bytes_read_ = stream_->stream_bytes_read();
bytes_written_ = stream_->stream_bytes_written();
stream_ = NULL;
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index d02905a..1bb4f07 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -61,7 +61,7 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
// Returns NULL if the maximum number of streams have already been created.
QuicReliableClientStream* GetOrCreateStream();
- QuicErrorCode stream_error() { return stream_error_; }
+ QuicRstStreamErrorCode stream_error() { return stream_error_; }
QuicErrorCode connection_error() { return connection_error_; }
QuicClient* client() { return &client_; }
@@ -75,7 +75,7 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
QuicClient client_; // The actual client
QuicReliableClientStream* stream_;
- QuicErrorCode stream_error_;
+ QuicRstStreamErrorCode stream_error_;
QuicErrorCode connection_error_;
BalsaHeaders headers_;