summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-23 21:16:04 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-23 21:16:04 +0000
commit86a318db1d9c40724fdf062d3f2ef19cf6b2961c (patch)
treefc9808f5ac1e4d20e7d27d0e180e6311101049a9 /net/quic
parent037366110f4f8593d826f731fc268c9fdb172fb2 (diff)
downloadchromium_src-86a318db1d9c40724fdf062d3f2ef19cf6b2961c.zip
chromium_src-86a318db1d9c40724fdf062d3f2ef19cf6b2961c.tar.gz
chromium_src-86a318db1d9c40724fdf062d3f2ef19cf6b2961c.tar.bz2
Added QuicBandwidth class
Merge internal change: 41339414 Adding an interface between the dispatcher and the connection that represents entities that want to be notified when the underlying socket becomes writable again. Merge internal change: 41313884 Refactored how QUIC handles historic sent packets and how we calculate sent bitrate. Merge internal change: 41311241 Fixed one spot where the frame count was still included in the packet overhead calculations. Merge internal change: 41291694 Cleanup CL based on Jim's comments in Chromium 11958018 and 11968021. Merge internal change: 41287854 Add FromSeconds method to QuicTime. Merge internal change: 41259799 Adding framing for public reset packet. Merge internal change: 41251245 Do not send ack after connection is closed by other send. Merge internal change: 41245780 Removing the number of frames from the header and fix ack truncating such that acks are being truncated at a clean boundary, not a random byte. Merge internal change: 41232422 TBR=jar@chromium.org Review URL: https://chromiumcodereview.appspot.com/11953033 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178382 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc3
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h3
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc5
-rw-r--r--net/quic/congestion_control/quic_send_scheduler.cc163
-rw-r--r--net/quic/congestion_control/quic_send_scheduler.h41
-rw-r--r--net/quic/congestion_control/quic_send_scheduler_test.cc18
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h19
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc3
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h3
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc9
-rw-r--r--net/quic/quic_bandwidth.cc86
-rw-r--r--net/quic/quic_bandwidth.h76
-rw-r--r--net/quic/quic_bandwidth_test.cc61
-rw-r--r--net/quic/quic_blocked_writer_interface.h26
-rw-r--r--net/quic/quic_connection.cc52
-rw-r--r--net/quic/quic_connection.h13
-rw-r--r--net/quic/quic_connection_test.cc57
-rw-r--r--net/quic/quic_framer.cc110
-rw-r--r--net/quic/quic_framer.h18
-rw-r--r--net/quic/quic_framer_test.cc380
-rw-r--r--net/quic/quic_packet_creator.cc1
-rw-r--r--net/quic/quic_packet_creator.h2
-rw-r--r--net/quic/quic_protocol.h24
-rw-r--r--net/quic/quic_time.cc31
-rw-r--r--net/quic/quic_time.h8
-rw-r--r--net/quic/quic_time_test.cc8
-rw-r--r--net/quic/quic_utils.cc2
-rw-r--r--net/quic/test_tools/quic_test_utils.h3
28 files changed, 911 insertions, 314 deletions
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 46ca0b5..758a6c1 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -26,7 +26,8 @@ FixRateSender::FixRateSender(const QuicClock* clock)
}
void FixRateSender::OnIncomingQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& feedback) {
+ const QuicCongestionFeedbackFrame& feedback,
+ const SentPacketsMap& /*sent_packets*/) {
DCHECK(feedback.type == kFixRate) <<
"Invalid incoming CongestionFeedbackType:" << feedback.type;
if (feedback.type == kFixRate) {
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index 146ea23..1c91fd0 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -24,7 +24,8 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
// Start implementation of SendAlgorithmInterface.
virtual void OnIncomingQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& feedback) OVERRIDE;
+ const QuicCongestionFeedbackFrame& feedback,
+ const SentPacketsMap& sent_packets) OVERRIDE;
virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
size_t acked_bytes,
QuicTime::Delta rtt) OVERRIDE;
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index 6cb4956..33a739f 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -28,6 +28,7 @@ class FixRateTest : public ::testing::Test {
}
const QuicTime::Delta rtt_;
MockClock clock_;
+ SendAlgorithmInterface::SentPacketsMap not_used_;
scoped_ptr<FixRateSender> sender_;
scoped_ptr<FixRateReceiver> receiver_;
};
@@ -46,7 +47,7 @@ TEST_F(FixRateTest, SenderAPI) {
QuicCongestionFeedbackFrame feedback;
feedback.type = kFixRate;
feedback.fix_rate.bitrate_in_bytes_per_second = 300000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
+ sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
EXPECT_EQ(300000, sender_->BandwidthEstimate());
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
EXPECT_EQ(kMaxPacketSize * 2, sender_->AvailableCongestionWindow());
@@ -74,7 +75,7 @@ TEST_F(FixRateTest, FixRatePacing) {
QuicCongestionFeedbackFrame feedback;
receiver_->SetBitrate(240000); // Bytes per second.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
+ sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
QuicTime acc_advance_time(QuicTime::Zero());
QuicPacketSequenceNumber sequence_number = 0;
for (int i = 0; i < num_packets; i += 2) {
diff --git a/net/quic/congestion_control/quic_send_scheduler.cc b/net/quic/congestion_control/quic_send_scheduler.cc
index ba18c96..8b9acf5 100644
--- a/net/quic/congestion_control/quic_send_scheduler.cc
+++ b/net/quic/congestion_control/quic_send_scheduler.cc
@@ -14,6 +14,15 @@
#include "net/quic/congestion_control/send_algorithm_interface.h"
//#include "util/gtl/map-util.h"
+namespace {
+const int kBitrateSmoothingPeriodMs = 3000;
+const int kMinBitrateSmoothingPeriodMs = 500;
+const int kHistoryPeriodMs = 5000;
+
+COMPILE_ASSERT(kHistoryPeriodMs >= kBitrateSmoothingPeriodMs,
+ history_must_be_longer_or_equal_to_the_smoothing_period);
+}
+
using std::map;
using std::max;
@@ -25,74 +34,68 @@ QuicSendScheduler::QuicSendScheduler(
const QuicClock* clock,
CongestionFeedbackType type)
: clock_(clock),
- current_estimated_bandwidth_(-1),
+ current_estimated_bandwidth_(0),
max_estimated_bandwidth_(-1),
last_sent_packet_(QuicTime::FromMicroseconds(0)),
- current_packet_bucket_(-1),
- first_packet_bucket_(-1),
send_algorithm_(SendAlgorithmInterface::Create(clock, type)) {
- memset(packet_history_, 0, sizeof(packet_history_));
}
QuicSendScheduler::~QuicSendScheduler() {
- STLDeleteContainerPairSecondPointers(pending_packets_.begin(),
- pending_packets_.end());
-}
-
-int QuicSendScheduler::UpdatePacketHistory() {
- int timestamp_scaled = clock_->Now().ToMicroseconds() /
- kBitrateSmoothingPeriod;
- int bucket = timestamp_scaled % kBitrateSmoothingBuckets;
- if (!HasSentPacket()) {
- // First packet.
- current_packet_bucket_ = bucket;
- first_packet_bucket_ = bucket;
- }
- if (current_packet_bucket_ != bucket) {
- // We need to make sure to zero out any skipped buckets.
- // Max loop count is kBitrateSmoothingBuckets.
- do {
- current_packet_bucket_ =
- (1 + current_packet_bucket_) % kBitrateSmoothingBuckets;
- packet_history_[current_packet_bucket_] = 0;
- if (first_packet_bucket_ == current_packet_bucket_) {
- // We have filled the whole window, no need to keep track of first
- // bucket.
- first_packet_bucket_ = -1;
- }
- } while (current_packet_bucket_ != bucket);
- }
- return bucket;
+ STLDeleteValues(&packet_history_map_);
}
void QuicSendScheduler::SentPacket(QuicPacketSequenceNumber sequence_number,
size_t bytes,
bool is_retransmission) {
- int bucket = UpdatePacketHistory();
- packet_history_[bucket] += bytes;
+ DCHECK(!ContainsKey(pending_packets_, sequence_number));
send_algorithm_->SentPacket(sequence_number, bytes, is_retransmission);
- if (!is_retransmission) {
- pending_packets_[sequence_number] =
- new PendingPacket(bytes, clock_->Now());
- }
+
+ packet_history_map_[sequence_number] =
+ new class SendAlgorithmInterface::SentPacket(bytes, clock_->Now());
+ pending_packets_[sequence_number] = bytes;
+ CleanupPacketHistory();
DLOG(INFO) << "Sent sequence number:" << sequence_number;
}
void QuicSendScheduler::OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& congestion_feedback_frame) {
send_algorithm_->OnIncomingQuicCongestionFeedbackFrame(
- congestion_feedback_frame);
+ congestion_feedback_frame, packet_history_map_);
+}
+
+void QuicSendScheduler::CleanupPacketHistory() {
+ const QuicTime::Delta kHistoryPeriod =
+ QuicTime::Delta::FromMilliseconds(kHistoryPeriodMs);
+ QuicTime Now = clock_->Now();
+
+ SendAlgorithmInterface::SentPacketsMap::iterator history_it =
+ packet_history_map_.begin();
+ for (; history_it != packet_history_map_.end(); ++history_it) {
+ if (Now.Subtract(history_it->second->SendTimestamp()) <= kHistoryPeriod) {
+ return;
+ }
+ DLOG(INFO) << "Clear sequence number:" << history_it->first
+ << "from history";
+ delete history_it->second;
+ packet_history_map_.erase(history_it);
+ history_it = packet_history_map_.begin();
}
+}
void QuicSendScheduler::OnIncomingAckFrame(const QuicAckFrame& ack_frame) {
+ // We calculate the RTT based on the highest ACKed sequence number, the lower
+ // sequence numbers will include the ACK aggregation delay.
+ QuicTime::Delta rtt = QuicTime::Delta::Zero();
+ SendAlgorithmInterface::SentPacketsMap::iterator history_it =
+ packet_history_map_.find(ack_frame.received_info.largest_observed);
+ if (history_it != packet_history_map_.end()) {
+ rtt = clock_->Now().Subtract(history_it->second->SendTimestamp());
+ }
// We want to.
// * Get all packets lower(including) than largest_observed
// from pending_packets_.
// * Remove all missing packets.
// * Send each ACK in the list to send_algorithm_.
- QuicTime last_timestamp(QuicTime::FromMicroseconds(0));
- map<QuicPacketSequenceNumber, size_t> acked_packets;
-
PendingPacketsMap::iterator it, it_upper;
it = pending_packets_.begin();
it_upper = pending_packets_.upper_bound(
@@ -102,27 +105,15 @@ void QuicSendScheduler::OnIncomingAckFrame(const QuicAckFrame& ack_frame) {
QuicPacketSequenceNumber sequence_number = it->first;
if (!ack_frame.received_info.IsAwaitingPacket(sequence_number)) {
// Not missing, hence implicitly acked.
- scoped_ptr<PendingPacket> pending_packet_cleaner(it->second);
- acked_packets[sequence_number] = pending_packet_cleaner->BytesSent();
- last_timestamp = pending_packet_cleaner->SendTimestamp();
+ send_algorithm_->OnIncomingAck(sequence_number,
+ it->second,
+ rtt);
+ DLOG(INFO) << "ACKed sequence number:" << sequence_number;
pending_packets_.erase(it++); // Must be incremented post to work.
} else {
++it;
}
}
- // We calculate the RTT based on the highest ACKed sequence number, the lower
- // sequence numbers will include the ACK aggregation delay.
- QuicTime::Delta rtt = clock_->Now().Subtract(last_timestamp);
-
- map<QuicPacketSequenceNumber, size_t>::iterator it_acked_packets;
- for (it_acked_packets = acked_packets.begin();
- it_acked_packets != acked_packets.end();
- ++it_acked_packets) {
- send_algorithm_->OnIncomingAck(it_acked_packets->first,
- it_acked_packets->second,
- rtt);
- DLOG(INFO) << "ACKed sequence number:" << it_acked_packets->first;
- }
}
QuicTime::Delta QuicSendScheduler::TimeUntilSend(bool is_retransmission) {
@@ -142,37 +133,35 @@ int QuicSendScheduler::BandwidthEstimate() {
return bandwidth_estimate;
}
-bool QuicSendScheduler::HasSentPacket() {
- return (current_packet_bucket_ != -1);
-}
-
-// TODO(pwestin) add a timer to make this accurate even if not called.
+// TODO(pwestin): add a timer to make max_estimated_bandwidth_ accurate.
int QuicSendScheduler::SentBandwidth() {
- UpdatePacketHistory();
-
- if (first_packet_bucket_ != -1) {
- // We don't have a full set of data.
- int number_of_buckets = (current_packet_bucket_ - first_packet_bucket_) + 1;
- if (number_of_buckets < 0) {
- // We have a wrap in bucket index.
- number_of_buckets = kBitrateSmoothingBuckets + number_of_buckets;
- }
- int64 sum = 0;
- int bucket = first_packet_bucket_;
- for (int n = 0; n < number_of_buckets; bucket++, n++) {
- bucket = bucket % kBitrateSmoothingBuckets;
- sum += packet_history_[bucket];
+ const QuicTime::Delta kBitrateSmoothingPeriod =
+ QuicTime::Delta::FromMilliseconds(kBitrateSmoothingPeriodMs);
+ const QuicTime::Delta kMinBitrateSmoothingPeriod =
+ QuicTime::Delta::FromMilliseconds(kMinBitrateSmoothingPeriodMs);
+
+ QuicTime Now = clock_->Now();
+ size_t sum_bytes_sent = 0;
+
+ // Sum packet from new until they are kBitrateSmoothingPeriod old.
+ SendAlgorithmInterface::SentPacketsMap::reverse_iterator history_rit =
+ packet_history_map_.rbegin();
+
+ QuicTime::Delta max_diff = QuicTime::Delta::Zero();
+ for (; history_rit != packet_history_map_.rend(); ++history_rit) {
+ QuicTime::Delta diff = Now.Subtract(history_rit->second->SendTimestamp());
+ if (diff > kBitrateSmoothingPeriod) {
+ break;
}
- current_estimated_bandwidth_ = (sum *
- (kNumMicrosPerSecond / kBitrateSmoothingPeriod)) / number_of_buckets;
- } else {
- int64 sum = 0;
- for (uint32 bucket = 0; bucket < kBitrateSmoothingBuckets; ++bucket) {
- sum += packet_history_[bucket];
- }
- current_estimated_bandwidth_ = (sum * (kNumMicrosPerSecond /
- kBitrateSmoothingPeriod)) / kBitrateSmoothingBuckets;
+ sum_bytes_sent += history_rit->second->BytesSent();
+ max_diff = diff;
+ }
+ if (max_diff < kMinBitrateSmoothingPeriod) {
+ // No estimate.
+ return 0;
}
+ current_estimated_bandwidth_ = sum_bytes_sent * kNumMicrosPerSecond /
+ max_diff.ToMicroseconds();
max_estimated_bandwidth_ = max(max_estimated_bandwidth_,
current_estimated_bandwidth_);
return current_estimated_bandwidth_;
@@ -180,9 +169,7 @@ int QuicSendScheduler::SentBandwidth() {
int QuicSendScheduler::PeakSustainedBandwidth() {
// To make sure that we get the latest estimate we call SentBandwidth.
- if (HasSentPacket()) {
SentBandwidth();
- }
return max_estimated_bandwidth_;
}
diff --git a/net/quic/congestion_control/quic_send_scheduler.h b/net/quic/congestion_control/quic_send_scheduler.h
index c5f1c83..53793bd 100644
--- a/net/quic/congestion_control/quic_send_scheduler.h
+++ b/net/quic/congestion_control/quic_send_scheduler.h
@@ -23,29 +23,8 @@
namespace net {
-const uint32 kBitrateSmoothingBuckets = 300;
-
-// 10 ms in micro seconds, must be less than 1 second for current
-// implementation due to overflow resulting in a potential divide by zero.
-const uint32 kBitrateSmoothingPeriod = 10000;
-
class NET_EXPORT_PRIVATE QuicSendScheduler {
public:
- class PendingPacket {
- public:
- PendingPacket(size_t bytes, QuicTime timestamp)
- : bytes_sent_(bytes),
- send_timestamp_(timestamp) {
- }
- size_t BytesSent() { return bytes_sent_; }
- QuicTime& SendTimestamp() { return send_timestamp_; }
-
- private:
- size_t bytes_sent_;
- QuicTime send_timestamp_;
- };
- typedef std::map<QuicPacketSequenceNumber, PendingPacket*> PendingPacketsMap;
-
// Enable pacing to prevent a large congestion window to be sent all at once,
// when pacing is enabled a large congestion window will be sent in multiple
// bursts of packet(s) instead of one big burst that might introduce packet
@@ -88,24 +67,16 @@ class NET_EXPORT_PRIVATE QuicSendScheduler {
int PeakSustainedBandwidth(); // In bytes per second.
private:
- // Have we sent any packets during this session?
- bool HasSentPacket();
- int UpdatePacketHistory();
+ typedef std::map<QuicPacketSequenceNumber, size_t> PendingPacketsMap;
+
+ void CleanupPacketHistory();
const QuicClock* clock_;
- int current_estimated_bandwidth_;
- int max_estimated_bandwidth_;
+ int64 current_estimated_bandwidth_;
+ int64 max_estimated_bandwidth_;
QuicTime last_sent_packet_;
- // To keep track of the real sent bitrate we keep track of the last sent bytes
- // by keeping an array containing the number of bytes sent in a short timespan
- // kBitrateSmoothingPeriod; multiple of these buckets kBitrateSmoothingBuckets
- // create a time window in which we calculate the average bitrate.
- int current_packet_bucket_; // Last active bucket in window.
- int first_packet_bucket_; // First active bucket in window.
- uint32 packet_history_[kBitrateSmoothingBuckets]; // The window.
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
- // TODO(pwestin): should we combine the packet_history_ bucket with this map?
- // For now I keep it separate for easy implementation.
+ SendAlgorithmInterface::SentPacketsMap packet_history_map_;
PendingPacketsMap pending_packets_;
};
diff --git a/net/quic/congestion_control/quic_send_scheduler_test.cc b/net/quic/congestion_control/quic_send_scheduler_test.cc
index a59c0e7..9347b2c 100644
--- a/net/quic/congestion_control/quic_send_scheduler_test.cc
+++ b/net/quic/congestion_control/quic_send_scheduler_test.cc
@@ -116,8 +116,8 @@ TEST_F(QuicSendSchedulerTest, FixedRateBandwidth) {
sender_->OnIncomingAckFrame(ack);
}
EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_EQ(101010, sender_->PeakSustainedBandwidth());
- EXPECT_EQ(101010, sender_->SentBandwidth());
+ EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 4000);
+ EXPECT_NEAR(100000, sender_->SentBandwidth(), 4000);
}
TEST_F(QuicSendSchedulerTest, BandwidthWith3SecondGap) {
@@ -140,13 +140,13 @@ TEST_F(QuicSendSchedulerTest, BandwidthWith3SecondGap) {
sender_->OnIncomingAckFrame(ack);
}
EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_EQ(100000, sender_->PeakSustainedBandwidth());
- EXPECT_EQ(100000, sender_->SentBandwidth());
+ EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 2000);
+ EXPECT_NEAR(100000, sender_->SentBandwidth(), 2000);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
- EXPECT_EQ(50000, sender_->SentBandwidth());
+ EXPECT_NEAR(50000, sender_->SentBandwidth(), 1000);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2100));
- EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_EQ(100000, sender_->PeakSustainedBandwidth());
+ EXPECT_NEAR(100000, sender_->BandwidthEstimate(), 2000);
+ EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 2000);
EXPECT_EQ(0, sender_->SentBandwidth());
for (int i = 1; i <= 150; ++i) {
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
@@ -158,8 +158,8 @@ TEST_F(QuicSendSchedulerTest, BandwidthWith3SecondGap) {
sender_->OnIncomingAckFrame(ack);
}
EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_EQ(100000, sender_->PeakSustainedBandwidth());
- EXPECT_EQ(50000, sender_->SentBandwidth());
+ EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 2000);
+ EXPECT_NEAR(100000, sender_->SentBandwidth(), 2000);
}
TEST_F(QuicSendSchedulerTest, Pacing) {
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 63aef3a..8f83615 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -19,6 +19,22 @@ const int kNoValidEstimate = -1;
class NET_EXPORT_PRIVATE SendAlgorithmInterface {
public:
+ class SentPacket {
+ public:
+ SentPacket(size_t bytes, QuicTime timestamp)
+ : bytes_sent_(bytes),
+ send_timestamp_(timestamp) {
+ }
+ size_t BytesSent() { return bytes_sent_; }
+ QuicTime& SendTimestamp() { return send_timestamp_; }
+
+ private:
+ size_t bytes_sent_;
+ QuicTime send_timestamp_;
+ };
+
+ typedef std::map<QuicPacketSequenceNumber, SentPacket*> SentPacketsMap;
+
static SendAlgorithmInterface* Create(const QuicClock* clock,
CongestionFeedbackType type);
@@ -26,7 +42,8 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
// Called when we receive congestion feedback from remote peer.
virtual void OnIncomingQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& feedback) = 0;
+ const QuicCongestionFeedbackFrame& feedback,
+ const SentPacketsMap& sent_packets) = 0;
// Called for each received ACK, with sequence number from remote peer.
virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 001fff5..8087283 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -34,7 +34,8 @@ TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno)
}
void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& feedback) {
+ const QuicCongestionFeedbackFrame& feedback,
+ const SentPacketsMap& /*sent_packets*/) {
if (last_received_accumulated_number_of_lost_packets_ !=
feedback.tcp.accumulated_number_of_lost_packets) {
int recovered_lost_packets =
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 628ff56..54efedd 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -26,7 +26,8 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
// Start implementation of SendAlgorithmInterface.
virtual void OnIncomingQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& feedback) OVERRIDE;
+ const QuicCongestionFeedbackFrame& feedback,
+ const SentPacketsMap& sent_packets) OVERRIDE;
virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
size_t acked_bytes,
QuicTime::Delta rtt) OVERRIDE;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 3f48c22..1ce7d7a 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -51,6 +51,7 @@ class QuicTcpCubicSenderTest : public ::testing::Test {
const QuicTime::Delta rtt_;
const QuicTime::Delta one_ms_;
MockClock clock_;
+ SendAlgorithmInterface::SentPacketsMap not_used_;
scoped_ptr<TcpCubicSender> sender_;
scoped_ptr<TcpReceiver> receiver_;
QuicPacketSequenceNumber sequence_number_;
@@ -66,7 +67,7 @@ TEST_F(QuicTcpCubicSenderTest, SimpleSender) {
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
+ sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
// Make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
// And that window is un-affected.
@@ -83,7 +84,7 @@ TEST_F(QuicTcpCubicSenderTest, ExponentialSlowStart) {
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
+ sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
// Make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
@@ -109,7 +110,7 @@ TEST_F(QuicTcpCubicSenderTest, SlowStartAckTrain) {
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
+ sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
// Make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
@@ -149,7 +150,7 @@ TEST_F(QuicTcpCubicSenderTest, SlowStartPacketLoss) {
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
+ sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
// Make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
diff --git a/net/quic/quic_bandwidth.cc b/net/quic/quic_bandwidth.cc
new file mode 100644
index 0000000..c270d01
--- /dev/null
+++ b/net/quic/quic_bandwidth.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_bandwidth.h"
+
+#include "base/logging.h"
+#include "base/time.h"
+
+namespace net {
+
+// Highest number that QuicBandwidth can hold.
+const int64 kQuicInfiniteBandwidth = 0x7fffffffffffffffll;
+
+// static
+QuicBandwidth QuicBandwidth::Zero() {
+ return QuicBandwidth(0);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromBitsPerSecond(int64 bits_per_second) {
+ return QuicBandwidth(bits_per_second);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromKBitsPerSecond(int64 k_bits_per_second) {
+ DCHECK(k_bits_per_second < kQuicInfiniteBandwidth / 1000);
+ return QuicBandwidth(k_bits_per_second * 1000);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromBytesPerSecond(int64 bytes_per_second) {
+ DCHECK(bytes_per_second < kQuicInfiniteBandwidth / 8);
+ return QuicBandwidth(bytes_per_second * 8);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromKBytesPerSecond(int64 k_bytes_per_second) {
+ DCHECK(k_bytes_per_second < kQuicInfiniteBandwidth / 8000);
+ return QuicBandwidth(k_bytes_per_second * 8000);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromBytesAndTimeDelta(int64 bytes,
+ QuicTime::Delta delta) {
+ DCHECK_LT(bytes,
+ kQuicInfiniteBandwidth / (8 * base::Time::kMicrosecondsPerSecond));
+ int64 bytes_per_second = (bytes * base::Time::kMicrosecondsPerSecond) /
+ delta.ToMicroseconds();
+ return QuicBandwidth(bytes_per_second * 8);
+}
+
+QuicBandwidth::QuicBandwidth(int64 bits_per_second)
+ : bits_per_second_(bits_per_second) {
+ DCHECK_GE(bits_per_second, 0);
+}
+
+int64 QuicBandwidth::ToBitsPerSecond() const {
+ return bits_per_second_;
+}
+
+int64 QuicBandwidth::ToKBitsPerSecond() const {
+ return bits_per_second_ / 1000;
+}
+
+int64 QuicBandwidth::ToBytesPerSecond() const {
+ return bits_per_second_ / 8;
+}
+
+int64 QuicBandwidth::ToKBytesPerSecond() const {
+ return bits_per_second_ / 8000;
+}
+
+bool QuicBandwidth::IsZero() const {
+ return (bits_per_second_ == 0);
+}
+
+QuicBandwidth QuicBandwidth::Add(const QuicBandwidth& delta) const {
+ return QuicBandwidth(bits_per_second_ + delta.bits_per_second_);
+}
+
+QuicBandwidth QuicBandwidth::Subtract(const QuicBandwidth& delta) const {
+ return QuicBandwidth(bits_per_second_ - delta.bits_per_second_);
+}
+
+} // namespace net
diff --git a/net/quic/quic_bandwidth.h b/net/quic/quic_bandwidth.h
new file mode 100644
index 0000000..522bd4c
--- /dev/null
+++ b/net/quic/quic_bandwidth.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// QuicBandwidth represents a bandwidth, stored in bits per second resolution.
+
+#ifndef NET_QUIC_QUIC_BANDWIDTH_H_
+#define NET_QUIC_QUIC_BANDWIDTH_H_
+
+#include "base/basictypes.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicBandwidth {
+ public:
+ // Creates a new QuicBandwidth with an internal value of 0.
+ static QuicBandwidth Zero();
+
+ // Create a new QuicBandwidth holding the bits per second.
+ static QuicBandwidth FromBitsPerSecond(int64 bits_per_second);
+
+ // Create a new QuicBandwidth holding the kilo bits per second.
+ static QuicBandwidth FromKBitsPerSecond(int64 k_bits_per_second);
+
+ // Create a new QuicBandwidth holding the bytes per second.
+ static QuicBandwidth FromBytesPerSecond(int64 bytes_per_second);
+
+ // Create a new QuicBandwidth holding the kilo bytes per second.
+ static QuicBandwidth FromKBytesPerSecond(int64 k_bytes_per_second);
+
+ // Create a new QuicBandwidth based on the bytes per the elapsed delta.
+ static QuicBandwidth FromBytesAndTimeDelta(int64 bytes,
+ QuicTime::Delta delta);
+
+ int64 ToBitsPerSecond() const;
+
+ int64 ToKBitsPerSecond() const;
+
+ int64 ToBytesPerSecond() const;
+
+ int64 ToKBytesPerSecond() const;
+
+ bool IsZero() const;
+
+ QuicBandwidth Add(const QuicBandwidth& delta) const;
+
+ QuicBandwidth Subtract(const QuicBandwidth& delta) const;
+
+ private:
+ explicit QuicBandwidth(int64 bits_per_second);
+ int64 bits_per_second_;
+};
+
+// Non-member relational operators for QuicBandwidth.
+inline bool operator==(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return lhs.ToBitsPerSecond() == rhs.ToBitsPerSecond();
+}
+inline bool operator!=(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return !(lhs == rhs);
+}
+inline bool operator<(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return lhs.ToBitsPerSecond() < rhs.ToBitsPerSecond();
+}
+inline bool operator>(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return rhs < lhs;
+}
+inline bool operator<=(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return !(rhs < lhs);
+}
+inline bool operator>=(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return !(lhs < rhs);
+}
+
+} // namespace net
+#endif // NET_QUIC_QUIC_BANDWIDTH_H_
diff --git a/net/quic/quic_bandwidth_test.cc b/net/quic/quic_bandwidth_test.cc
new file mode 100644
index 0000000..aa089e6
--- /dev/null
+++ b/net/quic/quic_bandwidth_test.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_bandwidth.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace testing {
+
+class QuicBandwidthTest : public ::testing::Test {
+};
+
+TEST_F(QuicBandwidthTest, FromTo) {
+ EXPECT_EQ(QuicBandwidth::FromKBitsPerSecond(1),
+ QuicBandwidth::FromBitsPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1),
+ QuicBandwidth::FromBytesPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(8000),
+ QuicBandwidth::FromBytesPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromKBitsPerSecond(8),
+ QuicBandwidth::FromKBytesPerSecond(1));
+
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToBitsPerSecond());
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToKBitsPerSecond());
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToBytesPerSecond());
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToKBytesPerSecond());
+
+ EXPECT_EQ(1, QuicBandwidth::FromBitsPerSecond(1000).ToKBitsPerSecond());
+ EXPECT_EQ(1000, QuicBandwidth::FromKBitsPerSecond(1).ToBitsPerSecond());
+ EXPECT_EQ(1, QuicBandwidth::FromBytesPerSecond(1000).ToKBytesPerSecond());
+ EXPECT_EQ(1000, QuicBandwidth::FromKBytesPerSecond(1).ToBytesPerSecond());
+}
+
+TEST_F(QuicBandwidthTest, Add) {
+ QuicBandwidth bandwidht_1 = QuicBandwidth::FromKBitsPerSecond(1);
+ QuicBandwidth bandwidht_2 = QuicBandwidth::FromKBytesPerSecond(1);
+
+ EXPECT_EQ(9000, bandwidht_1.Add(bandwidht_2).ToBitsPerSecond());
+ EXPECT_EQ(9000, bandwidht_2.Add(bandwidht_1).ToBitsPerSecond());
+}
+
+TEST_F(QuicBandwidthTest, Subtract) {
+ QuicBandwidth bandwidht_1 = QuicBandwidth::FromKBitsPerSecond(1);
+ QuicBandwidth bandwidht_2 = QuicBandwidth::FromKBytesPerSecond(1);
+
+ EXPECT_EQ(7000, bandwidht_2.Subtract(bandwidht_1).ToBitsPerSecond());
+}
+
+TEST_F(QuicBandwidthTest, TimeDelta) {
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1000),
+ QuicBandwidth::FromBytesAndTimeDelta(
+ 1000, QuicTime::Delta::FromMilliseconds(1)));
+
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(10),
+ QuicBandwidth::FromBytesAndTimeDelta(
+ 1000, QuicTime::Delta::FromMilliseconds(100)));
+}
+
+} // namespace testing
+} // namespace net
diff --git a/net/quic/quic_blocked_writer_interface.h b/net/quic/quic_blocked_writer_interface.h
new file mode 100644
index 0000000..d9cd6ad
--- /dev/null
+++ b/net/quic/quic_blocked_writer_interface.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is an interface for all objects that want to be notified that
+// the underlying UDP socket is available for writing (not write blocked
+// anymore).
+
+#ifndef NET_QUIC_QUIC_BLOCKED_WRITER_INTERFACE_H_
+#define NET_QUIC_QUIC_BLOCKED_WRITER_INTERFACE_H_
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicBlockedWriterInterface {
+ public:
+ virtual ~QuicBlockedWriterInterface() {}
+
+ // Called by the PacketWriter when the underlying socket becomes writable
+ // so that the BlockedWriter can go ahead and try writing. This methods
+ // should return false if the socket has become blocked while writing.
+ virtual bool OnCanWrite() = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_BLOCKED_WRITER_INTERFACE_H_
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index bf09e91..dcfcb1d 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -123,15 +123,17 @@ QuicConnection::QuicConnection(QuicGuid guid,
}
QuicConnection::~QuicConnection() {
- for (UnackedPacketMap::iterator u = unacked_packets_.begin();
- u != unacked_packets_.end(); ++u) {
- DeleteUnackedPacket(u->second);
+ // Call DeleteEnclosedFrames on each QuicPacket because the destructor does
+ // not delete enclosed frames.
+ for (UnackedPacketMap::iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it) {
+ DeleteEnclosedFrames(it->second);
}
STLDeleteValues(&unacked_packets_);
STLDeleteValues(&group_map_);
- for (QueuedPacketList::iterator q = queued_packets_.begin();
- q != queued_packets_.end(); ++q) {
- delete q->packet;
+ for (QueuedPacketList::iterator it = queued_packets_.begin();
+ it != queued_packets_.end(); ++it) {
+ delete it->packet;
}
}
@@ -160,7 +162,7 @@ void QuicConnection::DeleteEnclosedFrame(QuicFrame* frame) {
}
}
-void QuicConnection::DeleteUnackedPacket(UnackedPacket* unacked) {
+void QuicConnection::DeleteEnclosedFrames(UnackedPacket* unacked) {
for (QuicFrames::iterator it = unacked->frames.begin();
it != unacked->frames.end(); ++it) {
DCHECK(ShouldRetransmit(*it));
@@ -186,10 +188,21 @@ void QuicConnection::OnPacket(const IPEndPoint& self_address,
peer_address_ = peer_address;
}
+void QuicConnection::OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) {
+ CloseConnection(QUIC_PUBLIC_RESET, true);
+}
+
void QuicConnection::OnRevivedPacket() {
}
bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
+ if (header.public_header.guid != guid_) {
+ DLOG(INFO) << "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
@@ -344,7 +357,7 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer(
}
}
acked_packets.insert(it->first);
- DeleteUnackedPacket(it->second);
+ DeleteEnclosedFrames(it->second);
delete it->second;
UnackedPacketMap::iterator it_tmp = it;
++it;
@@ -690,6 +703,13 @@ bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number,
bool should_retransmit,
bool force,
bool is_retransmission) {
+ if (!connected_) {
+ DLOG(INFO)
+ << "Dropping packet to be sent since connection is disconnected.";
+ delete packet;
+ return false;
+ }
+
// If this packet is being forced, don't bother checking to see if we should
// write, just write.
if (!force) {
@@ -834,17 +854,19 @@ void QuicConnection::MaybeProcessRevivedPacket() {
if (group == NULL || !group->CanRevive()) {
return;
}
- DCHECK(!revived_payload_.get());
- revived_payload_.reset(new char[kMaxPacketSize]);
- size_t len = group->Revive(&revived_header_, revived_payload_.get(),
- kMaxPacketSize);
+ QuicPacketHeader revived_header;
+ char revived_payload[kMaxPacketSize];
+ size_t len = group->Revive(&revived_header, revived_payload, kMaxPacketSize);
+ revived_header.public_header.guid = guid_;
+ revived_header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE;
+ revived_header.private_flags = PACKET_PRIVATE_FLAGS_NONE;
+ revived_header.fec_group = kNoFecOffset;
group_map_.erase(last_header_.fec_group);
delete group;
last_packet_revived_ = true;
- framer_.ProcessRevivedPacket(revived_header_,
- StringPiece(revived_payload_.get(), len));
- revived_payload_.reset();
+ framer_.ProcessRevivedPacket(revived_header,
+ StringPiece(revived_payload, len));
}
QuicFecGroup* QuicConnection::GetFecGroup() {
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 6515e01..97cc61c 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -23,6 +23,7 @@
#include "base/hash_tables.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/congestion_control/quic_congestion_manager.h"
+#include "net/quic/quic_blocked_writer_interface.h"
#include "net/quic/quic_fec_group.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
@@ -126,7 +127,8 @@ class NET_EXPORT_PRIVATE QuicConnectionHelperInterface {
virtual void ClearAckAlarm() = 0;
};
-class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface {
+class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
+ public QuicBlockedWriterInterface {
public:
// Constructs a new QuicConnection for the specified |guid| and |address|.
// |helper| will be owned by this connection.
@@ -164,14 +166,17 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface {
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet);
+ // QuicBlockedWriterInterface
// Called when the underlying connection becomes writable to allow
// queued writes to happen. Returns false if the socket has become blocked.
- virtual bool OnCanWrite();
+ virtual bool OnCanWrite() OVERRIDE;
// From QuicFramerVisitorInterface
virtual void OnError(QuicFramer* framer) OVERRIDE;
virtual void OnPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address) OVERRIDE;
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) OVERRIDE;
virtual void OnRevivedPacket() OVERRIDE;
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
virtual void OnFecProtectedPayload(base::StringPiece payload) OVERRIDE;
@@ -314,7 +319,7 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface {
return QuicTime::Delta::FromMilliseconds(500);
}
- static void DeleteUnackedPacket(UnackedPacket* unacked);
+ static void DeleteEnclosedFrames(UnackedPacket* unacked);
static bool ShouldRetransmit(const QuicFrame& frame);
// Checks if a packet can be written now, and sets the timer if necessary.
@@ -390,8 +395,6 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface {
bool write_blocked_;
FecGroupMap group_map_;
- QuicPacketHeader revived_header_;
- scoped_array<char> revived_payload_;
QuicConnectionVisitorInterface* visitor_;
QuicPacketCreator packet_creator_;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 3e80dc9..2a91326 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -251,6 +251,13 @@ class QuicConnectionTest : public ::testing::Test {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
+ void ProcessClosePacket(QuicPacketSequenceNumber number,
+ QuicFecGroupNumber fec_group) {
+ scoped_ptr<QuicPacket> packet(ConstructClosePacket(number, fec_group));
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet));
+ connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+ }
+
// Sends an FEC packet that covers the packets that would have been sent.
void ProcessFecPacket(QuicPacketSequenceNumber number,
QuicPacketSequenceNumber min_protected_packet,
@@ -341,6 +348,25 @@ class QuicConnectionTest : public ::testing::Test {
return packet;
}
+ QuicPacket* ConstructClosePacket(QuicPacketSequenceNumber number,
+ QuicFecGroupNumber fec_group) {
+ header_.public_header.guid = guid_;
+ header_.packet_sequence_number = number;
+ header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE;
+ header_.fec_group = fec_group;
+
+ QuicConnectionCloseFrame qccf;
+ qccf.error_code = QUIC_CLIENT_GOING_AWAY;
+ qccf.ack_frame = QuicAckFrame(0, 1);
+
+ QuicFrames frames;
+ QuicFrame frame(&qccf);
+ frames.push_back(frame);
+ QuicPacket* packet = framer_.ConstructFrameDataPacket(header_, frames);
+ EXPECT_TRUE(packet != NULL);
+ return packet;
+ }
+
void SetFeedback(QuicCongestionFeedbackFrame* feedback) {
collector_ = new TestCollector(feedback);
connection_.SetCollector(collector_);
@@ -638,7 +664,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
ProcessAckPacket(&nack_two);
// The third nack should trigger a retransimission.
- EXPECT_CALL(*scheduler_, SentPacket(_, 38, true)).Times(1);
+ EXPECT_CALL(*scheduler_, SentPacket(_, 37, true)).Times(1);
ProcessAckPacket(&nack_two);
}
@@ -1078,6 +1104,35 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
1, "EnoughDataToQueue", 0, false).bytes_consumed);
}
+TEST_F(QuicConnectionTest, NoAckForClose) {
+ ProcessPacket(1);
+ EXPECT_CALL(*scheduler_, OnIncomingAckFrame(_));
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_CLIENT_GOING_AWAY, true));
+ EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(0);
+ ProcessClosePacket(2, 0);
+}
+
+TEST_F(QuicConnectionTest, SendWhenDisconnected) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_CLIENT_GOING_AWAY, false));
+ connection_.CloseConnection(QUIC_CLIENT_GOING_AWAY, false);
+ EXPECT_FALSE(connection_.connected());
+ QuicPacket* packet = ConstructDataPacket(1, 0);
+ EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0);
+ connection_.SendPacket(1, packet, true, false, false);
+}
+
+TEST_F(QuicConnectionTest, PublicReset) {
+ QuicPublicResetPacket header;
+ header.public_header.guid = guid_;
+ header.public_header.flags = PACKET_PUBLIC_FLAGS_RST;
+ header.rejected_sequence_number = 10101;
+ scoped_ptr<QuicEncryptedPacket> packet(
+ framer_.ConstructPublicResetPacket(header));
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_PUBLIC_RESET, true));
+ connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *packet);
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 2c359ed..b59f0d4 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -80,7 +80,6 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
// sizeof(member_) is not necessarily the same as sizeof(member_wire_format).
const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize);
size_t len = kPacketHeaderSize;
- len += 1; // frame count
bool truncating = false;
for (size_t i = 0; i < frames.size(); ++i) {
if (frames[i].type == PADDING_FRAME) {
@@ -114,6 +113,9 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
len += frame_len;
*num_consumed = i + 1;
}
+ if (truncating) {
+ DCHECK_EQ(1u, *num_consumed);
+ }
QuicDataWriter writer(len);
@@ -125,9 +127,6 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
if (*num_consumed > 256u) {
return NULL;
}
- if (!writer.WriteUInt8(*num_consumed)) {
- return NULL;
- }
for (size_t i = 0; i < *num_consumed; ++i) {
const QuicFrame& frame = frames[i];
@@ -140,8 +139,7 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
writer.WritePadding();
break;
case STREAM_FRAME:
- if (!AppendStreamFramePayload(*frame.stream_frame,
- &writer)) {
+ if (!AppendStreamFramePayload(*frame.stream_frame, &writer)) {
return NULL;
}
break;
@@ -157,8 +155,7 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
}
break;
case RST_STREAM_FRAME:
- if (!AppendRstStreamFramePayload(*frame.rst_stream_frame,
- &writer)) {
+ if (!AppendRstStreamFramePayload(*frame.rst_stream_frame, &writer)) {
return NULL;
}
break;
@@ -175,6 +172,8 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
}
DCHECK(truncating || len == writer.length());
+ // Save the length before writing, because take clears it.
+ len = writer.length();
QuicPacket* packet = QuicPacket::NewDataPacket(writer.take(), len, true);
if (fec_builder_) {
@@ -203,6 +202,35 @@ QuicPacket* QuicFramer::ConstructFecPacket(const QuicPacketHeader& header,
return QuicPacket::NewFecPacket(writer.take(), len, true);
}
+// static
+QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
+ const QuicPublicResetPacket& packet) {
+ DCHECK_EQ(PACKET_PUBLIC_FLAGS_RST,
+ PACKET_PUBLIC_FLAGS_RST & packet.public_header.flags);
+ size_t len = kPublicResetPacketSize;
+ QuicDataWriter writer(len);
+
+ if (!writer.WriteUInt64(packet.public_header.guid)) {
+ return NULL;
+ }
+
+ uint8 flags = static_cast<uint8>(packet.public_header.flags);
+ if (!writer.WriteUInt8(flags)) {
+ return NULL;
+ }
+
+ if (!writer.WriteUInt64(packet.nonce_proof)) {
+ return NULL;
+ }
+
+ if (!AppendPacketSequenceNumber(packet.rejected_sequence_number,
+ &writer)) {
+ return NULL;
+ }
+
+ return new QuicEncryptedPacket(writer.take(), len, true);
+}
+
// TODO(satyamshekhar): Framer doesn't need addresses. Get rid of them.
bool QuicFramer::ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
@@ -213,18 +241,20 @@ bool QuicFramer::ProcessPacket(const IPEndPoint& self_address,
// First parse the public header.
QuicPacketPublicHeader public_header;
if (!ProcessPublicHeader(&public_header)) {
- DLOG(WARNING) << "Unable to process header.";
+ DLOG(WARNING) << "Unable to process public header.";
reader_.reset(NULL);
return RaiseError(QUIC_INVALID_PACKET_HEADER);
}
- if (!ProcessDataPacket(public_header, self_address, peer_address, packet)) {
- reader_.reset(NULL);
- return false;
- };
+ bool rv;
+ if (public_header.flags & PACKET_PUBLIC_FLAGS_RST) {
+ rv = ProcessPublicResetPacket(public_header);
+ } else {
+ rv = ProcessDataPacket(public_header, self_address, peer_address, packet);
+ }
reader_.reset(NULL);
- return true;
+ return rv;
}
bool QuicFramer::ProcessDataPacket(
@@ -271,6 +301,24 @@ bool QuicFramer::ProcessDataPacket(
return true;
}
+bool QuicFramer::ProcessPublicResetPacket(
+ const QuicPacketPublicHeader& public_header) {
+ QuicPublicResetPacket packet(public_header);
+ if (!reader_->ReadUInt64(&packet.nonce_proof)) {
+ set_detailed_error("Unable to read nonce proof.");
+ return false;
+ }
+ // TODO(satyamshekhar): validate nonce to protect against DoS.
+
+ if (!reader_->ReadUInt48(&packet.rejected_sequence_number)) {
+ set_detailed_error("Unable to read rejected sequence number.");
+ return false;
+ }
+
+ visitor_->OnPublicResetPacket(packet);
+ return true;
+}
+
bool QuicFramer::ProcessRevivedPacket(const QuicPacketHeader& header,
StringPiece payload) {
DCHECK(!reader_.get());
@@ -303,7 +351,7 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header,
}
uint8 flags =static_cast<uint8>(header.public_header.flags);
- if (!writer->WriteBytes(&flags, 1)) {
+ if (!writer->WriteUInt8(flags)) {
return false;
}
@@ -312,8 +360,8 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header,
}
flags = static_cast<uint8>(header.private_flags);
- if (!writer->WriteBytes(&flags, 1)) {
- return false;
+ if (!writer->WriteUInt8(flags)) {
+ return false;
}
// Offset from the current packet sequence number to the first fec
@@ -352,6 +400,13 @@ QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire(
next_epoch + packet_sequence_number));
}
+/* static */
+bool QuicFramer::ReadGuidFromPacket(const QuicEncryptedPacket& packet,
+ QuicGuid* guid) {
+ QuicDataReader reader(packet.data(), packet.length());
+ return reader.ReadUInt64(guid);
+}
+
bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
if (!reader_->ReadUInt64(&public_header->guid)) {
set_detailed_error("Unable to read GUID.");
@@ -365,7 +420,7 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
}
if (public_flags > PACKET_PUBLIC_FLAGS_MAX) {
- set_detailed_error("Illegal flags value.");
+ set_detailed_error("Illegal public flags value.");
return false;
}
@@ -431,14 +486,11 @@ bool QuicFramer::ProcessPacketSequenceNumber(
}
bool QuicFramer::ProcessFrameData() {
- // TODO(ianswett): remove frame_count
- uint8 frame_count;
- if (!reader_->ReadBytes(&frame_count, 1)) {
- set_detailed_error("Unable to read frame count.");
+ if (reader_->IsDoneReading()) {
+ set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
-
- for (uint8 i = 0; i < frame_count; ++i) {
+ while (!reader_->IsDoneReading()) {
uint8 frame_type;
if (!reader_->ReadBytes(&frame_type, 1)) {
set_detailed_error("Unable to read frame type.");
@@ -479,7 +531,8 @@ bool QuicFramer::ProcessFrameData() {
break;
default:
set_detailed_error("Illegal frame type.");
- DLOG(WARNING) << "Illegal frame type: " << (int)frame_type;
+ DLOG(WARNING) << "Illegal frame type: "
+ << static_cast<int>(frame_type);
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
}
@@ -752,7 +805,7 @@ bool QuicFramer::DecryptPayload(const QuicEncryptedPacket& packet) {
size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) {
size_t len = 0;
- // We use "magic numbers" here because sizeof(member_) is not necessairly the
+ // We use "magic numbers" here because sizeof(member_) is not necessarily the
// same as sizeof(member_wire_format).
switch (frame.type) {
case STREAM_FRAME:
@@ -824,9 +877,14 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) {
return len;
}
+// static
bool QuicFramer::AppendPacketSequenceNumber(
QuicPacketSequenceNumber packet_sequence_number,
QuicDataWriter* writer) {
+ // Ensure the entire sequence number can be written.
+ if (writer->capacity() - writer->length() < kSequenceNumberSize) {
+ return false;
+ }
return writer->WriteUInt48(packet_sequence_number & kSequenceNumberMask);
}
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 81c944a..31105f1 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -42,6 +42,11 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
virtual void OnPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address) = 0;
+ // Called when a public reset packet has been parsed but has not yet
+ // been validated.
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) = 0;
+
// Called when a lost packet has been recovered via FEC,
// before it has been processed.
virtual void OnRevivedPacket() = 0;
@@ -158,6 +163,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicPacket* ConstructFecPacket(const QuicPacketHeader& header,
const QuicFecData& fec);
+ // Returns a new public reset packet, owned by the caller.
+ static QuicEncryptedPacket* ConstructPublicResetPacket(
+ const QuicPublicResetPacket& packet);
+
// Returns a new encrypted packet, owned by the caller.
QuicEncryptedPacket* EncryptPacket(const QuicPacket& packet);
@@ -167,6 +176,11 @@ class NET_EXPORT_PRIVATE QuicFramer {
const std::string& detailed_error() { return detailed_error_; }
+ // Read the guid from a packet header.
+ // Return true on success, else false.
+ static bool ReadGuidFromPacket(const QuicEncryptedPacket& packet,
+ QuicGuid* guid);
+
private:
friend class test::QuicFramerPeer;
@@ -175,6 +189,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet);
+ bool ProcessPublicResetPacket(const QuicPacketPublicHeader& public_header);
+
bool WritePacketHeader(const QuicPacketHeader& header,
QuicDataWriter* writer);
@@ -204,7 +220,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
// Computes the wire size in bytes of the payload of |frame|.
size_t ComputeFramePayloadLength(const QuicFrame& frame);
- bool AppendPacketSequenceNumber(
+ static bool AppendPacketSequenceNumber(
QuicPacketSequenceNumber packet_sequence_number,
QuicDataWriter* writer);
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 6b10890..0133148 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -108,6 +108,10 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
peer_address_ = peer_address;
}
+ virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {
+ public_reset_packet_.reset(new QuicPublicResetPacket(packet));
+ }
+
virtual void OnRevivedPacket() {
revived_packets_++;
}
@@ -169,6 +173,7 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
IPEndPoint self_address_;
IPEndPoint peer_address_;
scoped_ptr<QuicPacketHeader> header_;
+ scoped_ptr<QuicPublicResetPacket> public_reset_packet_;
vector<QuicStreamFrame*> stream_frames_;
vector<QuicAckFrame*> ack_frames_;
vector<QuicCongestionFeedbackFrame*> congestion_feedback_frames_;
@@ -391,9 +396,7 @@ TEST_F(QuicFramerTest, LargePacket) {
// private flags
0x00,
// first fec protected packet offset
- 0xFF,
- // frame count
- 0x01,
+ 0xFF
};
memset(packet + kPacketHeaderSize, 0, kMaxPacketSize - kPacketHeaderSize + 1);
@@ -405,7 +408,7 @@ TEST_F(QuicFramerTest, LargePacket) {
// Make sure we've parsed the packet header, so we can send an error.
EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
visitor_.header_->public_header.guid);
- // Make sure the correct error is propogated.
+ // Make sure the correct error is propagated.
EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
}
@@ -455,13 +458,13 @@ TEST_F(QuicFramerTest, PacketHeader) {
}
}
-TEST_F(QuicFramerTest, PaddingFrame) {
+TEST_F(QuicFramerTest, InvalidPublicFlag) {
unsigned char packet[] = {
// guid
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// public flags
- 0x00,
+ 0x07,
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -472,6 +475,82 @@ TEST_F(QuicFramerTest, PaddingFrame) {
// frame count
0x01,
+ // frame type (stream frame)
+ 0x01,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // fin
+ 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ CheckProcessingFails(packet,
+ arraysize(packet),
+ "Illegal public flags value.",
+ QUIC_INVALID_PACKET_HEADER);
+};
+
+TEST_F(QuicFramerTest, InvalidPrivateFlag) {
+ unsigned char packet[] = {
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags
+ 0x00,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x07,
+ // first fec protected packet offset
+ 0xFF,
+
+ // frame count
+ 0x01,
+ // frame type (stream frame)
+ 0x01,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // fin
+ 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ CheckProcessingFails(packet,
+ arraysize(packet),
+ "Illegal private flags value.",
+ QUIC_INVALID_PACKET_HEADER);
+};
+
+TEST_F(QuicFramerTest, PaddingFrame) {
+ unsigned char packet[] = {
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags
+ 0x00,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+ // first fec protected packet offset
+ 0xFF,
+
// frame type (padding frame)
0x00,
// Ignored data (which in this case is a stream frame)
@@ -498,11 +577,9 @@ TEST_F(QuicFramerTest, PaddingFrame) {
EXPECT_EQ(0u, visitor_.ack_frames_.size());
// Now test framing boundaries
- for (size_t i = 0; i < 2; ++i) {
+ for (size_t i = 0; i < 1; ++i) {
string expected_error;
if (i < 1) {
- expected_error = "Unable to read frame count.";
- } else if (i < 2) {
expected_error = "Unable to read frame type.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -525,8 +602,6 @@ TEST_F(QuicFramerTest, StreamFrame) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (stream frame)
0x01,
// stream id
@@ -563,19 +638,17 @@ TEST_F(QuicFramerTest, StreamFrame) {
EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
// Now test framing boundaries
- for (size_t i = 0; i < 29; ++i) {
+ for (size_t i = 0; i < 28; ++i) {
string expected_error;
if (i < 1) {
- expected_error = "Unable to read frame count.";
- } else if (i < 2) {
expected_error = "Unable to read frame type.";
- } else if (i < 6) {
+ } else if (i < 5) {
expected_error = "Unable to read stream_id.";
- } else if (i < 7) {
+ } else if (i < 6) {
expected_error = "Unable to read fin.";
- } else if (i < 15) {
+ } else if (i < 14) {
expected_error = "Unable to read offset.";
- } else if (i < 29) {
+ } else if (i < 28) {
expected_error = "Unable to read frame data.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -600,8 +673,6 @@ TEST_F(QuicFramerTest, RejectPacket) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (stream frame)
0x01,
// stream id
@@ -633,8 +704,6 @@ TEST_F(QuicFramerTest, RejectPacket) {
TEST_F(QuicFramerTest, RevivedStreamFrame) {
unsigned char payload[] = {
- // frame count
- 0x01,
// frame type (stream frame)
0x01,
// stream id
@@ -699,8 +768,6 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) {
// first fec protected packet offset
0x02,
- // frame count
- 0x01,
// frame type (stream frame)
0x01,
// stream id
@@ -755,8 +822,6 @@ TEST_F(QuicFramerTest, AckFrame) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (ack frame)
0x02,
// least packet sequence number awaiting an ack
@@ -790,19 +855,17 @@ TEST_F(QuicFramerTest, AckFrame) {
EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked);
// Now test framing boundaries
- for (size_t i = 0; i < 21; ++i) {
+ for (size_t i = 0; i < 20; ++i) {
string expected_error;
if (i < 1) {
- expected_error = "Unable to read frame count.";
- } else if (i < 2) {
expected_error = "Unable to read frame type.";
- } else if (i < 8) {
+ } else if (i < 7) {
expected_error = "Unable to read least unacked.";
- } else if (i < 14) {
+ } else if (i < 13) {
expected_error = "Unable to read largest observed.";
- } else if (i < 15) {
+ } else if (i < 14) {
expected_error = "Unable to read num missing packets.";
- } else if (i < 21) {
+ } else if (i < 20) {
expected_error = "Unable to read sequence number in missing packets.";
} CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
QUIC_INVALID_FRAME_DATA);
@@ -824,8 +887,6 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (tcp)
@@ -853,17 +914,15 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
EXPECT_EQ(0x0403, frame.tcp.receive_window);
// Now test framing boundaries
- for (size_t i = 0; i < 7; ++i) {
+ for (size_t i = 0; i < 6; ++i) {
string expected_error;
if (i < 1) {
- expected_error = "Unable to read frame count.";
- } else if (i < 2) {
expected_error = "Unable to read frame type.";
- } else if (i < 3) {
+ } else if (i < 2) {
expected_error = "Unable to read congestion feedback type.";
- } else if (i < 5) {
+ } else if (i < 4) {
expected_error = "Unable to read accumulated number of lost packets.";
- } else if (i < 7) {
+ } else if (i < 6) {
expected_error = "Unable to read receive window.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -886,8 +945,6 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (inter arrival)
@@ -942,29 +999,27 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
iter->second);
// Now test framing boundaries
- for (size_t i = 0; i < 32; ++i) {
+ for (size_t i = 0; i < 31; ++i) {
string expected_error;
if (i < 1) {
- expected_error = "Unable to read frame count.";
- } else if (i < 2) {
expected_error = "Unable to read frame type.";
- } else if (i < 3) {
+ } else if (i < 2) {
expected_error = "Unable to read congestion feedback type.";
- } else if (i < 5) {
+ } else if (i < 4) {
expected_error = "Unable to read accumulated number of lost packets.";
- } else if (i < 6) {
+ } else if (i < 5) {
expected_error = "Unable to read num received packets.";
- } else if (i < 12) {
+ } else if (i < 11) {
expected_error = "Unable to read smallest received.";
- } else if (i < 20) {
+ } else if (i < 19) {
expected_error = "Unable to read time received.";
- } else if (i < 22) {
+ } else if (i < 21) {
expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < 26) {
+ } else if (i < 25) {
expected_error = "Unable to read time delta in received packets.";
- } else if (i < 28) {
+ } else if (i < 27) {
expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < 32) {
+ } else if (i < 31) {
expected_error = "Unable to read time delta in received packets.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -987,8 +1042,6 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (fix rate)
@@ -1013,15 +1066,13 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
frame.fix_rate.bitrate_in_bytes_per_second);
// Now test framing boundaries
- for (size_t i = 0; i < 7; ++i) {
+ for (size_t i = 0; i < 6; ++i) {
string expected_error;
if (i < 1) {
- expected_error = "Unable to read frame count.";
- } else if (i < 2) {
expected_error = "Unable to read frame type.";
- } else if (i < 3) {
+ } else if (i < 2) {
expected_error = "Unable to read congestion feedback type.";
- } else if (i < 7) {
+ } else if (i < 6) {
expected_error = "Unable to read bitrate.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -1045,8 +1096,6 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (invalid)
@@ -1074,8 +1123,6 @@ TEST_F(QuicFramerTest, RstStreamFrame) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (rst stream frame)
0x04,
// stream id
@@ -1110,15 +1157,15 @@ TEST_F(QuicFramerTest, RstStreamFrame) {
EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details);
// Now test framing boundaries
- for (size_t i = 3; i < 33; ++i) {
+ for (size_t i = 2; i < 32; ++i) {
string expected_error;
- if (i < 6) {
+ if (i < 5) {
expected_error = "Unable to read stream_id.";
- } else if (i < 14) {
+ } else if (i < 13) {
expected_error = "Unable to read offset in rst frame.";
- } else if (i < 18) {
+ } else if (i < 17) {
expected_error = "Unable to read rst stream error code.";
- } else if (i < 33) {
+ } else if (i < 32) {
expected_error = "Unable to read rst stream error details.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -1141,8 +1188,6 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (connection close frame)
0x05,
// error code
@@ -1168,14 +1213,6 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
// missing packet
0xBE, 0x9A, 0x78, 0x56,
0x34, 0x12,
- // congestion feedback type (inter arrival)
- 0x02,
- // accumulated_number_of_lost_packets
- 0x02, 0x03,
- // offset_time
- 0x04, 0x05,
- // delta_time
- 0x06, 0x07,
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
@@ -1200,11 +1237,11 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked);
// Now test framing boundaries
- for (size_t i = 3; i < 21; ++i) {
+ for (size_t i = 2; i < 20; ++i) {
string expected_error;
- if (i < 6) {
+ if (i < 5) {
expected_error = "Unable to read connection close error code.";
- } else if (i < 21) {
+ } else if (i < 20) {
expected_error = "Unable to read connection close error details.";
}
CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error,
@@ -1212,6 +1249,50 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
}
}
+TEST_F(QuicFramerTest, PublicResetPacket) {
+ unsigned char packet[] = {
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags (public reset)
+ 0x02,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.public_reset_packet_.get());
+ EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
+ visitor_.public_reset_packet_->public_header.guid);
+ EXPECT_EQ(PACKET_PUBLIC_FLAGS_RST,
+ visitor_.public_reset_packet_->public_header.flags);
+ EXPECT_EQ(GG_UINT64_C(0xABCDEF0123456789),
+ visitor_.public_reset_packet_->nonce_proof);
+ EXPECT_EQ(GG_UINT64_C(0x123456789ABC),
+ visitor_.public_reset_packet_->rejected_sequence_number);
+
+ // Now test framing boundaries
+ for (size_t i = 0; i < kPublicResetPacketSize; ++i) {
+ string expected_error;
+ if (i < kPublicFlagsOffset) {
+ expected_error = "Unable to read GUID.";
+ } else if (i < kPublicResetPacketNonceProofOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < kPublicResetPacketRejectedSequenceNumberOffset) {
+ expected_error = "Unable to read nonce proof.";
+ } else {
+ expected_error = "Unable to read rejected sequence number.";
+ }
+ CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
TEST_F(QuicFramerTest, FecPacket) {
unsigned char packet[] = {
// guid
@@ -1276,8 +1357,6 @@ TEST_F(QuicFramerTest, ConstructPaddingFramePacket) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (padding frame)
0x00,
};
@@ -1325,8 +1404,6 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (stream frame)
0x01,
// stream id
@@ -1383,8 +1460,6 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (ack frame)
0x02,
// least packet sequence number awaiting an ack
@@ -1438,8 +1513,6 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (TCP)
@@ -1495,8 +1568,6 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (inter arrival)
@@ -1559,8 +1630,6 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (congestion feedback frame)
0x03,
// congestion feedback type (fix rate)
@@ -1624,8 +1693,6 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (rst stream frame)
0x04,
// stream id
@@ -1689,8 +1756,6 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) {
// first fec protected packet offset
0xFF,
- // frame count
- 0x01,
// frame type (connection close frame)
0x05,
// error code
@@ -1725,6 +1790,36 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) {
AsChars(packet), arraysize(packet));
}
+TEST_F(QuicFramerTest, ConstructPublicResetPacket) {
+ QuicPublicResetPacket reset_packet;
+ reset_packet.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
+ reset_packet.public_header.flags = PACKET_PUBLIC_FLAGS_RST;
+ reset_packet.rejected_sequence_number = GG_UINT64_C(0x123456789ABC);
+ reset_packet.nonce_proof = GG_UINT64_C(0xABCDEF0123456789);
+
+ unsigned char packet[] = {
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags
+ 0x02,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+
+ scoped_ptr<QuicEncryptedPacket> data(
+ framer_.ConstructPublicResetPacket(reset_packet));
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_F(QuicFramerTest, ConstructFecPacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
@@ -1864,21 +1959,86 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) {
// Now make sure we can turn our ack packet back into an ack frame
ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, *ack_packet));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- ASSERT_EQ(peer_address_, visitor_.peer_address_);
- ASSERT_EQ(self_address_, visitor_.self_address_);
- EXPECT_EQ(1u, visitor_.ack_frames_.size());
// And do the same for the close frame.
ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_,
*close_packet));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- EXPECT_EQ(0x05060708, visitor_.connection_close_frame_.error_code);
- EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
+}
+
+TEST_F(QuicFramerTest, CleanTruncation) {
+ QuicPacketHeader header;
+ header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE;
+ header.private_flags = PACKET_PRIVATE_FLAGS_NONE;
+ header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.fec_group = 0;
+
+ QuicConnectionCloseFrame close_frame;
+ QuicAckFrame* ack_frame = &close_frame.ack_frame;
+ close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
+ close_frame.error_details = "because I can";
+ ack_frame->received_info.largest_observed = 201;
+ for (uint64 i = 1; i < ack_frame->received_info.largest_observed; ++i) {
+ ack_frame->received_info.missing_packets.insert(i);
+ }
+
+ // Create a packet with just the ack
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ scoped_ptr<QuicPacket> raw_ack_packet(
+ framer_.ConstructFrameDataPacket(header, frames));
+ ASSERT_TRUE(raw_ack_packet != NULL);
+
+ scoped_ptr<QuicEncryptedPacket> ack_packet(
+ framer_.EncryptPacket(*raw_ack_packet));
- ValidateTruncatedAck(visitor_.ack_frames_[0], 194);
- ValidateTruncatedAck(&visitor_.connection_close_frame_.ack_frame, 191);
+ // Create a packet with just connection close.
+ frames.clear();
+ frame.type = CONNECTION_CLOSE_FRAME;
+ frame.connection_close_frame = &close_frame;
+ frames.push_back(frame);
+
+ scoped_ptr<QuicPacket> raw_close_packet(
+ framer_.ConstructFrameDataPacket(header, frames));
+ ASSERT_TRUE(raw_close_packet != NULL);
+
+ scoped_ptr<QuicEncryptedPacket> close_packet(
+ framer_.EncryptPacket(*raw_close_packet));
+
+ // Now make sure we can turn our ack packet back into an ack frame
+ ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, *ack_packet));
+
+ // And do the same for the close frame.
+ ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_,
+ *close_packet));
+
+ // Test for clean truncation of the ack by comparing the length of the
+ // original packets to the re-serialized packets.
+ frames.clear();
+ frame.type = ACK_FRAME;
+ frame.ack_frame = visitor_.ack_frames_[0];
+ frames.push_back(frame);
+
+ size_t original_raw_length = raw_ack_packet->length();
+ raw_ack_packet.reset(
+ framer_.ConstructFrameDataPacket(header, frames));
+ ASSERT_TRUE(raw_ack_packet != NULL);
+ EXPECT_EQ(original_raw_length, raw_ack_packet->length());
+
+ frames.clear();
+ frame.type = CONNECTION_CLOSE_FRAME;
+ frame.connection_close_frame = &visitor_.connection_close_frame_;
+ frames.push_back(frame);
+
+ original_raw_length = raw_close_packet->length();
+ raw_close_packet.reset(
+ framer_.ConstructFrameDataPacket(header, frames));
+ ASSERT_TRUE(raw_ack_packet != NULL);
+ EXPECT_EQ(original_raw_length, raw_close_packet->length());
}
} // namespace test
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index cd79bbb..39d9f7e 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -44,6 +44,7 @@ bool QuicPacketCreator::ShouldSendFec(bool force_close) const {
void QuicPacketCreator::MaybeStartFEC() {
if (options_.max_packets_per_fec_group > 0) {
DCHECK(fec_group_.get() == NULL);
+ // Set the fec group number to the sequence number of the next packet.
fec_group_number_ = sequence_number() + 1;
fec_group_.reset(new QuicFecGroup());
}
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 0fc8176..f9836f3 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -73,6 +73,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// Packetize FEC data.
PacketPair SerializeFec();
+ // Creates a packet with connection close frame. Caller owns the created
+ // packet.
PacketPair CloseConnection(QuicConnectionCloseFrame* close_frame);
QuicPacketSequenceNumber sequence_number() const {
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index bc486dc..83f4ae8 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -33,6 +33,7 @@ typedef uint32 QuicStreamId;
typedef uint64 QuicStreamOffset;
typedef uint64 QuicPacketSequenceNumber;
typedef QuicPacketSequenceNumber QuicFecGroupNumber;
+typedef uint64 QuicPublicResetNonceProof;
// TODO(rch): Consider Quic specific names for these constants.
const size_t kMaxPacketSize = 1200; // Maximum size in bytes of a QUIC packet.
@@ -50,10 +51,15 @@ const size_t kSequenceNumberSize = 6;
const size_t kPrivateFlagsSize = 1;
// Number of bytes reserved for FEC group in the packet header.
const size_t kFecGroupSize = 1;
+// Number of bytes reserved for the nonce proof in public reset packet.
+const size_t kPublicResetNonceSize = 8;
// Size in bytes of the data or fec packet header.
const size_t kPacketHeaderSize = kQuicGuidSize + kPublicFlagsSize +
kPrivateFlagsSize + kSequenceNumberSize + kFecGroupSize;
+// Size in bytes of the public reset packet.
+const size_t kPublicResetPacketSize = kQuicGuidSize + kPublicFlagsSize +
+ kPublicResetNonceSize + kSequenceNumberSize;
// Index into the guid offset in the header.
const size_t kGuidOffset = 0;
@@ -67,6 +73,13 @@ const size_t kPrivateFlagsOffset = kSequenceNumberOffset + kSequenceNumberSize;
// Index into the fec group offset in the header.
const size_t kFecGroupOffset = kPrivateFlagsOffset + kPrivateFlagsSize;
+// Index into the nonce proof of the public reset packet.
+const size_t kPublicResetPacketNonceProofOffset = kPublicFlagsOffset +
+ kPublicFlagsSize;
+// Index into the rejected sequence number of the public reset packet.
+const size_t kPublicResetPacketRejectedSequenceNumberOffset =
+ kPublicResetPacketNonceProofOffset + kPublicResetNonceSize;
+
// Index of the first byte in a QUIC packet of FEC protected data.
const size_t kStartOfFecProtectedData = kPacketHeaderSize;
// Index of the first byte in a QUIC packet of encrypted data.
@@ -162,6 +175,8 @@ enum QuicErrorCode {
QUIC_INVALID_STREAM_ID,
// Too many streams already open.
QUIC_TOO_MANY_OPEN_STREAMS,
+ // Received public reset for this connection.
+ QUIC_PUBLIC_RESET,
// We hit our prenegotiated (or default) timeout
QUIC_CONNECTION_TIMED_OUT,
@@ -199,6 +214,15 @@ struct QuicPacketHeader {
QuicFecGroupNumber fec_group;
};
+struct QuicPublicResetPacket {
+ QuicPublicResetPacket() {}
+ explicit QuicPublicResetPacket(const QuicPacketPublicHeader& header)
+ : public_header(header) {}
+ QuicPacketPublicHeader public_header;
+ QuicPacketSequenceNumber rejected_sequence_number;
+ QuicPublicResetNonceProof nonce_proof;
+};
+
// A padding frame contains no payload.
struct NET_EXPORT_PRIVATE QuicPaddingFrame {
};
diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc
index 7d3ba66..a2c6901 100644
--- a/net/quic/quic_time.cc
+++ b/net/quic/quic_time.cc
@@ -15,26 +15,27 @@ QuicTime::Delta::Delta(base::TimeDelta delta)
: delta_(delta) {
}
+// static
QuicTime::Delta QuicTime::Delta::Zero() {
return QuicTime::Delta::FromMicroseconds(0);
}
+// static
QuicTime::Delta QuicTime::Delta::Infinite() {
return QuicTime::Delta::FromMicroseconds(kQuicInfiniteTimeUs);
}
-bool QuicTime::Delta::IsZero() const {
- return delta_.InMicroseconds() == 0;
-}
-
-bool QuicTime::Delta::IsInfinite() const {
- return delta_.InMicroseconds() == kQuicInfiniteTimeUs;
+// static
+QuicTime::Delta QuicTime::Delta::FromSeconds(int64 seconds) {
+ return QuicTime::Delta(base::TimeDelta::FromSeconds(seconds));
}
+// static
QuicTime::Delta QuicTime::Delta::FromMilliseconds(int64 ms) {
return QuicTime::Delta(base::TimeDelta::FromMilliseconds(ms));
}
+// static
QuicTime::Delta QuicTime::Delta::FromMicroseconds(int64 us) {
return QuicTime::Delta(base::TimeDelta::FromMicroseconds(us));
}
@@ -61,15 +62,20 @@ QuicTime::Delta QuicTime::Delta::Subtract(const Delta& delta) const {
delta.ToMicroseconds());
}
+bool QuicTime::Delta::IsZero() const {
+ return delta_.InMicroseconds() == 0;
+}
+
+bool QuicTime::Delta::IsInfinite() const {
+ return delta_.InMicroseconds() == kQuicInfiniteTimeUs;
+}
+
// static
QuicTime QuicTime::Zero() {
return QuicTime::FromMilliseconds(0);
}
-QuicTime::QuicTime(base::TimeTicks ticks)
- : ticks_(ticks) {
-}
-
+// static
QuicTime QuicTime::FromMilliseconds(int64 time_ms) {
// DateTime use 100 ns as resolution make sure we don't pass down too high
// values.
@@ -78,6 +84,7 @@ QuicTime QuicTime::FromMilliseconds(int64 time_ms) {
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.
@@ -86,6 +93,10 @@ QuicTime QuicTime::FromMicroseconds(int64 time_us) {
base::TimeDelta::FromMicroseconds(time_us));
}
+QuicTime::QuicTime(base::TimeTicks ticks)
+ : ticks_(ticks) {
+}
+
int64 QuicTime::ToMilliseconds() const {
return (ticks_ - base::TimeTicks()).InMilliseconds();
}
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index a1fb6a3..db95241 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -25,11 +25,14 @@ class NET_EXPORT_PRIVATE QuicTime {
public:
explicit Delta(base::TimeDelta delta);
+ // Create a object with an offset of 0.
+ static Delta Zero();
+
// Create a object with infinite offset time.
static Delta Infinite();
- // Create a object with infinite offset time.
- static Delta Zero();
+ // Converts a number of seconds to a time offset.
+ static Delta FromSeconds(int64 secs);
// Converts a number of milliseconds to a time offset.
static Delta FromMilliseconds(int64 ms);
@@ -58,6 +61,7 @@ class NET_EXPORT_PRIVATE QuicTime {
base::TimeDelta delta_;
friend class QuicTime;
+ friend class QuicClock;
};
explicit QuicTime(base::TimeTicks ticks);
diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc
index 5353289..811204bd 100644
--- a/net/quic/quic_time_test.cc
+++ b/net/quic/quic_time_test.cc
@@ -28,9 +28,17 @@ TEST_F(QuicTimeDeltaTest, Infinite) {
TEST_F(QuicTimeDeltaTest, FromTo) {
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1),
QuicTime::Delta::FromMicroseconds(1000));
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
+ QuicTime::Delta::FromMilliseconds(1000));
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
+ QuicTime::Delta::FromMicroseconds(1000000));
+
EXPECT_EQ(1, QuicTime::Delta::FromMicroseconds(1000).ToMilliseconds());
EXPECT_EQ(2, QuicTime::Delta::FromMilliseconds(2000).ToSeconds());
EXPECT_EQ(1000, QuicTime::Delta::FromMilliseconds(1).ToMicroseconds());
+ EXPECT_EQ(1, QuicTime::Delta::FromMicroseconds(1000).ToMilliseconds());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2000).ToMicroseconds(),
+ QuicTime::Delta::FromSeconds(2).ToMicroseconds());
}
TEST_F(QuicTimeDeltaTest, Add) {
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 0ff25d0..ee88289 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -13,7 +13,6 @@ namespace net {
size_t QuicUtils::StreamFramePacketOverhead(int num_frames) {
// TODO(jar): Use sizeof(some name).
return kPacketHeaderSize +
- 1 + // frame count
(1 + // 8 bit type
kMinStreamFrameLength) * num_frames;
}
@@ -68,6 +67,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID);
RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS);
+ RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET);
RETURN_STRING_LITERAL(QUIC_CONNECTION_TIMED_OUT);
// Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here.
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index b2600df..61d204b 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -45,6 +45,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
MOCK_METHOD1(OnError, void(QuicFramer* framer));
MOCK_METHOD2(OnPacket, void(const IPEndPoint& self_address,
const IPEndPoint& peer_address));
+ MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header));
MOCK_METHOD0(OnRevivedPacket, void());
// The constructor set this up to return true by default.
MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header));
@@ -70,6 +71,8 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface {
virtual void OnError(QuicFramer* framer) OVERRIDE {}
virtual void OnPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address) OVERRIDE {}
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) OVERRIDE {}
virtual void OnRevivedPacket() OVERRIDE {}
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
virtual void OnFecProtectedPayload(base::StringPiece payload) OVERRIDE {}