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;