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

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


The following commit(s) were added to refs/heads/quic-latest by this push:
     new 3454522  [draft-13] Add Frame Type field in CONNECTION_CLOSE frame
3454522 is described below

commit 34545229747c748d2b79d44353f1ced3e2a7a769
Author: Masaori Koshiba <[email protected]>
AuthorDate: Fri Aug 3 09:34:15 2018 +0900

    [draft-13] Add Frame Type field in CONNECTION_CLOSE frame
---
 iocore/net/quic/QUICFrame.cc           | 107 ++++++++++++++++++++++++++++-----
 iocore/net/quic/QUICFrame.h            |  13 +++-
 iocore/net/quic/QUICTypes.cc           |   7 +++
 iocore/net/quic/QUICTypes.h            |   9 ++-
 iocore/net/quic/test/test_QUICFrame.cc |  68 ++++++++++++---------
 5 files changed, 154 insertions(+), 50 deletions(-)

diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index f0c47bf..2b3f669 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -22,6 +22,9 @@
  */
 
 #include "QUICFrame.h"
+
+#include <algorithm>
+
 #include "QUICStream.h"
 #include "QUICIntUtil.h"
 #include "QUICDebugNames.h"
@@ -1211,19 +1214,21 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, 
size_t limit) const
 //
 // CONNECTION_CLOSE frame
 //
-QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode 
error_code, uint64_t reason_phrase_length,
-                                                   const char *reason_phrase, 
bool protection)
-  : QUICFrame(protection)
+QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode 
error_code, QUICFrameType frame_type,
+                                                   uint64_t 
reason_phrase_length, const char *reason_phrase, bool protection)
+  : QUICFrame(protection),
+    _error_code(error_code),
+    _frame_type(frame_type),
+    _reason_phrase_length(reason_phrase_length),
+    _reason_phrase(reason_phrase)
 {
-  this->_error_code           = error_code;
-  this->_reason_phrase_length = reason_phrase_length;
-  this->_reason_phrase        = reason_phrase;
 }
 
 QUICFrameUPtr
 QUICConnectionCloseFrame::clone() const
 {
-  return QUICFrameFactory::create_connection_close_frame(this->error_code(), 
this->reason_phrase_length(), this->reason_phrase());
+  return QUICFrameFactory::create_connection_close_frame(this->error_code(), 
this->frame_type(), this->reason_phrase_length(),
+                                                         
this->reason_phrase());
 }
 
 QUICFrameType
@@ -1235,10 +1240,16 @@ QUICConnectionCloseFrame::type() const
 size_t
 QUICConnectionCloseFrame::size() const
 {
-  return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode) + 
this->_get_reason_phrase_length_field_length() +
+  return this->_get_reason_phrase_length_field_offset() + 
this->_get_reason_phrase_length_field_length() +
          this->reason_phrase_length();
 }
 
+/**
+   Store CONNECTION_CLOSE frame in buffer.
+
+   PADDING frame in Frame Type field means frame type that triggered the error 
is unknown.
+   When `_frame_type` is QUICFrameType::UNKNOWN, it's converted to 
QUICFrameType::PADDING (0x0).
+ */
 size_t
 QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const
 {
@@ -1254,10 +1265,24 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t 
*len, size_t limit) const
     uint8_t *p = buf;
     *p         = static_cast<uint8_t>(QUICFrameType::CONNECTION_CLOSE);
     ++p;
+
+    // Error Code (16)
     QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n);
     p += n;
+
+    // Frame Type (i)
+    QUICFrameType frame_type = this->_frame_type;
+    if (frame_type == QUICFrameType::UNKNOWN) {
+      frame_type = QUICFrameType::PADDING;
+    }
+    *p = static_cast<uint8_t>(frame_type);
+    ++p;
+
+    // Reason Phrase Length (i)
     QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n);
     p += n;
+
+    // Reason Phrase (*)
     if (this->_reason_phrase_length > 0) {
       memcpy(p, this->_reason_phrase, this->_reason_phrase_length);
       p += this->_reason_phrase_length;
@@ -1269,16 +1294,54 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t 
*len, size_t limit) const
   return *len;
 }
 
