You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2017/10/13 00:33:59 UTC

[trafficserver] branch quic-05 updated (ff2d8a7 -> 92d7c3a)

This is an automated email from the ASF dual-hosted git repository.

maskit pushed a change to branch quic-05
in repository https://gitbox.apache.org/repos/asf/trafficserver.git.


    from ff2d8a7  Call the QUICFrame destructor before freeing into the ClassAllocator
     new 46cf6d5  add QUICInBuffer feature
     new 1a70d29  Fix building unit tests of quic
     new 92d7c3a  Fix heap-use-after-free in QUICStreamFrame::store

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |   1 +
 iocore/net/quic/Makefile.am                        |   3 +-
 iocore/net/quic/QUICFrame.cc                       |  11 +-
 iocore/net/quic/QUICFrame.h                        |   4 +-
 iocore/net/quic/QUICIncomingFrameBuffer.cc         | 135 +++++++++++++
 ...CApplicationMap.h => QUICIncomingFrameBuffer.h} |  34 +++-
 iocore/net/quic/QUICStream.cc                      |  36 ++--
 iocore/net/quic/QUICStream.h                       |   7 +-
 iocore/net/quic/test/Makefile.am                   |  43 ++++-
 iocore/net/quic/test/test_QUICFrame.cc             |  50 ++++-
 iocore/net/quic/test/test_QUICFrameDispatcher.cc   |   7 +-
 .../net/quic/test/test_QUICIncomingFrameBuffer.cc  | 177 +++++++++++++++++
 iocore/net/quic/test/test_QUICStream.cc            | 215 ++++++++++++---------
 13 files changed, 572 insertions(+), 151 deletions(-)
 create mode 100644 iocore/net/quic/QUICIncomingFrameBuffer.cc
 copy iocore/net/quic/{QUICApplicationMap.h => QUICIncomingFrameBuffer.h} (57%)
 create mode 100644 iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].

[trafficserver] 02/03: Fix building unit tests of quic

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch quic-05
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 1a70d2953c6d0fef88f1512b6e4f390288c80daf
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Thu Oct 12 14:11:32 2017 +0900

    Fix building unit tests of quic
    
    (cherry picked from commit d46ff1251c628b642f1822591d1ac5126e916933)
---
 .gitignore                       | 1 +
 iocore/net/quic/test/Makefile.am | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/.gitignore b/.gitignore
index de3eff5..ed253d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,6 +103,7 @@ iocore/net/quic/test/test_QUICTypeUtil
 iocore/net/quic/test/test_QUICAckFrameCreator
 iocore/net/quic/test/test_QUICVersionNegotiator
 iocore/net/quic/test/test_QUICFlowController
+iocore/net/quic/test/test_QUICIncomingFrameBuffer
 iocore/net/quic/ts_quic_client
 iocore/aio/test_AIO
 iocore/eventsystem/test_Buffer
diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am
index e25eced..b53ec4d 100644
--- a/iocore/net/quic/test/Makefile.am
+++ b/iocore/net/quic/test/Makefile.am
@@ -132,6 +132,7 @@ test_QUICFrame_SOURCES = \
   ../QUICTypes.cc \
   ../QUICStream.cc \
   ../QUICStreamState.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICDebugNames.cc \
   ../QUICFlowController.cc \
   ../../SSLNextProtocolSet.cc
@@ -166,6 +167,7 @@ test_QUICFrameDispatcher_SOURCES = \
   ../QUICPacket.cc \
   ../QUICStream.cc \
   ../QUICStreamState.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICApplication.cc \
   ../QUICHandshake.cc \
   ../QUICTypes.cc \
@@ -252,6 +254,7 @@ test_QUICStreamManager_SOURCES = \
   event_processor_main.cc \
   test_QUICStreamManager.cc \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICFrameDispatcher.cc \
   ../QUICStreamManager.cc \
   ../QUICApplicationMap.cc \
@@ -290,6 +293,7 @@ test_QUICTransportParameters_SOURCES = \
   ../QUICCrypto.cc \
   $(QUICCrypto_impl) \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICStreamState.cc \
   ../QUICStreamManager.cc \
   ../QUICFlowController.cc \
@@ -380,6 +384,7 @@ test_QUICTypeUtil_SOURCES = \
   main.cc \
   test_QUICTypeUtil.cc \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICStreamState.cc \
   ../QUICFlowController.cc \
   ../QUICDebugNames.cc \
@@ -411,6 +416,7 @@ test_QUICAckFrameCreator_SOURCES = \
   ../QUICFrame.cc \
   ../QUICPacket.cc \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICStreamState.cc \
   ../QUICFlowController.cc \
   ../QUICDebugNames.cc \
@@ -449,6 +455,7 @@ test_QUICVersionNegotiator_SOURCES = \
   ../QUICApplicationMap.cc \
   ../QUICHandshake.cc \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICStreamState.cc \
   ../QUICStreamManager.cc \
   ../QUICFlowController.cc \
