| // 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 <algorithm> |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "net/quic/crypto/crypto_protocol.h" |
| #include "net/quic/crypto/quic_random.h" |
| #include "net/quic/quic_bug_tracker.h" |
| #include "net/quic/quic_data_writer.h" |
| #include "net/quic/quic_flags.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::string; |
| using std::vector; |
| |
| namespace net { |
| |
| QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id, |
| QuicFramer* framer, |
| QuicRandom* random_generator, |
| QuicBufferAllocator* buffer_allocator, |
| DelegateInterface* delegate) |
| : delegate_(delegate), |
| debug_delegate_(nullptr), |
| framer_(framer), |
| random_bool_source_(random_generator), |
| buffer_allocator_(buffer_allocator), |
| send_version_in_packet_(framer->perspective() == Perspective::IS_CLIENT), |
| send_path_id_in_packet_(false), |
| next_packet_number_length_(PACKET_1BYTE_PACKET_NUMBER), |
| have_diversification_nonce_(false), |
| max_packet_length_(0), |
| connection_id_length_(PACKET_8BYTE_CONNECTION_ID), |
| packet_size_(0), |
| connection_id_(connection_id), |
| packet_(kDefaultPathId, |
| 0, |
| PACKET_1BYTE_PACKET_NUMBER, |
| nullptr, |
| 0, |
| 0, |
| false, |
| false) { |
| SetMaxPacketLength(kDefaultMaxPacketSize); |
| } |
| |
| QuicPacketCreator::~QuicPacketCreator() { |
| QuicUtils::DeleteFrames(&packet_.retransmittable_frames); |
| } |
| |
| void QuicPacketCreator::SetEncrypter(EncryptionLevel level, |
| QuicEncrypter* encrypter) { |
| framer_->SetEncrypter(level, encrypter); |
| max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); |
| } |
| |
| bool QuicPacketCreator::CanSetMaxPacketLength() const { |
| // |max_packet_length_| should not be changed mid-packet. |
| return queued_frames_.empty(); |
| } |
| |
| void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { |
| DCHECK(CanSetMaxPacketLength()); |
| |
| // Avoid recomputing |max_plaintext_size_| if the length does not actually |
| // change. |
| if (length == max_packet_length_) { |
| return; |
| } |
| |
| max_packet_length_ = length; |
| max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); |
| } |
| |
| void QuicPacketCreator::MaybeUpdatePacketNumberLength() { |
| DCHECK(!FLAGS_quic_simple_packet_number_length); |
| if (!queued_frames_.empty()) { |
| // Don't change creator state if there are frames queued. |
| return; |
| } |
| |
| // Update packet number length only on packet boundary. |
| packet_.packet_number_length = next_packet_number_length_; |
| } |
| |
| // 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::SetDiversificationNonce( |
| const DiversificationNonce nonce) { |
| DCHECK(!have_diversification_nonce_); |
| have_diversification_nonce_ = true; |
| memcpy(&diversification_nonce_, nonce, sizeof(diversification_nonce_)); |
| } |
| |
| void QuicPacketCreator::UpdatePacketNumberLength( |
| QuicPacketNumber least_packet_awaited_by_peer, |
| QuicPacketCount max_packets_in_flight) { |
| if (FLAGS_quic_simple_packet_number_length && !queued_frames_.empty()) { |
| // Don't change creator state if there are frames queued. |
| QUIC_BUG << "Called UpdatePacketNumberLength with " << queued_frames_.size() |
| << " queued_frames."; |
| return; |
| } |
| |
| DCHECK_LE(least_packet_awaited_by_peer, packet_.packet_number + 1); |
| const QuicPacketNumber current_delta = |
| packet_.packet_number + 1 - least_packet_awaited_by_peer; |
| const uint64_t delta = max(current_delta, max_packets_in_flight); |
| if (FLAGS_quic_simple_packet_number_length) { |
| packet_.packet_number_length = |
| QuicFramer::GetMinSequenceNumberLength(delta * 4); |
| } else { |
| next_packet_number_length_ = |
| QuicFramer::GetMinSequenceNumberLength(delta * 4); |
| } |
| } |
| |
| bool QuicPacketCreator::ConsumeData(QuicStreamId id, |
| QuicIOVector iov, |
| size_t iov_offset, |
| QuicStreamOffset offset, |
| bool fin, |
| bool needs_full_padding, |
| QuicFrame* frame) { |
| if (!HasRoomForStreamFrame(id, offset)) { |
| return false; |
| } |
| CreateStreamFrame(id, iov, iov_offset, offset, fin, frame); |
| // Explicitly disallow multi-packet CHLOs. |
| if (id == kCryptoStreamId && |
| frame->stream_frame->data_length >= sizeof(kCHLO) && |
| strncmp(frame->stream_frame->data_buffer, |
| reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0) { |
| DCHECK_EQ(static_cast<size_t>(0), iov_offset); |
| if (frame->stream_frame->data_length < iov.iov->iov_len) { |
| const string error_details = "Client hello won't fit in a single packet."; |
| QUIC_BUG << error_details << " Constructed stream frame length: " |
| << frame->stream_frame->data_length |
| << " CHLO length: " << iov.iov->iov_len; |
| delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details, |
| ConnectionCloseSource::FROM_SELF); |
| delete frame->stream_frame; |
| return false; |
| } |
| } |
| if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) { |
| // Fails if we try to write unencrypted stream data. |
| delete frame->stream_frame; |
| return false; |
| } |
| if (needs_full_padding) { |
| packet_.num_padding_bytes = -1; |
| } |
| return true; |
| } |
| |
| bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id, |
| QuicStreamOffset offset) { |
| return BytesFree() > QuicFramer::GetMinStreamFrameSize(id, offset, true); |
| } |
| |
| // static |
| size_t QuicPacketCreator::StreamFramePacketOverhead( |
| QuicVersion version, |
| QuicConnectionIdLength connection_id_length, |
| bool include_version, |
| bool include_path_id, |
| bool include_diversification_nonce, |
| QuicPacketNumberLength packet_number_length, |
| QuicStreamOffset offset) { |
| return GetPacketHeaderSize(version, connection_id_length, include_version, |
| include_path_id, include_diversification_nonce, |
| packet_number_length) + |
| // Assumes this is a stream with a single lone packet. |
| QuicFramer::GetMinStreamFrameSize(1u, offset, true); |
| } |
| |
| void QuicPacketCreator::CreateStreamFrame(QuicStreamId id, |
| QuicIOVector iov, |
| size_t iov_offset, |
| QuicStreamOffset offset, |
| bool fin, |
| QuicFrame* frame) { |
| DCHECK_GT(max_packet_length_, |
| StreamFramePacketOverhead(framer_->version(), connection_id_length_, |
| kIncludeVersion, kIncludePathId, |
| IncludeNonceInPublicHeader(), |
| PACKET_6BYTE_PACKET_NUMBER, offset)); |
| |
| if (!FLAGS_quic_simple_packet_number_length) { |
| MaybeUpdatePacketNumberLength(); |
| } |
| QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset)) |
| << "No room for Stream frame, BytesFree: " << BytesFree() |
| << " MinStreamFrameSize: " |
| << QuicFramer::GetMinStreamFrameSize(id, offset, true); |
| |
| if (iov_offset == iov.total_length) { |
| QUIC_BUG_IF(!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, StringPiece())); |
| return; |
| } |
| |
| const size_t data_size = iov.total_length - iov_offset; |
| size_t min_frame_size = QuicFramer::GetMinStreamFrameSize( |
| id, offset, /* last_frame_in_packet= */ true); |
| size_t bytes_consumed = min<size_t>(BytesFree() - min_frame_size, data_size); |
| |
| bool set_fin = fin && bytes_consumed == data_size; // Last frame. |
| UniqueStreamBuffer buffer = |
| NewStreamBuffer(buffer_allocator_, bytes_consumed); |
| CopyToBuffer(iov, iov_offset, bytes_consumed, buffer.get()); |
| *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed, |
| std::move(buffer))); |
| } |
| |
| // static |
| void QuicPacketCreator::CopyToBuffer(QuicIOVector iov, |
| size_t iov_offset, |
| size_t length, |
| char* buffer) { |
| int iovnum = 0; |
| while (iovnum < iov.iov_count && iov_offset >= iov.iov[iovnum].iov_len) { |
| iov_offset -= iov.iov[iovnum].iov_len; |
| ++iovnum; |
| } |
| DCHECK_LE(iovnum, iov.iov_count); |
| DCHECK_LE(iov_offset, iov.iov[iovnum].iov_len); |
| if (iovnum >= iov.iov_count || length == 0) { |
| return; |
| } |
| |
| // Unroll the first iteration that handles iov_offset. |
| const size_t iov_available = iov.iov[iovnum].iov_len - iov_offset; |
| size_t copy_len = min(length, iov_available); |
| |
| // Try to prefetch the next iov if there is at least one more after the |
| // current. Otherwise, it looks like an irregular access that the hardware |
| // prefetcher won't speculatively prefetch. Only prefetch one iov because |
| // generally, the iov_offset is not 0, input iov consists of 2K buffers and |
| // the output buffer is ~1.4K. |
| if (copy_len == iov_available && iovnum + 1 < iov.iov_count) { |
| // TODO(ckrasic) - this is unused without prefetch() |
| // char* next_base = static_cast<char*>(iov.iov[iovnum + 1].iov_base); |
| // char* next_base = static_cast<char*>(iov.iov[iovnum + 1].iov_base); |
| // Prefetch 2 cachelines worth of data to get the prefetcher started; leave |
| // it to the hardware prefetcher after that. |
| // TODO(ckrasic) - investigate what to do about prefetch directives. |
| // prefetch(next_base, PREFETCH_HINT_T0); |
| if (iov.iov[iovnum + 1].iov_len >= 64) { |
| // TODO(ckrasic) - investigate what to do about prefetch directives. |
| // prefetch(next_base + CACHELINE_SIZE, PREFETCH_HINT_T0); |
| } |
| } |
| |
| const char* src = static_cast<char*>(iov.iov[iovnum].iov_base) + iov_offset; |
| while (true) { |
| memcpy(buffer, src, copy_len); |
| length -= copy_len; |
| buffer += copy_len; |
| if (length == 0 || ++iovnum >= iov.iov_count) { |
| break; |
| } |
| src = static_cast<char*>(iov.iov[iovnum].iov_base); |
| copy_len = min(length, iov.iov[iovnum].iov_len); |
| } |
| QUIC_BUG_IF(length > 0) << "Failed to copy entire length to buffer."; |
| } |
| |
| void QuicPacketCreator::ReserializeAllFrames( |
| const PendingRetransmission& retransmission, |
| char* buffer, |
| size_t buffer_len) { |
| DCHECK(queued_frames_.empty()); |
| DCHECK_EQ(0, packet_.num_padding_bytes); |
| QUIC_BUG_IF(retransmission.retransmittable_frames.empty()) |
| << "Attempt to serialize empty packet"; |
| const QuicPacketNumberLength saved_length = packet_.packet_number_length; |
| const QuicPacketNumberLength saved_next_length = next_packet_number_length_; |
| const EncryptionLevel default_encryption_level = packet_.encryption_level; |
| |
| // Temporarily set the packet number length and change the encryption level. |
| packet_.packet_number_length = retransmission.packet_number_length; |
| if (!FLAGS_quic_simple_packet_number_length) { |
| next_packet_number_length_ = retransmission.packet_number_length; |
| } |
| packet_.num_padding_bytes = retransmission.num_padding_bytes; |
| // Only preserve the original encryption level if it's a handshake packet or |
| // if we haven't gone forward secure. |
| if (retransmission.has_crypto_handshake || |
| packet_.encryption_level != ENCRYPTION_FORWARD_SECURE) { |
| packet_.encryption_level = retransmission.encryption_level; |
| } |
| |
| // Serialize the packet and restore packet number length state. |
| for (const QuicFrame& frame : retransmission.retransmittable_frames) { |
| bool success = AddFrame(frame, false); |
| LOG_IF(DFATAL, !success) |
| << " Failed to add frame of type:" << frame.type |
| << " num_frames:" << retransmission.retransmittable_frames.size() |
| << " retransmission.packet_number_length:" |
| << retransmission.packet_number_length |
| << " packet_.packet_number_length:" << packet_.packet_number_length; |
| } |
| SerializePacket(buffer, buffer_len); |
| packet_.original_path_id = retransmission.path_id; |
| packet_.original_packet_number = retransmission.packet_number; |
| packet_.transmission_type = retransmission.transmission_type; |
| OnSerializedPacket(); |
| // Restore old values. |
| if (!FLAGS_quic_simple_packet_number_length) { |
| // OnSerializedPacket updates the packet_number_length, so it's incorrect to |
| // restore it here. |
| packet_.packet_number_length = saved_length; |
| next_packet_number_length_ = saved_next_length; |
| } |
| packet_.encryption_level = default_encryption_level; |
| } |
| |
| void QuicPacketCreator::Flush() { |
| if (!HasPendingFrames()) { |
| return; |
| } |
| |
| // TODO(rtenneti): Change the default 64 alignas value (used the default |
| // value from CACHELINE_SIZE). |
| ALIGNAS(64) char seralized_packet_buffer[kMaxPacketSize]; |
| SerializePacket(seralized_packet_buffer, kMaxPacketSize); |
| OnSerializedPacket(); |
| } |
| |
| void QuicPacketCreator::OnSerializedPacket() { |
| if (packet_.encrypted_buffer == nullptr) { |
| const string error_details = "Failed to SerializePacket."; |
| QUIC_BUG << error_details; |
| delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, |
| error_details, |
| ConnectionCloseSource::FROM_SELF); |
| return; |
| } |
| |
| delegate_->OnSerializedPacket(&packet_); |
| ClearPacket(); |
| // Maximum packet size may be only enacted while no packet is currently being |
| // constructed, so here we have a good opportunity to actually change it. |
| if (CanSetMaxPacketLength()) { |
| SetMaxPacketLength(max_packet_length_); |
| } |
| } |
| |
| void QuicPacketCreator::ClearPacket() { |
| packet_.has_ack = false; |
| packet_.has_stop_waiting = false; |
| packet_.has_crypto_handshake = NOT_HANDSHAKE; |
| packet_.num_padding_bytes = 0; |
| packet_.original_path_id = kInvalidPathId; |
| packet_.original_packet_number = 0; |
| packet_.transmission_type = NOT_RETRANSMISSION; |
| packet_.encrypted_buffer = nullptr; |
| packet_.encrypted_length = 0; |
| DCHECK(packet_.retransmittable_frames.empty()); |
| packet_.listeners.clear(); |
| } |
| |
| void QuicPacketCreator::CreateAndSerializeStreamFrame( |
| QuicStreamId id, |
| const QuicIOVector& iov, |
| QuicStreamOffset iov_offset, |
| QuicStreamOffset stream_offset, |
| bool fin, |
| QuicAckListenerInterface* listener, |
| char* encrypted_buffer, |
| size_t encrypted_buffer_len, |
| size_t* num_bytes_consumed) { |
| DCHECK(queued_frames_.empty()); |
| // Write out the packet header |
| QuicPacketHeader header; |
| FillPacketHeader(&header); |
| QuicDataWriter writer(kMaxPacketSize, encrypted_buffer); |
| if (!framer_->AppendPacketHeader(header, &writer)) { |
| QUIC_BUG << "AppendPacketHeader failed"; |
| return; |
| } |
| |
| // Create a Stream frame with the remaining space. |
| QUIC_BUG_IF(iov_offset == iov.total_length && !fin) |
| << "Creating a stream frame with no data or fin."; |
| const size_t remaining_data_size = iov.total_length - iov_offset; |
| const size_t min_frame_size = QuicFramer::GetMinStreamFrameSize( |
| id, stream_offset, /* last_frame_in_packet= */ true); |
| const size_t available_size = |
| max_plaintext_size_ - writer.length() - min_frame_size; |
| const size_t bytes_consumed = |
| min<size_t>(available_size, remaining_data_size); |
| |
| const bool set_fin = fin && (bytes_consumed == remaining_data_size); |
| UniqueStreamBuffer stream_buffer = |
| NewStreamBuffer(buffer_allocator_, bytes_consumed); |
| CopyToBuffer(iov, iov_offset, bytes_consumed, stream_buffer.get()); |
| std::unique_ptr<QuicStreamFrame> frame(new QuicStreamFrame( |
| id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer))); |
| |
| // TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized |
| // into one method that takes a QuicStreamFrame, if warranted. |
| if (!framer_->AppendTypeByte(QuicFrame(frame.get()), |
| /* no stream frame length */ true, &writer)) { |
| QUIC_BUG << "AppendTypeByte failed"; |
| return; |
| } |
| if (!framer_->AppendStreamFrame(*frame, /* no stream frame length */ true, |
| &writer)) { |
| QUIC_BUG << "AppendStreamFrame failed"; |
| return; |
| } |
| |
| size_t encrypted_length = framer_->EncryptInPlace( |
| packet_.encryption_level, packet_.path_id, packet_.packet_number, |
| GetStartOfEncryptedData(framer_->version(), header), writer.length(), |
| encrypted_buffer_len, encrypted_buffer); |
| if (encrypted_length == 0) { |
| QUIC_BUG << "Failed to encrypt packet number " << header.packet_number; |
| return; |
| } |
| // TODO(ianswett): Optimize the storage so RetransmitableFrames can be |
| // unioned with a QuicStreamFrame and a UniqueStreamBuffer. |
| *num_bytes_consumed = bytes_consumed; |
| packet_size_ = 0; |
| packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header); |
| packet_.encrypted_buffer = encrypted_buffer; |
| packet_.encrypted_length = encrypted_length; |
| if (listener != nullptr) { |
| packet_.listeners.emplace_back(listener, bytes_consumed); |
| } |
| packet_.retransmittable_frames.push_back(QuicFrame(frame.release())); |
| OnSerializedPacket(); |
| } |
| |
| bool QuicPacketCreator::HasPendingFrames() const { |
| return !queued_frames_.empty(); |
| } |
| |
| bool QuicPacketCreator::HasPendingRetransmittableFrames() const { |
| return !packet_.retransmittable_frames.empty(); |
| } |
| |
| size_t QuicPacketCreator::ExpansionOnNewFrame() const { |
| // 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() { |
| DCHECK_GE(max_plaintext_size_, PacketSize()); |
| return max_plaintext_size_ - |
| min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame()); |
| } |
| |
| size_t QuicPacketCreator::PacketSize() { |
| if (!queued_frames_.empty()) { |
| return packet_size_; |
| } |
| // Update packet number length on packet boundary. |
| if (!FLAGS_quic_simple_packet_number_length) { |
| packet_.packet_number_length = next_packet_number_length_; |
| } |
| packet_size_ = GetPacketHeaderSize( |
| framer_->version(), connection_id_length_, send_version_in_packet_, |
| send_path_id_in_packet_, IncludeNonceInPublicHeader(), |
| packet_.packet_number_length); |
| return packet_size_; |
| } |
| |
| bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) { |
| return AddFrame(frame, /*save_retransmittable_frames=*/true); |
| } |
| |
| bool QuicPacketCreator::AddPaddedSavedFrame(const QuicFrame& frame) { |
| if (AddFrame(frame, /*save_retransmittable_frames=*/true)) { |
| packet_.num_padding_bytes = -1; |
| return true; |
| } |
| return false; |
| } |
| |
| void QuicPacketCreator::AddAckListener(QuicAckListenerInterface* listener, |
| QuicPacketLength length) { |
| DCHECK(!queued_frames_.empty()); |
| packet_.listeners.emplace_back(listener, length); |
| } |
| |
| void QuicPacketCreator::SerializePacket(char* encrypted_buffer, |
| size_t encrypted_buffer_len) { |
| DCHECK_LT(0u, encrypted_buffer_len); |
| QUIC_BUG_IF(queued_frames_.empty()) << "Attempt to serialize empty packet"; |
| QuicPacketHeader header; |
| // FillPacketHeader increments packet_number_. |
| FillPacketHeader(&header); |
| |
| MaybeAddPadding(); |
| |
| DCHECK_GE(max_plaintext_size_, packet_size_); |
| // Use the packet_size_ instead of the buffer size to ensure smaller |
| // packet sizes are properly used. |
| size_t length = framer_->BuildDataPacket(header, queued_frames_, |
| encrypted_buffer, packet_size_); |
| if (length == 0) { |
| QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames."; |
| return; |
| } |
| |
| // 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; |
| // 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_, length); |
| } |
| const size_t encrypted_length = framer_->EncryptInPlace( |
| packet_.encryption_level, packet_.path_id, packet_.packet_number, |
| GetStartOfEncryptedData(framer_->version(), header), length, |
| encrypted_buffer_len, encrypted_buffer); |
| if (encrypted_length == 0) { |
| QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number; |
| return; |
| } |
| |
| packet_size_ = 0; |
| queued_frames_.clear(); |
| packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header); |
| packet_.encrypted_buffer = encrypted_buffer; |
| packet_.encrypted_length = encrypted_length; |
| } |
| |
| QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket( |
| const QuicVersionVector& supported_versions) { |
| DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); |
| QuicEncryptedPacket* encrypted = QuicFramer::BuildVersionNegotiationPacket( |
| connection_id_, supported_versions); |
| DCHECK(encrypted); |
| DCHECK_GE(max_packet_length_, encrypted->length()); |
| return encrypted; |
| } |
| |
| // TODO(jri): Make this a public method of framer? |
| SerializedPacket QuicPacketCreator::NoPacket() { |
| return SerializedPacket(kInvalidPathId, 0, PACKET_1BYTE_PACKET_NUMBER, |
| nullptr, 0, 0, false, false); |
| } |
| |
| void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { |
| header->public_header.connection_id = connection_id_; |
| header->public_header.connection_id_length = connection_id_length_; |
| header->public_header.multipath_flag = send_path_id_in_packet_; |
| header->public_header.reset_flag = false; |
| header->public_header.version_flag = send_version_in_packet_; |
| if (IncludeNonceInPublicHeader()) { |
| DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); |
| header->public_header.nonce = &diversification_nonce_; |
| } else { |
| header->public_header.nonce = nullptr; |
| } |
| header->path_id = packet_.path_id; |
| header->packet_number = ++packet_.packet_number; |
| header->public_header.packet_number_length = packet_.packet_number_length; |
| header->entropy_flag = random_bool_source_.RandBool(); |
| } |
| |
| bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) { |
| switch (frame.type) { |
| case ACK_FRAME: |
| case PADDING_FRAME: |
| case STOP_WAITING_FRAME: |
| case MTU_DISCOVERY_FRAME: |
| return false; |
| default: |
| return true; |
| } |
| } |
| |
| bool QuicPacketCreator::AddFrame(const QuicFrame& frame, |
| bool save_retransmittable_frames) { |
| DVLOG(1) << "Adding frame: " << frame; |
| if (FLAGS_quic_never_write_unencrypted_data && frame.type == STREAM_FRAME && |
| frame.stream_frame->stream_id != kCryptoStreamId && |
| packet_.encryption_level == ENCRYPTION_NONE) { |
| const string error_details = "Cannot send stream data without encryption."; |
| QUIC_BUG << error_details; |
| delegate_->OnUnrecoverableError( |
| QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details, |
| ConnectionCloseSource::FROM_SELF); |
| return false; |
| } |
| if (!FLAGS_quic_simple_packet_number_length) { |
| MaybeUpdatePacketNumberLength(); |
| } |
| size_t frame_len = framer_->GetSerializedFrameLength( |
| frame, BytesFree(), queued_frames_.empty(), true, |
| packet_.packet_number_length); |
| if (frame_len == 0) { |
| // Current open packet is full. |
| Flush(); |
| return false; |
| } |
| DCHECK_LT(0u, packet_size_); |
| packet_size_ += ExpansionOnNewFrame() + frame_len; |
| |
| if (save_retransmittable_frames && ShouldRetransmit(frame)) { |
| if (packet_.retransmittable_frames.empty()) { |
| packet_.retransmittable_frames.reserve(2); |
| } |
| packet_.retransmittable_frames.push_back(frame); |
| queued_frames_.push_back(frame); |
| if (frame.type == STREAM_FRAME && |
| frame.stream_frame->stream_id == kCryptoStreamId) { |
| packet_.has_crypto_handshake = IS_HANDSHAKE; |
| } |
| } else { |
| queued_frames_.push_back(frame); |
| } |
| |
| if (frame.type == ACK_FRAME) { |
| packet_.has_ack = true; |
| } |
| if (frame.type == STOP_WAITING_FRAME) { |
| packet_.has_stop_waiting = true; |
| } |
| if (debug_delegate_ != nullptr) { |
| debug_delegate_->OnFrameAddedToPacket(frame); |
| } |
| |
| return true; |
| } |
| |
| void QuicPacketCreator::MaybeAddPadding() { |
| if (packet_.num_padding_bytes == 0) { |
| return; |
| } |
| |
| if (BytesFree() == 0) { |
| // Don't pad full packets. |
| return; |
| } |
| |
| bool success = |
| AddFrame(QuicFrame(QuicPaddingFrame(packet_.num_padding_bytes)), false); |
| DCHECK(success); |
| } |
| |
| void QuicPacketCreator::SetCurrentPath( |
| QuicPathId path_id, |
| QuicPacketNumber least_packet_awaited_by_peer, |
| QuicPacketCount max_packets_in_flight) { |
| if (packet_.path_id == path_id) { |
| return; |
| } |
| |
| if (HasPendingFrames()) { |
| QUIC_BUG << "Unable to change paths when a packet is under construction."; |
| return; |
| } |
| // Save current packet number and load switching path's packet number. |
| multipath_packet_number_[packet_.path_id] = packet_.packet_number; |
| std::unordered_map<QuicPathId, QuicPacketNumber>::iterator it = |
| multipath_packet_number_.find(path_id); |
| // If path_id is not in the map, it's a new path. Set packet_number to 0. |
| packet_.packet_number = it == multipath_packet_number_.end() ? 0 : it->second; |
| packet_.path_id = path_id; |
| DCHECK(packet_.path_id != kInvalidPathId); |
| // Send path in packet if current path is not the default path. |
| send_path_id_in_packet_ = packet_.path_id != kDefaultPathId ? true : false; |
| // Switching path needs to update packet number length. |
| UpdatePacketNumberLength(least_packet_awaited_by_peer, max_packets_in_flight); |
| } |
| |
| bool QuicPacketCreator::IncludeNonceInPublicHeader() { |
| return have_diversification_nonce_ && |
| packet_.encryption_level == ENCRYPTION_INITIAL; |
| } |
| |
| QuicPacketCreator::QuicRandomBoolSource::QuicRandomBoolSource( |
| QuicRandom* random) |
| : random_(random), bit_bucket_(0), bit_mask_(0) {} |
| |
| QuicPacketCreator::QuicRandomBoolSource::~QuicRandomBoolSource() {} |
| |
| bool QuicPacketCreator::QuicRandomBoolSource::RandBool() { |
| if (bit_mask_ == 0) { |
| bit_bucket_ = random_->RandUint64(); |
| bit_mask_ = 1; |
| } |
| bool result = ((bit_bucket_ & bit_mask_) != 0); |
| bit_mask_ <<= 1; |
| return result; |
| } |
| |
| } // namespace net |