Skip to content

Commit

Permalink
Land Recent QUIC changes.
Browse files Browse the repository at this point in the history
Merge internal change: 47341065

Fix to ensure the version matches before declaring that the public header
flags exceed the max value. b/9190456

Merge internal change: 47324563

Fixing another backup bug (exposed by the last fix) that if we failed to
write a standalone fin the stream would not be marked as write blocked.

Merge internal change: 47272116

Don't add QuicStreams to ActiveSessionList; Instead call DumpSession on
alive streams via QuicSession.

Merge internal change: 47226512

Making the packet sequence number variable length to minimize bytes on the wire.

Merge internal change: 47220850

Fixing a bug in quic stream where we'd send rst stream packets for
successful streams. The fin bit should be sufficient for both good
request/response pairs and early response pairs.

Merge internal change: 47086343

Don't let FEC packets consume congestion window forever. If a FEC packet
is not acked after a certain time, it is cleared from the congestion
window. This timeout is higher than normal RTO.

Merge internal change: 47056082

Add QuicSession to ActiveSessionList.

Merge internal change: 47048300

Fixing a backup/resumption bug in QUIC.

It's possible to have a full congestion window worth of packets on the wire.

If we are in this state and a session tries to SendStreamData, the
QuicPacketGenerator short-circuits without queuing packets because it checks
to see if the connection CanWrite.

When we get an ack, we check to see if we have locally queued packets, but
never call OnCanWrite on the session to clear any streams which write blocked
without queueing packets.

Merge internal change: 47000173

QUIC: wire up the server-nonce parameters to the server config.

Merge internal change: 46985067

R=rch@chromium.org

Review URL: https://codereview.chromium.org/16256017

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204046 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rtenneti@chromium.org committed Jun 4, 2013
1 parent d0ec6c4 commit 059cad5
Show file tree
Hide file tree
Showing 31 changed files with 1,195 additions and 414 deletions.
1 change: 1 addition & 0 deletions net/quic/congestion_control/quic_congestion_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void QuicCongestionManager::AbandoningPacket(
QuicPacketSequenceNumber sequence_number) {
PendingPacketsMap::iterator it = pending_packets_.find(sequence_number);
if (it != pending_packets_.end()) {
// Shouldn't this report loss as well? (decrease cgst window).
send_algorithm_->AbandoningPacket(sequence_number, it->second);
pending_packets_.erase(it);
}
Expand Down
12 changes: 12 additions & 0 deletions net/quic/crypto/crypto_server_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,18 @@ void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
source_address_token_lifetime_secs_ = lifetime_secs;
}

void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries(
uint32 max_entries) {
DCHECK(!server_nonce_strike_register_.get());
server_nonce_strike_register_max_entries_ = max_entries;
}

void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs(
uint32 window_secs) {
DCHECK(!server_nonce_strike_register_.get());
server_nonce_strike_register_window_secs_ = window_secs;
}

string QuicCryptoServerConfig::NewSourceAddressToken(
const IPEndPoint& ip,
QuicRandom* rand,
Expand Down
15 changes: 15 additions & 0 deletions net/quic/crypto/crypto_server_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,21 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// source-address token will be valid for.
void set_source_address_token_lifetime_secs(uint32 lifetime_secs);

// set_server_nonce_strike_register_max_entries sets the number of entries in
// the server-nonce strike-register. This is used to record that server nonce
// values have been used. If the number of entries is too small then clients
// which are depending on server nonces may fail to handshake because their
// nonce has expired in the amount of time it took to go from the server to
// the client and back.
void set_server_nonce_strike_register_max_entries(uint32 max_entries);

// set_server_nonce_strike_register_window_secs sets the number of seconds
// around the current time that the server-nonce strike-register will accept
// nonces from. Setting a larger value allows for clients to delay follow-up
// client hellos for longer and still use server nonces as proofs of
// uniqueness.
void set_server_nonce_strike_register_window_secs(uint32 window_secs);

private:
friend class test::QuicCryptoServerConfigPeer;

Expand Down
175 changes: 120 additions & 55 deletions net/quic/quic_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ QuicConnection::~QuicConnection() {
it != queued_packets_.end(); ++it) {
delete it->packet;
}
LOG(ERROR) << "Quic connection " << write_blocked_;
DLOG(INFO) << ENDPOINT << "write_blocked: " << write_blocked_;
}

