Index: net/quic/quic_connection.cc |
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc |
index 0698dd354dc3d2bf142c53a3ff0c430a5cb81a86..9932032f0ac3b2b868dc9c615c9f08e6e8caa499 100644 |
--- a/net/quic/quic_connection.cc |
+++ b/net/quic/quic_connection.cc |
@@ -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( |
@@ -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; |
@@ -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_; |
} |
@@ -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. |
@@ -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 |
@@ -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); |
} |
@@ -725,7 +749,7 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, |
self_address_ = self_address; |
} |
- if (!(peer_address == peer_address_) && (self_address == self_address_)) { |
+ if (!(peer_address == peer_address_ && self_address == self_address_)) { |
address_migrating_ = true; |
} |
@@ -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()) { |
@@ -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 |
@@ -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); |
@@ -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); |
@@ -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, |
@@ -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. |
// |
@@ -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); |
} |
} |
@@ -1377,21 +1439,21 @@ 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() { |
@@ -1399,6 +1461,9 @@ bool QuicConnection::CheckForTimeout() { |
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() |