@@ -483,6 +490,7 @@ test_QUICFlowController_SOURCES = \
   test_QUICFlowController.cc \
   ../QUICFlowController.cc \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICStreamState.cc \
   ../QUICDebugNames.cc \
   ../QUICTypes.cc \

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 03/03: Fix heap-use-after-free in QUICStreamFrame::store

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch quic-05
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 92d7c3a29e988a4a80433b3d27efd3fea6ea1427
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Thu Oct 12 16:34:14 2017 +0900

    Fix heap-use-after-free in QUICStreamFrame::store
    
    Make data of QUICStramFrame ats_unique_buf. Copy data of _write_vio
    to the buffer, when QUICStream sends frame. Ideally this malloc and
    copy should be avoided.
    
    (cherry picked from commit 2250a414d8818b5f6b781a9ee9811521d6022e20)
---
 iocore/net/quic/QUICFrame.cc                     |  11 +-
 iocore/net/quic/QUICFrame.h                      |   4 +-
 iocore/net/quic/test/test_QUICFrame.cc           |  50 +++++-
 iocore/net/quic/test/test_QUICFrameDispatcher.cc |   7 +-
 iocore/net/quic/test/test_QUICStream.cc          | 215 +++++++++++++----------
 5 files changed, 174 insertions(+), 113 deletions(-)

diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 69951d4..4bb02b4 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -72,9 +72,9 @@ QUICFrame::reset(const uint8_t *buf, size_t len)
 // STREAM Frame
 //
 
-QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last)
+QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last)
 {
-  this->_data      = data;
+  this->_data      = std::move(data);
   this->_data_len  = data_len;
   this->_stream_id = stream_id;
   this->_offset    = offset;
@@ -183,7 +183,7 @@ QUICStreamFrame::data() const
   if (this->_buf) {
     return this->_buf + this->_get_data_offset();
   } else {
-    return this->_data;
+    return this->_data.get();
   }
 }
 
@@ -1315,8 +1315,11 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len)
 QUICStreamFrameUPtr
 QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last)
 {
+  ats_unique_buf buf = ats_unique_malloc(data_len);
+  memcpy(buf.get(), data, data_len);
+
   QUICStreamFrame *frame = quicStreamFrameAllocator.alloc();
-  new (frame) QUICStreamFrame(data, data_len, stream_id, offset, last);
+  new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last);
   return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame);
 }
 
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 772d65a..9f2b356 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -59,7 +59,7 @@ class QUICStreamFrame : public QUICFrame
 public:
   QUICStreamFrame() : QUICFrame() {}
   QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
-  QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false);
+  QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false);
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual void store(uint8_t *buf, size_t *len) const override;
@@ -74,7 +74,7 @@ public:
   LINK(QUICStreamFrame, link);
 
 private:
-  const uint8_t *_data    = nullptr;
+  ats_unique_buf _data    = {nullptr, [](void *p) { ats_free(p); }};
   size_t _data_len        = 0;
   QUICStreamId _stream_id = 0;
   QUICOffset _offset      = 0;
diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc
index 90c82fb..36f1eee 100644
--- a/iocore/net/quic/test/test_QUICFrame.cc
+++ b/iocore/net/quic/test/test_QUICFrame.cc
@@ -55,11 +55,14 @@ TEST_CASE("QUICFrame Type", "[quic]")
 
 TEST_CASE("Construct QUICFrame", "[quic]")
 {
-  uint8_t payload[] = "foo";
+  uint8_t raw[]          = "foo";
+  ats_unique_buf payload = ats_unique_malloc(sizeof(raw));
+  memcpy(payload.get(), raw, sizeof(raw));
+
   uint8_t buf[65536];
   size_t len;
 
-  QUICStreamFrame frame1(payload, sizeof(payload), 0xffcc9966, 0xffddbb9977553311);
+  QUICStreamFrame frame1(std::move(payload), sizeof(raw), 0xffcc9966, 0xffddbb9977553311);
   frame1.store(buf, &len);
   CHECK(frame1.type() == QUICFrameType::STREAM);
   CHECK(frame1.size() == 19);
@@ -119,7 +122,12 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                   // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data
   };
-  QUICStreamFrame streamFrame1(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00);
+
+  uint8_t raw1[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload1 = ats_unique_malloc(5);
+  memcpy(payload1.get(), raw1, 5);
+
+  QUICStreamFrame streamFrame1(std::move(payload1), 5, 0x01, 0x00);
   streamFrame1.store(buf, &len);
   CHECK(len == 9);
   CHECK(memcmp(buf, expected1, len) == 0);
@@ -132,7 +140,11 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                   // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data
   };
-  QUICStreamFrame streamFrame2(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x01, 0x01);
+  uint8_t raw2[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload2 = ats_unique_malloc(5);
+  memcpy(payload2.get(), raw2, 5);
+
+  QUICStreamFrame streamFrame2(std::move(payload2), 5, 0x01, 0x01);
   streamFrame2.store(buf, &len);
   CHECK(len == 11);
   CHECK(memcmp(buf, expected2, len) == 0);
@@ -145,7 +157,11 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                   // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data
   };
