diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-28 01:51:15 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-28 01:51:15 +0000 |
commit | 583bcbcff1814196c2e7fa4b999712c3d66b126a (patch) | |
tree | 11b67f5bab0d47b8863b4ea05b4c9accd81f794e /net/quic/quic_connection.cc | |
parent | 963eac2fb452fe9b9c1ba69ddabb3d1a012eff20 (diff) | |
download | chromium_src-583bcbcff1814196c2e7fa4b999712c3d66b126a.zip chromium_src-583bcbcff1814196c2e7fa4b999712c3d66b126a.tar.gz chromium_src-583bcbcff1814196c2e7fa4b999712c3d66b126a.tar.bz2 |
Land Recent QUIC changes.
Enables the padding of QUIC handshake packets to the max packet
size. Does not pad packets which do not leave enough space to fit a
padding frame after expanding the final stream frame. An alternative
would be to add a new type of padding frame which could show up
earlier in the packet, but this is good enough for now.
flag to enable the padding of QUIC handshake packets to full size
Merge internal change: 55118010
Add a set_seed method to the PacketDroppingTestWriter to facilitate
reproducing test behavior.
Merge internal change: 55107501
Consistently pass the IsHandshake flag to the congestion control
algorithm in QUIC.
Merge internal change: 55046282
The goal is parity between HTTP and QUIC testing.
Merge internal change: 55000555
Fixed comments - found while back porting changes to server.
Merge internal change: 54999641
Fix bug in QuicPacketCreator's packet size calculation when a stream
frame is close to the maximum possible.
Merge internal change: 54933729
Remove unused random_reorder field from QuicPacketCreator::Options
Merge internal change: 54885136
Using GFE's IOVector to replace uses of struct iovec on the QUIC's
Write path.
Merge internal change: 54805402
R=rch@chromium.org
Review URL: https://codereview.chromium.org/46903002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231278 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic/quic_connection.cc')
-rw-r--r-- | net/quic/quic_connection.cc | 203 |
1 files changed, 101 insertions, 102 deletions
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 7448b51..ea575aa 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -17,6 +17,7 @@ #include "base/stl_util.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/iovector.h" #include "net/quic/quic_bandwidth.h" #include "net/quic/quic_utils.h" @@ -175,10 +176,13 @@ net::QuicConnection::Force HasForcedFrames( } net::IsHandshake HasCryptoHandshake( - const RetransmittableFrames& retransmittable_frames) { - for (size_t i = 0; i < retransmittable_frames.frames().size(); ++i) { - if (retransmittable_frames.frames()[i].type == STREAM_FRAME && - retransmittable_frames.frames()[i].stream_frame->stream_id == + const RetransmittableFrames* retransmittable_frames) { + if (!retransmittable_frames) { + return net::NOT_HANDSHAKE; + } + for (size_t i = 0; i < retransmittable_frames->frames().size(); ++i) { + if (retransmittable_frames->frames()[i].type == STREAM_FRAME && + retransmittable_frames->frames()[i].stream_frame->stream_id == kCryptoStreamId) { return net::IS_HANDSHAKE; } @@ -846,10 +850,9 @@ void QuicConnection::SendVersionNegotiationPacket() { pending_version_negotiation_packet_ = true; } -QuicConsumedData QuicConnection::SendvStreamDataInner( +QuicConsumedData QuicConnection::SendStreamDataInner( QuicStreamId id, - const struct iovec* iov, - int iov_count, + const IOVector& data, QuicStreamOffset offset, bool fin, QuicAckNotifier* notifier) { @@ -861,17 +864,18 @@ QuicConsumedData QuicConnection::SendvStreamDataInner( size_t bytes_written = 0; bool fin_consumed = false; - for (int i = 0; i < iov_count; ++i) { - bool send_fin = fin && (i == iov_count - 1); - if (!send_fin && iov[i].iov_len == 0) { + for (int i = 0; i < data.Size(); ++i) { + bool send_fin = fin && (i == data.Size() - 1); + if (!send_fin && data.iovec()[i].iov_len == 0) { LOG(DFATAL) << "Attempt to send empty stream frame"; } - StringPiece data(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); + StringPiece data_piece(static_cast<char*>(data.iovec()[i].iov_base), + data.iovec()[i].iov_len); int currentOffset = offset + bytes_written; QuicConsumedData consumed_data = packet_generator_.ConsumeData(id, - data, + data_piece, currentOffset, send_fin, notifier); @@ -881,12 +885,12 @@ QuicConsumedData QuicConnection::SendvStreamDataInner( fin_consumed = consumed_data.fin_consumed; // If no bytes were consumed, bail now, because the stream can not write // more data. - if (consumed_data.bytes_consumed < iov[i].iov_len) { + if (consumed_data.bytes_consumed < data.iovec()[i].iov_len) { break; } } // Handle the 0 byte write properly. - if (iov_count == 0) { + if (data.Empty()) { DCHECK(fin); QuicConsumedData consumed_data = packet_generator_.ConsumeData( id, StringPiece(), offset, fin, NULL); @@ -897,22 +901,20 @@ QuicConsumedData QuicConnection::SendvStreamDataInner( return QuicConsumedData(bytes_written, fin_consumed); } -QuicConsumedData QuicConnection::SendvStreamData(QuicStreamId id, - const struct iovec* iov, - int iov_count, - QuicStreamOffset offset, - bool fin) { - return SendvStreamDataInner(id, iov, iov_count, offset, fin, NULL); +QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, + const IOVector& data, + QuicStreamOffset offset, + bool fin) { + return SendStreamDataInner(id, data, offset, fin, NULL); } -QuicConsumedData QuicConnection::SendvStreamDataAndNotifyWhenAcked( +QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked( QuicStreamId id, - const struct iovec* iov, - int iov_count, + const IOVector& data, QuicStreamOffset offset, bool fin, QuicAckNotifier::DelegateInterface* delegate) { - if (!fin && iov_count == 0) { + if (!fin && data.Empty()) { LOG(DFATAL) << "Attempt to send empty stream frame"; } @@ -920,7 +922,7 @@ QuicConsumedData QuicConnection::SendvStreamDataAndNotifyWhenAcked( // no data was consumed). QuicAckNotifier* notifier = new QuicAckNotifier(delegate); QuicConsumedData consumed_data = - SendvStreamDataInner(id, iov, iov_count, offset, fin, notifier); + SendStreamDataInner(id, data, offset, fin, notifier); if (consumed_data.bytes_consumed == 0) { // No data was consumed, delete the notifier. @@ -1066,6 +1068,7 @@ bool QuicConnection::WriteQueuedPackets() { packet_iterator->packet, packet_iterator->transmission_type, packet_iterator->retransmittable, + packet_iterator->handshake, packet_iterator->forced)) { packet_iterator = queued_packets_.erase(packet_iterator); } else { @@ -1086,7 +1089,7 @@ void QuicConnection::WritePendingRetransmissions() { sent_packet_manager_.NextPendingRetransmission(); if (HasForcedFrames(&pending.retransmittable_frames) == NO_FORCE && !CanWrite(pending.transmission_type, HAS_RETRANSMITTABLE_DATA, - HasCryptoHandshake(pending.retransmittable_frames))) { + HasCryptoHandshake(&pending.retransmittable_frames))) { break; } @@ -1117,6 +1120,8 @@ void QuicConnection::WritePendingRetransmissions() { serialized_packet.entropy_hash, pending.transmission_type, HAS_RETRANSMITTABLE_DATA, + HasCryptoHandshake( + serialized_packet.retransmittable_frames), HasForcedFrames( serialized_packet.retransmittable_frames)); } @@ -1242,70 +1247,13 @@ bool QuicConnection::WritePacket(EncryptionLevel level, QuicPacket* packet, TransmissionType transmission_type, HasRetransmittableData retransmittable, + IsHandshake handshake, Force forced) { - if (!connected_) { - DLOG(INFO) << ENDPOINT - << "Not sending packet as connection is disconnected."; + if (ShouldDiscardPacket(level, sequence_number, retransmittable)) { delete packet; - // Returning true because we deleted the packet and the caller shouldn't - // delete it again. return true; } - if (encryption_level_ == ENCRYPTION_FORWARD_SECURE && - level == ENCRYPTION_NONE) { - // Drop packets that are NULL encrypted since the peer won't accept them - // anymore. - DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number - << " since the packet is NULL encrypted."; - sent_packet_manager_.DiscardUnackedPacket(sequence_number); - delete packet; - return true; - } - - if (retransmittable == HAS_RETRANSMITTABLE_DATA) { - if (!sent_packet_manager_.IsUnacked(sequence_number)) { - // This is a crazy edge case, but if we retransmit a packet, - // (but have to queue it for some reason) then receive an ack - // for the previous transmission (but not the retransmission) - // then receive a truncated ACK which causes us to raise the - // high water mark, all before we're able to send the packet - // then we can simply drop it. - DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number - << " since it has already been acked."; - delete packet; - return true; - } - - 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. - DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number - << " since it has already been retransmitted."; - delete packet; - return true; - } - - if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) { - DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number - << " since a previous transmission has been acked."; - sent_packet_manager_.DiscardUnackedPacket(sequence_number); - delete packet; - return true; - } - } - - // TODO(wtc): use the same logic that is used in the packet generator. - // Namely, a packet is a handshake if it contains a stream frame for the - // crypto stream. It should be possible to look at the RetransmittableFrames - // in the SerializedPacket to determine this for a packet. - IsHandshake handshake = level == ENCRYPTION_NONE ? IS_HANDSHAKE - : NOT_HANDSHAKE; - // If we are not forced and we can't write, then simply return false; if (forced == NO_FORCE && !CanWrite(transmission_type, retransmittable, handshake)) { @@ -1351,7 +1299,13 @@ bool QuicConnection::WritePacket(EncryptionLevel level, packet->is_fec_packet(), packet->length())); - WriteResult result = WritePacketToWire(sequence_number, level, *encrypted); + WriteResult result = + writer_->WritePacket(encrypted->data(), encrypted->length(), + self_address().address(), peer_address(), this); + if (debug_visitor_) { + // Pass the write result to the visitor. + debug_visitor_->OnPacketSent(sequence_number, level, *encrypted, result); + } 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 @@ -1376,6 +1330,62 @@ bool QuicConnection::WritePacket(EncryptionLevel level, return false; } +bool QuicConnection::ShouldDiscardPacket( + EncryptionLevel level, + QuicPacketSequenceNumber sequence_number, + HasRetransmittableData retransmittable) { + if (!connected_) { + DLOG(INFO) << ENDPOINT + << "Not sending packet as connection is disconnected."; + return true; + } + + if (encryption_level_ == ENCRYPTION_FORWARD_SECURE && + level == ENCRYPTION_NONE) { + // Drop packets that are NULL encrypted since the peer won't accept them + // anymore. + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since the packet is NULL encrypted."; + sent_packet_manager_.DiscardUnackedPacket(sequence_number); + return true; + } + + if (retransmittable == HAS_RETRANSMITTABLE_DATA) { + if (!sent_packet_manager_.IsUnacked(sequence_number)) { + // This is a crazy edge case, but if we retransmit a packet, + // (but have to queue it for some reason) then receive an ack + // for the previous transmission (but not the retransmission) + // then receive a truncated ACK which causes us to raise the + // high water mark, all before we're able to send the packet + // then we can simply drop it. + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since it has already been acked."; + return true; + } + + 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. + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since it has already been retransmitted."; + return true; + } + + if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) { + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since a previous transmission has been acked."; + sent_packet_manager_.DiscardUnackedPacket(sequence_number); + return true; + } + } + + return false; +} + bool QuicConnection::OnPacketSent(WriteResult result) { DCHECK_NE(WRITE_STATUS_BLOCKED, result.status); if (pending_write_.get() == NULL) { @@ -1435,20 +1445,6 @@ bool QuicConnection::OnPacketSent(WriteResult result) { return true; } -WriteResult QuicConnection::WritePacketToWire( - QuicPacketSequenceNumber sequence_number, - EncryptionLevel level, - const QuicEncryptedPacket& packet) { - WriteResult result = - writer_->WritePacket(packet.data(), packet.length(), - self_address().address(), peer_address(), this); - if (debug_visitor_) { - // Pass the write result to the visitor. - debug_visitor_->OnPacketSent(sequence_number, level, packet, result); - } - return result; -} - bool QuicConnection::OnSerializedPacket( const SerializedPacket& serialized_packet) { if (serialized_packet.retransmittable_frames) { @@ -1467,6 +1463,8 @@ bool QuicConnection::OnSerializedPacket( serialized_packet.retransmittable_frames != NULL ? HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA, + HasCryptoHandshake( + serialized_packet.retransmittable_frames), HasForcedFrames( serialized_packet.retransmittable_frames)); } @@ -1490,13 +1488,14 @@ bool QuicConnection::SendOrQueuePacket(EncryptionLevel level, QuicPacketEntropyHash entropy_hash, TransmissionType transmission_type, HasRetransmittableData retransmittable, + IsHandshake handshake, Force forced) { sent_entropy_manager_.RecordPacketEntropyHash(sequence_number, entropy_hash); if (!WritePacket(level, sequence_number, packet, - transmission_type, retransmittable, forced)) { + transmission_type, retransmittable, handshake, forced)) { queued_packets_.push_back(QueuedPacket(sequence_number, packet, level, transmission_type, retransmittable, - forced)); + handshake, forced)); return false; } return true; |