Index: net/quic/quic_packet_creator.cc |
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc |
deleted file mode 100644 |
index e91efa21b2b037fecf8eca3cd3a1dd8a304ca71f..0000000000000000000000000000000000000000 |
--- a/net/quic/quic_packet_creator.cc |
+++ /dev/null |
@@ -1,563 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/quic/quic_packet_creator.h" |
- |
-#include "base/basictypes.h" |
-#include "base/logging.h" |
-#include "net/quic/crypto/quic_random.h" |
-#include "net/quic/quic_ack_notifier.h" |
-#include "net/quic/quic_data_writer.h" |
-#include "net/quic/quic_fec_group.h" |
-#include "net/quic/quic_utils.h" |
- |
-using base::StringPiece; |
-using std::make_pair; |
-using std::max; |
-using std::min; |
-using std::pair; |
-using std::vector; |
- |
-namespace net { |
- |
-namespace { |
- |
-// Default max packets in an FEC group. |
-static const size_t kDefaultMaxPacketsPerFecGroup = 10; |
-// Lowest max packets in an FEC group. |
-static const size_t kLowestMaxPacketsPerFecGroup = 2; |
- |
-} // namespace |
- |
-// A QuicRandom wrapper that gets a bucket of entropy and distributes it |
-// bit-by-bit. Replenishes the bucket as needed. Not thread-safe. Expose this |
-// class if single bit randomness is needed elsewhere. |
-class QuicRandomBoolSource { |
- public: |
- // random: Source of entropy. Not owned. |
- explicit QuicRandomBoolSource(QuicRandom* random) |
- : random_(random), |
- bit_bucket_(0), |
- bit_mask_(0) {} |
- |
- ~QuicRandomBoolSource() {} |
- |
- // Returns the next random bit from the bucket. |
- bool RandBool() { |
- if (bit_mask_ == 0) { |
- bit_bucket_ = random_->RandUint64(); |
- bit_mask_ = 1; |
- } |
- bool result = ((bit_bucket_ & bit_mask_) != 0); |
- bit_mask_ <<= 1; |
- return result; |
- } |
- |
- private: |
- // Source of entropy. |
- QuicRandom* random_; |
- // Stored random bits. |
- uint64 bit_bucket_; |
- // The next available bit has "1" in the mask. Zero means empty bucket. |
- uint64 bit_mask_; |
- |
- DISALLOW_COPY_AND_ASSIGN(QuicRandomBoolSource); |
-}; |
- |
-QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, |
- QuicFramer* framer, |
- QuicRandom* random_generator) |
- : connection_id_(connection_id), |
- encryption_level_(ENCRYPTION_NONE), |
- framer_(framer), |
- random_bool_source_(new QuicRandomBoolSource(random_generator)), |
- sequence_number_(0), |
- should_fec_protect_(false), |
- fec_group_number_(0), |
- send_version_in_packet_(!framer->is_server()), |
- max_packet_length_(kDefaultMaxPacketSize), |
- max_packets_per_fec_group_(kDefaultMaxPacketsPerFecGroup), |
- connection_id_length_(PACKET_8BYTE_CONNECTION_ID), |
- next_sequence_number_length_(PACKET_1BYTE_SEQUENCE_NUMBER), |
- sequence_number_length_(next_sequence_number_length_), |
- packet_size_(0) { |
- framer_->set_fec_builder(this); |
-} |
- |
-QuicPacketCreator::~QuicPacketCreator() { |
-} |
- |
-void QuicPacketCreator::OnBuiltFecProtectedPayload( |
- const QuicPacketHeader& header, StringPiece payload) { |
- if (fec_group_.get()) { |
- DCHECK_NE(0u, header.fec_group); |
- fec_group_->Update(encryption_level_, header, payload); |
- } |
-} |
- |
-void QuicPacketCreator::set_max_packets_per_fec_group( |
- size_t max_packets_per_fec_group) { |
- max_packets_per_fec_group_ = max(kLowestMaxPacketsPerFecGroup, |
- max_packets_per_fec_group); |
- DCHECK_LT(0u, max_packets_per_fec_group_); |
-} |
- |
-bool QuicPacketCreator::ShouldSendFec(bool force_close) const { |
- DCHECK(!HasPendingFrames()); |
- return fec_group_.get() != nullptr && fec_group_->NumReceivedPackets() > 0 && |
- (force_close || |
- fec_group_->NumReceivedPackets() >= max_packets_per_fec_group_); |
-} |
- |
-bool QuicPacketCreator::IsFecGroupOpen() const { |
- return fec_group_.get() != nullptr; |
-} |
- |
-void QuicPacketCreator::StartFecProtectingPackets() { |
- if (!IsFecEnabled()) { |
- LOG(DFATAL) << "Cannot start FEC protection when FEC is not enabled."; |
- return; |
- } |
- // TODO(jri): This currently requires that the generator flush out any |
- // pending frames when FEC protection is turned on. If current packet can be |
- // converted to an FEC protected packet, do it. This will require the |
- // generator to check if the resulting expansion still allows the incoming |
- // frame to be added to the packet. |
- if (HasPendingFrames()) { |
- LOG(DFATAL) << "Cannot start FEC protection with pending frames."; |
- return; |
- } |
- DCHECK(!should_fec_protect_); |
- should_fec_protect_ = true; |
-} |
- |
-void QuicPacketCreator::StopFecProtectingPackets() { |
- if (fec_group_.get() != nullptr) { |
- LOG(DFATAL) << "Cannot stop FEC protection with open FEC group."; |
- return; |
- } |
- DCHECK(should_fec_protect_); |
- should_fec_protect_ = false; |
- fec_group_number_ = 0; |
-} |
- |
-bool QuicPacketCreator::IsFecProtected() const { |
- return should_fec_protect_; |
-} |
- |
-bool QuicPacketCreator::IsFecEnabled() const { |
- return max_packets_per_fec_group_ > 0; |
-} |
- |
-InFecGroup QuicPacketCreator::MaybeUpdateLengthsAndStartFec() { |
- if (fec_group_.get() != nullptr) { |
- // Don't update any lengths when an FEC group is open, to ensure same |
- // packet header size in all packets within a group. |
- return IN_FEC_GROUP; |
- } |
- if (!queued_frames_.empty()) { |
- // Don't change creator state if there are frames queued. |
- return fec_group_.get() == nullptr ? NOT_IN_FEC_GROUP : IN_FEC_GROUP; |
- } |
- |
- // Update sequence number length only on packet and FEC group boundaries. |
- sequence_number_length_ = next_sequence_number_length_; |
- |
- if (!should_fec_protect_) { |
- return NOT_IN_FEC_GROUP; |
- } |
- // Start a new FEC group since protection is on. Set the fec group number to |
- // the sequence number of the next packet. |
- fec_group_number_ = sequence_number() + 1; |
- fec_group_.reset(new QuicFecGroup()); |
- return IN_FEC_GROUP; |
-} |
- |
-// Stops serializing version of the protocol in packets sent after this call. |
-// A packet that is already open might send kQuicVersionSize bytes less than the |
-// maximum packet size if we stop sending version before it is serialized. |
-void QuicPacketCreator::StopSendingVersion() { |
- DCHECK(send_version_in_packet_); |
- send_version_in_packet_ = false; |
- if (packet_size_ > 0) { |
- DCHECK_LT(kQuicVersionSize, packet_size_); |
- packet_size_ -= kQuicVersionSize; |
- } |
-} |
- |
-void QuicPacketCreator::UpdateSequenceNumberLength( |
- QuicPacketSequenceNumber least_packet_awaited_by_peer, |
- QuicPacketCount max_packets_in_flight) { |
- DCHECK_LE(least_packet_awaited_by_peer, sequence_number_ + 1); |
- // Since the packet creator will not change sequence number length mid FEC |
- // group, include the size of an FEC group to be safe. |
- const QuicPacketSequenceNumber current_delta = |
- max_packets_per_fec_group_ + sequence_number_ + 1 |
- - least_packet_awaited_by_peer; |
- const uint64 delta = max(current_delta, max_packets_in_flight); |
- next_sequence_number_length_ = |
- QuicFramer::GetMinSequenceNumberLength(delta * 4); |
-} |
- |
-bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id, |
- QuicStreamOffset offset) const { |
- // TODO(jri): This is a simple safe decision for now, but make |
- // is_in_fec_group a parameter. Same as with all public methods in |
- // QuicPacketCreator. |
- return BytesFree() > |
- QuicFramer::GetMinStreamFrameSize(id, offset, true, |
- should_fec_protect_ ? IN_FEC_GROUP : |
- NOT_IN_FEC_GROUP); |
-} |
- |
-// static |
-size_t QuicPacketCreator::StreamFramePacketOverhead( |
- QuicConnectionIdLength connection_id_length, |
- bool include_version, |
- QuicSequenceNumberLength sequence_number_length, |
- QuicStreamOffset offset, |
- InFecGroup is_in_fec_group) { |
- return GetPacketHeaderSize(connection_id_length, include_version, |
- sequence_number_length, is_in_fec_group) + |
- // Assumes this is a stream with a single lone packet. |
- QuicFramer::GetMinStreamFrameSize(1u, offset, true, is_in_fec_group); |
-} |
- |
-size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, |
- const IOVector& data, |
- QuicStreamOffset offset, |
- bool fin, |
- QuicFrame* frame) { |
- DCHECK_GT(max_packet_length_, StreamFramePacketOverhead( |
- connection_id_length_, kIncludeVersion, |
- PACKET_6BYTE_SEQUENCE_NUMBER, offset, IN_FEC_GROUP)); |
- |
- InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec(); |
- |
- LOG_IF(DFATAL, !HasRoomForStreamFrame(id, offset)) |
- << "No room for Stream frame, BytesFree: " << BytesFree() |
- << " MinStreamFrameSize: " |
- << QuicFramer::GetMinStreamFrameSize(id, offset, true, is_in_fec_group); |
- |
- if (data.Empty()) { |
- LOG_IF(DFATAL, !fin) |
- << "Creating a stream frame with no data or fin."; |
- // Create a new packet for the fin, if necessary. |
- *frame = QuicFrame(new QuicStreamFrame(id, true, offset, data)); |
- return 0; |
- } |
- |
- const size_t data_size = data.TotalBufferSize(); |
- size_t min_frame_size = QuicFramer::GetMinStreamFrameSize( |
- id, offset, /* last_frame_in_packet= */ true, is_in_fec_group); |
- size_t bytes_consumed = min<size_t>(BytesFree() - min_frame_size, data_size); |
- |
- bool set_fin = fin && bytes_consumed == data_size; // Last frame. |
- IOVector frame_data; |
- frame_data.AppendIovecAtMostBytes(data.iovec(), data.Size(), |
- bytes_consumed); |
- DCHECK_EQ(frame_data.TotalBufferSize(), bytes_consumed); |
- *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, frame_data)); |
- return bytes_consumed; |
-} |
- |
-SerializedPacket QuicPacketCreator::ReserializeAllFrames( |
- const RetransmittableFrames& frames, |
- QuicSequenceNumberLength original_length) { |
- DCHECK(fec_group_.get() == nullptr); |
- const QuicSequenceNumberLength saved_length = sequence_number_length_; |
- const QuicSequenceNumberLength saved_next_length = |
- next_sequence_number_length_; |
- const bool saved_should_fec_protect = should_fec_protect_; |
- const EncryptionLevel default_encryption_level = encryption_level_; |
- |
- // Temporarily set the sequence number length, stop FEC protection, |
- // and change the encryption level. |
- sequence_number_length_ = original_length; |
- next_sequence_number_length_ = original_length; |
- should_fec_protect_ = false; |
- encryption_level_ = frames.encryption_level(); |
- |
- // Serialize the packet and restore the FEC and sequence number length state. |
- SerializedPacket serialized_packet = SerializeAllFrames(frames.frames()); |
- sequence_number_length_ = saved_length; |
- next_sequence_number_length_ = saved_next_length; |
- should_fec_protect_ = saved_should_fec_protect; |
- encryption_level_ = default_encryption_level; |
- |
- return serialized_packet; |
-} |
- |
-// TODO(ianswett): Remove this method, because it's test only. |
-SerializedPacket QuicPacketCreator::SerializeAllFrames( |
- const QuicFrames& frames) { |
- // TODO(satyamshekhar): Verify that this DCHECK won't fail. What about queued |
- // frames from SendStreamData()[send_stream_should_flush_ == false && |
- // data.empty() == true] and retransmit due to RTO. |
- DCHECK_EQ(0u, queued_frames_.size()); |
- LOG_IF(DFATAL, frames.empty()) |
- << "Attempt to serialize empty packet"; |
- for (const QuicFrame& frame : frames) { |
- bool success = AddFrame(frame, false); |
- DCHECK(success); |
- } |
- SerializedPacket packet = SerializePacket(); |
- DCHECK(packet.retransmittable_frames == nullptr); |
- return packet; |
-} |
- |
-bool QuicPacketCreator::HasPendingFrames() const { |
- return !queued_frames_.empty(); |
-} |
- |
-bool QuicPacketCreator::HasPendingRetransmittableFrames() const { |
- return queued_retransmittable_frames_.get() != nullptr && |
- !queued_retransmittable_frames_->frames().empty(); |
-} |
- |
-size_t QuicPacketCreator::ExpansionOnNewFrame() const { |
- // If packet is FEC protected, there's no expansion. |
- if (should_fec_protect_) { |
- return 0; |
- } |
- // If the last frame in the packet is a stream frame, then it will expand to |
- // include the stream_length field when a new frame is added. |
- bool has_trailing_stream_frame = |
- !queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME; |
- return has_trailing_stream_frame ? kQuicStreamPayloadLengthSize : 0; |
-} |
- |
-size_t QuicPacketCreator::BytesFree() const { |
- const size_t max_plaintext_size = |
- framer_->GetMaxPlaintextSize(max_packet_length_); |
- DCHECK_GE(max_plaintext_size, PacketSize()); |
- return max_plaintext_size - min(max_plaintext_size, PacketSize() |
- + ExpansionOnNewFrame()); |
-} |
- |
-size_t QuicPacketCreator::PacketSize() const { |
- if (!queued_frames_.empty()) { |
- return packet_size_; |
- } |
- if (fec_group_.get() == nullptr) { |
- // Update sequence number length on packet and FEC boundary. |
- sequence_number_length_ = next_sequence_number_length_; |
- } |
- packet_size_ = GetPacketHeaderSize( |
- connection_id_length_, send_version_in_packet_, sequence_number_length_, |
- should_fec_protect_ ? IN_FEC_GROUP : NOT_IN_FEC_GROUP); |
- return packet_size_; |
-} |
- |
-bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) { |
- return AddFrame(frame, true); |
-} |
- |
-SerializedPacket QuicPacketCreator::SerializePacket() { |
- LOG_IF(DFATAL, queued_frames_.empty()) |
- << "Attempt to serialize empty packet"; |
- DCHECK_GE(sequence_number_ + 1, fec_group_number_); |
- QuicPacketHeader header; |
- FillPacketHeader(should_fec_protect_ ? fec_group_number_ : 0, false, &header); |
- |
- MaybeAddPadding(); |
- |
- size_t max_plaintext_size = |
- framer_->GetMaxPlaintextSize(max_packet_length_); |
- DCHECK_GE(max_plaintext_size, packet_size_); |
- // ACK Frames will be truncated due to length only if they're the only frame |
- // in the packet, and if packet_size_ was set to max_plaintext_size. If |
- // truncation due to length occurred, then GetSerializedFrameLength will have |
- // returned all bytes free. |
- bool possibly_truncated_by_length = packet_size_ == max_plaintext_size && |
- queued_frames_.size() == 1 && |
- queued_frames_.back().type == ACK_FRAME; |
- char buffer[kMaxPacketSize]; |
- scoped_ptr<QuicPacket> packet; |
- // Use the packet_size_ instead of the buffer size to ensure smaller |
- // packet sizes are properly used. |
- scoped_ptr<char[]> large_buffer; |
- if (packet_size_ <= kMaxPacketSize) { |
- packet.reset( |
- framer_->BuildDataPacket(header, queued_frames_, buffer, packet_size_)); |
- } else { |
- large_buffer.reset(new char[packet_size_]); |
- packet.reset(framer_->BuildDataPacket(header, queued_frames_, |
- large_buffer.get(), packet_size_)); |
- } |
- LOG_IF(DFATAL, packet == nullptr) << "Failed to serialize " |
- << queued_frames_.size() << " frames."; |
- // Because of possible truncation, we can't be confident that our |
- // packet size calculation worked correctly. |
- if (!possibly_truncated_by_length) { |
- DCHECK_EQ(packet_size_, packet->length()); |
- } |
- // Immediately encrypt the packet, to ensure we don't encrypt the same packet |
- // sequence number multiple times. |
- QuicEncryptedPacket* encrypted = |
- framer_->EncryptPacket(encryption_level_, sequence_number_, *packet); |
- if (encrypted == nullptr) { |
- LOG(DFATAL) << "Failed to encrypt packet number " << sequence_number_; |
- SerializedPacket kNoPacket(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, |
- nullptr); |
- return kNoPacket; |
- } |
- |
- packet_size_ = 0; |
- queued_frames_.clear(); |
- return SerializedPacket(header.packet_sequence_number, |
- header.public_header.sequence_number_length, |
- encrypted, QuicFramer::GetPacketEntropyHash(header), |
- queued_retransmittable_frames_.release()); |
-} |
- |
-SerializedPacket QuicPacketCreator::SerializeFec() { |
- if (fec_group_.get() == nullptr || fec_group_->NumReceivedPackets() <= 0) { |
- LOG(DFATAL) << "SerializeFEC called but no group or zero packets in group."; |
- // TODO(jri): Make this a public method of framer? |
- SerializedPacket kNoPacket(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, |
- nullptr); |
- return kNoPacket; |
- } |
- DCHECK_EQ(0u, queued_frames_.size()); |
- QuicPacketHeader header; |
- FillPacketHeader(fec_group_number_, true, &header); |
- QuicFecData fec_data; |
- fec_data.fec_group = fec_group_->min_protected_packet(); |
- fec_data.redundancy = fec_group_->payload_parity(); |
- scoped_ptr<QuicPacket> packet(framer_->BuildFecPacket(header, fec_data)); |
- fec_group_.reset(nullptr); |
- packet_size_ = 0; |
- LOG_IF(DFATAL, packet == nullptr) |
- << "Failed to serialize fec packet for group:" << fec_data.fec_group; |
- DCHECK_GE(max_packet_length_, packet->length()); |
- // Immediately encrypt the packet, to ensure we don't encrypt the same packet |
- // sequence number multiple times. |
- QuicEncryptedPacket* encrypted = |
- framer_->EncryptPacket(encryption_level_, sequence_number_, *packet); |
- if (encrypted == nullptr) { |
- LOG(DFATAL) << "Failed to encrypt packet number " << sequence_number_; |
- SerializedPacket kNoPacket(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, |
- nullptr); |
- return kNoPacket; |
- } |
- SerializedPacket serialized( |
- header.packet_sequence_number, |
- header.public_header.sequence_number_length, encrypted, |
- QuicFramer::GetPacketEntropyHash(header), nullptr); |
- serialized.is_fec_packet = true; |
- return serialized; |
-} |
- |
-SerializedPacket QuicPacketCreator::SerializeConnectionClose( |
- QuicConnectionCloseFrame* close_frame) { |
- QuicFrames frames; |
- frames.push_back(QuicFrame(close_frame)); |
- return SerializeAllFrames(frames); |
-} |
- |
-QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket( |
- const QuicVersionVector& supported_versions) { |
- DCHECK(framer_->is_server()); |
- QuicPacketPublicHeader header; |
- header.connection_id = connection_id_; |
- header.reset_flag = false; |
- header.version_flag = true; |
- header.versions = supported_versions; |
- QuicEncryptedPacket* encrypted = |
- framer_->BuildVersionNegotiationPacket(header, supported_versions); |
- DCHECK(encrypted); |
- DCHECK_GE(max_packet_length_, encrypted->length()); |
- return encrypted; |
-} |
- |
-void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group, |
- bool fec_flag, |
- QuicPacketHeader* header) { |
- header->public_header.connection_id = connection_id_; |
- header->public_header.connection_id_length = connection_id_length_; |
- header->public_header.reset_flag = false; |
- header->public_header.version_flag = send_version_in_packet_; |
- header->fec_flag = fec_flag; |
- header->packet_sequence_number = ++sequence_number_; |
- header->public_header.sequence_number_length = sequence_number_length_; |
- header->entropy_flag = random_bool_source_->RandBool(); |
- header->is_in_fec_group = fec_group == 0 ? NOT_IN_FEC_GROUP : IN_FEC_GROUP; |
- header->fec_group = fec_group; |
-} |
- |
-bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) { |
- switch (frame.type) { |
- case ACK_FRAME: |
- case PADDING_FRAME: |
- case STOP_WAITING_FRAME: |
- return false; |
- default: |
- return true; |
- } |
-} |
- |
-bool QuicPacketCreator::AddFrame(const QuicFrame& frame, |
- bool save_retransmittable_frames) { |
- DVLOG(1) << "Adding frame: " << frame; |
- InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec(); |
- |
- size_t frame_len = framer_->GetSerializedFrameLength( |
- frame, BytesFree(), queued_frames_.empty(), true, is_in_fec_group, |
- sequence_number_length_); |
- if (frame_len == 0) { |
- return false; |
- } |
- DCHECK_LT(0u, packet_size_); |
- packet_size_ += ExpansionOnNewFrame() + frame_len; |
- |
- if (save_retransmittable_frames && ShouldRetransmit(frame)) { |
- if (queued_retransmittable_frames_.get() == nullptr) { |
- queued_retransmittable_frames_.reset(new RetransmittableFrames()); |
- } |
- if (frame.type == STREAM_FRAME) { |
- queued_frames_.push_back( |
- queued_retransmittable_frames_->AddStreamFrame(frame.stream_frame)); |
- } else { |
- queued_frames_.push_back( |
- queued_retransmittable_frames_->AddNonStreamFrame(frame)); |
- } |
- } else { |
- queued_frames_.push_back(frame); |
- } |
- return true; |
-} |
- |
-void QuicPacketCreator::MaybeAddPadding() { |
- if (BytesFree() == 0) { |
- // Don't pad full packets. |
- return; |
- } |
- |
- // Since ReserializeAllFrames does not populate queued_retransmittable_frames_ |
- // it's not sufficient to simply call |
- // queued_retransmittable_frames_->HasCryptoHandshake(). |
- // TODO(rch): we should really make ReserializeAllFrames not be a special |
- // case! |
- |
- // If any of the frames in the current packet are on the crypto stream |
- // then they contain handshake messagses, and we should pad them. |
- bool is_handshake = false; |
- for (const QuicFrame& frame : queued_frames_) { |
- if (frame.type == STREAM_FRAME && |
- frame.stream_frame->stream_id == kCryptoStreamId) { |
- is_handshake = true; |
- break; |
- } |
- } |
- if (!is_handshake) { |
- return; |
- } |
- |
- QuicPaddingFrame padding; |
- bool success = AddFrame(QuicFrame(&padding), false); |
- DCHECK(success); |
-} |
- |
-} // namespace net |