-  QUICStreamFrame streamFrame3(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x01, 0x010000);
+  uint8_t raw3[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload3 = ats_unique_malloc(5);
+  memcpy(payload3.get(), raw3, 5);
+
+  QUICStreamFrame streamFrame3(std::move(payload3), 5, 0x01, 0x010000);
   streamFrame3.store(buf, &len);
   CHECK(len == 13);
   CHECK(memcmp(buf, expected3, len) == 0);
@@ -158,7 +174,11 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                                     // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05,                   // Stream Data
   };
-  QUICStreamFrame streamFrame4(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x01, 0x0100000000);
+  uint8_t raw4[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload4 = ats_unique_malloc(5);
+  memcpy(payload4.get(), raw4, 5);
+
+  QUICStreamFrame streamFrame4(std::move(payload4), 5, 0x01, 0x0100000000);
   streamFrame4.store(buf, &len);
   CHECK(len == 17);
   CHECK(memcmp(buf, expected4, len) == 0);
@@ -171,7 +191,11 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                                     // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05,                   // Stream Data
   };
-  QUICStreamFrame streamFrame5(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x0100, 0x0100000000);
+  uint8_t raw5[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload5 = ats_unique_malloc(5);
+  memcpy(payload5.get(), raw5, 5);
+
+  QUICStreamFrame streamFrame5(std::move(payload5), 5, 0x0100, 0x0100000000);
   streamFrame5.store(buf, &len);
   CHECK(len == 18);
   CHECK(memcmp(buf, expected5, len) == 0);
@@ -184,7 +208,11 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                                     // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05,                   // Stream Data
   };
-  QUICStreamFrame streamFrame6(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x010000, 0x0100000000);
+  uint8_t raw6[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload6 = ats_unique_malloc(5);
+  memcpy(payload6.get(), raw6, 5);
+
+  QUICStreamFrame streamFrame6(std::move(payload6), 5, 0x010000, 0x0100000000);
   streamFrame6.store(buf, &len);
   CHECK(len == 19);
   CHECK(memcmp(buf, expected6, len) == 0);
@@ -197,7 +225,11 @@ TEST_CASE("Store STREAM Frame", "[quic]")
     0x00, 0x05,                                     // Data Length
     0x01, 0x02, 0x03, 0x04, 0x05,                   // Stream Data
   };