+int
+QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const
+{
+  int len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s 
frame=%s", this->size(),
+                     QUICDebugNames::error_code(this->error_code()), 
QUICDebugNames::frame_type(this->frame_type()));
+
+  if (this->reason_phrase_length() != 0) {
+    memcpy(msg + len, " reason=", 8);
+    len += 8;
+
+    int phrase_len = std::min(msg_len - len, 
static_cast<size_t>(this->reason_phrase_length()));
+    memcpy(msg + len, this->reason_phrase(), phrase_len);
+    len += phrase_len;
+  }
+
+  return len;
+}
+
 QUICTransErrorCode
 QUICConnectionCloseFrame::error_code() const
 {
   if (this->_buf) {
-    return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + 1);
+    return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + 
sizeof(QUICFrameType));
   } else {
     return this->_error_code;
   }
 }
 
+/**
+   Frame Type Field Accessor
+
+   PADDING frame in Frame Type field means frame type that triggered the error 
is unknown.
+   Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0).
+ */
+QUICFrameType
+QUICConnectionCloseFrame::frame_type() const
+{
+  if (this->_buf) {
+    QUICFrameType frame = QUICFrame::type(this->_buf + 
this->_get_frame_type_field_offset());
+    if (frame == QUICFrameType::PADDING) {
+      frame = QUICFrameType::UNKNOWN;
+    }
+    return frame;
+  } else {
+    return this->_frame_type;
+  }
+}
+
 uint64_t
 QUICConnectionCloseFrame::reason_phrase_length() const
 {
@@ -1293,19 +1356,30 @@ const char *
 QUICConnectionCloseFrame::reason_phrase() const
 {
   if (this->_buf) {
-    return reinterpret_cast<const char *>(this->_buf + 
this->_get_reason_phrase_field_offset());
+    size_t offset = this->_get_reason_phrase_field_offset();
+    if (offset > this->_len) {
+      return nullptr;
+    } else {
+      return reinterpret_cast<const char *>(this->_buf + offset);
+    }
   } else {
     return this->_reason_phrase;
   }
 }
 
 size_t
-QUICConnectionCloseFrame::_get_reason_phrase_length_field_offset() const
+QUICConnectionCloseFrame::_get_frame_type_field_offset() const
 {
   return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode);
 }
 
 size_t
+QUICConnectionCloseFrame::_get_reason_phrase_length_field_offset() const
+{
+  return this->_get_frame_type_field_offset() + sizeof(QUICFrameType);
+}
+
+size_t
 QUICConnectionCloseFrame::_get_reason_phrase_length_field_length() const
 {
   if (this->_buf) {
@@ -2533,11 +2607,11 @@ QUICFrameFactory::create_ack_frame(QUICPacketNumber 
largest_acknowledged, uint64
 }
 
 std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc>
-QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, 
uint16_t reason_phrase_length,
-                                                const char *reason_phrase)
+QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, 
QUICFrameType frame_type,
+                                                uint16_t reason_phrase_length, 
const char *reason_phrase)
 {
   QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc();
-  new (frame) QUICConnectionCloseFrame(error_code, reason_phrase_length, 
reason_phrase);
+  new (frame) QUICConnectionCloseFrame(error_code, frame_type, 
reason_phrase_length, reason_phrase);
   return std::unique_ptr<QUICConnectionCloseFrame, 
QUICFrameDeleterFunc>(frame, &QUICFrameDeleter::delete_connection_close_frame);
 }
 
@@ -2546,9 +2620,10 @@ 
QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error)
 {
   ink_assert(error->cls == QUICErrorClass::TRANSPORT);
   if (error->msg) {
-    return 
QUICFrameFactory::create_connection_close_frame(error->trans_error_code, 
strlen(error->msg), error->msg);
+    return 
QUICFrameFactory::create_connection_close_frame(error->trans_error_code, 
error->frame_type(), strlen(error->msg),
+                                                           error->msg);
   } else {
-    return 
QUICFrameFactory::create_connection_close_frame(error->trans_error_code);
+    return 
QUICFrameFactory::create_connection_close_frame(error->trans_error_code, 
error->frame_type());
   }
 }
 
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 1d5598f..d4feb26 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -350,22 +350,27 @@ class QUICConnectionCloseFrame : public QUICFrame
 public:
   QUICConnectionCloseFrame() : QUICFrame() {}
   QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = 
true) : QUICFrame(buf, len, protection) {}
-  QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t 
reason_phrase_length, const char *reason_phrase,
-                           bool protection = true);
+  QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType 
frame_type, uint64_t reason_phrase_length,
+                           const char *reason_phrase, bool protection = true);
   QUICFrameUPtr clone() const override;
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override;
+  virtual int debug_msg(char *msg, size_t msg_len) const override;
+
   QUICTransErrorCode error_code() const;
