diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 83054bf501..be365e1bca 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -536,7 +536,7 @@ QUICCryptoFrame::store(uint8_t *buf, size_t *len, size_t 
limit) const
   *len += n;
 
   // Crypto Data (*)
-  memcpy(buf + *len, this->data(), this->data_length());
+  memcpy(buf + *len, this->data()->start(), this->data_length());
   *len += this->data_length();
 
   return *len;
@@ -554,10 +554,10 @@ QUICCryptoFrame::data_length() const
   return this->_block->read_avail();
 }
 
-const uint8_t *
+IOBufferBlock *
 QUICCryptoFrame::data() const
 {
-  return reinterpret_cast<const uint8_t *>(this->_block->start());
+  return this->_block.get();
 }
 
 //
@@ -2896,8 +2896,9 @@ QUICFrameFactory::create_stream_frame(Ptr<IOBufferBlock> 
&block, QUICStreamId st
 QUICCryptoFrameUPtr
 QUICFrameFactory::create_crypto_frame(Ptr<IOBufferBlock> &block, QUICOffset 
offset, QUICFrameId id, QUICFrameGenerator *owner)
 {
-  QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc();
-  new (frame) QUICCryptoFrame(block, offset, id, owner);
+  Ptr<IOBufferBlock> new_block = make_ptr<IOBufferBlock>(block->clone());
+  QUICCryptoFrame *frame       = quicCryptoFrameAllocator.alloc();
+  new (frame) QUICCryptoFrame(new_block, offset, id, owner);
   return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame);
 }
 
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 0f8a435ee2..3291a6606a 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -143,7 +143,7 @@ class QUICCryptoFrame : public QUICFrame
 
   QUICOffset offset() const;
   uint64_t data_length() const;
-  const uint8_t *data() const;
+  IOBufferBlock *data() const;
 
   LINK(QUICCryptoFrame, link);
 
diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc 
b/iocore/net/quic/QUICFrameRetransmitter.cc
index dfa6352659..485e13d5d4 100644
--- a/iocore/net/quic/QUICFrameRetransmitter.cc
+++ b/iocore/net/quic/QUICFrameRetransmitter.cc
@@ -54,6 +54,9 @@ 
QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, ui
     case QUICFrameType::STREAM:
       frame = this->_create_stream_frame(info, maximum_frame_size, tmp_queue, 
id, owner);
       break;
+    case QUICFrameType::CRYPTO:
+      frame = this->_create_crypto_frame(info, maximum_frame_size, tmp_queue, 
id, owner);
+      break;
     default:
       ink_assert("unknown frame type");
       Error("unknown frame type: %s", QUICDebugNames::frame_type(info->type));
@@ -70,7 +73,7 @@ 
QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, ui
 }
 
 void