-  QUICStreamFrame streamFrame7(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05"), 5, 0x01000000, 0x0100000000);
+  uint8_t raw7[]          = "\x01\x02\x03\x04\x05";
+  ats_unique_buf payload7 = ats_unique_malloc(5);
+  memcpy(payload7.get(), raw7, 5);
+
+  QUICStreamFrame streamFrame7(std::move(payload7), 5, 0x01000000, 0x0100000000);
   streamFrame7.store(buf, &len);
   CHECK(len == 20);
   CHECK(memcmp(buf, expected7, len) == 0);
diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc
index 8573dce..215303f 100644
--- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc
+++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc
@@ -29,8 +29,11 @@
 
 TEST_CASE("QUICFrameHandler", "[quic]")
 {
-  uint8_t payload[] = {0x01};
-  QUICStreamFrame streamFrame(payload, 1, 0x03, 0);
+  uint8_t raw[]          = {0x01};
+  ats_unique_buf payload = ats_unique_malloc(1);
+  memcpy(payload.get(), raw, 1);
+
+  QUICStreamFrame streamFrame(std::move(payload), 1, 0x03, 0);
 
   auto connection           = new MockQUICConnection();
   auto streamManager        = new MockQUICStreamManager();
diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc
index 632ad91..ef523ab 100644
--- a/iocore/net/quic/test/test_QUICStream.cc
+++ b/iocore/net/quic/test/test_QUICStream.cc
@@ -26,101 +26,124 @@
 #include "quic/QUICStream.h"
 #include "quic/Mock.h"
 
-namespace
+TEST_CASE("QUICStream", "[quic]")
 {
-// Test Data
-uint8_t payload[]  = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
-uint32_t stream_id = 0x03;
-
-std::shared_ptr<QUICStreamFrame> frame_1 = std::make_shared<QUICStreamFrame>(payload, 2, stream_id, 0);
-std::shared_ptr<QUICStreamFrame> frame_2 = std::make_shared<QUICStreamFrame>(payload + 2, 2, stream_id, 2);
-std::shared_ptr<QUICStreamFrame> frame_3 = std::make_shared<QUICStreamFrame>(payload + 4, 2, stream_id, 4);
-std::shared_ptr<QUICStreamFrame> frame_4 = std::make_shared<QUICStreamFrame>(payload + 6, 2, stream_id, 6);
-std::shared_ptr<QUICStreamFrame> frame_5 = std::make_shared<QUICStreamFrame>(payload + 8, 2, stream_id, 8);
-std::shared_ptr<QUICStreamFrame> frame_6 = std::make_shared<QUICStreamFrame>(payload + 10, 2, stream_id, 10);
-std::shared_ptr<QUICStreamFrame> frame_7 = std::make_shared<QUICStreamFrame>(payload + 12, 2, stream_id, 12);
-std::shared_ptr<QUICStreamFrame> frame_8 = std::make_shared<QUICStreamFrame>(payload + 14, 2, stream_id, 14);
-
-TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]")
-{
-  MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
-  IOBufferReader *reader = read_buffer->alloc_reader();
-  MockQUICFrameTransmitter tx;
-
-  std::unique_ptr<QUICStream> stream(new QUICStream());
-  stream->init(&tx, 0, stream_id, 1024, 1024);
-  stream->do_io_read(nullptr, 0, read_buffer);
-
-  stream->recv(frame_1);
-  stream->recv(frame_2);
-  stream->recv(frame_3);
-  stream->recv(frame_4);
-  stream->recv(frame_5);
-  stream->recv(frame_6);
-  stream->recv(frame_7);
-  stream->recv(frame_8);
-
-  uint8_t buf[32];
-  int64_t len = reader->read_avail();
-  reader->read(buf, len);
-
-  CHECK(len == 16);
-  CHECK(memcmp(buf, payload, len) == 0);
-}
-
-TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]")
-{
-  MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
-  IOBufferReader *reader = read_buffer->alloc_reader();
-  MockQUICFrameTransmitter tx;
-
-  std::unique_ptr<QUICStream> stream(new QUICStream());
-  stream->init(&tx, 0, stream_id);
-  stream->do_io_read(nullptr, 0, read_buffer);
-
-  stream->recv(frame_8);
-  stream->recv(frame_7);
-  stream->recv(frame_6);
-  stream->recv(frame_5);
-  stream->recv(frame_4);
-  stream->recv(frame_3);
-  stream->recv(frame_2);
-  stream->recv(frame_1);
-
-  uint8_t buf[32];
-  int64_t len = reader->read_avail();
-  reader->read(buf, len);
-
-  CHECK(len == 16);
-  CHECK(memcmp(buf, payload, len) == 0);
-}
-
-TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]")
-{
-  MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
-  IOBufferReader *reader = read_buffer->alloc_reader();
-  MockQUICFrameTransmitter tx;
-
-  std::unique_ptr<QUICStream> stream(new QUICStream());
-  stream->init(&tx, 0, stream_id);
-  stream->do_io_read(nullptr, 0, read_buffer);
-
-  stream->recv(frame_8);
-  stream->recv(frame_7);
-  stream->recv(frame_6);
-  stream->recv(frame_7); // duplicated frame
-  stream->recv(frame_5);
-  stream->recv(frame_3);
-  stream->recv(frame_1);
-  stream->recv(frame_2);
-  stream->recv(frame_4);
-  stream->recv(frame_5); // duplicated frame
-
-  uint8_t buf[32];
-  int64_t len = reader->read_avail();
-  reader->read(buf, len);
-
-  CHECK(len == 16);
-  CHECK(memcmp(buf, payload, len) == 0);
-}
+  // Test Data
+  uint8_t payload[]  = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
+  uint32_t stream_id = 0x03;
+
+  ats_unique_buf payload1 = ats_unique_malloc(2);
+  memcpy(payload1.get(), payload, 2);
+  std::shared_ptr<QUICStreamFrame> frame_1 = std::make_shared<QUICStreamFrame>(std::move(payload1), 2, stream_id, 0);
+
+  ats_unique_buf payload2 = ats_unique_malloc(2);
+  memcpy(payload2.get(), payload + 2, 2);
+  std::shared_ptr<QUICStreamFrame> frame_2 = std::make_shared<QUICStreamFrame>(std::move(payload2), 2, stream_id, 2);
+
+  ats_unique_buf payload3 = ats_unique_malloc(2);
+  memcpy(payload3.get(), payload + 4, 2);
+  std::shared_ptr<QUICStreamFrame> frame_3 = std::make_shared<QUICStreamFrame>(std::move(payload3), 2, stream_id, 4);
+
+  ats_unique_buf payload4 = ats_unique_malloc(2);
+  memcpy(payload4.get(), payload + 6, 2);
+  std::shared_ptr<QUICStreamFrame> frame_4 = std::make_shared<QUICStreamFrame>(std::move(payload4), 2, stream_id, 6);
+
+  ats_unique_buf payload5 = ats_unique_malloc(2);
+  memcpy(payload5.get(), payload + 8, 2);
+  std::shared_ptr<QUICStreamFrame> frame_5 = std::make_shared<QUICStreamFrame>(std::move(payload5), 2, stream_id, 8);
+
+  ats_unique_buf payload6 = ats_unique_malloc(2);
+  memcpy(payload6.get(), payload + 10, 2);
+  std::shared_ptr<QUICStreamFrame> frame_6 = std::make_shared<QUICStreamFrame>(std::move(payload6), 2, stream_id, 10);
+
+  ats_unique_buf payload7 = ats_unique_malloc(2);
+  memcpy(payload7.get(), payload + 12, 2);
+  std::shared_ptr<QUICStreamFrame> frame_7 = std::make_shared<QUICStreamFrame>(std::move(payload7), 2, stream_id, 12);
+
+  ats_unique_buf payload8 = ats_unique_malloc(2);
+  memcpy(payload8.get(), payload + 14, 2);
+  std::shared_ptr<QUICStreamFrame> frame_8 = std::make_shared<QUICStreamFrame>(std::move(payload8), 2, stream_id, 14);
+
+  SECTION("QUICStream_assembling_byte_stream_1")
+  {
+    MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
+    IOBufferReader *reader = read_buffer->alloc_reader();
+    MockQUICFrameTransmitter tx;
+
+    std::unique_ptr<QUICStream> stream(new QUICStream());
+    stream->init(&tx, 0, stream_id, 1024, 1024);
+    stream->do_io_read(nullptr, 0, read_buffer);
+
+    stream->recv(frame_1);
+    stream->recv(frame_2);
+    stream->recv(frame_3);
+    stream->recv(frame_4);
+    stream->recv(frame_5);
+    stream->recv(frame_6);
+    stream->recv(frame_7);
+    stream->recv(frame_8);
+
+    uint8_t buf[32];
+    int64_t len = reader->read_avail();
+    reader->read(buf, len);
+
+    CHECK(len == 16);
+    CHECK(memcmp(buf, payload, len) == 0);
+  }
+
+  SECTION("QUICStream_assembling_byte_stream_2")
+  {
+    MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
+    IOBufferReader *reader = read_buffer->alloc_reader();
+    MockQUICFrameTransmitter tx;
+
+    std::unique_ptr<QUICStream> stream(new QUICStream());
+    stream->init(&tx, 0, stream_id);
+    stream->do_io_read(nullptr, 0, read_buffer);
+
+    stream->recv(frame_8);
+    stream->recv(frame_7);
+    stream->recv(frame_6);
+    stream->recv(frame_5);
+    stream->recv(frame_4);
+    stream->recv(frame_3);
+    stream->recv(frame_2);
+    stream->recv(frame_1);
+
+    uint8_t buf[32];
+    int64_t len = reader->read_avail();
+    reader->read(buf, len);
+
+    CHECK(len == 16);
+    CHECK(memcmp(buf, payload, len) == 0);
+  }
+
+  SECTION("QUICStream_assembling_byte_stream_3")
+  {
+    MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K);
+    IOBufferReader *reader = read_buffer->alloc_reader();
+    MockQUICFrameTransmitter tx;
+
+    std::unique_ptr<QUICStream> stream(new QUICStream());
+    stream->init(&tx, 0, stream_id);
+    stream->do_io_read(nullptr, 0, read_buffer);
+
+    stream->recv(frame_8);
+    stream->recv(frame_7);
+    stream->recv(frame_6);
+    stream->recv(frame_7); // duplicated frame
+    stream->recv(frame_5);
+    stream->recv(frame_3);
+    stream->recv(frame_1);
+    stream->recv(frame_2);
+    stream->recv(frame_4);
+    stream->recv(frame_5); // duplicated frame
+
+    uint8_t buf[32];
+    int64_t len = reader->read_avail();
+    reader->read(buf, len);
+
+    CHECK(len == 16);
+    CHECK(memcmp(buf, payload, len) == 0);
+  }
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 01/03: add QUICInBuffer feature

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch quic-05
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 46cf6d50173562002642278d0c6d9cb0886f3cbe
Author: scw00 <sc...@apache.org>
AuthorDate: Tue Oct 10 08:19:00 2017 +0800

    add QUICInBuffer feature
    
    (cherry picked from commit 2f5caad25df450b16f9458c7119a421652f6ddb5)
