blob: f98c31b177ec41e21d335bc0b3a7eabdfed387f0 [file] [log] [blame] [edit]
// 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/third_party/quiche/src/quic/core/quic_packet_generator.h"
#include <cstdint>
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
namespace quic {
QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId server_connection_id,
QuicFramer* framer,
QuicRandom* random_generator,
DelegateInterface* delegate)
: delegate_(delegate),
packet_creator_(server_connection_id, framer, random_generator, delegate),
next_transmission_type_(NOT_RETRANSMISSION),
flusher_attached_(false),
should_send_ack_(false),
should_send_stop_waiting_(false),
random_generator_(random_generator),
fully_pad_crypto_handshake_packets_(true),
deprecate_ack_bundling_mode_(
GetQuicReloadableFlag(quic_deprecate_ack_bundling_mode)),
deprecate_queued_control_frames_(
deprecate_ack_bundling_mode_ &&
GetQuicReloadableFlag(quic_deprecate_queued_control_frames)) {}
QuicPacketGenerator::~QuicPacketGenerator() {
DeleteFrames(&queued_control_frames_);
}
void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) {
DCHECK(!deprecate_ack_bundling_mode_);
if (packet_creator_.has_ack()) {
// Ack already queued, nothing to do.
return;
}
if (also_send_stop_waiting && packet_creator_.has_stop_waiting()) {
QUIC_BUG << "Should only ever be one pending stop waiting frame.";
return;
}
should_send_ack_ = true;
should_send_stop_waiting_ = also_send_stop_waiting;
SendQueuedFrames(/*flush=*/false);
}
bool QuicPacketGenerator::ConsumeRetransmittableControlFrame(
const QuicFrame& frame) {
QUIC_BUG_IF(IsControlFrame(frame.type) && !GetControlFrameId(frame))
<< "Adding a control frame with no control frame id: " << frame;
DCHECK(QuicUtils::IsRetransmittableFrame(frame.type)) << frame;
if (deprecate_ack_bundling_mode_) {
MaybeBundleAckOpportunistically();
}
if (deprecate_queued_control_frames_) {
QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_queued_control_frames);
if (packet_creator_.HasPendingFrames()) {
if (packet_creator_.AddSavedFrame(frame, next_transmission_type_)) {
// There is pending frames and current frame fits.
return true;
}
}
DCHECK(!packet_creator_.HasPendingFrames());
if (frame.type != PING_FRAME && frame.type != CONNECTION_CLOSE_FRAME &&
!delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
// Do not check congestion window for ping or connection close frames.
return false;
}
const bool success =
packet_creator_.AddSavedFrame(frame, next_transmission_type_);
DCHECK(success);
return success;
}
queued_control_frames_.push_back(frame);
SendQueuedFrames(/*flush=*/false);
return true;
}
size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level,
size_t write_length,
QuicStreamOffset offset) {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to write crypto data.";
if (deprecate_ack_bundling_mode_) {
MaybeBundleAckOpportunistically();
}
// To make reasoning about crypto frames easier, we don't combine them with
// other retransmittable frames in a single packet.
// TODO(nharper): Once we have separate packet number spaces, everything
// should be driven by encryption level, and we should stop flushing in this
// spot.
const bool flush = packet_creator_.HasPendingRetransmittableFrames();
SendQueuedFrames(flush);
size_t total_bytes_consumed = 0;
while (total_bytes_consumed < write_length) {
QuicFrame frame;
if (!packet_creator_.ConsumeCryptoData(
level, write_length - total_bytes_consumed,
offset + total_bytes_consumed, fully_pad_crypto_handshake_packets_,
next_transmission_type_, &frame)) {
// The only pending data in the packet is non-retransmittable frames. I'm
// assuming here that they won't occupy so much of the packet that a
// CRYPTO frame won't fit.
QUIC_BUG << "Failed to ConsumeCryptoData at level " << level;
return 0;
}
total_bytes_consumed += frame.crypto_frame->data_length;
// TODO(ianswett): Move to having the creator flush itself when it's full.
packet_creator_.Flush();
}
// Don't allow the handshake to be bundled with other retransmittable frames.
SendQueuedFrames(/*flush=*/true);
return total_bytes_consumed;
}
QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
size_t write_length,
QuicStreamOffset offset,
StreamSendingState state) {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to write stream data.";
bool has_handshake =
QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id);
if (deprecate_ack_bundling_mode_) {
MaybeBundleAckOpportunistically();
}
bool fin = state != NO_FIN;
QUIC_BUG_IF(has_handshake && fin)
<< "Handshake packets should never send a fin";
// To make reasoning about crypto frames easier, we don't combine them with
// other retransmittable frames in a single packet.
const bool flush =
has_handshake && packet_creator_.HasPendingRetransmittableFrames();
SendQueuedFrames(flush);
size_t total_bytes_consumed = 0;
bool fin_consumed = false;
if (!packet_creator_.HasRoomForStreamFrame(id, offset, write_length)) {
packet_creator_.Flush();
}
if (!fin && (write_length == 0)) {
QUIC_BUG << "Attempt to consume empty data without FIN.";
return QuicConsumedData(0, false);
}
// We determine if we can enter the fast path before executing
// the slow path loop.
bool run_fast_path =
!has_handshake && state != FIN_AND_PADDING && !HasQueuedFrames() &&
write_length - total_bytes_consumed > kMaxOutgoingPacketSize;
while (!run_fast_path && delegate_->ShouldGeneratePacket(
HAS_RETRANSMITTABLE_DATA,
has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
QuicFrame frame;
bool needs_full_padding =
has_handshake && fully_pad_crypto_handshake_packets_;
if (!packet_creator_.ConsumeData(id, write_length - total_bytes_consumed,
offset + total_bytes_consumed, fin,
needs_full_padding,
next_transmission_type_, &frame)) {
// The creator is always flushed if there's not enough room for a new
// stream frame before ConsumeData, so ConsumeData should always succeed.
QUIC_BUG << "Failed to ConsumeData, stream:" << id;
return QuicConsumedData(0, false);
}
// A stream frame is created and added.
size_t bytes_consumed = frame.stream_frame.data_length;
total_bytes_consumed += bytes_consumed;
fin_consumed = fin && total_bytes_consumed == write_length;
if (fin_consumed && state == FIN_AND_PADDING) {
AddRandomPadding();
}
DCHECK(total_bytes_consumed == write_length ||
(bytes_consumed > 0 && packet_creator_.HasPendingFrames()));
if (total_bytes_consumed == write_length) {
// We're done writing the data. Exit the loop.
// We don't make this a precondition because we could have 0 bytes of data
// if we're simply writing a fin.
break;
}
// TODO(ianswett): Move to having the creator flush itself when it's full.
packet_creator_.Flush();
run_fast_path =
!has_handshake && state != FIN_AND_PADDING && !HasQueuedFrames() &&
write_length - total_bytes_consumed > kMaxOutgoingPacketSize;
}
if (run_fast_path) {
return ConsumeDataFastPath(id, write_length, offset, state != NO_FIN,
total_bytes_consumed);
}
// Don't allow the handshake to be bundled with other retransmittable frames.
if (has_handshake) {
SendQueuedFrames(/*flush=*/true);
}
return QuicConsumedData(total_bytes_consumed, fin_consumed);
}
QuicConsumedData QuicPacketGenerator::ConsumeDataFastPath(
QuicStreamId id,
size_t write_length,
QuicStreamOffset offset,
bool fin,
size_t total_bytes_consumed) {
DCHECK(!QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id));
while (total_bytes_consumed < write_length &&
delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
// Serialize and encrypt the packet.
size_t bytes_consumed = 0;
packet_creator_.CreateAndSerializeStreamFrame(
id, write_length, total_bytes_consumed, offset + total_bytes_consumed,
fin, next_transmission_type_, &bytes_consumed);
total_bytes_consumed += bytes_consumed;
}
return QuicConsumedData(total_bytes_consumed,
fin && (total_bytes_consumed == write_length));
}
void QuicPacketGenerator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) {
// MTU discovery frames must be sent by themselves.
if (!packet_creator_.CanSetMaxPacketLength()) {
QUIC_BUG << "MTU discovery packets should only be sent when no other "
<< "frames needs to be sent.";
return;
}
const QuicByteCount current_mtu = GetCurrentMaxPacketLength();
// The MTU discovery frame is allocated on the stack, since it is going to be
// serialized within this function.
QuicMtuDiscoveryFrame mtu_discovery_frame;
QuicFrame frame(mtu_discovery_frame);
// Send the probe packet with the new length.
SetMaxPacketLength(target_mtu);
const bool success =
packet_creator_.AddPaddedSavedFrame(frame, next_transmission_type_);
packet_creator_.Flush();
// The only reason AddFrame can fail is that the packet is too full to fit in
// a ping. This is not possible for any sane MTU.
DCHECK(success);
// Reset the packet length back.
SetMaxPacketLength(current_mtu);
}
bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
DCHECK(HasPendingFrames() || packet_creator_.pending_padding_bytes() > 0);
HasRetransmittableData retransmittable =
(should_send_ack_ || should_send_stop_waiting_ ||
packet_creator_.pending_padding_bytes() > 0)
? NO_RETRANSMITTABLE_DATA
: HAS_RETRANSMITTABLE_DATA;
if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
DCHECK(!queued_control_frames_.empty()); // These are retransmittable.
}
return delegate_->ShouldGeneratePacket(retransmittable, NOT_HANDSHAKE);
}
void QuicPacketGenerator::SendQueuedFrames(bool flush) {
// Only add pending frames if we are SURE we can then send the whole packet.
while (HasPendingFrames() &&
(flush || CanSendWithNextPendingFrameAddition())) {
bool first_frame = packet_creator_.CanSetMaxPacketLength();
if (!AddNextPendingFrame() && first_frame) {
// A single frame cannot fit into the packet, tear down the connection.
QUIC_BUG << "A single frame cannot fit into packet."
<< " should_send_ack: " << should_send_ack_
<< " should_send_stop_waiting: " << should_send_stop_waiting_
<< " number of queued_control_frames: "
<< queued_control_frames_.size();
if (!queued_control_frames_.empty()) {
QUIC_LOG(INFO) << queued_control_frames_[0];
}
delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
"Single frame cannot fit into a packet",
ConnectionCloseSource::FROM_SELF);
return;
}
}
if (flush) {
packet_creator_.Flush();
}
}
bool QuicPacketGenerator::PacketFlusherAttached() const {
return flusher_attached_;
}
void QuicPacketGenerator::AttachPacketFlusher() {
flusher_attached_ = true;
}
void QuicPacketGenerator::Flush() {
SendQueuedFrames(/*flush=*/false);
packet_creator_.Flush();
SendRemainingPendingPadding();
flusher_attached_ = false;
}
void QuicPacketGenerator::FlushAllQueuedFrames() {
SendQueuedFrames(/*flush=*/true);
}
bool QuicPacketGenerator::HasQueuedFrames() const {
return packet_creator_.HasPendingFrames() || HasPendingFrames();
}
bool QuicPacketGenerator::IsPendingPacketEmpty() const {
return !packet_creator_.HasPendingFrames();
}
bool QuicPacketGenerator::HasPendingFrames() const {
return should_send_ack_ || should_send_stop_waiting_ ||
!queued_control_frames_.empty();
}
bool QuicPacketGenerator::AddNextPendingFrame() {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to write control frames.";
if (should_send_ack_) {
should_send_ack_ = !packet_creator_.AddSavedFrame(
delegate_->GetUpdatedAckFrame(), next_transmission_type_);
return !should_send_ack_;
}
if (should_send_stop_waiting_) {
delegate_->PopulateStopWaitingFrame(&pending_stop_waiting_frame_);
// If we can't this add the frame now, then we still need to do so later.
should_send_stop_waiting_ = !packet_creator_.AddSavedFrame(
QuicFrame(pending_stop_waiting_frame_), next_transmission_type_);
// Return success if we have cleared out this flag (i.e., added the frame).
// If we still need to send, then the frame is full, and we have failed.
return !should_send_stop_waiting_;
}
QUIC_BUG_IF(queued_control_frames_.empty())
<< "AddNextPendingFrame called with no queued control frames.";
if (!packet_creator_.AddSavedFrame(queued_control_frames_.back(),
next_transmission_type_)) {
// Packet was full.
return false;
}
queued_control_frames_.pop_back();
return true;
}
void QuicPacketGenerator::StopSendingVersion() {
packet_creator_.StopSendingVersion();
}
void QuicPacketGenerator::SetDiversificationNonce(
const DiversificationNonce& nonce) {
packet_creator_.SetDiversificationNonce(nonce);
}
QuicPacketNumber QuicPacketGenerator::packet_number() const {
return packet_creator_.packet_number();
}
QuicByteCount QuicPacketGenerator::GetCurrentMaxPacketLength() const {
return packet_creator_.max_packet_length();
}
void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) {
DCHECK(packet_creator_.CanSetMaxPacketLength());
packet_creator_.SetMaxPacketLength(length);
}
std::unique_ptr<QuicEncryptedPacket>
QuicPacketGenerator::SerializeVersionNegotiationPacket(
bool ietf_quic,
const ParsedQuicVersionVector& supported_versions) {
return packet_creator_.SerializeVersionNegotiationPacket(ietf_quic,
supported_versions);
}
OwningSerializedPacketPointer
QuicPacketGenerator::SerializeConnectivityProbingPacket() {
return packet_creator_.SerializeConnectivityProbingPacket();
}
OwningSerializedPacketPointer
QuicPacketGenerator::SerializePathChallengeConnectivityProbingPacket(
QuicPathFrameBuffer* payload) {
return packet_creator_.SerializePathChallengeConnectivityProbingPacket(
payload);
}
OwningSerializedPacketPointer
QuicPacketGenerator::SerializePathResponseConnectivityProbingPacket(
const QuicDeque<QuicPathFrameBuffer>& payloads,
const bool is_padded) {
return packet_creator_.SerializePathResponseConnectivityProbingPacket(
payloads, is_padded);
}
void QuicPacketGenerator::ReserializeAllFrames(
const QuicPendingRetransmission& retransmission,
char* buffer,
size_t buffer_len) {
packet_creator_.ReserializeAllFrames(retransmission, buffer, buffer_len);
}
void QuicPacketGenerator::UpdatePacketNumberLength(
QuicPacketNumber least_packet_awaited_by_peer,
QuicPacketCount max_packets_in_flight) {
return packet_creator_.UpdatePacketNumberLength(least_packet_awaited_by_peer,
max_packets_in_flight);
}
void QuicPacketGenerator::SetServerConnectionIdLength(uint32_t length) {
if (length == 0) {
packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_ABSENT);
} else {
packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_PRESENT);
}
}
void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) {
packet_creator_.set_encryption_level(level);
}
void QuicPacketGenerator::SetEncrypter(
EncryptionLevel level,
std::unique_ptr<QuicEncrypter> encrypter) {
packet_creator_.SetEncrypter(level, std::move(encrypter));
}
void QuicPacketGenerator::AddRandomPadding() {
packet_creator_.AddPendingPadding(
random_generator_->RandUint64() % kMaxNumRandomPaddingBytes + 1);
}
void QuicPacketGenerator::SendRemainingPendingPadding() {
while (packet_creator_.pending_padding_bytes() > 0 && !HasQueuedFrames() &&
CanSendWithNextPendingFrameAddition()) {
packet_creator_.Flush();
}
}
bool QuicPacketGenerator::HasRetransmittableFrames() const {
return !queued_control_frames_.empty() ||
packet_creator_.HasPendingRetransmittableFrames();
}
bool QuicPacketGenerator::HasPendingStreamFramesOfStream(
QuicStreamId id) const {
return packet_creator_.HasPendingStreamFramesOfStream(id);
}
void QuicPacketGenerator::SetTransmissionType(TransmissionType type) {
packet_creator_.SetTransmissionType(type);
if (packet_creator_.can_set_transmission_type()) {
next_transmission_type_ = type;
}
}
void QuicPacketGenerator::SetRetryToken(QuicStringPiece retry_token) {
packet_creator_.SetRetryToken(retry_token);
}
void QuicPacketGenerator::SetCanSetTransmissionType(
bool can_set_transmission_type) {
packet_creator_.set_can_set_transmission_type(can_set_transmission_type);
}
MessageStatus QuicPacketGenerator::AddMessageFrame(QuicMessageId message_id,
QuicMemSliceSpan message) {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to add message frame.";
if (deprecate_ack_bundling_mode_) {
MaybeBundleAckOpportunistically();
}
const QuicByteCount message_length = message.total_length();
if (message_length > GetCurrentLargestMessagePayload()) {
return MESSAGE_STATUS_TOO_LARGE;
}
SendQueuedFrames(/*flush=*/false);
if (!packet_creator_.HasRoomForMessageFrame(message_length)) {
packet_creator_.Flush();
}
QuicMessageFrame* frame = new QuicMessageFrame(message_id, message);
const bool success =
packet_creator_.AddSavedFrame(QuicFrame(frame), next_transmission_type_);
if (!success) {
QUIC_BUG << "Failed to send message " << message_id;
delete frame;
return MESSAGE_STATUS_INTERNAL_ERROR;
}
return MESSAGE_STATUS_SUCCESS;
}
void QuicPacketGenerator::MaybeBundleAckOpportunistically() {
DCHECK(deprecate_ack_bundling_mode_);
if (packet_creator_.has_ack()) {
// Ack already queued, nothing to do.
return;
}
if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
return;
}
const bool flushed =
FlushAckFrame(delegate_->MaybeBundleAckOpportunistically());
DCHECK(flushed);
}
bool QuicPacketGenerator::FlushAckFrame(const QuicFrames& frames) {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to send ACK frame.";
for (const auto& frame : frames) {
DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME);
if (frame.type == ACK_FRAME && frame.ack_frame->packets.Empty()) {
continue;
}
if (packet_creator_.HasPendingFrames()) {
if (packet_creator_.AddSavedFrame(frame, next_transmission_type_)) {
// There is pending frames and current frame fits.
continue;
}
}
DCHECK(!packet_creator_.HasPendingFrames());
// There is no pending frames, consult the delegate whether a packet can be
// generated.
if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
return false;
}
const bool success =
packet_creator_.AddSavedFrame(frame, next_transmission_type_);
QUIC_BUG_IF(!success) << "Failed to flush " << frame;
}
return true;
}
QuicPacketLength QuicPacketGenerator::GetCurrentLargestMessagePayload() const {
return packet_creator_.GetCurrentLargestMessagePayload();
}
QuicPacketLength QuicPacketGenerator::GetGuaranteedLargestMessagePayload()
const {
return packet_creator_.GetGuaranteedLargestMessagePayload();
}
void QuicPacketGenerator::SetServerConnectionId(
QuicConnectionId server_connection_id) {
packet_creator_.SetServerConnectionId(server_connection_id);
}
void QuicPacketGenerator::SetClientConnectionId(
QuicConnectionId client_connection_id) {
packet_creator_.SetClientConnectionId(client_connection_id);
}
} // namespace quic