-QUICFrameRetransmitter::save_frame_info(QUICFrameInformationUPtr &info)
+QUICFrameRetransmitter::save_frame_info(QUICFrameInformationUPtr info)
 {
   for (auto type : RETRANSMITTED_FRAME_TYPE) {
     if (type == info->type) {
@@ -128,3 +131,40 @@ 
QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin
   ink_assert(frame != nullptr);
   return frame;
 }
+
+QUICFrameUPtr
+QUICFrameRetransmitter::_create_crypto_frame(QUICFrameInformationUPtr &info, 
uint16_t maximum_frame_size,
+                                             
std::deque<QUICFrameInformationUPtr> &tmp_queue, QUICFrameId id,
+                                             QUICFrameGenerator *owner)
+{
+  CryptoFrameInfo *crypto_info = reinterpret_cast<CryptoFrameInfo 
*>(info->data);
+  // FIXME: has_offset and has_length should be configurable.
+  auto frame = QUICFrameFactory::create_crypto_frame(crypto_info->block, 
crypto_info->offset, id, owner);
+  if (frame->size() > maximum_frame_size) {
+    QUICCryptoFrame *crypto_frame = static_cast<QUICCryptoFrame 
*>(frame.get());
+    if (crypto_frame->size() - crypto_frame->data_length() > 
maximum_frame_size) {
+      // header length is larger than maximum_frame_size.
+      tmp_queue.push_back(std::move(info));
+      return QUICFrameFactory::create_null_frame();
+    }
+
+    IOBufferBlock *block = crypto_frame->data();
+    size_t over_length   = crypto_frame->size() - maximum_frame_size;
+    block->_end          = std::max(block->start(), block->_end - over_length);
+    if (block->read_avail() == 0) {
+      // no payload
+      tmp_queue.push_back(std::move(info));
+      return QUICFrameFactory::create_null_frame();
+    }
+
+    crypto_info->block->consume(crypto_frame->data_length());
+    crypto_info->offset += crypto_frame->data_length();
+    ink_assert(frame->size() <= maximum_frame_size);
+    tmp_queue.push_back(std::move(info));
+    return frame;
+  }
+
+  crypto_info->block = nullptr;
+  ink_assert(frame != nullptr);
+  return frame;
+}
diff --git a/iocore/net/quic/QUICFrameRetransmitter.h 
b/iocore/net/quic/QUICFrameRetransmitter.h
index a9ac6fc555..f64d71fe5b 100644
--- a/iocore/net/quic/QUICFrameRetransmitter.h
+++ b/iocore/net/quic/QUICFrameRetransmitter.h
@@ -41,7 +41,7 @@ struct QUICFrameInformationDeleter {
 
 using QUICFrameInformationUPtr = std::unique_ptr<QUICFrameInformation, 
QUICFrameInformationDeleter>;
 
-constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM};
+constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM, 
QUICFrameType::CRYPTO};
 
 struct StreamFrameInfo {
   QUICStreamId stream_id;
@@ -73,11 +73,13 @@ class QUICFrameRetransmitter
 public:
   virtual QUICFrameUPtr create_retransmitted_frame(QUICEncryptionLevel level, 
uint16_t maximum_frame_size, QUICFrameId id = 0,
                                                    QUICFrameGenerator *owner = 
nullptr);
-  virtual void save_frame_info(QUICFrameInformationUPtr &info);
+  virtual void save_frame_info(QUICFrameInformationUPtr info);
 
 private:
   QUICFrameUPtr _create_stream_frame(QUICFrameInformationUPtr &info, uint16_t 
maximum_frame_size,
                                      std::deque<QUICFrameInformationUPtr> 
&tmp_queue, QUICFrameId id, QUICFrameGenerator *owner);
+  QUICFrameUPtr _create_crypto_frame(QUICFrameInformationUPtr &info, uint16_t 
maximum_frame_size,
+                                     std::deque<QUICFrameInformationUPtr> 
&tmp_queue, QUICFrameId id, QUICFrameGenerator *owner);
 
   void _append_info_queue(std::deque<QUICFrameInformationUPtr> &tmp_queue);
 
diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc 
b/iocore/net/quic/QUICPacketRetransmitter.cc
index 8b8e40ab31..44f4ff60c3 100644
--- a/iocore/net/quic/QUICPacketRetransmitter.cc
+++ b/iocore/net/quic/QUICPacketRetransmitter.cc
@@ -55,6 +55,8 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket 
&packet)
     case QUICFrameType::STOP_SENDING:
     case QUICFrameType::CONNECTION_CLOSE:
     case QUICFrameType::APPLICATION_CLOSE:
+    case QUICFrameType::STREAM:
+    case QUICFrameType::CRYPTO:
       break;
     default:
       frame     = 
QUICFrameFactory::create_retransmission_frame(frame->clone(), packet);
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 48af1ccfc0..9edb646b8e 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -408,7 +408,12 @@ QUICStream::generate_frame(QUICEncryptionLevel level, 
uint64_t connection_credit
 {
   SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
 
-  QUICFrameUPtr frame = QUICFrameFactory::create_null_frame();
+  QUICFrameUPtr frame = this->create_retransmitted_frame(level, 
maximum_frame_size, this->_issue_frame_id(), this);
+  if (frame != nullptr) {
+    ink_assert(frame->type() == QUICFrameType::STREAM);
+    this->_records_stream_frame(*static_cast<QUICStreamFrame *>(frame.get()));
+    return frame;
+  }
 
   // RST_STREAM
   if (this->_reset_reason && !this->_is_reset_sent) {
@@ -516,7 +521,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, 
uint64_t connection_credit
     this->_send_offset += len;
     this->_write_vio.ndone += len;
   }
-  this->_records_stream_frame(*static_cast<QUICStreamFrame *>(frame.get()), 
block);
+  this->_records_stream_frame(*static_cast<QUICStreamFrame *>(frame.get()));
 
   this->_signal_write_event();
   this->_state.update_with_sending_frame(*frame);
@@ -525,14 +530,14 @@ QUICStream::generate_frame(QUICEncryptionLevel level, 
uint64_t connection_credit
 }
 
 void
-QUICStream::_records_stream_frame(const QUICStreamFrame &frame, 
Ptr<IOBufferBlock> &block)
+QUICStream::_records_stream_frame(const QUICStreamFrame &frame)
 {
   QUICFrameInformationUPtr info = 
QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
   info->type                    = frame.type();
   StreamFrameInfo *frame_info   = reinterpret_cast<StreamFrameInfo 
*>(info->data);
   frame_info->offset            = frame.offset();
   frame_info->has_fin           = frame.has_fin_flag();
-  frame_info->block             = block;
+  frame_info->block             = frame.data();
   this->_records_frame(frame.id(), std::move(info));
 }
 
@@ -583,7 +588,6 @@ QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info)
 void
 QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info)
 {
-  StreamFrameInfo *frame_info = nullptr;
   switch (info->type) {
   case QUICFrameType::RST_STREAM:
     // [draft-16] 13.2.  Retransmission of Information
@@ -595,8 +599,7 @@ QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info)
     this->_is_reset_sent = false;
     break;
   case QUICFrameType::STREAM:
-    frame_info        = reinterpret_cast<StreamFrameInfo *>(info->data);
-    frame_info->block = nullptr;
+    this->save_frame_info(std::move(info));
     break;
   case QUICFrameType::STOP_SENDING:
     this->_is_stop_sending_sent = false;
@@ -821,7 +824,7 @@ QUICCryptoStream::recv(const QUICCryptoFrame &frame)
   while (new_frame != nullptr) {
     QUICCryptoFrameSPtr crypto_frame = std::static_pointer_cast<const 
QUICCryptoFrame>(new_frame);
 
-    this->_read_buffer->write(crypto_frame->data(), 
crypto_frame->data_length());
+    this->_read_buffer->write(reinterpret_cast<uint8_t 
*>(crypto_frame->data()->start()), crypto_frame->data_length());
     new_frame = this->_received_stream_frame_buffer.pop();
   }
 
@@ -861,7 +864,12 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel 
level, uint64_t connection_
     return QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason);
   }
 
