blob: 160222f27f4f500eb56b19f296d2e2ff14508a9c [file] [log] [blame]
// 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"
#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.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),
random_generator_(random_generator),
fully_pad_crypto_handshake_packets_(true) {}
QuicPacketGenerator::~QuicPacketGenerator() {}
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;
MaybeBundleAckOpportunistically();
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;
}
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.";
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.
if (packet_creator_.HasPendingRetransmittableFrames()) {
packet_creator_.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.
packet_creator_.Flush();
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);
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.
if (has_handshake && packet_creator_.HasPendingRetransmittableFrames()) {
packet_creator_.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 && !HasPendingFrames() &&
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 && !HasPendingFrames() &&
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) {
packet_creator_.Flush();
}
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::PacketFlusherAttached() const {
return flusher_attached_;
}
void QuicPacketGenerator::AttachPacketFlusher() {
flusher_attached_ = true;
if (!write_start_packet_number_.IsInitialized()) {
write_start_packet_number_ = packet_creator_.NextSendingPacketNumber();
}
}
void QuicPacketGenerator::Flush() {
packet_creator_.Flush();
SendRemainingPendingPadding();
flusher_attached_ = false;
if (GetQuicFlag(FLAGS_quic_export_server_num_packets_per_write_histogram)) {
if (!write_start_packet_number_.IsInitialized()) {
QUIC_BUG << "write_start_packet_number is not initialized";
return;
}
QUIC_SERVER_HISTOGRAM_COUNTS(
"quic_server_num_written_packets_per_write",
packet_creator_.NextSendingPacketNumber() - write_start_packet_number_,
1, 200, 50, "Number of QUIC packets written per write operation");
}
write_start_packet_number_.Clear();
}
void QuicPacketGenerator::FlushAllQueuedFrames() {
packet_creator_.Flush();
}
bool QuicPacketGenerator::HasPendingFrames() const {
return packet_creator_.HasPendingFrames();
}
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,
bool use_length_prefix,
const ParsedQuicVersionVector& supported_versions) {
return packet_creator_.SerializeVersionNegotiationPacket(
ietf_quic, use_length_prefix, 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 && !HasPendingFrames() &&
delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) {
packet_creator_.Flush();
}
}
bool QuicPacketGenerator::HasRetransmittableFrames() const {
return 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.";
MaybeBundleAckOpportunistically();
const QuicByteCount message_length = message.total_length();
if (message_length > GetCurrentLargestMessagePayload()) {
return MESSAGE_STATUS_TOO_LARGE;
}
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() {
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 (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