bool QuicConnection::SelectMutualVersion(
Expand Down Expand Up @@ -242,6 +242,7 @@ void QuicConnection::OnVersionNegotiationPacket(
if (!SelectMutualVersion(packet.versions)) {
SendConnectionCloseWithDetails(QUIC_INVALID_VERSION,
"no common version found");
return;
}

version_negotiation_state_ = NEGOTIATED_VERSION;
Expand Down Expand Up @@ -361,19 +362,18 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
congestion_manager_.OnIncomingAckFrame(incoming_ack,
time_of_last_received_packet_);

// Now the we have received an ack, we might be able to send queued packets.
if (!queued_packets_.empty()) {
QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
time_of_last_received_packet_, NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA);
if (delay.IsZero()) {
helper_->UnregisterSendAlarmIfRegistered();
if (!write_blocked_) {
OnCanWrite();
}
} else if (!delay.IsInfinite()) {
helper_->SetSendAlarm(time_of_last_received_packet_.Add(delay));
// 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 = congestion_manager_.TimeUntilSend(
time_of_last_received_packet_, NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA);
if (delay.IsZero()) {
helper_->UnregisterSendAlarmIfRegistered();
if (!write_blocked_) {
OnCanWrite();
}
} else if (!delay.IsInfinite()) {
helper_->SetSendAlarm(time_of_last_received_packet_.Add(delay));
}
return connected_;
}
Expand Down Expand Up @@ -461,24 +461,8 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
return true;
}

void QuicConnection::UpdatePacketInformationReceivedByPeer(
const QuicAckFrame& incoming_ack) {
SequenceNumberSet acked_packets;

// ValidateAck should fail if largest_observed ever shrinks.
DCHECK_LE(peer_largest_observed_packet_,
incoming_ack.received_info.largest_observed);
peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed;

if (incoming_ack.received_info.missing_packets.empty()) {
least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1;
} else {
least_packet_awaited_by_peer_ =
*(incoming_ack.received_info.missing_packets.begin());
}

entropy_manager_.ClearSentEntropyBefore(least_packet_awaited_by_peer_ - 1);

void QuicConnection::HandleAckForSentPackets(const QuicAckFrame& incoming_ack,
SequenceNumberSet* acked_packets) {
int retransmitted_packets = 0;
// Go through the packets we have not received an ack for and see if this
// incoming_ack shows they've been seen by the peer.
Expand All @@ -492,11 +476,9 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer(
if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) {
// Packet was acked, so remove it from our unacked packet list.
DVLOG(1) << ENDPOINT <<"Got an ack for packet " << sequence_number;
acked_packets.insert(sequence_number);
acked_packets->insert(sequence_number);
delete unacked;
UnackedPacketMap::iterator it_tmp = it;
++it;
unacked_packets_.erase(it_tmp);
unacked_packets_.erase(it++);
retransmission_map_.erase(sequence_number);
} else {
// This is a packet which we planned on retransmitting and has not been
Expand All @@ -522,6 +504,48 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer(
}
}
}
}

void QuicConnection::HandleAckForSentFecPackets(
const QuicAckFrame& incoming_ack, SequenceNumberSet* acked_packets) {
UnackedPacketMap::iterator it = unacked_fec_packets_.begin();
while (it != unacked_fec_packets_.end()) {
QuicPacketSequenceNumber sequence_number = it->first;
if (sequence_number > peer_largest_observed_packet_) {
break;
}
if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) {
DVLOG(1) << ENDPOINT << "Got an ack for fec packet: " << sequence_number;
acked_packets->insert(sequence_number);
unacked_fec_packets_.erase(it++);
} else {
DVLOG(1) << ENDPOINT << "Still missing ack for fec packet: "
<< sequence_number;
++it;
}
}
}