-  QUICFrameUPtr frame = QUICFrameFactory::create_null_frame();
+  QUICFrameUPtr frame = this->create_retransmitted_frame(level, 
maximum_frame_size, this->_issue_frame_id(), this);
+  if (frame != nullptr) {
+    ink_assert(frame->type() == QUICFrameType::CRYPTO);
+    this->_records_crypto_frame(*static_cast<QUICCryptoFrame *>(frame.get()));
+    return frame;
+  }
 
   if (maximum_frame_size <= MAX_CRYPTO_FRAME_OVERHEAD) {
     return frame;
@@ -879,17 +887,10 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel 
level, uint64_t connection_
   block->_end = std::min(block->start() + frame_payload_size, block->_buf_end);
   ink_assert(static_cast<uint64_t>(block->read_avail()) == frame_payload_size);
 
-  QUICFrameInformationUPtr info      = 
QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
-  info->type                         = QUICFrameType::CRYPTO;
-  QUICFrameId frame_id               = this->_issue_frame_id();
-  CryptoFrameInfo *crypto_frame_info = reinterpret_cast<CryptoFrameInfo 
*>(info->data);
-  crypto_frame_info->offset          = this->_send_offset;
-  crypto_frame_info->block           = block;
-  this->_records_frame(frame_id, std::move(info));
-
-  frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, 
frame_id, this);
+  frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, 
this->_issue_frame_id(), this);
   this->_send_offset += frame_payload_size;
   this->_write_buffer_reader->consume(frame_payload_size);
+  this->_records_crypto_frame(*static_cast<QUICCryptoFrame *>(frame.get()));
 
   return frame;
 }
