| Index: net/quic/quic_connection.cc
|
| diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
|
| index ab1e0fe8de4158f8b83c41e962a17843d4154a26..4adf6246d7ef9c061c2953ea6ed5c9e31e5829d7 100644
|
| --- a/net/quic/quic_connection.cc
|
| +++ b/net/quic/quic_connection.cc
|
| @@ -154,35 +154,14 @@ class PingAlarm : public QuicAlarm::Delegate {
|
| DISALLOW_COPY_AND_ASSIGN(PingAlarm);
|
| };
|
|
|
| -QuicConnection::PacketType GetPacketType(
|
| - const RetransmittableFrames* retransmittable_frames) {
|
| - if (!retransmittable_frames) {
|
| - return QuicConnection::NORMAL;
|
| - }
|
| - for (size_t i = 0; i < retransmittable_frames->frames().size(); ++i) {
|
| - if (retransmittable_frames->frames()[i].type == CONNECTION_CLOSE_FRAME) {
|
| - return QuicConnection::CONNECTION_CLOSE;
|
| - }
|
| - }
|
| - return QuicConnection::NORMAL;
|
| -}
|
| -
|
| } // namespace
|
|
|
| QuicConnection::QueuedPacket::QueuedPacket(SerializedPacket packet,
|
| EncryptionLevel level,
|
| TransmissionType transmission_type)
|
| - : sequence_number(packet.sequence_number),
|
| - packet(packet.packet),
|
| + : serialized_packet(packet),
|
| encryption_level(level),
|
| - transmission_type(transmission_type),
|
| - retransmittable((transmission_type != NOT_RETRANSMISSION ||
|
| - packet.retransmittable_frames != NULL) ?
|
| - HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA),
|
| - handshake(packet.retransmittable_frames == NULL ?
|
| - NOT_HANDSHAKE : packet.retransmittable_frames->HasCryptoHandshake()),
|
| - type(GetPacketType(packet.retransmittable_frames)),
|
| - length(packet.packet->length()) {
|
| + transmission_type(transmission_type) {
|
| }
|
|
|
| #define ENDPOINT (is_server_ ? "Server: " : " Client: ")
|
| @@ -262,7 +241,7 @@ QuicConnection::~QuicConnection() {
|
| STLDeleteValues(&group_map_);
|
| for (QueuedPacketList::iterator it = queued_packets_.begin();
|
| it != queued_packets_.end(); ++it) {
|
| - delete it->packet;
|
| + delete it->serialized_packet.packet;
|
| }
|
| }
|
|
|
| @@ -300,13 +279,15 @@ void QuicConnection::OnError(QuicFramer* framer) {
|
|
|
| void QuicConnection::OnPacket() {
|
| DCHECK(last_stream_frames_.empty() &&
|
| + last_ack_frames_.empty() &&
|
| + last_congestion_frames_.empty() &&
|
| + last_stop_waiting_frames_.empty() &&
|
| + last_rst_frames_.empty() &&
|
| last_goaway_frames_.empty() &&
|
| last_window_update_frames_.empty() &&
|
| last_blocked_frames_.empty() &&
|
| - last_rst_frames_.empty() &&
|
| - last_ack_frames_.empty() &&
|
| - last_congestion_frames_.empty() &&
|
| - last_stop_waiting_frames_.empty());
|
| + last_ping_frames_.empty() &&
|
| + last_close_frames_.empty());
|
| }
|
|
|
| void QuicConnection::OnPublicResetPacket(
|
| @@ -363,6 +344,9 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
|
|
|
| version_negotiation_state_ = NEGOTIATED_VERSION;
|
| visitor_->OnSuccessfulVersionNegotiation(received_version);
|
| + if (debug_visitor_.get() != NULL) {
|
| + debug_visitor_->OnSuccessfulVersionNegotiation(received_version);
|
| + }
|
| DVLOG(1) << ENDPOINT << "version negotiated " << received_version;
|
|
|
| // Store the new version.
|
| @@ -489,6 +473,9 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
|
| DCHECK_EQ(header.public_header.versions[0], version());
|
| version_negotiation_state_ = NEGOTIATED_VERSION;
|
| visitor_->OnSuccessfulVersionNegotiation(version());
|
| + if (debug_visitor_.get() != NULL) {
|
| + debug_visitor_->OnSuccessfulVersionNegotiation(version());
|
| + }
|
| }
|
| } else {
|
| DCHECK(!header.public_header.version_flag);
|
| @@ -497,6 +484,9 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
|
| packet_generator_.StopSendingVersion();
|
| version_negotiation_state_ = NEGOTIATED_VERSION;
|
| visitor_->OnSuccessfulVersionNegotiation(version());
|
| + if (debug_visitor_.get() != NULL) {
|
| + debug_visitor_->OnSuccessfulVersionNegotiation(version());
|
| + }
|
| }
|
| }
|
|
|
| @@ -617,6 +607,7 @@ bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) {
|
| if (debug_visitor_.get() != NULL) {
|
| debug_visitor_->OnPingFrame(frame);
|
| }
|
| + last_ping_frames_.push_back(frame);
|
| return true;
|
| }
|
|
|
| @@ -778,17 +769,17 @@ void QuicConnection::OnPacketComplete() {
|
|
|
| DVLOG(1) << ENDPOINT << (last_packet_revived_ ? "Revived" : "Got")
|
| << " packet " << last_header_.packet_sequence_number
|
| - << " with " << last_ack_frames_.size() << " acks, "
|
| + << " with " << last_stream_frames_.size()<< " stream frames "
|
| + << last_ack_frames_.size() << " acks, "
|
| << last_congestion_frames_.size() << " congestions, "
|
| << last_stop_waiting_frames_.size() << " stop_waiting, "
|
| + << last_rst_frames_.size() << " rsts, "
|
| << last_goaway_frames_.size() << " goaways, "
|
| << last_window_update_frames_.size() << " window updates, "
|
| << last_blocked_frames_.size() << " blocked, "
|
| - << last_rst_frames_.size() << " rsts, "
|
| + << last_ping_frames_.size() << " pings, "
|
| << last_close_frames_.size() << " closes, "
|
| - << last_stream_frames_.size()
|
| - << " stream frames for "
|
| - << last_header_.public_header.connection_id;
|
| + << "for " << last_header_.public_header.connection_id;
|
|
|
| // Call MaybeQueueAck() before recording the received packet, since we want
|
| // to trigger an ack if the newly received packet was previously missing.
|
| @@ -881,13 +872,15 @@ void QuicConnection::MaybeQueueAck() {
|
|
|
| void QuicConnection::ClearLastFrames() {
|
| last_stream_frames_.clear();
|
| + last_ack_frames_.clear();
|
| + last_congestion_frames_.clear();
|
| + last_stop_waiting_frames_.clear();
|
| + last_rst_frames_.clear();
|
| last_goaway_frames_.clear();
|
| last_window_update_frames_.clear();
|
| last_blocked_frames_.clear();
|
| - last_rst_frames_.clear();
|
| - last_ack_frames_.clear();
|
| - last_stop_waiting_frames_.clear();
|
| - last_congestion_frames_.clear();
|
| + last_ping_frames_.clear();
|
| + last_close_frames_.clear();
|
| }
|
|
|
| QuicAckFrame* QuicConnection::CreateAckFrame() {
|
| @@ -913,7 +906,8 @@ bool QuicConnection::ShouldLastPacketInstigateAck() const {
|
| !last_goaway_frames_.empty() ||
|
| !last_rst_frames_.empty() ||
|
| !last_window_update_frames_.empty() ||
|
| - !last_blocked_frames_.empty()) {
|
| + !last_blocked_frames_.empty() ||
|
| + !last_ping_frames_.empty()) {
|
| return true;
|
| }
|
|
|
| @@ -1212,16 +1206,10 @@ void QuicConnection::WriteQueuedPackets() {
|
| }
|
|
|
| QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
|
| - while (!writer_->IsWriteBlocked() &&
|
| - packet_iterator != queued_packets_.end()) {
|
| - if (WritePacket(*packet_iterator)) {
|
| - delete packet_iterator->packet;
|
| - packet_iterator = queued_packets_.erase(packet_iterator);
|
| - } else {
|
| - // Continue, because some queued packets may still be writable.
|
| - // This can happen if a retransmit send fails.
|
| - ++packet_iterator;
|
| - }
|
| + while (packet_iterator != queued_packets_.end() &&
|
| + WritePacket(*packet_iterator)) {
|
| + delete packet_iterator->serialized_packet.packet;
|
| + packet_iterator = queued_packets_.erase(packet_iterator);
|
| }
|
| }
|
|
|
| @@ -1231,8 +1219,7 @@ void QuicConnection::WritePendingRetransmissions() {
|
| while (sent_packet_manager_.HasPendingRetransmissions()) {
|
| const QuicSentPacketManager::PendingRetransmission pending =
|
| sent_packet_manager_.NextPendingRetransmission();
|
| - if (GetPacketType(&pending.retransmittable_frames) == NORMAL &&
|
| - !CanWrite(HAS_RETRANSMITTABLE_DATA)) {
|
| + if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
|
| break;
|
| }
|
|
|
| @@ -1316,22 +1303,17 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
|
| return true;
|
| }
|
|
|
| -bool QuicConnection::WritePacket(QueuedPacket packet) {
|
| - QuicPacketSequenceNumber sequence_number = packet.sequence_number;
|
| +bool QuicConnection::WritePacket(const QueuedPacket& packet) {
|
| + QuicPacketSequenceNumber sequence_number =
|
| + packet.serialized_packet.sequence_number;
|
| if (ShouldDiscardPacket(packet.encryption_level,
|
| sequence_number,
|
| - packet.retransmittable)) {
|
| + IsRetransmittable(packet))) {
|
| ++stats_.packets_discarded;
|
| return true;
|
| }
|
| -
|
| - // If the packet is CONNECTION_CLOSE, we need to try to send it immediately
|
| - // and encrypt it to hand it off to TimeWaitListManager.
|
| - // If the packet is QUEUED, we don't re-consult the congestion control.
|
| - // This ensures packets are sent in sequence number order.
|
| - // TODO(ianswett): The congestion control should have been consulted before
|
| - // serializing the packet, so this could be turned into a LOG_IF(DFATAL).
|
| - if (packet.type == NORMAL && !CanWrite(packet.retransmittable)) {
|
| + // Connection close packets are encypted and saved, so don't exit early.
|
| + if (writer_->IsWriteBlocked() && !IsConnectionClose(packet)) {
|
| return false;
|
| }
|
|
|
| @@ -1341,7 +1323,9 @@ bool QuicConnection::WritePacket(QueuedPacket packet) {
|
| sequence_number_of_last_sent_packet_ = sequence_number;
|
|
|
| QuicEncryptedPacket* encrypted = framer_.EncryptPacket(
|
| - packet.encryption_level, sequence_number, *packet.packet);
|
| + packet.encryption_level,
|
| + sequence_number,
|
| + *packet.serialized_packet.packet);
|
| if (encrypted == NULL) {
|
| LOG(DFATAL) << ENDPOINT << "Failed to encrypt packet number "
|
| << sequence_number;
|
| @@ -1353,7 +1337,7 @@ bool QuicConnection::WritePacket(QueuedPacket packet) {
|
| // Connection close packets are eventually owned by TimeWaitListManager.
|
| // Others are deleted at the end of this call.
|
| scoped_ptr<QuicEncryptedPacket> encrypted_deleter;
|
| - if (packet.type == CONNECTION_CLOSE) {
|
| + if (IsConnectionClose(packet)) {
|
| DCHECK(connection_close_packet_.get() == NULL);
|
| connection_close_packet_.reset(encrypted);
|
| // This assures we won't try to write *forced* packets when blocked.
|
| @@ -1370,16 +1354,19 @@ bool QuicConnection::WritePacket(QueuedPacket packet) {
|
| DCHECK_LE(encrypted->length(), kMaxPacketSize);
|
| }
|
| DCHECK_LE(encrypted->length(), packet_generator_.max_packet_length());
|
| - DVLOG(1) << ENDPOINT << "Sending packet " << sequence_number
|
| - << " : " << (packet.packet->is_fec_packet() ? "FEC " :
|
| - (packet.retransmittable == HAS_RETRANSMITTABLE_DATA
|
| - ? "data bearing " : " ack only "))
|
| + DVLOG(1) << ENDPOINT << "Sending packet " << sequence_number << " : "
|
| + << (packet.serialized_packet.packet->is_fec_packet() ? "FEC " :
|
| + (IsRetransmittable(packet) == HAS_RETRANSMITTABLE_DATA
|
| + ? "data bearing " : " ack only "))
|
| << ", encryption level: "
|
| << QuicUtils::EncryptionLevelToString(packet.encryption_level)
|
| - << ", length:" << packet.packet->length() << ", encrypted length:"
|
| + << ", length:"
|
| + << packet.serialized_packet.packet->length()
|
| + << ", encrypted length:"
|
| << encrypted->length();
|
| DVLOG(2) << ENDPOINT << "packet(" << sequence_number << "): " << std::endl
|
| - << QuicUtils::StringToHexASCIIDump(packet.packet->AsStringPiece());
|
| + << QuicUtils::StringToHexASCIIDump(
|
| + packet.serialized_packet.packet->AsStringPiece());
|
|
|
| WriteResult result = writer_->WritePacket(encrypted->data(),
|
| encrypted->length(),
|
| @@ -1422,12 +1409,12 @@ bool QuicConnection::WritePacket(QueuedPacket packet) {
|
| sent_packet_manager_.least_packet_awaited_by_peer(),
|
| sent_packet_manager_.GetCongestionWindow());
|
|
|
| - bool reset_retransmission_alarm =
|
| - sent_packet_manager_.OnPacketSent(sequence_number,
|
| - now,
|
| - encrypted->length(),
|
| - packet.transmission_type,
|
| - packet.retransmittable);
|
| + bool reset_retransmission_alarm = sent_packet_manager_.OnPacketSent(
|
| + sequence_number,
|
| + now,
|
| + encrypted->length(),
|
| + packet.transmission_type,
|
| + IsRetransmittable(packet));
|
|
|
| if (reset_retransmission_alarm || !retransmission_alarm_->IsSet()) {
|
| retransmission_alarm_->Update(sent_packet_manager_.GetRetransmissionTime(),
|
| @@ -1523,6 +1510,7 @@ void QuicConnection::OnHandshakeComplete() {
|
| bool QuicConnection::SendOrQueuePacket(EncryptionLevel level,
|
| const SerializedPacket& packet,
|
| TransmissionType transmission_type) {
|
| + // The caller of this function is responsible for checking CanWrite().
|
| if (packet.packet == NULL) {
|
| LOG(DFATAL) << "NULL packet passed in to SendOrQueuePacket";
|
| return true;
|
| @@ -1531,14 +1519,12 @@ bool QuicConnection::SendOrQueuePacket(EncryptionLevel level,
|
| sent_entropy_manager_.RecordPacketEntropyHash(packet.sequence_number,
|
| packet.entropy_hash);
|
| QueuedPacket queued_packet(packet, level, transmission_type);
|
| - // If there are already queued packets, put this at the end,
|
| - // unless it's ConnectionClose, in which case it is written immediately.
|
| - if ((queued_packet.type == CONNECTION_CLOSE || queued_packets_.empty()) &&
|
| - WritePacket(queued_packet)) {
|
| + LOG_IF(DFATAL, !queued_packets_.empty() && !writer_->IsWriteBlocked())
|
| + << "Packets should only be left queued if we're write blocked.";
|
| + if (WritePacket(queued_packet)) {
|
| delete packet.packet;
|
| return true;
|
| }
|
| - queued_packet.type = QUEUED;
|
| queued_packets_.push_back(queued_packet);
|
| return false;
|
| }
|
| @@ -1991,4 +1977,31 @@ QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
|
| connection_->packet_generator_.InBatchMode());
|
| }
|
|
|
| +HasRetransmittableData QuicConnection::IsRetransmittable(
|
| + QueuedPacket packet) {
|
| + // TODO(cyr): Understand why the first check here is necessary. Without it,
|
| + // DiscardRetransmit test fails.
|
| + if (packet.transmission_type != NOT_RETRANSMISSION ||
|
| + packet.serialized_packet.retransmittable_frames != NULL) {
|
| + return HAS_RETRANSMITTABLE_DATA;
|
| + } else {
|
| + return NO_RETRANSMITTABLE_DATA;
|
| + }
|
| +}
|
| +
|
| +bool QuicConnection::IsConnectionClose(
|
| + QueuedPacket packet) {
|
| + RetransmittableFrames* retransmittable_frames =
|
| + packet.serialized_packet.retransmittable_frames;
|
| + if (!retransmittable_frames) {
|
| + return false;
|
| + }
|
| + for (size_t i = 0; i < retransmittable_frames->frames().size(); ++i) {
|
| + if (retransmittable_frames->frames()[i].type == CONNECTION_CLOSE_FRAME) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| } // namespace net
|
|
|