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);
}