diff options
Diffstat (limited to 'net/quic/quic_connection.cc')
-rw-r--r-- | net/quic/quic_connection.cc | 193 |
1 files changed, 72 insertions, 121 deletions
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 2073919..59759f7 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -52,9 +52,8 @@ namespace { // This will likely have to be tuned. const QuicPacketSequenceNumber kMaxPacketGap = 5000; -// We want to make sure if we get a nack packet which triggers several -// retransmissions, we don't queue up too many packets. 10 is TCP's default -// initial congestion window(RFC 6928). +// We want to make sure if we get a large nack packet, we don't queue up too +// many packets at once. 10 is a common default initial congestion window. const size_t kMaxRetransmissionsPerAck = 10; // TCP retransmits after 2 nacks. We allow for a third in case of out-of-order @@ -216,7 +215,6 @@ QuicConnection::QuicConnection(QuicGuid guid, guid_(guid), peer_address_(address), largest_seen_packet_with_ack_(0), - pending_version_negotiation_packet_(false), write_blocked_(false), ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))), @@ -506,15 +504,11 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { } void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) { - // Latch current least unacked sequence number. This allows us to reset the - // retransmission and FEC abandonment timers conditionally below. - QuicPacketSequenceNumber least_unacked_sent_before = - sent_packet_manager_.GetLeastUnackedSentPacket(); - largest_seen_packet_with_ack_ = last_header_.packet_sequence_number; - received_truncated_ack_ = incoming_ack.received_info.missing_packets.size() >= - QuicFramer::GetMaxUnackedPackets(last_header_); + received_truncated_ack_ = + incoming_ack.received_info.missing_packets.size() >= + QuicFramer::GetMaxUnackedPackets(last_header_); received_packet_manager_.UpdatePacketInformationReceivedByPeer(incoming_ack); received_packet_manager_.UpdatePacketInformationSentByPeer(incoming_ack); @@ -525,42 +519,35 @@ void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) { received_packet_manager_.least_packet_awaited_by_peer() - 1); retransmitted_nacked_packet_count_ = 0; - sent_packet_manager_.OnIncomingAck(incoming_ack.received_info, - received_truncated_ack_); - - // Get the updated least unacked sequence number. - QuicPacketSequenceNumber least_unacked_sent_after = - sent_packet_manager_.GetLeastUnackedSentPacket(); - - // Used to set RTO and FEC alarms. - QuicTime::Delta retransmission_delay = - congestion_manager_.GetRetransmissionDelay( - sent_packet_manager_.GetNumUnackedPackets(), 0); - - // If there are outstanding packets, and the least unacked sequence number - // has increased after processing this latest AckFrame, then reschedule the - // retransmission timer. - if (sent_packet_manager_.HasUnackedPackets() && - least_unacked_sent_before < least_unacked_sent_after) { - DCHECK(retransmission_alarm_->IsSet()); - - retransmission_alarm_->Cancel(); - retransmission_alarm_->Set( - clock_->ApproximateNow().Add(retransmission_delay)); + SequenceNumberSet acked_packets; + sent_packet_manager_.OnIncomingAck( + incoming_ack.received_info, received_truncated_ack_, &acked_packets); + if (acked_packets.size() > 0) { + // Reset the RTO timeout for each packet when an ack is received. + if (retransmission_alarm_->IsSet()) { + retransmission_alarm_->Cancel(); + // Only reschedule the timer if there are outstanding packets. + if (sent_packet_manager_.HasUnackedPackets()) { + QuicTime::Delta retransmission_delay = + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), 0); + retransmission_alarm_->Set(clock_->ApproximateNow().Add( + retransmission_delay)); + } + } + if (abandon_fec_alarm_->IsSet()) { + abandon_fec_alarm_->Cancel(); + // Only reschedule the timer if there are outstanding fec packets. + if (sent_packet_manager_.HasUnackedFecPackets()) { + QuicTime::Delta retransmission_delay = + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), 0); + abandon_fec_alarm_->Set(clock_->ApproximateNow().Add( + retransmission_delay)); + } + } consecutive_rto_count_ = 0; - } else if (!sent_packet_manager_.HasUnackedPackets()) { - retransmission_alarm_->Cancel(); } - - // If there are outstanding FEC packets, and the least unacked sequence number - // has increased after processing this latest AckFrame, then reschedule the - // abandon FEC timer. - abandon_fec_alarm_->Cancel(); - if (sent_packet_manager_.HasUnackedFecPackets() && - least_unacked_sent_before < least_unacked_sent_after) { - abandon_fec_alarm_->Set(clock_->ApproximateNow().Add(retransmission_delay)); - } - congestion_manager_.OnIncomingAckFrame(incoming_ack, time_of_last_received_packet_); } @@ -753,6 +740,7 @@ void QuicConnection::OnPacketComplete() { MaybeSendInResponseToPacket(send_ack_immediately, last_packet_should_instigate_ack); + ClearLastFrames(); } @@ -845,25 +833,12 @@ void QuicConnection::SendVersionNegotiationPacket() { for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) { supported_versions.push_back(kSupportedQuicVersions[i]); } - scoped_ptr<QuicEncryptedPacket> version_packet( - packet_creator_.SerializeVersionNegotiationPacket(supported_versions)); + QuicEncryptedPacket* encrypted = + packet_creator_.SerializeVersionNegotiationPacket(supported_versions); // TODO(satyamshekhar): implement zero server state negotiation. - WriteResult result = - helper_->WritePacketToWire(*version_packet); - if (result.status == WRITE_STATUS_OK || - (result.status == WRITE_STATUS_BLOCKED && - helper_->IsWriteBlockedDataBuffered())) { - pending_version_negotiation_packet_ = false; - return; - } - if (result.status == WRITE_STATUS_ERROR) { - // We can't send an error as the socket is presumably borked. - CloseConnection(QUIC_PACKET_WRITE_ERROR, false); - } - if (result.status == WRITE_STATUS_BLOCKED) { - write_blocked_ = true; - } - pending_version_negotiation_packet_ = true; + int error; + helper_->WritePacketToWire(*encrypted, &error); + delete encrypted; } QuicConsumedData QuicConnection::SendvStreamDataInner( @@ -1074,10 +1049,6 @@ bool QuicConnection::ProcessValidatedPacket() { bool QuicConnection::WriteQueuedPackets() { DCHECK(!write_blocked_); - if (pending_version_negotiation_packet_) { - SendVersionNegotiationPacket(); - } - QueuedPacketList::iterator packet_iterator = queued_packets_.begin(); while (!write_blocked_ && packet_iterator != queued_packets_.end()) { if (WritePacket(packet_iterator->encryption_level, @@ -1232,8 +1203,9 @@ void QuicConnection::SetupRetransmission( return; } - // Do not set the retransmission alarm if we're already handling one, since - // it will be reset when OnRetransmissionTimeout completes. + // Do not set the retransmission alarm if we're already handling the + // retransmission alarm because the retransmission alarm will be reset when + // OnRetransmissionTimeout completes. if (retransmission_alarm_->IsSet()) { return; } @@ -1366,51 +1338,27 @@ bool QuicConnection::WritePacket(EncryptionLevel level, << packet->length() << " " << encrypted->length() << " " << " forced: " << (forced == FORCE ? "yes" : "no"); - DCHECK(pending_write_.get() == NULL); - pending_write_.reset(new PendingWrite(sequence_number, transmission_type, - retransmittable, level, packet)); - - WriteResult result = WritePacketToWire(sequence_number, level, *encrypted); - if (result.status == WRITE_STATUS_BLOCKED) { - // TODO(satyashekhar): It might be more efficient (fewer system calls), if - // all connections share this variable i.e this becomes a part of - // PacketWriterInterface. - write_blocked_ = true; - // 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 - // when the packet is actually sent. - if (helper_->IsWriteBlockedDataBuffered()) { - return true; + int error; + QuicTime now = clock_->Now(); + if (WritePacketToWire(sequence_number, level, *encrypted, &error) == -1) { + if (helper_->IsWriteBlocked(error)) { + // TODO(satyashekhar): It might be more efficient (fewer system calls), if + // all connections share this variable i.e this becomes a part of + // PacketWriterInterface. + write_blocked_ = true; + // 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. + if (helper_->IsWriteBlockedDataBuffered()) { + delete packet; + return true; + } + return false; } - pending_write_.reset(); - return false; - } - - return OnPacketSent(result); -} - -bool QuicConnection::OnPacketSent(WriteResult result) { - DCHECK_NE(WRITE_STATUS_BLOCKED, result.status); - if (pending_write_.get() == NULL) { - LOG(DFATAL) << "OnPacketSent called without a pending write."; - return false; - } - - QuicPacketSequenceNumber sequence_number = pending_write_->sequence_number; - TransmissionType transmission_type = pending_write_->transmission_type; - HasRetransmittableData retransmittable = pending_write_->retransmittable; - EncryptionLevel level = pending_write_->level; - QuicPacket* packet = pending_write_->packet; - pending_write_.reset(); - - 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 false; } - - QuicTime now = clock_->Now(); if (transmission_type == NOT_RETRANSMISSION) { time_of_last_sent_packet_ = now; } @@ -1436,12 +1384,12 @@ bool QuicConnection::OnPacketSent(WriteResult result) { congestion_manager_.OnPacketSent(sequence_number, now, packet->length(), transmission_type, retransmittable); - stats_.bytes_sent += result.bytes_written; + stats_.bytes_sent += encrypted->length(); ++stats_.packets_sent; if (transmission_type == NACK_RETRANSMISSION || transmission_type == RTO_RETRANSMISSION) { - stats_.bytes_retransmitted += result.bytes_written; + stats_.bytes_retransmitted += encrypted->length(); ++stats_.packets_retransmitted; } @@ -1449,16 +1397,18 @@ bool QuicConnection::OnPacketSent(WriteResult result) { return true; } -WriteResult QuicConnection::WritePacketToWire( - QuicPacketSequenceNumber sequence_number, - EncryptionLevel level, - const QuicEncryptedPacket& packet) { - WriteResult result = helper_->WritePacketToWire(packet); +int QuicConnection::WritePacketToWire(QuicPacketSequenceNumber sequence_number, + EncryptionLevel level, + const QuicEncryptedPacket& packet, + int* error) { + int bytes_written = helper_->WritePacketToWire(packet, error); if (debug_visitor_) { - // Pass the write result to the visitor. - debug_visitor_->OnPacketSent(sequence_number, level, packet, result); + // WritePacketToWire returned -1, then |error| will be populated with + // an error code, which we want to pass along to the visitor. + debug_visitor_->OnPacketSent(sequence_number, level, packet, + bytes_written == -1 ? *error : bytes_written); } - return result; + return bytes_written; } bool QuicConnection::OnSerializedPacket( @@ -1556,6 +1506,8 @@ void QuicConnection::OnRetransmissionTimeout() { return; } + // TODO(ianswett): When multiple RTO's fire, the subsequent RTO should send + // the same data packet as the first RTO according to the TCP spec. // TODO(ianswett): When an RTO fires, but the connection has not been // established as forward secure, re-send the client hello first. ++stats_.rto_count; @@ -1813,8 +1765,7 @@ void QuicConnection::Flush() { } bool QuicConnection::HasQueuedData() const { - return pending_version_negotiation_packet_ || - !queued_packets_.empty() || packet_generator_.HasQueuedFrames(); + return !queued_packets_.empty() || packet_generator_.HasQueuedFrames(); } void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) { |