---
 iocore/net/quic/Makefile.am                        |   3 +-
 iocore/net/quic/QUICIncomingFrameBuffer.cc         | 135 ++++++++++++++++
 iocore/net/quic/QUICIncomingFrameBuffer.h          |  58 +++++++
 iocore/net/quic/QUICStream.cc                      |  36 ++---
 iocore/net/quic/QUICStream.h                       |   7 +-
 iocore/net/quic/test/Makefile.am                   |  35 +++-
 .../net/quic/test/test_QUICIncomingFrameBuffer.cc  | 177 +++++++++++++++++++++
 7 files changed, 421 insertions(+), 30 deletions(-)

diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am
index 90ba2fe..3fc2585 100644
--- a/iocore/net/quic/Makefile.am
+++ b/iocore/net/quic/Makefile.am
@@ -61,7 +61,8 @@ libquic_a_SOURCES = \
   QUICConfig.cc \
   QUICDebugNames.cc \
   QUICApplication.cc \
-  QUICApplicationMap.cc
+  QUICApplicationMap.cc \
+  QUICIncomingFrameBuffer.cc
 
 include $(top_srcdir)/build/tidy.mk
 
diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc
new file mode 100644
index 0000000..e769054
--- /dev/null
+++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc
@@ -0,0 +1,135 @@
+/** @file
+ *
+ *  A brief file description
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "QUICIncomingFrameBuffer.h"
+
+QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer()
+{
+  this->_out_of_order_queue.clear();
+
+  while (!this->_recv_buffer.empty()) {
+    this->_recv_buffer.pop();
+  }
+}
+
+std::shared_ptr<const QUICStreamFrame>
+QUICIncomingFrameBuffer::pop()
+{
+  if (this->_recv_buffer.empty()) {
+    auto frame = this->_out_of_order_queue.find(this->_recv_offset);
+    while (frame != this->_out_of_order_queue.end()) {
+      this->_recv_buffer.push(frame->second);
+      this->_recv_offset += frame->second->data_length();
+      this->_out_of_order_queue.erase(frame);
+      frame = this->_out_of_order_queue.find(this->_recv_offset);
+    }
+  }
+
+  if (!this->_recv_buffer.empty()) {
+    auto frame = this->_recv_buffer.front();
+    this->_recv_buffer.pop();
+    return frame;
+  }
+  return nullptr;
+}
+
+QUICErrorUPtr
+QUICIncomingFrameBuffer::insert(const std::shared_ptr<const QUICStreamFrame> frame)
+{
+  QUICOffset offset = frame->offset();
+  size_t len        = frame->data_length();
+
+  QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, frame->has_fin_flag());
+  if (err->cls != QUICErrorClass::NONE) {
+    return err;
+  }
+
+  if (this->_recv_offset > offset) {
+    // dup frame;
+    return QUICErrorUPtr(new QUICNoError());
+  } else if (this->_recv_offset == offset) {
+    this->_recv_offset = offset + len;
+    this->_recv_buffer.push(frame);
+  } else {
+    this->_out_of_order_queue.insert(std::make_pair(offset, frame));
+  }
+
+  return QUICErrorUPtr(new QUICNoError());
+}
+
+void
+QUICIncomingFrameBuffer::clear()
+{
+  this->_out_of_order_queue.clear();
+
+  while (!this->_recv_buffer.empty()) {
+    this->_recv_buffer.pop();
+  }
+
+  this->_fin_offset  = UINT64_MAX;
+  this->_max_offset  = 0;
+  this->_recv_offset = 0;
+}
+
+bool
+QUICIncomingFrameBuffer::empty()
+{
+  return this->_out_of_order_queue.empty() && this->_recv_buffer.empty();
+}
+
+QUICErrorUPtr
+QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag)
+{
+  // stream with fin flag {11.3. Stream Final Offset}
+  // Once a final offset for a stream is known, it cannot change.
+  // If a RST_STREAM or STREAM frame causes the final offset to change for a stream,
+  // an endpoint SHOULD respond with a FINAL_OFFSET_ERROR error (see Section 12).
+  // A receiver SHOULD treat receipt of data at or beyond the final offset as a
+  // FINAL_OFFSET_ERROR error, even after a stream is closed.
+
+  // {11.3. Stream Final Offset}
+  // A receiver SHOULD treat receipt of data at or beyond the final offset as a
+  // FINAL_OFFSET_ERROR error, even after a stream is closed.
+  if (fin_flag) {
+    if (this->_fin_offset != UINT64_MAX) {
+      if (this->_fin_offset == offset) {
+        // dup fin frame
+        return QUICErrorUPtr(new QUICNoError());
+      }
+      return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR));
+    }
+
+    this->_fin_offset = offset;
+
+    if (this->_max_offset >= this->_fin_offset) {
+      return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR));
+    }
+
+  } else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) {
+    return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR));
+  }
+
+  this->_max_offset = std::max(offset, this->_max_offset);
+
+  return QUICErrorUPtr(new QUICNoError());
+}
diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h
new file mode 100644
index 0000000..ab79a44
--- /dev/null
+++ b/iocore/net/quic/QUICIncomingFrameBuffer.h
@@ -0,0 +1,58 @@
+/** @file
+ *
+ *  A brief file description
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <queue>
+
+#include "QUICTypes.h"
+#include "QUICFrame.h"
+
+class QUICIncomingFrameBuffer
+{
+public:
+  QUICIncomingFrameBuffer(QUICStream *stream) : _stream(stream) {}
+
+  ~QUICIncomingFrameBuffer();
+
+  std::shared_ptr<const QUICStreamFrame> pop();
+
+  QUICErrorUPtr insert(const std::shared_ptr<const QUICStreamFrame>);
+
+  void clear();
+
+  bool empty();
+
+private:
+  QUICOffset _recv_offset = 0;
+  QUICOffset _max_offset  = 0;
+  QUICOffset _fin_offset  = UINT64_MAX;
+
+  QUICErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false);
+
+  std::queue<std::shared_ptr<const QUICStreamFrame>> _recv_buffer;
+  std::map<QUICOffset, std::shared_ptr<const QUICStreamFrame>> _out_of_order_queue;
+
+  QUICStream *_stream = nullptr;
+};
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 7a7bbdc..f0ec0ff 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -273,25 +273,14 @@ QUICStream::_write_to_read_vio(const std::shared_ptr<const QUICStreamFrame> &fra
 
   int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length());
   this->_read_vio.nbytes += bytes_added;
-  this->_recv_offset += frame->data_length();
-  this->_local_flow_controller->forward_limit(this->_recv_offset + this->_flow_control_buffer_size);
+  // frame->offset() + frame->data_length() == this->_recv_offset
+  this->_local_flow_controller->forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size);
   DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(),
                     this->_local_flow_controller->current_limit());
 
   this->_state.update_with_received_frame(*frame);
 }
 
-void
-QUICStream::_reorder_data()
-{
-  auto frame = _received_stream_frame_buffer.find(this->_recv_offset);
-  while (frame != this->_received_stream_frame_buffer.end()) {
-    this->_write_to_read_vio(frame->second);
-    this->_received_stream_frame_buffer.erase(frame);
-    frame = _received_stream_frame_buffer.find(this->_recv_offset);
-  }
-}
-
 /**
  * @brief Receive STREAM frame
  * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio.
@@ -317,17 +306,16 @@ QUICStream::recv(const std::shared_ptr<const QUICStreamFrame> frame)
     return error;
   }
 
-  // Reordering - Some frames may be delayed or be dropped
-  if (this->_recv_offset > frame->offset()) {
-    // Do nothing. Just ignore STREAM frame.
-    return QUICErrorUPtr(new QUICNoError());
-  } else if (this->_recv_offset == frame->offset()) {
-    this->_write_to_read_vio(frame);
-    this->_reorder_data();
-  } else {
-    // NOTE: push fragments in _received_stream_frame_buffer temporally.
-    // They will be reordered when missing data is filled and offset is matched.
-    this->_received_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame));
+  error = this->_received_stream_frame_buffer.insert(frame);
+  if (error->cls != QUICErrorClass::NONE) {
+    this->_received_stream_frame_buffer.clear();
+    return error;
+  }
+
+  auto new_frame = this->_received_stream_frame_buffer.pop();
+  while (new_frame != nullptr) {
+    this->_write_to_read_vio(new_frame);
+    new_frame = this->_received_stream_frame_buffer.pop();
   }
 
   return QUICErrorUPtr(new QUICNoError());
diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h
index b1d0765..282b434 100644
--- a/iocore/net/quic/QUICStream.h
+++ b/iocore/net/quic/QUICStream.h
@@ -31,6 +31,7 @@
 #include "QUICFrame.h"
 #include "QUICStreamState.h"
 #include "QUICFlowController.h"
+#include "QUICIncomingFrameBuffer.h"
 
 class QUICNetVConnection;
 class QUICFrameTransmitter;
@@ -44,7 +45,7 @@ class QUICStreamManager;
 class QUICStream : public VConnection
 {
 public:
-  QUICStream() : VConnection(nullptr) {}
+  QUICStream() : VConnection(nullptr), _received_stream_frame_buffer(this) {}
   ~QUICStream() {}
   void init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId id, uint64_t recv_max_stream_data = 0,
             uint64_t send_max_stream_data = 0);
@@ -82,7 +83,6 @@ private:
   QUICErrorUPtr _send();
 
   void _write_to_read_vio(const std::shared_ptr<const QUICStreamFrame> &);
-  void _reorder_data();
   // NOTE: Those are called update_read_request/update_write_request in Http2Stream
   // void _read_from_net(uint64_t read_len, bool direct);
   // void _write_to_net(IOBufferReader *buf_reader, int64_t write_len, bool direct);
@@ -95,7 +95,6 @@ private:
   bool _fin                       = false;
   QUICConnectionId _connection_id = 0;
   QUICStreamId _id                = 0;
-  QUICOffset _recv_offset         = 0;
   QUICOffset _send_offset         = 0;
 
   QUICRemoteStreamFlowController *_remote_flow_controller = nullptr;
@@ -110,7 +109,7 @@ private:
 
   // Fragments of received STREAM frame (offset is unmatched)
   // TODO: Consider to replace with ts/RbTree.h or other data structure
-  std::map<QUICOffset, std::shared_ptr<const QUICStreamFrame>> _received_stream_frame_buffer;
+  QUICIncomingFrameBuffer _received_stream_frame_buffer;
 
   QUICStreamManager *_stream_manager = nullptr;
   QUICFrameTransmitter *_tx          = nullptr;
diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am
index 487e532..e25eced 100644
--- a/iocore/net/quic/test/Makefile.am
+++ b/iocore/net/quic/test/Makefile.am
@@ -31,7 +31,8 @@ check_PROGRAMS = \
   test_QUICTypeUtil \
   test_QUICAckFrameCreator \
   test_QUICVersionNegotiator \
-  test_QUICFlowController
+  test_QUICFlowController \
+  test_QUICIncomingFrameBuffer
 
 
 AM_CPPFLAGS += \
@@ -220,6 +221,7 @@ test_QUICStream_SOURCES = \
   event_processor_main.cc \
   test_QUICStream.cc \
   ../QUICStream.cc \
+  ../QUICIncomingFrameBuffer.cc \
   ../QUICFrameDispatcher.cc \
   ../QUICStreamManager.cc \
   ../QUICApplicationMap.cc \
@@ -489,6 +491,37 @@ test_QUICFlowController_SOURCES = \
   $(QUICCrypto_impl) \
   ../QUICFrame.cc
 
+#
+# test_QUICIncomingFrameBuffer
+#
+test_QUICIncomingFrameBuffer_CPPFLAGS = \
+  $(AM_CPPFLAGS)
+
+test_QUICIncomingFrameBuffer_LDFLAGS = \
+  @AM_LDFLAGS@
+
+test_QUICIncomingFrameBuffer_SOURCES = \
+  event_processor_main.cc \
+  ../QUICStream.cc \
+  ../QUICFrameDispatcher.cc \
+  ../QUICStreamManager.cc \
+  ../QUICApplicationMap.cc \
+  ../QUICCongestionController.cc \
+  ../../SSLNextProtocolSet.cc \
+  ../QUICIncomingFrameBuffer.cc \
+  test_QUICIncomingFrameBuffer.cc
+
+test_QUICIncomingFrameBuffer_LDADD = \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  $(top_builddir)/iocore/eventsystem/libinkevent.a \
+  $(top_builddir)/iocore/net/quic/libquic.a \
+  $(top_builddir)/lib/records/librecords_p.a \
+  $(top_builddir)/mgmt/libmgmt_p.la \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  $(top_builddir)/proxy/shared/libUglyLogStubs.a \
+  @LIBTCL@ \
+  @HWLOC_LIBS@
+
 include $(top_srcdir)/build/tidy.mk
 
 tidy-local: $(DIST_SOURCES)
diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
new file mode 100644
index 0000000..844607a
--- /dev/null
+++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
@@ -0,0 +1,177 @@
+/** @file
+ *
+ *  A brief file description
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "catch.hpp"
+
+#include "quic/QUICIncomingFrameBuffer.h"
+#include "quic/QUICStream.h"
+#include <memory>
+
+TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]")
+{
+  QUICStream *stream = new QUICStream();
+  QUICIncomingFrameBuffer buffer(stream);
+  QUICErrorUPtr err = nullptr;
+
+  uint8_t data[1024] = {0};
+
+  std::shared_ptr<QUICStreamFrame> stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072, true);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096);
+
+  buffer.insert(stream1_frame_0_r);
+  buffer.insert(stream1_frame_1_r);
+  buffer.insert(stream1_frame_2_r);
+  err = buffer.insert(stream1_frame_3_r);
+  CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR);
+
+  QUICIncomingFrameBuffer buffer2(stream);
+
+  buffer2.insert(stream1_frame_3_r);
+  buffer2.insert(stream1_frame_0_r);
+  buffer2.insert(stream1_frame_1_r);
+  err = buffer2.insert(stream1_frame_2_r);
+  CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR);
+
+  QUICIncomingFrameBuffer buffer3(stream);
+
+  buffer3.insert(stream1_frame_4_r);
+  err = buffer3.insert(stream1_frame_3_r);
+  CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR);
+
+  delete stream;
+}
+
+TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]")
+{
+  QUICStream *stream = new QUICStream();
+  QUICIncomingFrameBuffer buffer(stream);
+  QUICErrorUPtr err = nullptr;
+
+  uint8_t data[1024] = {0};
+
+  std::shared_ptr<QUICStreamFrame> stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096, true);
+
+  buffer.insert(stream1_frame_0_r);
+  buffer.insert(stream1_frame_1_r);
+  buffer.insert(stream1_frame_2_r);
+  buffer.insert(stream1_frame_3_r);
+  buffer.insert(stream1_frame_4_r);
+  CHECK(!buffer.empty());
+
+  auto frame = buffer.pop();
+  CHECK(frame->offset() == 0);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 1024);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 2048);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 3072);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 4096);
+  CHECK(buffer.empty());
+
+  buffer.clear();
+
+  buffer.insert(stream1_frame_4_r);
+  buffer.insert(stream1_frame_3_r);
+  buffer.insert(stream1_frame_2_r);
+  buffer.insert(stream1_frame_1_r);
+  buffer.insert(stream1_frame_0_r);
+  CHECK(!buffer.empty());
+
+  frame = buffer.pop();
+  CHECK(frame->offset() == 0);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 1024);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 2048);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 3072);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 4096);
+  CHECK(buffer.empty());
+
+  delete stream;
+}
+
+TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]")
+{
+  QUICStream *stream = new QUICStream();
+  QUICIncomingFrameBuffer buffer(stream);
+  QUICErrorUPtr err = nullptr;
+
+  uint8_t data[1024] = {0};
+
+  std::shared_ptr<QUICStreamFrame> stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true);
+  std::shared_ptr<QUICStreamFrame> stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true);
+
+  buffer.insert(stream1_frame_0_r);
+  buffer.insert(stream1_frame_1_r);
+  buffer.insert(stream1_frame_2_r);
+  err = buffer.insert(stream1_frame_3_r);
+  CHECK(err->cls == QUICErrorClass::NONE);
+
+  auto frame = buffer.pop();
+  CHECK(frame->offset() == 0);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 1024);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 2048);
+  frame = buffer.pop();
+  CHECK(frame == nullptr);
+  CHECK(buffer.empty());
+
+  buffer.clear();
+
+  std::shared_ptr<QUICStreamFrame> stream2_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0);
+  std::shared_ptr<QUICStreamFrame> stream2_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024);
+  std::shared_ptr<QUICStreamFrame> stream2_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024);
+  std::shared_ptr<QUICStreamFrame> stream2_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true);
+
+  buffer.insert(stream2_frame_0_r);
+  buffer.insert(stream2_frame_1_r);
+  buffer.insert(stream2_frame_2_r);
+  err = buffer.insert(stream2_frame_3_r);
+  CHECK(err->cls == QUICErrorClass::NONE);
+
+  frame = buffer.pop();
+  CHECK(frame->offset() == 0);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 1024);
+  frame = buffer.pop();
+  CHECK(frame->offset() == 2048);
+  frame = buffer.pop();
+  CHECK(frame == nullptr);
+  CHECK(buffer.empty());
+
+  delete stream;
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.