+  QUICFrameType frame_type() const;
   uint64_t reason_phrase_length() const;
   const char *reason_phrase() const;
 
 private:
+  size_t _get_frame_type_field_offset() const;
   size_t _get_reason_phrase_length_field_offset() const;
   size_t _get_reason_phrase_length_field_length() const;
   size_t _get_reason_phrase_field_offset() const;
 
   QUICTransErrorCode _error_code;
+  QUICFrameType _frame_type      = QUICFrameType::UNKNOWN;
   uint64_t _reason_phrase_length = 0;
   const char *_reason_phrase     = nullptr;
 };
@@ -929,7 +934,9 @@ public:
    * Creates a CONNECTION_CLOSE frame.
    */
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> 
create_connection_close_frame(
-    QUICTransErrorCode error_code, uint16_t reason_phrase_length = 0, const 
char *reason_phrase = nullptr);
+    QUICTransErrorCode error_code, QUICFrameType frame_type, uint16_t 
reason_phrase_length = 0,
+    const char *reason_phrase = nullptr);
+
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> 
create_connection_close_frame(
     QUICConnectionErrorUPtr error);
 
diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc
index 0577d45..4698823 100644
--- a/iocore/net/quic/QUICTypes.cc
+++ b/iocore/net/quic/QUICTypes.cc
@@ -280,6 +280,13 @@ QUICError::code()
   return static_cast<uint16_t>(this->trans_error_code);
 }
 
+QUICFrameType
+QUICConnectionError::frame_type() const
+{
+  ink_assert(this->cls != QUICErrorClass::APPLICATION);
+  return _frame_type;
+}
+
 //
 // QUICFiveTuple
 //
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index b58b007..c3f53f0 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -197,8 +197,15 @@ class QUICConnectionError : public QUICError
 {
 public:
   QUICConnectionError() : QUICError() {}
-  QUICConnectionError(const QUICTransErrorCode error_code, const char 
*error_msg = nullptr) : QUICError(error_code, error_msg){};
+  QUICConnectionError(const QUICTransErrorCode error_code, const char 
*error_msg = nullptr,
+                      QUICFrameType frame_type = QUICFrameType::UNKNOWN)
+    : QUICError(error_code, error_msg), _frame_type(frame_type){};
   QUICConnectionError(const QUICAppErrorCode error_code, const char *error_msg 
= nullptr) : QUICError(error_code, error_msg){};
+
+  QUICFrameType frame_type() const;
+
+private:
+  QUICFrameType _frame_type = QUICFrameType::UNKNOWN;
 };
 
 class QUICStream;
diff --git a/iocore/net/quic/test/test_QUICFrame.cc 
b/iocore/net/quic/test/test_QUICFrame.cc
index ad67a6f..1a8843a 100644
--- a/iocore/net/quic/test/test_QUICFrame.cc
+++ b/iocore/net/quic/test/test_QUICFrame.cc
@@ -624,82 +624,89 @@ TEST_CASE("Store Padding Frame", "[quic]")
   CHECK(memcmp(buf, expected, len) == 0);
 }
 
-TEST_CASE("Load ConnectionClose Frame", "[quic]")
+TEST_CASE("ConnectionClose Frame", "[quic]")
 {
-  SECTION("w/ reason phrase")
+  uint8_t reason_phrase[]  = {0x41, 0x42, 0x43, 0x44, 0x45};
+  size_t reason_phrase_len = sizeof(reason_phrase);
+
+  SECTION("loading w/ reason phrase")
   {
-    uint8_t buf1[] = {
+    uint8_t buf[] = {
       0x02,                        // Type
       0x00, 0x0A,                  // Error Code
+      0x00,                        // Frame Type
       0x05,                        // Reason Phrase Length
       0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE");
     };
-    std::shared_ptr<const QUICFrame> frame1 = QUICFrameFactory::create(buf1, 
sizeof(buf1));
-    CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE);
-    CHECK(frame1->size() == 9);
+
+    std::shared_ptr<const QUICFrame> frame = QUICFrameFactory::create(buf, 
sizeof(buf));
+    CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE);
+    CHECK(frame->size() == sizeof(buf));
 
     std::shared_ptr<const QUICConnectionCloseFrame> conn_close_frame =
-      std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame1);
+      std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame);
     CHECK(conn_close_frame != nullptr);
     CHECK(conn_close_frame->error_code() == 
QUICTransErrorCode::PROTOCOL_VIOLATION);
-    CHECK(conn_close_frame->reason_phrase_length() == 5);
-    CHECK(memcmp(conn_close_frame->reason_phrase(), buf1 + 4, 5) == 0);
+    CHECK(conn_close_frame->frame_type() == QUICFrameType::UNKNOWN);
+    CHECK(conn_close_frame->reason_phrase_length() == reason_phrase_len);
+    CHECK(memcmp(conn_close_frame->reason_phrase(), reason_phrase, 
reason_phrase_len) == 0);
   }
 
