gfe-relnote: Combine QuicPacketGenerator and QuicPacketCreator. Protected by gfe2_reloadable_flag_quic_combine_generator_and_creator. PiperOrigin-RevId: 269432631 Change-Id: I8270ff623e168db2f780df1da26aad100c05b1b5
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc index 1f985dc..e863814 100644 --- a/quic/core/quic_packet_creator.cc +++ b/quic/core/quic_packet_creator.cc
@@ -22,6 +22,7 @@ #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_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -84,8 +85,16 @@ false), pending_padding_bytes_(0), needs_full_padding_(false), - can_set_transmission_type_(false) { + can_set_transmission_type_(false), + next_transmission_type_(NOT_RETRANSMISSION), + flusher_attached_(false), + fully_pad_crypto_handshake_packets_(true), + combine_generator_and_creator_( + GetQuicReloadableFlag(quic_combine_generator_and_creator)) { SetMaxPacketLength(kDefaultMaxPacketSize); + if (combine_generator_and_creator_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_combine_generator_and_creator); + } } QuicPacketCreator::~QuicPacketCreator() { @@ -886,6 +895,330 @@ retry_token_ = std::string(retry_token); } +bool QuicPacketCreator::ConsumeRetransmittableControlFrame( + const QuicFrame& frame) { + DCHECK(combine_generator_and_creator_); + 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 (HasPendingFrames()) { + if (AddSavedFrame(frame, next_transmission_type_)) { + // There is pending frames and current frame fits. + return true; + } + } + DCHECK(!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 = AddSavedFrame(frame, next_transmission_type_); + DCHECK(success); + return success; +} + +QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state) { + DCHECK(combine_generator_and_creator_); + QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " + "generator tries to write stream data."; + bool has_handshake = QuicUtils::IsCryptoStreamId(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 && HasPendingRetransmittableFrames()) { + FlushCurrentPacket(); + } + + size_t total_bytes_consumed = 0; + bool fin_consumed = false; + + if (!HasRoomForStreamFrame(id, offset, write_length)) { + FlushCurrentPacket(); + } + + 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 (!ConsumeDataToFillCurrentPacket(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 && 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; + } + FlushCurrentPacket(); + + 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) { + FlushCurrentPacket(); + } + + return QuicConsumedData(total_bytes_consumed, fin_consumed); +} + +QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( + QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + bool fin, + size_t total_bytes_consumed) { + DCHECK(combine_generator_and_creator_); + DCHECK(!QuicUtils::IsCryptoStreamId(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; + 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)); +} + +size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset) { + DCHECK(combine_generator_and_creator_); + 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 (HasPendingRetransmittableFrames()) { + FlushCurrentPacket(); + } + + size_t total_bytes_consumed = 0; + + while (total_bytes_consumed < write_length) { + QuicFrame frame; + if (!ConsumeCryptoDataToFillCurrentPacket( + 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; + FlushCurrentPacket(); + } + + // Don't allow the handshake to be bundled with other retransmittable frames. + FlushCurrentPacket(); + + return total_bytes_consumed; +} + +void QuicPacketCreator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { + DCHECK(combine_generator_and_creator_); + // MTU discovery frames must be sent by themselves. + if (!CanSetMaxPacketLength()) { + QUIC_BUG << "MTU discovery packets should only be sent when no other " + << "frames needs to be sent."; + return; + } + const QuicByteCount current_mtu = max_packet_length(); + + // 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 = AddPaddedSavedFrame(frame, next_transmission_type_); + FlushCurrentPacket(); + // 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); +} + +void QuicPacketCreator::MaybeBundleAckOpportunistically() { + DCHECK(combine_generator_and_creator_); + if (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 QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) { + DCHECK(combine_generator_and_creator_); + 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 (HasPendingFrames()) { + if (AddSavedFrame(frame, next_transmission_type_)) { + // There is pending frames and current frame fits. + continue; + } + } + DCHECK(!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 = AddSavedFrame(frame, next_transmission_type_); + QUIC_BUG_IF(!success) << "Failed to flush " << frame; + } + return true; +} + +void QuicPacketCreator::AddRandomPadding() { + DCHECK(combine_generator_and_creator_); + AddPendingPadding(random_->RandUint64() % kMaxNumRandomPaddingBytes + 1); +} + +void QuicPacketCreator::AttachPacketFlusher() { + DCHECK(combine_generator_and_creator_); + flusher_attached_ = true; + if (!write_start_packet_number_.IsInitialized()) { + write_start_packet_number_ = NextSendingPacketNumber(); + } +} + +void QuicPacketCreator::Flush() { + DCHECK(combine_generator_and_creator_); + FlushCurrentPacket(); + 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", + NextSendingPacketNumber() - write_start_packet_number_, 1, 200, 50, + "Number of QUIC packets written per write operation"); + } + write_start_packet_number_.Clear(); +} + +void QuicPacketCreator::SendRemainingPendingPadding() { + DCHECK(combine_generator_and_creator_); + while ( + pending_padding_bytes() > 0 && !HasPendingFrames() && + delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) { + FlushCurrentPacket(); + } +} + +void QuicPacketCreator::SetServerConnectionIdLength(uint32_t length) { + DCHECK(combine_generator_and_creator_); + if (length == 0) { + SetServerConnectionIdIncluded(CONNECTION_ID_ABSENT); + } else { + SetServerConnectionIdIncluded(CONNECTION_ID_PRESENT); + } +} + +void QuicPacketCreator::SetTransmissionType(TransmissionType type) { + DCHECK(combine_generator_and_creator_); + SetTransmissionTypeOfNextPackets(type); + if (can_set_transmission_type()) { + next_transmission_type_ = type; + } +} + +MessageStatus QuicPacketCreator::AddMessageFrame(QuicMessageId message_id, + QuicMemSliceSpan message) { + DCHECK(combine_generator_and_creator_); + 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 (!HasRoomForMessageFrame(message_length)) { + FlushCurrentPacket(); + } + QuicMessageFrame* frame = new QuicMessageFrame(message_id, message); + const bool success = 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; +} + QuicVariableLengthIntegerLength QuicPacketCreator::GetLengthLength() const { if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && HasIetfLongHeader()) { @@ -1188,5 +1521,10 @@ return packet_number() + 1; } +bool QuicPacketCreator::PacketFlusherAttached() const { + DCHECK(combine_generator_and_creator_); + return flusher_attached_; +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h index 9ef910a..d9b0e19 100644 --- a/quic/core/quic_packet_creator.h +++ b/quic/core/quic_packet_creator.h
@@ -281,6 +281,74 @@ // Sets the retry token to be sent over the wire in IETF Initial packets. void SetRetryToken(QuicStringPiece retry_token); + // Consumes retransmittable control |frame|. Returns true if the frame is + // successfully consumed. Returns false otherwise. + bool ConsumeRetransmittableControlFrame(const QuicFrame& frame); + + // Given some data, may consume part or all of it and pass it to the + // packet creator to be serialized into packets. If not in batch + // mode, these packets will also be sent during this call. + // When |state| is FIN_AND_PADDING, random padding of size [1, 256] will be + // added after stream frames. If current constructed packet cannot + // accommodate, the padding will overflow to the next packet(s). + QuicConsumedData ConsumeData(QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state); + + // Sends as many data only packets as allowed by the send algorithm and the + // available iov. + // This path does not support padding, or bundling pending frames. + // In case we access this method from ConsumeData, total_bytes_consumed + // keeps track of how many bytes have already been consumed. + QuicConsumedData ConsumeDataFastPath(QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + bool fin, + size_t total_bytes_consumed); + + // Consumes data for CRYPTO frames sent at |level| starting at |offset| for a + // total of |write_length| bytes, and returns the number of bytes consumed. + // The data is passed into the packet creator and serialized into one or more + // packets. + size_t ConsumeCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset); + + // Generates an MTU discovery packet of specified size. + void GenerateMtuDiscoveryPacket(QuicByteCount target_mtu); + + // Called when there is data to be sent, Retrieves updated ACK frame from + // delegate_ and flushes it. + void MaybeBundleAckOpportunistically(); + + // Called to flush ACK and STOP_WAITING frames, returns false if the flush + // fails. + bool FlushAckFrame(const QuicFrames& frames); + + // Adds a random amount of padding (between 1 to 256 bytes). + void AddRandomPadding(); + + // Attaches packet flusher. + void AttachPacketFlusher(); + + // Flushes everything, including current open packet and pending padding. + void Flush(); + + // Sends remaining pending padding. + // Pending paddings should only be sent when there is nothing else to send. + void SendRemainingPendingPadding(); + + // Set the minimum number of bytes for the server connection id length; + void SetServerConnectionIdLength(uint32_t length); + + // Set transmission type of next constructed packets. + void SetTransmissionType(TransmissionType type); + + // Tries to add a message frame containing |message| and returns the status. + MessageStatus AddMessageFrame(QuicMessageId message_id, + QuicMemSliceSpan message); + // Returns the largest payload that will fit into a single MESSAGE frame. QuicPacketLength GetCurrentLargestMessagePayload() const; // Returns the largest payload that will fit into a single MESSAGE frame at @@ -310,6 +378,23 @@ // Returns the minimum size that the plaintext of a packet must be. static size_t MinPlaintextPacketSize(const ParsedQuicVersion& version); + // Indicates whether packet flusher is currently attached. + bool PacketFlusherAttached() const; + + void set_fully_pad_crypto_hadshake_packets(bool new_value) { + DCHECK(combine_generator_and_creator_); + fully_pad_crypto_handshake_packets_ = new_value; + } + + bool fully_pad_crypto_handshake_packets() const { + DCHECK(combine_generator_and_creator_); + return fully_pad_crypto_handshake_packets_; + } + + bool combine_generator_and_creator() const { + return combine_generator_and_creator_; + } + private: friend class test::QuicPacketCreatorPeer; @@ -444,6 +529,23 @@ // If true, packet_'s transmission type is only set by // SetPacketTransmissionType and does not get cleared in ClearPacket. bool can_set_transmission_type_; + + // Transmission type of the next serialized packet. + TransmissionType next_transmission_type_; + + // True if packet flusher is currently attached. + bool flusher_attached_; + + // Whether crypto handshake packets should be fully padded. + bool fully_pad_crypto_handshake_packets_; + + // Packet number of the first packet of a write operation. This gets set + // when the out-most flusher attaches and gets cleared when the out-most + // flusher detaches. + QuicPacketNumber write_start_packet_number_; + + // Latched value of quic_combine_generator_and_creator. + const bool combine_generator_and_creator_; }; } // namespace quic
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc index 5240b01..7312ebf 100644 --- a/quic/core/quic_packet_generator.cc +++ b/quic/core/quic_packet_generator.cc
@@ -34,6 +34,9 @@ bool QuicPacketGenerator::ConsumeRetransmittableControlFrame( const QuicFrame& frame) { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.ConsumeRetransmittableControlFrame(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; @@ -60,6 +63,9 @@ size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset) { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.ConsumeCryptoData(level, write_length, offset); + } QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write crypto data."; MaybeBundleAckOpportunistically(); @@ -102,6 +108,9 @@ size_t write_length, QuicStreamOffset offset, StreamSendingState state) { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.ConsumeData(id, write_length, offset, state); + } QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write stream data."; bool has_handshake = @@ -193,6 +202,10 @@ QuicStreamOffset offset, bool fin, size_t total_bytes_consumed) { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.ConsumeDataFastPath(id, write_length, offset, fin, + total_bytes_consumed); + } DCHECK(!QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id)); while (total_bytes_consumed < write_length && @@ -211,6 +224,10 @@ } void QuicPacketGenerator::GenerateMtuDiscoveryPacket(QuicByteCount target_mtu) { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.GenerateMtuDiscoveryPacket(target_mtu); + return; + } // MTU discovery frames must be sent by themselves. if (!packet_creator_.CanSetMaxPacketLength()) { QUIC_BUG << "MTU discovery packets should only be sent when no other " @@ -238,10 +255,17 @@ } bool QuicPacketGenerator::PacketFlusherAttached() const { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.PacketFlusherAttached(); + } return flusher_attached_; } void QuicPacketGenerator::AttachPacketFlusher() { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.AttachPacketFlusher(); + return; + } flusher_attached_ = true; if (!write_start_packet_number_.IsInitialized()) { write_start_packet_number_ = packet_creator_.NextSendingPacketNumber(); @@ -249,6 +273,10 @@ } void QuicPacketGenerator::Flush() { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.Flush(); + return; + } packet_creator_.FlushCurrentPacket(); SendRemainingPendingPadding(); flusher_attached_ = false; @@ -347,6 +375,10 @@ } void QuicPacketGenerator::SetServerConnectionIdLength(uint32_t length) { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.SetServerConnectionIdLength(length); + return; + } if (length == 0) { packet_creator_.SetServerConnectionIdIncluded(CONNECTION_ID_ABSENT); } else { @@ -365,11 +397,19 @@ } void QuicPacketGenerator::AddRandomPadding() { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.AddRandomPadding(); + return; + } packet_creator_.AddPendingPadding( random_generator_->RandUint64() % kMaxNumRandomPaddingBytes + 1); } void QuicPacketGenerator::SendRemainingPendingPadding() { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.SendRemainingPendingPadding(); + return; + } while ( packet_creator_.pending_padding_bytes() > 0 && !HasPendingFrames() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)) { @@ -387,6 +427,10 @@ } void QuicPacketGenerator::SetTransmissionType(TransmissionType type) { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.SetTransmissionType(type); + return; + } packet_creator_.SetTransmissionTypeOfNextPackets(type); if (packet_creator_.can_set_transmission_type()) { next_transmission_type_ = type; @@ -404,6 +448,9 @@ MessageStatus QuicPacketGenerator::AddMessageFrame(QuicMessageId message_id, QuicMemSliceSpan message) { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.AddMessageFrame(message_id, message); + } QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to add message frame."; MaybeBundleAckOpportunistically(); @@ -426,6 +473,10 @@ } void QuicPacketGenerator::MaybeBundleAckOpportunistically() { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.MaybeBundleAckOpportunistically(); + return; + } if (packet_creator_.has_ack()) { // Ack already queued, nothing to do. return; @@ -440,6 +491,9 @@ } bool QuicPacketGenerator::FlushAckFrame(const QuicFrames& frames) { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.FlushAckFrame(frames); + } QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to send ACK frame."; for (const auto& frame : frames) { @@ -483,4 +537,20 @@ packet_creator_.SetClientConnectionId(client_connection_id); } +void QuicPacketGenerator::set_fully_pad_crypto_hadshake_packets( + bool new_value) { + if (packet_creator_.combine_generator_and_creator()) { + packet_creator_.set_fully_pad_crypto_hadshake_packets(new_value); + return; + } + fully_pad_crypto_handshake_packets_ = new_value; +} + +bool QuicPacketGenerator::fully_pad_crypto_handshake_packets() const { + if (packet_creator_.combine_generator_and_creator()) { + return packet_creator_.fully_pad_crypto_handshake_packets(); + } + return fully_pad_crypto_handshake_packets_; +} + } // namespace quic
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h index 4b27d1d..992d119 100644 --- a/quic/core/quic_packet_generator.h +++ b/quic/core/quic_packet_generator.h
@@ -225,13 +225,9 @@ packet_creator_.set_debug_delegate(debug_delegate); } - void set_fully_pad_crypto_hadshake_packets(bool new_value) { - fully_pad_crypto_handshake_packets_ = new_value; - } + void set_fully_pad_crypto_hadshake_packets(bool new_value); - bool fully_pad_crypto_handshake_packets() const { - return fully_pad_crypto_handshake_packets_; - } + bool fully_pad_crypto_handshake_packets() const; private: friend class test::QuicPacketGeneratorPeer;