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