| Index: net/quic/quic_connection.cc
|
| diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
|
| index f1e25d6e24b4989a0fc8062db44263385b8777b9..737fee4d2c94610cee37c76a2bf41043de1ac34e 100644
|
| --- a/net/quic/quic_connection.cc
|
| +++ b/net/quic/quic_connection.cc
|
| @@ -167,6 +167,7 @@ QuicConnection::QuicConnection(QuicGuid guid,
|
| 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 @@ void QuicConnection::OnPacketComplete() {
|
| << 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 @@ void QuicConnection::OnPacketComplete() {
|
|
|
| // 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 @@ bool QuicConnection::ShouldLastPacketInstigateAck() {
|
| 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 @@ bool QuicConnection::ShouldLastPacketInstigateAck() {
|
| 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 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
|
| << last_header_.packet_sequence_number;
|
| return;
|
| }
|
| +
|
| MaybeProcessUndecryptablePackets();
|
| MaybeProcessRevivedPacket();
|
| + MaybeSendInResponseToPacket();
|
| }
|
|
|
| bool QuicConnection::OnCanWrite() {
|
| @@ -1027,6 +1040,7 @@ bool QuicConnection::CanWrite(TransmissionType transmission_type,
|
| HasRetransmittableData retransmittable,
|
| IsHandshake handshake) {
|
| if (writer_->IsWriteBlocked()) {
|
| + visitor_->OnWriteBlocked();
|
| return false;
|
| }
|
|
|
| @@ -1107,6 +1121,7 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
| // 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 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
|
|
| 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 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
|
| 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 @@ bool QuicConnection::ShouldDiscardPacket(
|
| 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;
|
|
|