Land Recent QUIC Changes.
Cleanup: remove BlockedWriterInterface from QuicPacketWriter.
No behavior changes.
Merge internal change: 60499316
https://codereview.chromium.org/135363006/
Properly trigger OnCanWrite processing from PacketDroppingTestWriter.
Re-enable the LargePostWithPacketLossAndBlockedSocket test.
Testing only.
Dialing back the loss from 30% to 10% seems to have stabilized the test.
Merge internal change: 60479729
https://codereview.chromium.org/131503016/
Use LOG_IF instead of LOG_IF_FIRST_N in a few places, as per avd's
suggestion.
Merge internal change: 60382807
https://codereview.chromium.org/149163004/
Change the default RTT from 60ms to 100ms, which is more typical of
internal server's.
Merge internal change: 60366147
https://codereview.chromium.org/146583006/
Remove an impossible check in QuicConnection for when a packet is
retransmitted before it is sent.
Updating the tests also found and fixed an edge case where a truncated
ack could cause the SentPacketManager to raise the high water mark above
a pending packet.
Merge internal change: 60169343
https://codereview.chromium.org/145123003/
Export primary insecure and secure QUIC config id via internal server
status pages.
Merge internal change: 60108488
https://codereview.chromium.org/137423015/
Export SCIDs, QUIC secret seed names and orbits to varz.
Merge internal change: 60107113
https://codereview.chromium.org/144033006/
Refactor QuicConnection to use explicit notification for getting onto
the write blocked list. Remove the PacketWriter interface from
QuicDispatcher.
Merge internal change: 60103466
Fix build. Build got broken by a race between presubmit tests and me
editing the file that was in the process of being submitted. :(
Merge internal change: 60104577
https://codereview.chromium.org/149263002/
Remove the word Payload from AddFrame methods in QUIC framer.
Merge internal change: 60101552
https://codereview.chromium.org/131513022/
Fixes QUIC's Cubic sender to use correct alpha when in Reno mode.
Merge internal change: 60088487
https://codereview.chromium.org/136453013/
Add DFATALs to QuicFramer branches where packet creation fails.
Merge internal change: 60077767
https://codereview.chromium.org/148073002/
Fix a QUIC bug where previously undecryptable packets were not decrypted
before sending out an ack when the encryption level changed.
Merge internal change: 60051502
Added logging for all frame types.
Added code to dump frames and packet_headers. Changes to make
QuicHttpStreamTest work.
https://codereview.chromium.org/144063012/
[email protected]
Review URL: https://codereview.chromium.org/146033003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247827 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc
index 2212098..938faaea 100644
--- a/net/quic/congestion_control/cubic.cc
+++ b/net/quic/congestion_control/cubic.cc
@@ -26,10 +26,26 @@
const int kCubeCongestionWindowScale = 410;
const uint64 kCubeFactor = (GG_UINT64_C(1) << kCubeScale) /
kCubeCongestionWindowScale;
-const uint32 kBetaSPDY = 939; // Back off factor after loss for SPDY, reduces
- // the CWND by 1/12th.
-const uint32 kBetaLastMax = 871; // Additional back off factor after loss for
- // the stored max value.
+
+const uint32 kNumConnections = 2;
+const float kBeta = static_cast<float>(0.7); // Default Cubic backoff factor.
+// Additional backoff factor when loss occurs in the concave part of the Cubic
+// curve. This additional backoff factor is expected to give up bandwidth to
+// new concurrent flows and speed up convergence.
+const float kBetaLastMax = static_cast<float>(0.85);
+
+// kNConnectionBeta is the backoff factor after loss for our N-connection
+// emulation, which emulates the effective backoff of an ensemble of N TCP-Reno
+// connections on a single loss event. The effective multiplier is computed as:
+const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
+
+// TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that
+// kBeta here is a cwnd multiplier, and is equal to 1-beta from the CUBIC paper.
+// We derive the equivalent kNConnectionAlpha for an N-connection emulation as:
+const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
+ (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
+// TODO(jri): Compute kNConnectionBeta and kNConnectionAlpha from
+// number of active streams.
} // namespace
Cubic::Cubic(const QuicClock* clock)
@@ -57,12 +73,12 @@
// We never reached the old max, so assume we are competing with another
// flow. Use our extra back off factor to allow the other flow to go up.
last_max_congestion_window_ =
- (kBetaLastMax * current_congestion_window) >> 10;
+ static_cast<int>(kBetaLastMax * current_congestion_window);
} else {
last_max_congestion_window_ = current_congestion_window;
}
epoch_ = QuicTime::Zero(); // Reset time.
- return (current_congestion_window * kBetaSPDY) >> 10;
+ return static_cast<int>(current_congestion_window * kNConnectionBeta);
}
QuicTcpCongestionWindow Cubic::CongestionWindowAfterAck(
@@ -114,13 +130,21 @@
// We have a new cubic congestion window.
last_target_congestion_window_ = target_congestion_window;
- // Update estimated TCP congestion_window.
- // Note: we do a normal Reno congestion avoidance calculation not the
- // calculation described in section 3.3 TCP-friendly region of the document.
- while (acked_packets_count_ >= estimated_tcp_congestion_window_) {
- acked_packets_count_ -= estimated_tcp_congestion_window_;
+ DCHECK_LT(0u, estimated_tcp_congestion_window_);
+ // With dynamic beta/alpha based on number of active streams, it is possible
+ // for the required_ack_count to become much lower than acked_packets_count_
+ // suddenly, leading to more than one iteration through the following loop.
+ while (true) {
+ // Update estimated TCP congestion_window.
+ uint32 required_ack_count =
+ estimated_tcp_congestion_window_ / kNConnectionAlpha;
+ if (acked_packets_count_ < required_ack_count) {
+ break;
+ }
+ acked_packets_count_ -= required_ack_count;
estimated_tcp_congestion_window_++;
}
+
// Compute target congestion_window based on cubic target and estimated TCP
// congestion_window, use highest (fastest).
if (target_congestion_window < estimated_tcp_congestion_window_) {
diff --git a/net/quic/congestion_control/cubic_test.cc b/net/quic/congestion_control/cubic_test.cc
index 8e0d8e9e..00bd37b 100644
--- a/net/quic/congestion_control/cubic_test.cc
+++ b/net/quic/congestion_control/cubic_test.cc
@@ -11,6 +11,12 @@
namespace net {
namespace test {
+const float kBeta = static_cast<float>(0.7); // Default Cubic backoff factor.
+const uint32 kNumConnections = 2;
+const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
+const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
+ (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
+
class CubicTest : public ::testing::Test {
protected:
CubicTest()
@@ -24,7 +30,7 @@
Cubic cubic_;
};
-TEST_F(CubicTest, AboveOrgin) {
+TEST_F(CubicTest, AboveOrigin) {
// Convex growth.
const QuicTime::Delta rtt_min = hundred_ms_;
uint32 current_cwnd = 10;
@@ -36,14 +42,14 @@
current_cwnd = expected_cwnd;
// Normal TCP phase.
for (int i = 0; i < 48; ++i) {
- for (uint32 n = 1; n < current_cwnd; ++n) {
+ for (uint32 n = 1; n < current_cwnd / kNConnectionAlpha; ++n) {
// Call once per ACK.
- EXPECT_EQ(current_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
+ EXPECT_NEAR(current_cwnd,
+ cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min), 1);
}
clock_.AdvanceTime(hundred_ms_);
current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
- EXPECT_EQ(expected_cwnd, current_cwnd);
+ EXPECT_NEAR(expected_cwnd, current_cwnd, 1);
expected_cwnd++;
}
// Cubic phase.
@@ -70,15 +76,15 @@
clock_.AdvanceTime(one_ms_);
EXPECT_EQ(expected_cwnd,
cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- expected_cwnd = current_cwnd * 939 / 1024;
+ expected_cwnd = static_cast<int>(current_cwnd * kNConnectionBeta);
EXPECT_EQ(expected_cwnd,
cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
- expected_cwnd = current_cwnd * 939 / 1024;
+ expected_cwnd = static_cast<int>(current_cwnd * kNConnectionBeta);
EXPECT_EQ(expected_cwnd,
cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
}
-TEST_F(CubicTest, BelowOrgin) {
+TEST_F(CubicTest, BelowOrigin) {
// Concave growth.
const QuicTime::Delta rtt_min = hundred_ms_;
uint32 current_cwnd = 422;
@@ -87,23 +93,18 @@
clock_.AdvanceTime(one_ms_);
EXPECT_EQ(expected_cwnd,
cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- expected_cwnd = current_cwnd * 939 / 1024;
+ expected_cwnd = static_cast<int>(current_cwnd * kNConnectionBeta);
EXPECT_EQ(expected_cwnd,
cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
current_cwnd = expected_cwnd;
- // First update after epoch.
+ // First update after loss to initialize the epoch.
current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
// Cubic phase.
- for (int i = 0; i < 54; ++i) {
- for (uint32 n = 1; n < current_cwnd; ++n) {
- // Call once per ACK.
- EXPECT_EQ(current_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- }
+ for (int i = 0; i < 40 ; ++i) {
clock_.AdvanceTime(hundred_ms_);
current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
}
- expected_cwnd = 440;
+ expected_cwnd = 422;
EXPECT_EQ(expected_cwnd, current_cwnd);
}
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index a978cf6d..b44d2da 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -24,7 +24,7 @@
const int64 kInitialCongestionWindow = 10;
const int kMaxBurstLength = 3;
// Constants used for RTT calculation.
-const int kInitialRttMs = 60; // At a typical RTT 60 ms.
+const int kInitialRttMs = 100; // At a typical RTT 100 ms.
const float kAlpha = 0.125f;
const float kOneMinusAlpha = (1 - kAlpha);
const float kBeta = 0.25f;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 9faecc4..88921ba 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -498,7 +498,9 @@
TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) {
const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
- const int kNumberOfAcks = 1000;
+ // Set to 10000 to compensate for small cubic alpha.
+ const int kNumberOfAcks = 10000;
+
sender_.reset(
new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index 8d8c203..e2b0583 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -147,6 +147,11 @@
// static
const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
+PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {
+}
+
+PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {
+}
ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {
}
@@ -416,6 +421,14 @@
return ok;
}
+void QuicCryptoServerConfig::GetConfigIds(vector<string>* scids) const {
+ base::AutoLock locked(configs_lock_);
+ for (ConfigMap::const_iterator it = configs_.begin();
+ it != configs_.end(); ++it) {
+ scids->push_back(it->first);
+ }
+}
+
void QuicCryptoServerConfig::ValidateClientHello(
const CryptoHandshakeMessage& client_hello,
IPEndPoint client_ip,
@@ -784,6 +797,9 @@
<< base::HexEncode(
reinterpret_cast<const char*>(primary_config_->orbit),
kOrbitSize);
+ if (primary_config_changed_cb_.get() != NULL) {
+ primary_config_changed_cb_->Run(primary_config_->id);
+ }
return;
}
@@ -801,6 +817,9 @@
reinterpret_cast<const char*>(primary_config_->orbit),
kOrbitSize);
next_config_promotion_time_ = QuicWallTime::Zero();
+ if (primary_config_changed_cb_.get() != NULL) {
+ primary_config_changed_cb_->Run(primary_config_->id);
+ }
}
void QuicCryptoServerConfig::EvaluateClientHello(
@@ -1184,6 +1203,12 @@
server_nonce_strike_register_window_secs_ = window_secs;
}
+void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
+ PrimaryConfigChangedCallback* cb) {
+ base::AutoLock locked(configs_lock_);
+ primary_config_changed_cb_.reset(cb);
+}
+
string QuicCryptoServerConfig::NewSourceAddressToken(
const IPEndPoint& ip,
QuicRandom* rand,
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index 0886a52f..0b76268e 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -39,6 +39,14 @@
class QuicCryptoServerConfigPeer;
} // namespace test
+// Hook that allows application code to subscribe to primary config changes.
+class PrimaryConfigChangedCallback {
+ public:
+ PrimaryConfigChangedCallback();
+ virtual ~PrimaryConfigChangedCallback();
+ virtual void Run(const std::string& scid) = 0;
+};
+
// Callback used to accept the result of the |client_hello| validation step.
class NET_EXPORT_PRIVATE ValidateClientHelloResultCallback {
public:
@@ -134,6 +142,9 @@
bool SetConfigs(const std::vector<QuicServerConfigProtobuf*>& protobufs,
QuicWallTime now);
+ // Get the server config ids for all known configs.
+ void GetConfigIds(std::vector<std::string>* scids) const;
+
// Checks |client_hello| for gross errors and determines whether it
// can be shown to be fresh (i.e. not a replay). The result of the
// validation step must be interpreted by calling
@@ -254,6 +265,9 @@
// uniqueness.
void set_server_nonce_strike_register_window_secs(uint32 window_secs);
+ // Set and take ownership of the callback to invoke on primary config changes.
+ void AcquirePrimaryConfigChangedCb(PrimaryConfigChangedCallback* cb);
+
private:
friend class test::QuicCryptoServerConfigPeer;
@@ -382,6 +396,8 @@
// next_config_promotion_time_ contains the nearest, future time when an
// active config will be promoted to primary.
mutable QuicWallTime next_config_promotion_time_;
+ // Callback to invoke when the primary config changes.
+ scoped_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_;
// Protects access to the pointer held by strike_register_client_.
mutable base::Lock strike_register_client_lock_;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 8dd50413..5e0ea536 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -37,8 +37,7 @@
virtual WriteResult WritePacket(
const char* buffer, size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
+ const IPEndPoint& peer_address) OVERRIDE {
QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), true);
FramerVisitorCapturingFrames visitor;
framer.set_visitor(&visitor);
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index f1e25d6..737fee4 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -167,6 +167,7 @@
largest_seen_packet_with_ack_(0),
pending_version_negotiation_packet_(false),
received_packet_manager_(kTCP),
+ ack_queued_(false),
ack_alarm_(helper->CreateAlarm(new AckAlarm(this))),
retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))),
send_alarm_(helper->CreateAlarm(new SendAlarm(this))),
@@ -636,13 +637,7 @@
<< last_stream_frames_.size()
<< " stream frames for " << last_header_.public_header.guid;
- // Must called before ack processing, because processing acks removes entries
- // from unacket_packets_, increasing the least_unacked.
- const bool last_packet_should_instigate_ack = ShouldLastPacketInstigateAck();
-
- // If the incoming packet was missing, send an ack immediately.
- bool send_ack_immediately = received_packet_manager_.IsMissing(
- last_header_.packet_sequence_number);
+ MaybeQueueAck();
// Discard the packet if the visitor fails to process the stream frames.
if (!last_stream_frames_.empty() &&
@@ -680,15 +675,36 @@
// If there are new missing packets to report, send an ack immediately.
if (received_packet_manager_.HasNewMissingPackets()) {
- send_ack_immediately = true;
+ ack_queued_ = true;
+ ack_alarm_->Cancel();
}
- MaybeSendInResponseToPacket(send_ack_immediately,
- last_packet_should_instigate_ack);
-
ClearLastFrames();
}
+void QuicConnection::MaybeQueueAck() {
+ // If the incoming packet was missing, send an ack immediately.
+ ack_queued_ = received_packet_manager_.IsMissing(
+ last_header_.packet_sequence_number);
+
+ // ShouldLastPacketInstigateAck must called before ack processing, because
+ // processing acks removes entries from unacket_packets_, increasing the
+ // least_unacked.
+ if (!ack_queued_ && ShouldLastPacketInstigateAck()) {
+ if (ack_alarm_->IsSet()) {
+ ack_queued_ = true;
+ } else {
+ ack_alarm_->Set(clock_->ApproximateNow().Add(
+ sent_packet_manager_.DelayedAckTime()));
+ DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
+ }
+ }
+
+ if (ack_queued_) {
+ ack_alarm_->Cancel();
+ }
+}
+
void QuicConnection::ClearLastFrames() {
last_stream_frames_.clear();
last_goaway_frames_.clear();
@@ -717,9 +733,8 @@
return true;
}
- // If the peer is still waiting for a packet that we are no
- // longer planning to send, we should send an ack to raise
- // the high water mark.
+ // If the peer is still waiting for a packet that we are no longer planning to
+ // send, send an ack to raise the high water mark.
if (!last_ack_frames_.empty() &&
!last_ack_frames_.back().received_info.missing_packets.empty()) {
return sent_packet_manager_.GetLeastUnackedSentPacket() >
@@ -728,61 +743,57 @@
return false;
}
-void QuicConnection::MaybeSendInResponseToPacket(
- bool send_ack_immediately,
- bool last_packet_should_instigate_ack) {
- // |include_ack| is false since we decide about ack bundling below.
+void QuicConnection::MaybeSendInResponseToPacket() {
+ if (!connected_) {
+ return;
+ }
ScopedPacketBundler bundler(this, false);
-
- if (last_packet_should_instigate_ack) {
- // In general, we ack every second packet. When we don't ack the first
- // packet, we set the delayed ack alarm. Thus, if the ack alarm is set
- // then we know this is the second packet, and we should send an ack.
- if (send_ack_immediately || ack_alarm_->IsSet()) {
- SendAck();
- DCHECK(!ack_alarm_->IsSet());
- } else {
- ack_alarm_->Set(clock_->ApproximateNow().Add(
- sent_packet_manager_.DelayedAckTime()));
- DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
- }
+ if (ack_queued_) {
+ SendAck();
}
- if (!last_ack_frames_.empty()) {
- // Now the we have received an ack, we might be able to send packets which
- // are queued locally, or drain streams which are blocked.
- QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend(
- time_of_last_received_packet_, NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE);
- if (delay.IsZero()) {
- send_alarm_->Cancel();
- WriteIfNotBlocked();
- } else if (!delay.IsInfinite()) {
- send_alarm_->Cancel();
- send_alarm_->Set(time_of_last_received_packet_.Add(delay));
- }
+ // Now that we have received an ack, we might be able to send packets which
+ // are queued locally, or drain streams which are blocked.
+ QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend(
+ time_of_last_received_packet_, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE);
+ if (delay.IsZero()) {
+ send_alarm_->Cancel();
+ WriteIfNotBlocked();
+ } else if (!delay.IsInfinite()) {
+ send_alarm_->Cancel();
+ send_alarm_->Set(time_of_last_received_packet_.Add(delay));
}
}
void QuicConnection::SendVersionNegotiationPacket() {
+ // TODO(alyssar): implement zero server state negotiation.
+ pending_version_negotiation_packet_ = true;
+ if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked();
+ return;
+ }
scoped_ptr<QuicEncryptedPacket> version_packet(
packet_creator_.SerializeVersionNegotiationPacket(
framer_.supported_versions()));
- // TODO(satyamshekhar): implement zero server state negotiation.
- WriteResult result =
- writer_->WritePacket(version_packet->data(), version_packet->length(),
- self_address().address(), peer_address(), this);
- if (result.status == WRITE_STATUS_OK ||
- (result.status == WRITE_STATUS_BLOCKED &&
- writer_->IsWriteBlockedDataBuffered())) {
- pending_version_negotiation_packet_ = false;
- return;
- }
+ WriteResult result = writer_->WritePacket(
+ version_packet->data(), version_packet->length(),
+ self_address().address(), peer_address());
+
if (result.status == WRITE_STATUS_ERROR) {
// We can't send an error as the socket is presumably borked.
CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
+ return;
}
- pending_version_negotiation_packet_ = true;
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ visitor_->OnWriteBlocked();
+ if (writer_->IsWriteBlockedDataBuffered()) {
+ pending_version_negotiation_packet_ = false;
+ }
+ return;
+ }
+
+ pending_version_negotiation_packet_ = false;
}
QuicConsumedData QuicConnection::SendStreamData(
@@ -873,8 +884,10 @@
<< last_header_.packet_sequence_number;
return;
}
+
MaybeProcessUndecryptablePackets();
MaybeProcessRevivedPacket();
+ MaybeSendInResponseToPacket();
}
bool QuicConnection::OnCanWrite() {
@@ -1027,6 +1040,7 @@
HasRetransmittableData retransmittable,
IsHandshake handshake) {
if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked();
return false;
}
@@ -1107,6 +1121,7 @@
// This assures we won't try to write *forced* packets when blocked.
// Return true to stop processing.
if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked();
return true;
}
}
@@ -1141,7 +1156,7 @@
WriteResult result =
writer_->WritePacket(encrypted->data(), encrypted->length(),
- self_address().address(), peer_address(), this);
+ self_address().address(), peer_address());
if (result.error_code == ERR_IO_PENDING) {
DCHECK_EQ(WRITE_STATUS_BLOCKED, result.status);
}
@@ -1150,6 +1165,7 @@
debug_visitor_->OnPacketSent(sequence_number, level, *encrypted, result);
}
if (result.status == WRITE_STATUS_BLOCKED) {
+ visitor_->OnWriteBlocked();
// If the socket buffers the the data, then the packet should not
// be queued and sent again, which would result in an unnecessary
// duplicate packet being sent. The helper must call OnPacketSent
@@ -1195,25 +1211,12 @@
return true;
}
- if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
- if (sent_packet_manager_.IsPreviousTransmission(sequence_number)) {
- // If somehow we have already retransmitted this packet *before*
- // we actually send it for the first time (I think this is probably
- // impossible in the real world), then don't bother sending it.
- // We don't want to call DiscardUnackedPacket because in this case
- // the peer has not yet ACK'd the data. We need the subsequent
- // retransmission to be sent.
- DVLOG(1) << ENDPOINT << "Dropping packet: " << sequence_number
- << " since it has already been retransmitted.";
- return true;
- }
-
- if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) {
- DVLOG(1) << ENDPOINT << "Dropping packet: " << sequence_number
- << " since a previous transmission has been acked.";
- sent_packet_manager_.DiscardUnackedPacket(sequence_number);
- return true;
- }
+ if (retransmittable == HAS_RETRANSMITTABLE_DATA &&
+ !sent_packet_manager_.HasRetransmittableFrames(sequence_number)) {
+ DVLOG(1) << ENDPOINT << "Dropping packet: " << sequence_number
+ << " since a previous transmission has been acked.";
+ sent_packet_manager_.DiscardUnackedPacket(sequence_number);
+ return true;
}
return false;
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index c7b34b7..0b35c72 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -427,25 +427,6 @@
const SerializedPacket& packet,
TransmissionType transmission_type);
- // Writes the given packet to socket, encrypted with |level|, with the help
- // of helper. Returns true on successful write, false otherwise. However,
- // behavior is undefined if connection is not established or broken. In any
- // circumstances, a return value of true implies that |packet| has been
- // transmitted and may be destroyed. 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 FORCE, then the packet will be
- // sent immediately and the send scheduler will not be consulted.
- bool WritePacket(EncryptionLevel level,
- QuicPacketSequenceNumber sequence_number,
- const QuicPacket& packet,
- TransmissionType transmission_type,
- HasRetransmittableData retransmittable,
- IsHandshake handshake,
- Force force);
-
- // Make sure an ack we got from our peer is sane.
- bool ValidateAckFrame(const QuicAckFrame& incoming_ack);
-
QuicConnectionHelperInterface* helper() { return helper_; }
// Selects and updates the version of the protocol being used by selecting a
@@ -453,8 +434,6 @@
// such a version exists, false otherwise.
bool SelectMutualVersion(const QuicVersionVector& available_versions);
- QuicFramer framer_;
-
private:
// Stores current batch state for connection, puts the connection
// into batch mode, and destruction restores the stored batch state.
@@ -532,6 +511,24 @@
typedef std::list<QueuedPacket> QueuedPacketList;
typedef std::map<QuicFecGroupNumber, QuicFecGroup*> FecGroupMap;
+ // Writes the given packet to socket, encrypted with |level|. Returns true on
+ // successful write. Behavior is undefined if connection is not established or
+ // broken. In any circumstance, a return value of true implies that |packet|
+ // has been transmitted and may be destroyed. 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 FORCE, then the packet will be
+ // sent immediately and the send scheduler will not be consulted.
+ bool WritePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
+ const QuicPacket& packet,
+ TransmissionType transmission_type,
+ HasRetransmittableData retransmittable,
+ IsHandshake handshake,
+ Force force);
+
+ // Make sure an ack we got from our peer is sane.
+ bool ValidateAckFrame(const QuicAckFrame& incoming_ack);
+
// Sends a version negotiation packet to the peer.
void SendVersionNegotiationPacket();
@@ -578,13 +575,16 @@
// Update the |sent_info| for an outgoing ack.
void UpdateSentPacketInfo(SentPacketInfo* sent_info);
+ // Queues an ack or sets the ack alarm when an incoming packet arrives that
+ // should be acked.
+ void MaybeQueueAck();
+
// Checks if the last packet should instigate an ack.
bool ShouldLastPacketInstigateAck();
// Sends any packets which are a response to the last packet, including both
// acks and pending writes if an ack opened the congestion window.
- void MaybeSendInResponseToPacket(bool send_ack_immediately,
- bool last_packet_should_instigate_ack);
+ void MaybeSendInResponseToPacket();
// Get the FEC group associate with the last processed packet or NULL, if the
// group has already been deleted.
@@ -593,6 +593,7 @@
// Closes any FEC groups protecting packets before |sequence_number|.
void CloseFecGroupsBefore(QuicPacketSequenceNumber sequence_number);
+ QuicFramer framer_;
QuicConnectionHelperInterface* helper_; // Not owned.
QuicPacketWriter* writer_; // Not owned.
EncryptionLevel encryption_level_;
@@ -647,6 +648,9 @@
QuicReceivedPacketManager received_packet_manager_;
QuicSentEntropyManager sent_entropy_manager_;
+ // Indicates whether an ack should be sent the next time we try to write.
+ bool ack_queued_;
+
// An alarm that fires when an ACK should be sent to the peer.
scoped_ptr<QuicAlarm> ack_alarm_;
// An alarm that fires when a packet needs to be retransmitted.
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index e2b0fef..48aedd6 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -31,6 +31,7 @@
using std::vector;
using testing::_;
using testing::AnyNumber;
+using testing::AtLeast;
using testing::ContainerEq;
using testing::Contains;
using testing::DoAll;
@@ -274,7 +275,7 @@
TestPacketWriter()
: last_packet_size_(0),
write_blocked_(false),
- block_next_write_(false),
+ block_on_next_write_(false),
is_write_blocked_data_buffered_(false),
is_server_(true),
final_bytes_of_last_packet_(0),
@@ -287,8 +288,7 @@
virtual WriteResult WritePacket(
const char* buffer, size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
+ const IPEndPoint& peer_address) OVERRIDE {
QuicEncryptedPacket packet(buffer, buf_len);
++packets_write_attempts_;
@@ -305,9 +305,9 @@
visitor_.Reset();
framer.set_visitor(&visitor_);
EXPECT_TRUE(framer.ProcessPacket(packet));
- if (block_next_write_) {
+ if (block_on_next_write_) {
write_blocked_ = true;
- block_next_write_ = false;
+ block_on_next_write_ = false;
}
if (IsWriteBlocked()) {
return WriteResult(WRITE_STATUS_BLOCKED, -1);
@@ -324,7 +324,7 @@
virtual void SetWritable() OVERRIDE { write_blocked_ = false; }
- void BlockNextWrite() { block_next_write_ = true; }
+ void BlockOnNextWrite() { block_on_next_write_ = true; }
// Resets the visitor's state by clearing out the headers and frames.
void Reset() {
@@ -380,7 +380,7 @@
FramerVisitorCapturingFrames visitor_;
size_t last_packet_size_;
bool write_blocked_;
- bool block_next_write_;
+ bool block_on_next_write_;
bool is_write_blocked_data_buffered_;
bool is_server_;
uint32 final_bytes_of_last_packet_;
@@ -472,7 +472,7 @@
}
void set_version(QuicVersion version) {
- framer_.set_version(version);
+ QuicConnectionPeer::GetFramer(this)->set_version(version);
}
void set_is_server(bool is_server) {
@@ -841,6 +841,11 @@
QuicConnectionPeer::GetConnectionClosePacket(&connection_) == NULL);
}
+ void BlockOnNextWrite() {
+ writer_->BlockOnNextWrite();
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ }
+
QuicGuid guid_;
QuicFramer framer_;
QuicPacketCreator creator_;
@@ -1104,8 +1109,9 @@
// This should be fine.
creator_.set_sequence_number(1);
QuicAckFrame frame2 = InitAckFrame(0, 1);
- // The scheduler will not process out of order acks.
- EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
+ // The scheduler will not process out of order acks, but all packet processing
+ // causes the connection to try to write.
+ EXPECT_CALL(visitor_, OnCanWrite()).Times(1);
ProcessAckPacket(&frame2);
// Now claim it's one, but set the ordering so it was sent "after" the first
@@ -1257,8 +1263,6 @@
TEST_F(QuicConnectionTest, BasicSending) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-// EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
-// EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(6);
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
@@ -1340,7 +1344,7 @@
connection_.options()->max_packets_per_fec_group = 2;
EXPECT_EQ(0u, connection_.NumQueuedPackets());
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
const string payload(payload_length, 'a');
connection_.SendStreamDataWithString(1, payload, 0, !kFin, NULL);
EXPECT_FALSE(creator_.ShouldSendFec(true));
@@ -1610,7 +1614,7 @@
// Try to send two stream frames in 1 packet by using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
char data[] = "ABCD";
IOVector data_iov;
data_iov.AppendNoCoalesce(data, 2);
@@ -1729,10 +1733,9 @@
NackPacket(2, &nack_two);
// The first nack should trigger a fast retransmission, but we'll be
// write blocked, so the packet will be queued.
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _));
-
ProcessAckPacket(&nack_two);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1779,7 +1782,7 @@
}
// Block the congestion window and ensure they're queued.
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
clock_.AdvanceTime(DefaultRetransmissionTime());
// Only one packet should be retransmitted.
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
@@ -1798,9 +1801,8 @@
}
TEST_F(QuicConnectionTest, WriteBlockedThenSent) {
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
-
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -1811,8 +1813,7 @@
TEST_F(QuicConnectionTest, WriteBlockedAckedThenSent) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- writer_->BlockNextWrite();
-
+ BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -1832,9 +1833,8 @@
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
-
// Simulate the retransmission alarm firing.
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(_));
clock_.AdvanceTime(DefaultRetransmissionTime());
@@ -1852,7 +1852,7 @@
TEST_F(QuicConnectionTest, ResumptionAlarmWhenWriteBlocked) {
// Block the connection.
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_TRUE(writer_->IsWriteBlocked());
@@ -2255,7 +2255,7 @@
}
TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) {
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
// Make sure that RTO is not started when the packet is queued.
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -2306,7 +2306,7 @@
TEST_F(QuicConnectionTest, TestQueued) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -2461,7 +2461,7 @@
TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
@@ -2936,7 +2936,7 @@
framer_.set_version(QuicVersionMax());
connection_.set_is_server(true);
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
EXPECT_EQ(0u, writer_->last_packet_size());
EXPECT_TRUE(connection_.HasQueuedData());
@@ -2980,7 +2980,7 @@
framer_.set_version(QuicVersionMax());
connection_.set_is_server(true);
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
EXPECT_EQ(0u, writer_->last_packet_size());
@@ -3258,14 +3258,14 @@
}
TEST_F(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) {
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
TriggerConnectionClose();
EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_TRUE(writer_->IsWriteBlocked());
}
TEST_F(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
- writer_->BlockNextWrite();
+ BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
EXPECT_EQ(1u, writer_->packets_write_attempts());
diff --git a/net/quic/quic_default_packet_writer.cc b/net/quic/quic_default_packet_writer.cc
index e249ff1..5dd80c6 100644
--- a/net/quic/quic_default_packet_writer.cc
+++ b/net/quic/quic_default_packet_writer.cc
@@ -26,8 +26,7 @@
WriteResult QuicDefaultPacketWriter::WritePacket(
const char* buffer, size_t buf_len,
const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) {
+ const net::IPEndPoint& peer_address) {
scoped_refptr<StringIOBuffer> buf(
new StringIOBuffer(std::string(buffer, buf_len)));
DCHECK(!IsWriteBlocked());
diff --git a/net/quic/quic_default_packet_writer.h b/net/quic/quic_default_packet_writer.h
index 92543604..affc6f1 100644
--- a/net/quic/quic_default_packet_writer.h
+++ b/net/quic/quic_default_packet_writer.h
@@ -15,7 +15,7 @@
namespace net {
-class QuicBlockedWriterInterface;
+struct WriteResult;
// Chrome specific packet writer which uses a DatagramClientSocket for writing
// data.
@@ -29,8 +29,7 @@
virtual WriteResult WritePacket(
const char* buffer, size_t buf_len,
const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+ const net::IPEndPoint& peer_address) OVERRIDE;
virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
virtual bool IsWriteBlocked() const OVERRIDE;
virtual void SetWritable() OVERRIDE;
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 9d15c3c..964032c 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -311,6 +311,7 @@
const SerializedPacket kNoPacket(
0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL);
if (!AppendPacketHeader(header, &writer)) {
+ LOG(DFATAL) << "AppendPacketHeader failed";
return kNoPacket;
}
@@ -319,6 +320,7 @@
const bool last_frame_in_packet = i == (frames.size() - 1);
if (!AppendTypeByte(frame, last_frame_in_packet, &writer)) {
+ LOG(DFATAL) << "AppendTypeByte failed";
return kNoPacket;
}
@@ -327,41 +329,48 @@
writer.WritePadding();
break;
case STREAM_FRAME:
- if (!AppendStreamFramePayload(
+ if (!AppendStreamFrame(
*frame.stream_frame, last_frame_in_packet, &writer)) {
+ LOG(DFATAL) << "AppendStreamFrame failed";
return kNoPacket;
}
break;
case ACK_FRAME:
- if (!AppendAckFramePayloadAndTypeByte(
+ if (!AppendAckFrameAndTypeByte(
header, *frame.ack_frame, &writer)) {
+ LOG(DFATAL) << "AppendAckFrameAndTypeByte failed";
return kNoPacket;
}
break;
case CONGESTION_FEEDBACK_FRAME:
- if (!AppendQuicCongestionFeedbackFramePayload(
+ if (!AppendQuicCongestionFeedbackFrame(
*frame.congestion_feedback_frame, &writer)) {
+ LOG(DFATAL) << "AppendQuicCongestionFeedbackFrame failed";
return kNoPacket;
}
break;
case RST_STREAM_FRAME:
- if (!AppendRstStreamFramePayload(*frame.rst_stream_frame, &writer)) {
+ if (!AppendRstStreamFrame(*frame.rst_stream_frame, &writer)) {
+ LOG(DFATAL) << "AppendRstStreamFrame failed";
return kNoPacket;
}
break;
case CONNECTION_CLOSE_FRAME:
- if (!AppendConnectionCloseFramePayload(
+ if (!AppendConnectionCloseFrame(
*frame.connection_close_frame, &writer)) {
+ LOG(DFATAL) << "AppendConnectionCloseFrame failed";
return kNoPacket;
}
break;
case GOAWAY_FRAME:
- if (!AppendGoAwayFramePayload(*frame.goaway_frame, &writer)) {
+ if (!AppendGoAwayFrame(*frame.goaway_frame, &writer)) {
+ LOG(DFATAL) << "AppendGoAwayFrame failed";
return kNoPacket;
}
break;
default:
RaiseError(QUIC_INVALID_FRAME_DATA);
+ LOG(DFATAL) << "QUIC_INVALID_FRAME_DATA";
return kNoPacket;
}
}
@@ -397,10 +406,12 @@
const SerializedPacket kNoPacket(
0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL);
if (!AppendPacketHeader(header, &writer)) {
+ LOG(DFATAL) << "AppendPacketHeader failed";
return kNoPacket;
}
if (!writer.WriteBytes(fec.redundancy.data(), fec.redundancy.length())) {
+ LOG(DFATAL) << "Failed to add FEC";
return kNoPacket;
}
@@ -619,6 +630,7 @@
bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
QuicDataWriter* writer) {
+ DVLOG(1) << "Appending header: " << header;
DCHECK(header.fec_group > 0 || header.is_in_fec_group == NOT_IN_FEC_GROUP);
uint8 public_flags = 0;
if (header.public_header.reset_flag) {
@@ -1738,7 +1750,7 @@
}
}
-bool QuicFramer::AppendStreamFramePayload(
+bool QuicFramer::AppendStreamFrame(
const QuicStreamFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer) {
@@ -1766,7 +1778,7 @@
quic_version_ = version;
}
-bool QuicFramer::AppendAckFramePayloadAndTypeByte(
+bool QuicFramer::AppendAckFrameAndTypeByte(
const QuicPacketHeader& header,
const QuicAckFrame& frame,
QuicDataWriter* writer) {
@@ -1901,7 +1913,7 @@
return true;
}
-bool QuicFramer::AppendQuicCongestionFeedbackFramePayload(
+bool QuicFramer::AppendQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteBytes(&frame.type, 1)) {
@@ -1991,7 +2003,7 @@
return true;
}
-bool QuicFramer::AppendRstStreamFramePayload(
+bool QuicFramer::AppendRstStreamFrame(
const QuicRstStreamFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteUInt32(frame.stream_id)) {
@@ -2009,7 +2021,7 @@
return true;
}
-bool QuicFramer::AppendConnectionCloseFramePayload(
+bool QuicFramer::AppendConnectionCloseFrame(
const QuicConnectionCloseFrame& frame,
QuicDataWriter* writer) {
uint32 error_code = static_cast<uint32>(frame.error_code);
@@ -2022,8 +2034,8 @@
return true;
}
-bool QuicFramer::AppendGoAwayFramePayload(const QuicGoAwayFrame& frame,
- QuicDataWriter* writer) {
+bool QuicFramer::AppendGoAwayFrame(const QuicGoAwayFrame& frame,
+ QuicDataWriter* writer) {
uint32 error_code = static_cast<uint32>(frame.error_code);
if (!writer->WriteUInt32(error_code)) {
return false;
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 47cbb96ad..5d15411 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -430,22 +430,20 @@
bool AppendTypeByte(const QuicFrame& frame,
bool last_frame_in_packet,
QuicDataWriter* writer);
- bool AppendStreamFramePayload(const QuicStreamFrame& frame,
- bool last_frame_in_packet,
- QuicDataWriter* builder);
- bool AppendAckFramePayloadAndTypeByte(const QuicPacketHeader& header,
- const QuicAckFrame& frame,
- QuicDataWriter* builder);
- bool AppendQuicCongestionFeedbackFramePayload(
+ bool AppendStreamFrame(const QuicStreamFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* builder);
+ bool AppendAckFrameAndTypeByte(const QuicPacketHeader& header,
+ const QuicAckFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame,
QuicDataWriter* builder);
- bool AppendRstStreamFramePayload(const QuicRstStreamFrame& frame,
- QuicDataWriter* builder);
- bool AppendConnectionCloseFramePayload(
- const QuicConnectionCloseFrame& frame,
- QuicDataWriter* builder);
- bool AppendGoAwayFramePayload(const QuicGoAwayFrame& frame,
- QuicDataWriter* writer);
+ bool AppendRstStreamFrame(const QuicRstStreamFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendConnectionCloseFrame(const QuicConnectionCloseFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendGoAwayFrame(const QuicGoAwayFrame& frame, QuicDataWriter* writer);
bool RaiseError(QuicErrorCode error);
void set_error(QuicErrorCode error) {
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index b1ceb49..a45f376 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -20,6 +20,7 @@
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
using base::hash_set;
using base::StringPiece;
@@ -2978,8 +2979,10 @@
QuicFrames frames;
frames.push_back(QuicFrame(&congestion_feedback_frame));
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data;
+ EXPECT_DFATAL(
+ data.reset(framer_.BuildUnsizedDataPacket(header, frames).packet),
+ "AppendQuicCongestionFeedbackFrame failed");
ASSERT_TRUE(data == NULL);
}
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index a49d6bb..926ea2a1 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -263,6 +263,13 @@
sequence_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED);
}
+ scoped_ptr<QuicEncryptedPacket> ConstructAckAndRstStreamPacket(
+ QuicPacketSequenceNumber sequence_number) {
+ return maker_.MakeAckAndRstPacket(
+ sequence_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED,
+ 1, 1, !kIncludeCongestionFeedback);
+ }
+
scoped_ptr<QuicEncryptedPacket> ConstructAckPacket(
QuicPacketSequenceNumber sequence_number,
QuicPacketSequenceNumber largest_received,
@@ -611,7 +618,7 @@
} else {
AddWrite(ConstructDataPacket(1, kIncludeVersion, kFin, 0, request_data_));
}
- AddWrite(ConstructRstStreamPacket(2));
+ AddWrite(ConstructAckAndRstStreamPacket(2));
use_closing_stream_ = true;
Initialize();
@@ -648,7 +655,7 @@
} else {
AddWrite(ConstructDataPacket(1, kIncludeVersion, kFin, 0, request_data_));
}
- AddWrite(ConstructRstStreamPacket(2));
+ AddWrite(ConstructAckAndRstStreamPacket(2));
use_closing_stream_ = true;
Initialize();
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 2ac87474..419404e4 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -421,6 +421,7 @@
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
bool save_retransmittable_frames) {
+ DVLOG(1) << "Adding frame: " << frame;
size_t frame_len = framer_->GetSerializedFrameLength(
frame, BytesFree(), queued_frames_.empty(), true,
options()->send_sequence_number_length);
diff --git a/net/quic/quic_packet_writer.h b/net/quic/quic_packet_writer.h
index a4b26d6c..16b7ade 100644
--- a/net/quic/quic_packet_writer.h
+++ b/net/quic/quic_packet_writer.h
@@ -10,7 +10,6 @@
namespace net {
-class QuicBlockedWriterInterface;
struct WriteResult;
// An interface between writers and the entity managing the
@@ -27,8 +26,7 @@
virtual WriteResult WritePacket(
const char* buffer, size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) = 0;
+ const IPEndPoint& peer_address) = 0;
// Returns true if the writer buffers and subsequently rewrites data
// when an attempt to write results in the underlying socket becoming
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index a45c4af..69b0205 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -162,7 +162,7 @@
}
// Reading from the client so this should not be considered an ERROR.
DVLOG(1) << "Unsupported QuicTag version: "
- << QuicUtils::TagToString(version_tag);
+ << QuicUtils::TagToString(version_tag);
return QUIC_VERSION_UNSUPPORTED;
}
@@ -275,6 +275,83 @@
QuicCongestionFeedbackFrame::~QuicCongestionFeedbackFrame() {
}
+ostream& operator<<(ostream& os, const QuicFrame& frame) {
+ switch (frame.type) {
+ case PADDING_FRAME: {
+ os << "type { PADDING_FRAME } ";
+ break;
+ }
+ case RST_STREAM_FRAME: {
+ os << "type { " << RST_STREAM_FRAME << " } " << *(frame.rst_stream_frame);
+ break;
+ }
+ case CONNECTION_CLOSE_FRAME: {
+ os << "type { CONNECTION_CLOSE_FRAME } "
+ << *(frame.connection_close_frame);
+ break;
+ }
+ case GOAWAY_FRAME: {
+ os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame);
+ break;
+ }
+ case STREAM_FRAME: {
+ os << "type { STREAM_FRAME } " << *(frame.stream_frame);
+ break;
+ }
+ case ACK_FRAME: {
+ os << "type { ACK_FRAME } " << *(frame.ack_frame);
+ break;
+ }
+ case CONGESTION_FEEDBACK_FRAME: {
+ os << "type { CONGESTION_FEEDBACK_FRAME } "
+ << *(frame.congestion_feedback_frame);
+ break;
+ }
+ default: {
+ LOG(ERROR) << "Unknown frame type: " << frame.type;
+ break;
+ }
+ }
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicRstStreamFrame& rst_frame) {
+ os << "stream_id { " << rst_frame.stream_id << " } "
+ << "error_code { " << rst_frame.error_code << " } "
+ << "error_details { " << rst_frame.error_details << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os,
+ const QuicConnectionCloseFrame& connection_close_frame) {
+ os << "error_code { " << connection_close_frame.error_code << " } "
+ << "error_details { " << connection_close_frame.error_details << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicGoAwayFrame& goaway_frame) {
+ os << "error_code { " << goaway_frame.error_code << " } "
+ << "last_good_stream_id { " << goaway_frame.last_good_stream_id << " } "
+ << "reason_phrase { " << goaway_frame.reason_phrase << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicStreamFrame& stream_frame) {
+ os << "stream_id { " << stream_frame.stream_id << " } "
+ << "fin { " << stream_frame.fin << " } "
+ << "offset { " << stream_frame.offset << " } "
+ << "data { "
+ << QuicUtils::StringToHexASCIIDump(*(stream_frame.GetDataAsString()))
+ << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
+ os << "sent info { " << ack_frame.sent_info << " } "
+ << "received info { " << ack_frame.received_info << " }\n";
+ return os;
+}
+
ostream& operator<<(ostream& os,
const QuicCongestionFeedbackFrame& congestion_frame) {
os << "type: " << congestion_frame.type;
@@ -309,12 +386,6 @@
return os;
}
-ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
- os << "sent info { " << ack_frame.sent_info << " } "
- << "received info { " << ack_frame.received_info << " }\n";
- return os;
-}
-
CongestionFeedbackMessageFixRate::CongestionFeedbackMessageFixRate()
: bitrate(QuicBandwidth::Zero()) {
}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 1352c34..dc88446 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -537,6 +537,9 @@
QuicStreamOffset offset,
IOVector data);
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os, const QuicStreamFrame& s);
+
// Returns a copy of the IOVector |data| as a heap-allocated string.
// Caller must take ownership of the returned string.
std::string* GetDataAsString() const;
@@ -681,12 +684,18 @@
DCHECK_LE(error_code, std::numeric_limits<uint8>::max());
}
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os, const QuicRstStreamFrame& r);
+
QuicStreamId stream_id;
QuicRstStreamErrorCode error_code;
std::string error_details;
};
struct NET_EXPORT_PRIVATE QuicConnectionCloseFrame {
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os, const QuicConnectionCloseFrame& c);
+
QuicErrorCode error_code;
std::string error_details;
};
@@ -697,6 +706,9 @@
QuicStreamId last_good_stream_id,
const std::string& reason);
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os, const QuicGoAwayFrame& g);
+
QuicErrorCode error_code;
QuicStreamId last_good_stream_id;
std::string reason_phrase;
@@ -745,6 +757,9 @@
goaway_frame(frame) {
}
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os, const QuicFrame& frame);
+
QuicFrameType type;
union {
QuicPaddingFrame* padding_frame;
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index bb833bce..9d64131 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -173,8 +173,6 @@
previous_transmissions->insert(new_sequence_number);
unacked_packets_[new_sequence_number].previous_transmissions =
previous_transmissions;
-
- DCHECK(HasRetransmittableFrames(new_sequence_number));
}
bool QuicSentPacketManager::OnIncomingAck(
@@ -265,6 +263,9 @@
if (sequence_number == newest_transmission) {
break;
}
+ if (it->second.pending) {
+ break;
+ }
DCHECK(it->second.retransmittable_frames == NULL);
previous_transmissions->erase(sequence_number);
@@ -272,7 +273,6 @@
unacked_packets_[newest_transmission].previous_transmissions = NULL;
delete previous_transmissions;
}
- DCHECK(!it->second.pending);
unacked_packets_.erase(it++);
--num_to_clear;
}
@@ -314,8 +314,14 @@
void QuicSentPacketManager::MarkForRetransmission(
QuicPacketSequenceNumber sequence_number,
TransmissionType transmission_type) {
- DCHECK(ContainsKey(unacked_packets_, sequence_number));
- DCHECK(HasRetransmittableFrames(sequence_number));
+ TransmissionInfo* transmission_info =
+ FindOrNull(unacked_packets_, sequence_number);
+ if (transmission_info != NULL) {
+ LOG_IF(DFATAL, transmission_info->retransmittable_frames == NULL);
+ LOG_IF(DFATAL, transmission_info->sent_time == QuicTime::Zero());
+ } else {
+ LOG(DFATAL) << "Unable to retansmit packet: " << sequence_number;
+ }
// TODO(ianswett): Currently the RTO can fire while there are pending NACK
// retransmissions for the same data, which is not ideal.
if (ContainsKey(pending_retransmissions_, sequence_number)) {
@@ -345,26 +351,6 @@
transmission_info.sequence_number_length);
}
-bool QuicSentPacketManager::IsPreviousTransmission(
- QuicPacketSequenceNumber sequence_number) const {
- DCHECK(ContainsKey(unacked_packets_, sequence_number));
-
- UnackedPacketMap::const_iterator unacked_it =
- unacked_packets_.find(sequence_number);
- if (unacked_it == unacked_packets_.end()) {
- return false;
- }
- const TransmissionInfo* transmission_info = &unacked_it->second;
- if (transmission_info->previous_transmissions == NULL) {
- return false;
- }
-
- SequenceNumberSet* previous_transmissions =
- transmission_info->previous_transmissions;
- DCHECK(!previous_transmissions->empty());
- return *previous_transmissions->rbegin() != sequence_number;
-}
-
// static
bool QuicSentPacketManager::HasCryptoHandshake(
const TransmissionInfo& transmission_info) {
@@ -508,8 +494,7 @@
size_t num_unacked_packets = 0;
for (UnackedPacketMap::const_iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it) {
- QuicPacketSequenceNumber sequence_number = it->first;
- if (HasRetransmittableFrames(sequence_number)) {
+ if (it->second.retransmittable_frames != NULL) {
++num_unacked_packets;
}
}
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 8339fba..f608c5f 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -130,9 +130,6 @@
// Test only.
SequenceNumberSet GetUnackedPackets() const;
- // Returns true if |sequence_number| is a previous transmission of packet.
- bool IsPreviousTransmission(QuicPacketSequenceNumber sequence_number) const;
-
// Called when a congestion feedback frame is received from peer.
virtual void OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame,
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 832b8b9..ee6f949 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -191,9 +191,7 @@
}
TEST_F(QuicSentPacketManagerTest, IsUnAckedRetransmit) {
- SerializedPacket serialized_packet(CreateDataPacket(1));
-
- manager_.OnSerializedPacket(serialized_packet);
+ SendDataPacket(1);
RetransmitPacket(1, 2);
EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_, 2));
@@ -204,26 +202,26 @@
}
TEST_F(QuicSentPacketManagerTest, RetransmitThenAck) {
- SerializedPacket serialized_packet(CreateDataPacket(1));
-
- manager_.OnSerializedPacket(serialized_packet);
- RetransmitPacket(1, 2);
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
// Ack 2 but not 1.
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
received_info.missing_packets.insert(1);
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _)).Times(1);
manager_.OnIncomingAck(received_info, QuicTime::Zero());
- // No unacked packets remain.
- VerifyUnackedPackets(NULL, 0);
+ // Packet 1 is unacked, pending, but not retransmittable.
+ QuicPacketSequenceNumber unacked[] = { 1 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
VerifyRetransmittablePackets(NULL, 0);
}
TEST_F(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) {
- SerializedPacket serialized_packet(CreateDataPacket(1));
-
- manager_.OnSerializedPacket(serialized_packet);
+ SendDataPacket(1);
QuicSentPacketManagerPeer::MarkForRetransmission(
&manager_, 1, NACK_RETRANSMISSION);
EXPECT_TRUE(manager_.HasPendingRetransmissions());
@@ -231,6 +229,8 @@
// Ack 1.
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)).Times(1);
manager_.OnIncomingAck(received_info, QuicTime::Zero());
// There should no longer be a pending retransmission.
@@ -389,19 +389,23 @@
}
TEST_F(QuicSentPacketManagerTest, TruncatedAck) {
- SerializedPacket serialized_packet(CreateDataPacket(1));
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+ RetransmitAndSendPacket(2, 3);
+ RetransmitAndSendPacket(3, 4);
+ RetransmitAndSendPacket(4, 5);
- manager_.OnSerializedPacket(serialized_packet);
- RetransmitPacket(1, 2);
- RetransmitPacket(2, 3);
- RetransmitPacket(3, 4);
-
- // Truncated ack with 2 NACKs
+ // Truncated ack with 4 NACKs, so the first packet is lost.
ReceivedPacketInfo received_info;
- received_info.largest_observed = 2;
+ received_info.largest_observed = 4;
received_info.missing_packets.insert(1);
received_info.missing_packets.insert(2);
+ received_info.missing_packets.insert(3);
+ received_info.missing_packets.insert(4);
received_info.is_truncated = true;
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
manager_.OnIncomingAck(received_info, QuicTime::Zero());
// High water mark will be raised.
@@ -412,12 +416,10 @@
}
TEST_F(QuicSentPacketManagerTest, AckPreviousTransmissionThenTruncatedAck) {
- SerializedPacket serialized_packet(CreateDataPacket(1));
-
- manager_.OnSerializedPacket(serialized_packet);
- RetransmitPacket(1, 2);
- RetransmitPacket(2, 3);
- RetransmitPacket(3, 4);
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+ RetransmitAndSendPacket(2, 3);
+ RetransmitAndSendPacket(3, 4);
manager_.OnSerializedPacket(CreateDataPacket(5));
manager_.OnSerializedPacket(CreateDataPacket(6));
manager_.OnSerializedPacket(CreateDataPacket(7));
@@ -429,6 +431,8 @@
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
received_info.missing_packets.insert(1);
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _));
manager_.OnIncomingAck(received_info, QuicTime::Zero());
EXPECT_TRUE(manager_.IsUnacked(4));
}
@@ -442,6 +446,9 @@
received_info.missing_packets.insert(5);
received_info.missing_packets.insert(6);
received_info.is_truncated = true;
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(3, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(4, _));
manager_.OnIncomingAck(received_info, QuicTime::Zero());
}
@@ -452,130 +459,6 @@
VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
}
-TEST_F(QuicSentPacketManagerTest, SendDropAckRetransmitManyPackets) {
- manager_.OnSerializedPacket(CreateDataPacket(1));
- manager_.OnSerializedPacket(CreateDataPacket(2));
- manager_.OnSerializedPacket(CreateDataPacket(3));
-
- {
- // Ack packets 1 and 3.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = 3;
- received_info.missing_packets.insert(2);
- manager_.OnIncomingAck(received_info, QuicTime::Zero());
-
- QuicPacketSequenceNumber unacked[] = { 2 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketSequenceNumber retransmittable[] = { 2 };
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
- }
-
- manager_.OnSerializedPacket(CreateDataPacket(4));
- manager_.OnSerializedPacket(CreateDataPacket(5));
-
- {
- // Ack packets 5.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = 5;
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(4);
- manager_.OnIncomingAck(received_info, QuicTime::Zero());
-
- QuicPacketSequenceNumber unacked[] = { 2, 4 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketSequenceNumber retransmittable[] = { 2, 4 };
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
- }
-
- manager_.OnSerializedPacket(CreateDataPacket(6));
- manager_.OnSerializedPacket(CreateDataPacket(7));
-
- {
- // Ack packets 7.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = 7;
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(4);
- received_info.missing_packets.insert(6);
- manager_.OnIncomingAck(received_info, QuicTime::Zero());
-
- QuicPacketSequenceNumber unacked[] = { 2, 4, 6 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketSequenceNumber retransmittable[] = { 2, 4, 6 };
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
- }
-
- RetransmitPacket(2, 8);
- manager_.OnSerializedPacket(CreateDataPacket(9));
- manager_.OnSerializedPacket(CreateDataPacket(10));
-
- {
- // Ack packet 10.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = 10;
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(4);
- received_info.missing_packets.insert(6);
- received_info.missing_packets.insert(8);
- received_info.missing_packets.insert(9);
- manager_.OnIncomingAck(received_info, QuicTime::Zero());
-
- QuicPacketSequenceNumber unacked[] = { 2, 4, 6, 8, 9 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketSequenceNumber retransmittable[] = { 4, 6, 8, 9 };
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
- }
-
-
- RetransmitPacket(4, 11);
- manager_.OnSerializedPacket(CreateDataPacket(12));
- manager_.OnSerializedPacket(CreateDataPacket(13));
-
- {
- // Ack packet 13.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = 13;
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(4);
- received_info.missing_packets.insert(6);
- received_info.missing_packets.insert(8);
- received_info.missing_packets.insert(9);
- received_info.missing_packets.insert(11);
- received_info.missing_packets.insert(12);
- manager_.OnIncomingAck(received_info, QuicTime::Zero());
-
- QuicPacketSequenceNumber unacked[] = { 2, 4, 6, 8, 9, 11, 12 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketSequenceNumber retransmittable[] = { 6, 8, 9, 11, 12 };
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
- }
-
- RetransmitPacket(6, 14);
- manager_.OnSerializedPacket(CreateDataPacket(15));
- manager_.OnSerializedPacket(CreateDataPacket(16));
-
- {
- // Ack packet 16.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = 13;
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(4);
- received_info.missing_packets.insert(6);
- received_info.missing_packets.insert(8);
- received_info.missing_packets.insert(9);
- received_info.missing_packets.insert(11);
- received_info.missing_packets.insert(12);
- received_info.is_truncated = true;
- manager_.OnIncomingAck(received_info, QuicTime::Zero());
-
- // Truncated ack raises the high water mark by clearing out 2, 4, and 6.
- QuicPacketSequenceNumber unacked[] = { 8, 9, 11, 12, 14, 15, 16 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketSequenceNumber retransmittable[] = { 8, 9, 11, 12, 14, 15, 16 };
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
- }
-}
-
TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacket) {
EXPECT_CALL(helper_, GetNextPacketSequenceNumber()).WillOnce(Return(1u));
EXPECT_EQ(1u, manager_.GetLeastUnackedSentPacket());
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc
index 50303b8..38bd0c0 100644
--- a/net/quic/test_tools/quic_test_packet_maker.cc
+++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -40,6 +40,47 @@
return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(&rst)));
}
+scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket(
+ QuicPacketSequenceNumber num,
+ bool include_version,
+ QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code,
+ QuicPacketSequenceNumber largest_received,
+ QuicPacketSequenceNumber least_unacked,
+ bool send_feedback) {
+
+ QuicPacketHeader header;
+ header.public_header.guid = guid_;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = include_version;
+ header.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
+ header.packet_sequence_number = num;
+ header.entropy_flag = false;
+ header.fec_flag = false;
+ header.fec_group = 0;
+
+ QuicAckFrame ack(largest_received, QuicTime::Zero(), least_unacked);
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack));
+ if (send_feedback) {
+ QuicCongestionFeedbackFrame feedback;
+ feedback.type = kTCP;
+ feedback.tcp.accumulated_number_of_lost_packets = 0;
+ feedback.tcp.receive_window = 256000;
+
+ frames.push_back(QuicFrame(&feedback));
+ }
+
+ QuicRstStreamFrame rst(stream_id, error_code);
+ frames.push_back(QuicFrame(&rst));
+
+ QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), false);
+ scoped_ptr<QuicPacket> packet(
+ framer.BuildUnsizedDataPacket(header, frames).packet);
+ return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
+ ENCRYPTION_NONE, header.packet_sequence_number, *packet));
+}
+
scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeConnectionClosePacket(
QuicPacketSequenceNumber num) {
QuicPacketHeader header;
diff --git a/net/quic/test_tools/quic_test_packet_maker.h b/net/quic/test_tools/quic_test_packet_maker.h
index ac5051c..47d606e4b 100644
--- a/net/quic/test_tools/quic_test_packet_maker.h
+++ b/net/quic/test_tools/quic_test_packet_maker.h
@@ -28,6 +28,14 @@
bool include_version,
QuicStreamId stream_id,
QuicRstStreamErrorCode error_code);
+ scoped_ptr<QuicEncryptedPacket> MakeAckAndRstPacket(
+ QuicPacketSequenceNumber num,
+ bool include_version,
+ QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code,
+ QuicPacketSequenceNumber largest_received,
+ QuicPacketSequenceNumber least_unacked,
+ bool send_feedback);
scoped_ptr<QuicEncryptedPacket> MakeConnectionClosePacket(
QuicPacketSequenceNumber num);
scoped_ptr<QuicEncryptedPacket> MakeAckPacket(
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 78ffa35..17d0ac5 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -307,8 +307,8 @@
const SerializedPacket& packet,
TransmissionType transmission_type) {
packets_.push_back(packet.packet);
- QuicEncryptedPacket* encrypted =
- framer_.EncryptPacket(level, packet.sequence_number, *packet.packet);
+ QuicEncryptedPacket* encrypted = QuicConnectionPeer::GetFramer(this)->
+ EncryptPacket(level, packet.sequence_number, *packet.packet);
encrypted_packets_.push_back(encrypted);
return true;
}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 4c5be0d..a77cb086 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -385,12 +385,11 @@
MockPacketWriter();
virtual ~MockPacketWriter();
- MOCK_METHOD5(WritePacket,
+ MOCK_METHOD4(WritePacket,
WriteResult(const char* buffer,
size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer));
+ const IPEndPoint& peer_address));
MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool());
MOCK_CONST_METHOD0(IsWriteBlocked, bool());
MOCK_METHOD0(SetWritable, void());