-  SECTION("w/o reason phrase")
+  SECTION("loading w/o reason phrase")
   {
-    uint8_t buf2[] = {
+    uint8_t buf[] = {
       0x02,       // Type
       0x00, 0x0A, // Error Code
+      0x01,       // Frame Type
       0x00,       // Reason Phrase Length
     };
-    std::shared_ptr<const QUICFrame> frame2 = QUICFrameFactory::create(buf2, 
sizeof(buf2));
-    CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE);
-    CHECK(frame2->size() == 4);
+    std::shared_ptr<const QUICFrame> frame = QUICFrameFactory::create(buf, 
sizeof(buf));
+    CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE);
+    CHECK(frame->size() == sizeof(buf));
 
     std::shared_ptr<const QUICConnectionCloseFrame> conn_close_frame =
-      std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame2);
+      std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame);
     CHECK(conn_close_frame != nullptr);
     CHECK(conn_close_frame->error_code() == 
QUICTransErrorCode::PROTOCOL_VIOLATION);
+    CHECK(conn_close_frame->frame_type() == QUICFrameType::RST_STREAM);
     CHECK(conn_close_frame->reason_phrase_length() == 0);
   }
-}
 
-TEST_CASE("Store ConnectionClose Frame", "[quic]")
-{
-  SECTION("w/ reason phrase")
+  SECTION("storing w/ reason phrase")
   {
     uint8_t buf[32];
     size_t len;
 
-    uint8_t expected1[] = {
+    uint8_t expected[] = {
       0x02,                        // Type
       0x00, 0x0A,                  // Error Code
+      0x10,                        // Frame Type
       0x05,                        // Reason Phrase Length
       0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE");
     };
-    QUICConnectionCloseFrame 
connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE");
-    CHECK(connection_close_frame.size() == 9);
+    QUICConnectionCloseFrame 
connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 
QUICFrameType::STREAM, 5, "ABCDE");
+    CHECK(connection_close_frame.size() == sizeof(expected));
 
     connection_close_frame.store(buf, &len, 32);
-    CHECK(len == 9);
-    CHECK(memcmp(buf, expected1, len) == 0);
+    CHECK(len == sizeof(expected));
+    CHECK(memcmp(buf, expected, len) == 0);
   }
 
-  SECTION("w/o reason phrase")
+  SECTION("storing w/o reason phrase")
   {
     uint8_t buf[32];
     size_t len;
 
-    uint8_t expected2[] = {
+    uint8_t expected[] = {
       0x02,       // Type
       0x00, 0x0A, // Error Code
+      0x00,       // Frame Type
       0x00,       // Reason Phrase Length
     };
-    QUICConnectionCloseFrame 
connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr);
+    QUICConnectionCloseFrame 
connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 
QUICFrameType::UNKNOWN, 0, nullptr);
     connection_close_frame.store(buf, &len, 32);
-    CHECK(len == 4);
-    CHECK(memcmp(buf, expected2, len) == 0);
+    CHECK(len == sizeof(expected));
+    CHECK(memcmp(buf, expected, len) == 0);
   }
 }
 
@@ -1367,6 +1374,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]")
     uint8_t frame_buf[] = {
       0x02,                        // Type
       0x00, 0x0A,                  // Error Code
+      0x00,                        // Frame Type
       0x05,                        // Reason Phrase Length
       0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE");
     };
@@ -1378,7 +1386,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]")
     size_t len;
     frame->store(buf, &len, 32);
 
-    CHECK(len == 9);
+    CHECK(len == sizeof(frame_buf));
     CHECK(memcmp(buf, frame_buf, len) == 0);
   }
 

Reply via email to