@@ -906,6 +907,16 @@ void
 QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info)
 {
   ink_assert(info->type == QUICFrameType::CRYPTO);
+  this->save_frame_info(std::move(info));
+}
+
+void
+QUICCryptoStream::_records_crypto_frame(const QUICCryptoFrame &frame)
+{
+  QUICFrameInformationUPtr info      = 
QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
+  info->type                         = QUICFrameType::CRYPTO;
   CryptoFrameInfo *crypto_frame_info = reinterpret_cast<CryptoFrameInfo 
*>(info->data);
-  crypto_frame_info->block           = nullptr;
+  crypto_frame_info->offset          = frame.offset();
+  crypto_frame_info->block           = frame.data();
+  this->_records_frame(frame.id(), std::move(info));
 }
diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h
index c0aec9dff9..6f486d4faf 100644
--- a/iocore/net/quic/QUICStream.h
+++ b/iocore/net/quic/QUICStream.h
@@ -109,7 +109,7 @@ class QUICStream : public VConnection, public 
QUICFrameGenerator, public QUICTra
 
   void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t 
data_length, bool fin);
   void _records_rst_stream_frame(const QUICRstStreamFrame &frame);
-  void _records_stream_frame(const QUICStreamFrame &frame, Ptr<IOBufferBlock> 
&block);
+  void _records_stream_frame(const QUICStreamFrame &frame);
   void _records_stop_sending_frame(const QUICStopSendingFrame &frame);
 
   QUICStreamErrorUPtr _reset_reason        = nullptr;
@@ -157,7 +157,7 @@ class QUICStream : public VConnection, public 
QUICFrameGenerator, public QUICTra
  * - no flow control
  * - no state (never closed)
  */
-class QUICCryptoStream : public QUICFrameGenerator
+class QUICCryptoStream : public QUICFrameGenerator, public 
QUICFrameRetransmitter
 {
 public:
   QUICCryptoStream();
@@ -191,6 +191,8 @@ class QUICCryptoStream : public QUICFrameGenerator
   void _on_frame_acked(QUICFrameInformationUPtr &info) override;
   void _on_frame_lost(QUICFrameInformationUPtr &info) override;
 
+  void _records_crypto_frame(const QUICCryptoFrame &frame);
+
   QUICStreamErrorUPtr _reset_reason = nullptr;
   QUICOffset _send_offset           = 0;
 
diff --git a/iocore/net/quic/test/test_QUICFrame.cc 
b/iocore/net/quic/test/test_QUICFrame.cc
index 327d89d672..408c41a485 100644
--- a/iocore/net/quic/test/test_QUICFrame.cc
+++ b/iocore/net/quic/test/test_QUICFrame.cc
@@ -400,6 +400,7 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", 
stream_frame->data_length()) == 0);
     CHECK(stream_frame->offset() == 0x100000000);
 
+    frame1 = QUICFrameFactory::create_null_frame();
     CHECK(stream_frame2->data_length() == 5);
     CHECK(memcmp(stream_frame2->data()->start(), "\x11\x22\x33\x44\x55", 
stream_frame2->data_length()) == 0);
     CHECK(stream_frame2->offset() == 0x100000000 + 5);
@@ -426,7 +427,7 @@ TEST_CASE("CRYPTO Frame", "[quic]")
     std::shared_ptr<const QUICCryptoFrame> crypto_frame = 
std::dynamic_pointer_cast<const QUICCryptoFrame>(frame);
     CHECK(crypto_frame->offset() == 0x010000);
     CHECK(crypto_frame->data_length() == 5);
-    CHECK(memcmp(crypto_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0);
+    CHECK(memcmp(crypto_frame->data()->start(), "\x01\x02\x03\x04\x05", 5) == 
0);
   }
 
   SECTION("BAD Loading")
diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc 
b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc
index 5c8557baee..6ea6b11ab1 100644
--- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc
+++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc
@@ -34,7 +34,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which can not 
be retranmistted",
   info->type                    = QUICFrameType::PING;
   info->level                   = QUICEncryptionLevel::NONE;
 
-  retransmitter.save_frame_info(info);
+  retransmitter.save_frame_info(std::move(info));
   CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 
UINT16_MAX) == nullptr);
 }
 