void QuicConnection::UpdatePacketInformationReceivedByPeer(
const QuicAckFrame& incoming_ack) {
// ValidateAck should fail if largest_observed ever shrinks.
DCHECK_LE(peer_largest_observed_packet_,
incoming_ack.received_info.largest_observed);
peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed;

if (incoming_ack.received_info.missing_packets.empty()) {
least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1;
} else {
least_packet_awaited_by_peer_ =
*(incoming_ack.received_info.missing_packets.begin());
}

entropy_manager_.ClearSentEntropyBefore(least_packet_awaited_by_peer_ - 1);

SequenceNumberSet acked_packets;
HandleAckForSentPackets(incoming_ack, &acked_packets);
HandleAckForSentFecPackets(incoming_ack, &acked_packets);

if (acked_packets.size() > 0) {
visitor_->OnAck(acked_packets);
}
Expand Down Expand Up @@ -960,7 +984,7 @@ bool QuicConnection::IsRetransmission(
it->second.number_retransmissions > 0;
}

void QuicConnection::MaybeSetupRetransmission(
void QuicConnection::SetupRetransmission(
QuicPacketSequenceNumber sequence_number) {
RetransmissionMap::iterator it = retransmission_map_.find(sequence_number);
if (it == retransmission_map_.end()) {
Expand All @@ -973,9 +997,11 @@ void QuicConnection::MaybeSetupRetransmission(
congestion_manager_.GetRetransmissionDelay(
unacked_packets_.size(),
retransmission_info.number_retransmissions);
retransmission_info.scheduled_time =
clock_->ApproximateNow().Add(retransmission_delay);
retransmission_timeouts_.push(retransmission_info);

retransmission_timeouts_.push(RetransmissionTime(
sequence_number,
clock_->ApproximateNow().Add(retransmission_delay),
false));

// Do not set the retransmisson alarm if we're already handling the
// retransmission alarm because the retransmission alarm will be reset when
Expand All @@ -987,6 +1013,18 @@ void QuicConnection::MaybeSetupRetransmission(
// SendStreamData().
}

void QuicConnection::SetupAbandonFecTimer(
QuicPacketSequenceNumber sequence_number) {
DCHECK(ContainsKey(unacked_fec_packets_, sequence_number));
QuicTime::Delta retransmission_delay =
QuicTime::Delta::FromMilliseconds(
congestion_manager_.DefaultRetransmissionTime().ToMilliseconds() * 3);
retransmission_timeouts_.push(RetransmissionTime(
sequence_number,
clock_->ApproximateNow().Add(retransmission_delay),
true));
}

void QuicConnection::DropPacket(QuicPacketSequenceNumber sequence_number) {
UnackedPacketMap::iterator unacked_it =
unacked_packets_.find(sequence_number);
Expand Down Expand Up @@ -1077,7 +1115,11 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
// Set the retransmit alarm only when we have sent the packet to the client
// and not when it goes to the pending queue, otherwise we will end up adding
// an entry to retransmission_timeout_ every time we attempt a write.
MaybeSetupRetransmission(sequence_number);
if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
SetupRetransmission(sequence_number);
} else if (packet->is_fec_packet()) {
SetupAbandonFecTimer(sequence_number);
}

congestion_manager_.SentPacket(sequence_number, now, packet->length(),
retransmission);
Expand Down Expand Up @@ -1111,6 +1153,10 @@ bool QuicConnection::OnSerializedPacket(
retransmission_map_.insert(
make_pair(serialized_packet.sequence_number,
RetransmissionInfo(serialized_packet.sequence_number)));
} else if (serialized_packet.packet->is_fec_packet()) {
unacked_fec_packets_.insert(make_pair(
serialized_packet.sequence_number,
serialized_packet.retransmittable_frames));
}
return SendOrQueuePacket(encryption_level_,
serialized_packet.sequence_number,
Expand Down Expand Up @@ -1180,6 +1226,17 @@ void QuicConnection::SendAck() {
packet_generator_.SetShouldSendAck(send_feedback);
}

void QuicConnection::MaybeAbandonFecPacket(
QuicPacketSequenceNumber sequence_number) {
if (!ContainsKey(unacked_fec_packets_, sequence_number)) {
DVLOG(2) << ENDPOINT << "no need to abandon fec packet: "
<< sequence_number << "; it's already acked'";
return;
}
congestion_manager_.AbandoningPacket(sequence_number);
// TODO(satyashekhar): Should this decrease the congestion window?
}

QuicTime QuicConnection::OnRetransmissionTimeout() {
// This guards against registering the alarm later than we should.
//
Expand All @@ -1192,19 +1249,24 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {

for (size_t i = 0; i < max_packets_per_retransmission_alarm_ &&
!retransmission_timeouts_.empty(); ++i) {
RetransmissionInfo retransmission_info = retransmission_timeouts_.top();
DCHECK(retransmission_info.scheduled_time.IsInitialized());
if (retransmission_info.scheduled_time > clock_->ApproximateNow()) {
RetransmissionTime retransmission_time = retransmission_timeouts_.top();
DCHECK(retransmission_time.scheduled_time.IsInitialized());
if (retransmission_time.scheduled_time > clock_->ApproximateNow()) {
break;
}
retransmission_timeouts_.pop();
if (!MaybeRetransmitPacketForRTO(retransmission_info.sequence_number)) {

if (retransmission_time.for_fec) {
MaybeAbandonFecPacket(retransmission_time.sequence_number);
continue;
} else if (
!MaybeRetransmitPacketForRTO(retransmission_time.sequence_number)) {
DLOG(INFO) << ENDPOINT << "MaybeRetransmitPacketForRTO failed: "
<< "adding an extra delay for "
<< retransmission_info.sequence_number;
retransmission_info.scheduled_time = clock_->ApproximateNow().Add(
<< retransmission_time.sequence_number;
retransmission_time.scheduled_time = clock_->ApproximateNow().Add(
congestion_manager_.DefaultRetransmissionTime());
retransmission_timeouts_.push(retransmission_info);
retransmission_timeouts_.push(retransmission_time);
}
}

Expand Down Expand Up @@ -1377,28 +1439,31 @@ bool QuicConnection::HasQueuedData() const {
}

void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) {
// if (timeout < idle_network_timeout_) {
if (timeout < idle_network_timeout_) {
idle_network_timeout_ = timeout;
CheckForTimeout();
// } else {
// idle_network_timeout_ = timeout;
// }
} else {
idle_network_timeout_ = timeout;
}
}

void QuicConnection::SetOverallConnectionTimeout(QuicTime::Delta timeout) {
// if (timeout < overall_connection_timeout_) {
if (timeout < overall_connection_timeout_) {
overall_connection_timeout_ = timeout;
CheckForTimeout();
// } else {
// overall_connection_timeout_ = timeout;
// }
} else {
overall_connection_timeout_ = timeout;
}
}

bool QuicConnection::CheckForTimeout() {
QuicTime now = clock_->ApproximateNow();
QuicTime time_of_last_packet = std::max(time_of_last_received_packet_,
time_of_last_sent_packet_);

// |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
// is accurate time. However, this should not change the behavior of
// timeout handling.
QuicTime::Delta delta = now.Subtract(time_of_last_packet);
DVLOG(1) << ENDPOINT << "last packet "
<< time_of_last_packet.ToDebuggingValue()
Expand Down
Loading

0 comments on commit 059cad5

Please sign in to comment.