@@ -56,7 +56,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which has 
wrong level", "[quic]")
   info->type                    = QUICFrameType::STREAM;
   info->level                   = QUICEncryptionLevel::HANDSHAKE;
 
-  retransmitter.save_frame_info(info);
+  retransmitter.save_frame_info(std::move(info));
   CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 
UINT16_MAX) == nullptr);
 }
 
@@ -77,7 +77,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create 
retransmitted frame", "[qu
   frame_info->offset          = 0x67890;
   frame_info->block           = block;
 
-  retransmitter.save_frame_info(info);
+  retransmitter.save_frame_info(std::move(info));
 
   auto frame = 
retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 
UINT16_MAX);
   CHECK(frame != nullptr);
@@ -102,7 +102,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create 
stream frame", "[quic]")
   frame_info->block           = block;
 
   CHECK(block->refcount() == 2);
-  retransmitter.save_frame_info(info);
+  retransmitter.save_frame_info(std::move(info));
   CHECK(block->refcount() == 2); // block's refcount doesn't change
 
   auto frame = 
retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 
UINT16_MAX);
@@ -136,7 +136,7 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream 
frame", "[quic]")
   frame_info->block           = block;
   CHECK(block->refcount() == 2);
 
-  retransmitter.save_frame_info(info);
+  retransmitter.save_frame_info(std::move(info));
 
   auto frame = 
retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15);
   CHECK(frame != nullptr);
@@ -171,3 +171,54 @@ TEST_CASE("QUICFrameRetransmitter successfully split 
stream frame", "[quic]")
   CHECK(block->refcount() == 1);
   CHECK(block->data->refcount() == 1);
 }
+
+TEST_CASE("QUICFrameRetransmitter successfully split crypto frame", "[quic]")
+{
+  QUICFrameRetransmitter retransmitter;
+  QUICFrameInformationUPtr info = 
QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
+  info->type                    = QUICFrameType::CRYPTO;
+  info->level                   = QUICEncryptionLevel::INITIAL;
+
+  Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+  block->alloc();
+  memcpy(block->start(), data, sizeof(data));
+  block->fill(sizeof(data));
+
+  CryptoFrameInfo *frame_info = reinterpret_cast<CryptoFrameInfo 
*>(info->data);
+  frame_info->offset          = 0x67890;
+  frame_info->block           = block;
+  CHECK(block->refcount() == 2);
+
+  retransmitter.save_frame_info(std::move(info));
+
+  auto frame = 
retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15);
+  CHECK(frame != nullptr);
+  CHECK(frame->type() == QUICFrameType::CRYPTO);
+  auto crypto_frame = static_cast<QUICCryptoFrame *>(frame.get());
+  CHECK(crypto_frame->offset() == 0x67890);
+  CHECK(crypto_frame->size() <= 15);
+
+  auto size = crypto_frame->data_length();
+  CHECK(memcmp(crypto_frame->data()->start(), data, 
crypto_frame->data_length()) == 0);
+  // one for var block, one for the left data which saved in retransmitter
+  CHECK(block->data->refcount() == 2);
+  // one for var block, one for the left data which saved in retransmitter, 
one for var frame
+  CHECK(block->refcount() == 2);
+  frame = QUICFrameFactory::create_null_frame();
+  // one for var block, one for var info
+  CHECK(block->refcount() == 2);
+  CHECK(block->data->refcount() == 1);
+
+  frame = 
retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 
UINT16_MAX);
+  CHECK(frame != nullptr);
+  CHECK(frame->type() == QUICFrameType::CRYPTO);
+  crypto_frame = static_cast<QUICCryptoFrame *>(frame.get());
+  CHECK(crypto_frame->offset() == 0x67890 + size);
+  CHECK(crypto_frame->data_length() == sizeof(data) - size);
+  CHECK(memcmp(crypto_frame->data()->start(), data + size, 
crypto_frame->data_length()) == 0);
+  CHECK(block->refcount() == 1); // one for var block
+
+  frame = QUICFrameFactory::create_null_frame();
+  CHECK(block->refcount() == 1);
+  CHECK(block->data->refcount() == 1);
+}


With regards,
Apache Git Services

Reply via email to