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/11/15 05:16:05 UTC

[trafficserver] branch quic-latest updated: Add APPLICATION_CLOSE frame and change Error Code

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 f04b6b5  Add APPLICATION_CLOSE frame and change Error Code
f04b6b5 is described below

commit f04b6b5939cd3f59e0a0de4bbd7302112bdcf8cc
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Wed Nov 15 14:15:40 2017 +0900

    Add APPLICATION_CLOSE frame and change Error Code
---
 iocore/net/QUICNetVConnection.cc                   |  29 ++--
 iocore/net/quic/QUICDebugNames.cc                  |  54 +++-----
 iocore/net/quic/QUICDebugNames.h                   |   2 +-
 iocore/net/quic/QUICFlowController.cc              |   2 +-
 iocore/net/quic/QUICFrame.cc                       | 152 +++++++++++++++++----
 iocore/net/quic/QUICFrame.h                        |  66 +++++++--
 iocore/net/quic/QUICHandshake.cc                   |  17 +--
 iocore/net/quic/QUICIncomingFrameBuffer.cc         |   6 +-
 iocore/net/quic/QUICStream.cc                      |  12 +-
 iocore/net/quic/QUICStreamManager.cc               |   8 +-
 iocore/net/quic/QUICTypes.cc                       |  28 +++-
 iocore/net/quic/QUICTypes.h                        |  67 +++++----
 iocore/net/quic/test/test_QUICFlowController.cc    |   6 +-
 iocore/net/quic/test/test_QUICFrame.cc             | 134 +++++++++++++-----
 .../net/quic/test/test_QUICIncomingFrameBuffer.cc  |   6 +-
 iocore/net/quic/test/test_QUICStream.cc            |   3 +-
 iocore/net/quic/test/test_QUICStreamManager.cc     |   3 +-
 iocore/net/quic/test/test_QUICStreamState.cc       |   8 +-
 18 files changed, 416 insertions(+), 187 deletions(-)

diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 7a4c457..29833c6 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -301,7 +301,11 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error)
   } else {
     DebugQUICCon("Enter state_connection_closing");
     SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing);
-    this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error)));
+    if (error->cls == QUICErrorClass::APPLICATION) {
+      this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error)));
+    } else {
+      this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error)));
+    }
   }
 }
 
@@ -403,7 +407,7 @@ QUICNetVConnection::state_handshake(int event, Event *data)
       this_ethread()->schedule_imm_local(this, event);
       break;
     default:
-      error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR));
+      error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
       break;
     }
 
@@ -450,8 +454,7 @@ QUICNetVConnection::state_handshake(int event, Event *data)
 
     Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len);
     if (endpoint == nullptr) {
-      this->_handle_error(
-        QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::VERSION_NEGOTIATION_ERROR)));
+      this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR)));
     } else {
       endpoint->handleEvent(NET_EVENT_ACCEPT, this);
     }
@@ -489,7 +492,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data)
   }
 
   if (error->cls != QUICErrorClass::NONE) {
-    DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->code));
+    DebugQUICCon("QUICError: cls=%u, code=0x%" PRIu16, static_cast<unsigned int>(error->cls), error->code());
     this->_handle_error(std::move(error));
   }
 
@@ -708,8 +711,8 @@ QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr
                  packet->header_size(), plain_txt_len);
     return this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number());
   } else {
-    DebugQUICCon("CRYPTOGRAPHIC Error");
-    return QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::CRYPTOGRAPHIC_ERROR));
+    DebugQUICCon("Decrypt Error");
+    return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
   }
 }
 
@@ -732,7 +735,7 @@ QUICNetVConnection::_state_common_receive_packet()
     // FIXME Just ignore for now but it has to be acked (GitHub#2609)
     break;
   default:
-    error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR));
+    error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
     break;
   }
   return error;
@@ -941,8 +944,14 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptr<const QUICTr
 void
 QUICNetVConnection::_handle_error(QUICErrorUPtr error)
 {
-  DebugQUICCon("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast<unsigned int>(error->cls),
-               QUICDebugNames::error_code(error->code), static_cast<unsigned int>(error->code));
+  if (error->cls == QUICErrorClass::APPLICATION) {
+    DebugQUICCon("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls),
+                 static_cast<unsigned int>(error->cls), error->code());
+  } else {
+    DebugQUICCon("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls),
+                 static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->trans_error_code), error->code());
+  }
+
   if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
     // Stream Error
     QUICStreamError *serror = static_cast<QUICStreamError *>(error.release());
diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc
index 5526d2d..7e4fd44 100644
--- a/iocore/net/quic/QUICDebugNames.cc
+++ b/iocore/net/quic/QUICDebugNames.cc
@@ -94,58 +94,48 @@ QUICDebugNames::error_class(QUICErrorClass cls)
   switch (cls) {
   case QUICErrorClass::NONE:
     return "NONE";
-  case QUICErrorClass::AQPPLICATION_SPECIFIC:
-    return "AQPPLICATION_SPECIFIC";
-  case QUICErrorClass::HOST_LOCAL:
-    return "HOST_LOCAL";
-  case QUICErrorClass::QUIC_TRANSPORT:
-    return "QUIC_TRANSPORT";
-  case QUICErrorClass::CRYPTOGRAPHIC:
-    return "CRYPTOGRAPHIC";
+  case QUICErrorClass::TRANSPORT:
+    return "TRANSPORT";
+  case QUICErrorClass::APPLICATION:
+    return "APPLICATION";
   default:
     return "UNKNOWN";
   }
 }
 
 const char *
-QUICDebugNames::error_code(QUICErrorCode code)
+QUICDebugNames::error_code(QUICTransErrorCode code)
 {
   switch (code) {
-  case QUICErrorCode::APPLICATION_SPECIFIC_ERROR:
-    return "APPLICATION_SPECIFIC_ERROR";
-  case QUICErrorCode::HOST_LOCAL_ERROR:
-    return "HOST_LOCAL_ERROR";
-  case QUICErrorCode::NO_ERROR:
+  case QUICTransErrorCode::NO_ERROR:
     return "NO_ERROR";
-  case QUICErrorCode::INTERNAL_ERROR:
+  case QUICTransErrorCode::INTERNAL_ERROR:
     return "INTERNAL_ERROR";
-  case QUICErrorCode::CANCELLED:
-    return "CANCELLED";
-  case QUICErrorCode::FLOW_CONTROL_ERROR:
+  case QUICTransErrorCode::FLOW_CONTROL_ERROR:
     return "FLOW_CONTROL_ERROR";
-  case QUICErrorCode::STREAM_ID_ERROR:
+  case QUICTransErrorCode::STREAM_ID_ERROR:
     return "STREAM_ID_ERROR";
-  case QUICErrorCode::STREAM_STATE_ERROR:
+  case QUICTransErrorCode::STREAM_STATE_ERROR:
     return "STREAM_STATE_ERROR";
-  case QUICErrorCode::FINAL_OFFSET_ERROR:
+  case QUICTransErrorCode::FINAL_OFFSET_ERROR:
     return "FINAL_OFFSET_ERROR";
-  case QUICErrorCode::FRAME_FORMAT_ERROR:
+  case QUICTransErrorCode::FRAME_FORMAT_ERROR:
     return "FRAME_FORMAT_ERROR";
-  case QUICErrorCode::TRANSPORT_PARAMETER_ERROR:
+  case QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR:
     return "TRANSPORT_PARAMETER_ERROR";
-  case QUICErrorCode::VERSION_NEGOTIATION_ERROR:
+  case QUICTransErrorCode::VERSION_NEGOTIATION_ERROR:
     return "VERSION_NEGOTIATION_ERROR";
-  case QUICErrorCode::PROTOCOL_VIOLATION:
+  case QUICTransErrorCode::PROTOCOL_VIOLATION:
     return "PROTOCOL_VIOLATION";
-  case QUICErrorCode::QUIC_RECEIVED_RST:
-    return "QUIC_RECEIVED_RST";
-  case QUICErrorCode::CRYPTOGRAPHIC_ERROR:
-    return "CRYPTOGRAPHIC_ERROR";
-  case QUICErrorCode::TLS_HANDSHAKE_FAILED:
+  case QUICTransErrorCode::TLS_HANDSHAKE_FAILED:
     return "TLS_HANDSHAKE_FAILED";
+  case QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED:
+    return "TLS_FATAL_ALERT_GENERATED";
+  case QUICTransErrorCode::TLS_FATAL_ALERT_RECEIVED:
+    return "TLS_FATAL_ALERT_RECEIVED";
   default:
-    if ((static_cast<uint32_t>(code) & 0xFFFFFF00) == static_cast<uint32_t>(QUICErrorCode::FRAME_ERROR)) {
-      // TODO: Add frame type
+    if (0x0100 <= static_cast<uint16_t>(code) && static_cast<uint16_t>(code) <= 0x01FF) {
+      // TODO: Add frame types
       return "FRAME_ERROR";
     }
     return "UNKNOWN";
diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h
index 7b406d4..8ccac29 100644
--- a/iocore/net/quic/QUICDebugNames.h
+++ b/iocore/net/quic/QUICDebugNames.h
@@ -34,7 +34,7 @@ public:
   static const char *packet_type(QUICPacketType type);
   static const char *frame_type(QUICFrameType type);
   static const char *error_class(QUICErrorClass cls);
-  static const char *error_code(QUICErrorCode code);
+  static const char *error_code(QUICTransErrorCode code);
   static const char *transport_parameter_id(QUICTransportParameterId id);
   static const char *stream_state(QUICStreamState state);
   static const char *quic_event(int event);
diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc
index 18deeea..6c497aa 100644
--- a/iocore/net/quic/QUICFlowController.cc
+++ b/iocore/net/quic/QUICFlowController.cc
@@ -46,7 +46,7 @@ QUICFlowController::update(QUICOffset offset)
   if (this->_offset <= offset) {
     // Assume flow control is not initialized if the limit was 0
     if (this->_limit != 0 && offset > this->_limit) {
-      return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FLOW_CONTROL_ERROR));
+      return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR));
     }
     this->_offset = offset;
   }
diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 4bb02b4..4fb864b 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -29,6 +29,7 @@ ClassAllocator<QUICAckFrame> quicAckFrameAllocator("quicAckFrameAllocator");
 ClassAllocator<QUICPaddingFrame> quicPaddingFrameAllocator("quicPaddingFrameAllocator");
 ClassAllocator<QUICRstStreamFrame> quicRstStreamFrameAllocator("quicRstStreamFrameAllocator");
 ClassAllocator<QUICConnectionCloseFrame> quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator");
+ClassAllocator<QUICApplicationCloseFrame> quicApplicationCloseFrameAllocator("quicApplicationCloseFrameAllocator");
 ClassAllocator<QUICMaxDataFrame> quicMaxDataFrameAllocator("quicMaxDataFrameAllocator");
 ClassAllocator<QUICMaxStreamDataFrame> quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator");
 ClassAllocator<QUICMaxStreamIdFrame> quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator");
@@ -46,7 +47,6 @@ QUICFrame::type() const
   return QUICFrame::type(this->_buf);
 }
 
-// XXX QUICFrameType: 0x03 (GOAWAY frame) is removed
 QUICFrameType
 QUICFrame::type(const uint8_t *buf)
 {
@@ -54,7 +54,7 @@ QUICFrame::type(const uint8_t *buf)
     return QUICFrameType::STREAM;
   } else if (buf[0] >= static_cast<uint8_t>(QUICFrameType::ACK)) {
     return QUICFrameType::ACK;
-  } else if (buf[0] > static_cast<uint8_t>(QUICFrameType::STOP_SENDING) || buf[0] == 0x03) {
+  } else if (buf[0] > static_cast<uint8_t>(QUICFrameType::STOP_SENDING)) {
     return QUICFrameType::UNKNOWN;
   } else {
     return static_cast<QUICFrameType>(buf[0]);
@@ -664,7 +664,7 @@ QUICAckFrame::TimestampSection::store(uint8_t *buf, size_t *len) const
 // RST_STREAM frame
 //
 
-QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset)
+QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset)
   : _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset)
 {
 }
@@ -675,10 +675,11 @@ QUICRstStreamFrame::type() const
   return QUICFrameType::RST_STREAM;
 }
 
+// 8 + 32 + 16 + 64 bit
 size_t
 QUICRstStreamFrame::size() const
 {
-  return 17;
+  return 15;
 }
 
 void
@@ -690,7 +691,7 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const
   ++p;
   QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n);
   p += n;
-  QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n);
+  QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n);
   p += n;
   QUICTypeUtil::write_QUICOffset(this->_final_offset, 8, p, &n);
   p += n;
@@ -698,11 +699,11 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const
   *len = p - buf;
 }
 
-QUICErrorCode
+QUICAppErrorCode
 QUICRstStreamFrame::error_code() const
 {
   if (this->_buf) {
-    return QUICTypeUtil::read_QUICErrorCode(this->_buf + 5);
+    return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 5);
   } else {
     return this->_error_code;
   }
@@ -722,7 +723,7 @@ QUICOffset
 QUICRstStreamFrame::final_offset() const
 {
   if (this->_buf) {
-    return QUICTypeUtil::read_QUICOffset(this->_buf + 9, 8);
+    return QUICTypeUtil::read_QUICOffset(this->_buf + 7, 8);
   } else {
     return this->_final_offset;
   }
@@ -775,8 +776,7 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len) const
 //
 // CONNECTION_CLOSE frame
 //
-
-QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICErrorCode error_code, uint16_t reason_phrase_length,
+QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint16_t reason_phrase_length,
                                                    const char *reason_phrase)
 {
   this->_error_code           = error_code;
@@ -793,7 +793,7 @@ QUICConnectionCloseFrame::type() const
 size_t
 QUICConnectionCloseFrame::size() const
 {
-  return 7 + this->reason_phrase_length();
+  return 5 + this->reason_phrase_length();
 }
 
 void
@@ -803,7 +803,7 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const
   uint8_t *p = buf;
   *p         = static_cast<uint8_t>(QUICFrameType::CONNECTION_CLOSE);
   ++p;
-  QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n);
+  QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n);
   p += n;
   QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n);
   p += n;
@@ -815,11 +815,11 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const
   *len = p - buf;
 }
 
-QUICErrorCode
+QUICTransErrorCode
 QUICConnectionCloseFrame::error_code() const
 {
   if (this->_buf) {
-    return QUICTypeUtil::read_QUICErrorCode(this->_buf + 1);
+    return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + 1);
   } else {
     return this->_error_code;
   }
@@ -829,7 +829,7 @@ uint16_t
 QUICConnectionCloseFrame::reason_phrase_length() const
 {
   if (this->_buf) {
-    return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 5, 2);
+    return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 3, 2);
   } else {
     return this->_reason_phrase_length;
   }
@@ -839,7 +839,79 @@ const char *
 QUICConnectionCloseFrame::reason_phrase() const
 {
   if (this->_buf) {
-    return reinterpret_cast<const char *>(this->_buf + 7);
+    return reinterpret_cast<const char *>(this->_buf + 5);
+  } else {
+    return this->_reason_phrase;
+  }
+}
+
+//
+// APPLICATION_CLOSE frame
+//
+QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint16_t reason_phrase_length,
+                                                     const char *reason_phrase)
+{
+  this->_error_code           = error_code;
+  this->_reason_phrase_length = reason_phrase_length;
+  this->_reason_phrase        = reason_phrase;
+}
+
+QUICFrameType
+QUICApplicationCloseFrame::type() const
+{
+  return QUICFrameType::APPLICATION_CLOSE;
+}
+
+size_t
+QUICApplicationCloseFrame::size() const
+{
+  return 5 + this->reason_phrase_length();
+}
+
+void
+QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const
+{
+  size_t n;
+  uint8_t *p = buf;
+  *p         = static_cast<uint8_t>(QUICFrameType::APPLICATION_CLOSE);
+  ++p;
+  QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n);
+  p += n;
+  QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n);
+  p += n;
+  if (this->_reason_phrase_length > 0) {
+    memcpy(p, this->_reason_phrase, this->_reason_phrase_length);
+    p += this->_reason_phrase_length;
+  }
+
+  *len = p - buf;
+}
+
+QUICAppErrorCode
+QUICApplicationCloseFrame::error_code() const
+{
+  if (this->_buf) {
+    return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 1);
+  } else {
+    return this->_error_code;
+  }
+}
+
+uint16_t
+QUICApplicationCloseFrame::reason_phrase_length() const
+{
+  if (this->_buf) {
+    return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 3, 2);
+  } else {
+    return this->_reason_phrase_length;
+  }
+}
+
+const char *
+QUICApplicationCloseFrame::reason_phrase() const
+{
+  if (this->_buf) {
+    return reinterpret_cast<const char *>(this->_buf + 5);
   } else {
     return this->_reason_phrase;
   }
@@ -1135,7 +1207,7 @@ QUICNewConnectionIdFrame::connection_id() const
 // STOP_SENDING frame
 //
 
-QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICErrorCode error_code)
+QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code)
   : _stream_id(stream_id), _error_code(error_code)
 {
 }
@@ -1149,7 +1221,7 @@ QUICStopSendingFrame::type() const
 size_t
 QUICStopSendingFrame::size() const
 {
-  return 9;
+  return 7;
 }
 
 void
@@ -1161,17 +1233,17 @@ QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const
   ++p;
   QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n);
   p += n;
-  QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n);
+  QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n);
   p += n;
 
   *len = p - buf;
 }
 
-QUICErrorCode
+QUICAppErrorCode
 QUICStopSendingFrame::error_code() const
 {
   if (this->_buf) {
-    return QUICTypeUtil::read_QUICErrorCode(this->_buf + 5);
+    return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 5);
   } else {
     return this->_error_code;
   }
@@ -1249,6 +1321,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len)
     frame = quicConnectionCloseFrameAllocator.alloc();
     new (frame) QUICConnectionCloseFrame(buf, len);
     return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_connection_close_frame);
+  case QUICFrameType::APPLICATION_CLOSE:
+    frame = quicApplicationCloseFrameAllocator.alloc();
+    new (frame) QUICApplicationCloseFrame(buf, len);
+    return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_application_close_frame);
   case QUICFrameType::MAX_DATA:
     frame = quicMaxDataFrameAllocator.alloc();
     new (frame) QUICMaxDataFrame(buf, len);
@@ -1332,7 +1408,8 @@ QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint16
 }
 
 std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc>
-QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase)
+QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, uint16_t reason_phrase_length,
+                                                const char *reason_phrase)
 {
   QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc();
   new (frame) QUICConnectionCloseFrame(error_code, reason_phrase_length, reason_phrase);
@@ -1342,10 +1419,31 @@ QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16
 std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc>
 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);
+  } else {
+    return QUICFrameFactory::create_connection_close_frame(error->trans_error_code);
+  }
+}
+
+std::unique_ptr<QUICApplicationCloseFrame, QUICFrameDeleterFunc>
+QUICFrameFactory::create_application_close_frame(QUICAppErrorCode error_code, uint16_t reason_phrase_length,
+                                                 const char *reason_phrase)
+{
+  QUICApplicationCloseFrame *frame = quicApplicationCloseFrameAllocator.alloc();
+  new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase);
+  return std::unique_ptr<QUICApplicationCloseFrame, QUICFrameDeleterFunc>(frame, &QUICFrameDeleter::delete_connection_close_frame);
+}
+
+std::unique_ptr<QUICApplicationCloseFrame, QUICFrameDeleterFunc>
+QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error)
+{
+  ink_assert(error->cls == QUICErrorClass::APPLICATION);
   if (error->msg) {
-    return QUICFrameFactory::create_connection_close_frame(error->code, strlen(error->msg), error->msg);
+    return QUICFrameFactory::create_application_close_frame(error->app_error_code, strlen(error->msg), error->msg);
   } else {
-    return QUICFrameFactory::create_connection_close_frame(error->code);
+    return QUICFrameFactory::create_application_close_frame(error->app_error_code);
   }
 }
 
@@ -1382,7 +1480,7 @@ QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id)
 }
 
 std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc>
-QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset)
+QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset)
 {
   QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc();
   new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset);
@@ -1392,11 +1490,11 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode
 std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc>
 QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error)
 {
-  return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset());
+  return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->app_error_code, error->stream->final_offset());
 }
 
 std::unique_ptr<QUICStopSendingFrame, QUICFrameDeleterFunc>
-QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICErrorCode error_code)
+QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code)
 {
   QUICStopSendingFrame *frame = quicStopSendingFrameAllocator.alloc();
   new (frame) QUICStopSendingFrame(stream_id, error_code);
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index dad9a6c..87509aa 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -219,18 +219,18 @@ class QUICRstStreamFrame : public QUICFrame
 public:
   QUICRstStreamFrame() : QUICFrame() {}
   QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
-  QUICRstStreamFrame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset);
+  QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset);
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual void store(uint8_t *buf, size_t *len) const override;
-  QUICErrorCode error_code() const;
+  QUICAppErrorCode error_code() const;
   QUICStreamId stream_id() const;
   QUICOffset final_offset() const;
 
 private:
-  QUICStreamId _stream_id = 0;
-  QUICErrorCode _error_code;
-  QUICOffset _final_offset = 0;
+  QUICStreamId _stream_id      = 0;
+  QUICAppErrorCode _error_code = 0;
+  QUICOffset _final_offset     = 0;
 };
 
 //
@@ -268,16 +268,39 @@ class QUICConnectionCloseFrame : public QUICFrame
 public:
   QUICConnectionCloseFrame() : QUICFrame() {}
   QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
-  QUICConnectionCloseFrame(QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase);
+  QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase);
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual void store(uint8_t *buf, size_t *len) const override;
-  QUICErrorCode error_code() const;
+  QUICTransErrorCode error_code() const;
   uint16_t reason_phrase_length() const;
   const char *reason_phrase() const;
 
 private:
-  QUICErrorCode _error_code;
+  QUICTransErrorCode _error_code;
+  uint16_t _reason_phrase_length = 0;
+  const char *_reason_phrase     = nullptr;
+};
+
+//
+// APPLICATION_CLOSE
+//
+
+class QUICApplicationCloseFrame : public QUICFrame
+{
+public:
+  QUICApplicationCloseFrame() : QUICFrame() {}
+  QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
+  QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase);
+  virtual QUICFrameType type() const override;
+  virtual size_t size() const override;
+  virtual void store(uint8_t *buf, size_t *len) const override;
+  QUICAppErrorCode error_code() const;
+  uint16_t reason_phrase_length() const;
+  const char *reason_phrase() const;
+
+private:
+  QUICAppErrorCode _error_code   = 0;
   uint16_t _reason_phrase_length = 0;
   const char *_reason_phrase     = nullptr;
 };
@@ -416,16 +439,16 @@ class QUICStopSendingFrame : public QUICFrame
 public:
   QUICStopSendingFrame() : QUICFrame() {}
   QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
-  QUICStopSendingFrame(QUICStreamId stream_id, QUICErrorCode error_code);
+  QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code);
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual void store(uint8_t *buf, size_t *len) const override;
   QUICStreamId stream_id() const;
-  QUICErrorCode error_code() const;
+  QUICAppErrorCode error_code() const;
 
 private:
   QUICStreamId _stream_id = 0;
-  QUICErrorCode _error_code;
+  QUICAppErrorCode _error_code;
 };
 
 using QUICFrameDeleterFunc = void (*)(QUICFrame *p);
@@ -457,6 +480,7 @@ extern ClassAllocator<QUICAckFrame> quicAckFrameAllocator;
 extern ClassAllocator<QUICPaddingFrame> quicPaddingFrameAllocator;
 extern ClassAllocator<QUICRstStreamFrame> quicRstStreamFrameAllocator;
 extern ClassAllocator<QUICConnectionCloseFrame> quicConnectionCloseFrameAllocator;
+extern ClassAllocator<QUICApplicationCloseFrame> quicApplicationCloseFrameAllocator;
 extern ClassAllocator<QUICMaxDataFrame> quicMaxDataFrameAllocator;
 extern ClassAllocator<QUICMaxStreamDataFrame> quicMaxStreamDataFrameAllocator;
 extern ClassAllocator<QUICMaxStreamIdFrame> quicMaxStreamIdFrameAllocator;
@@ -509,6 +533,12 @@ public:
   }
 
   static void
+  delete_application_close_frame(QUICFrame *frame)
+  {
+    quicApplicationCloseFrameAllocator.free(static_cast<QUICApplicationCloseFrame *>(frame));
+  }
+
+  static void
   delete_max_data_frame(QUICFrame *frame)
   {
     quicMaxDataFrameAllocator.free(static_cast<QUICMaxDataFrame *>(frame));
@@ -603,11 +633,19 @@ public:
    * Creates a CONNECTION_CLOSE frame.
    */
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> create_connection_close_frame(
-    QUICErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr);
+    QUICTransErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr);
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> create_connection_close_frame(
     QUICConnectionErrorUPtr error);
 
   /*
+   * Creates a APPLICATION_CLOSE frame.
+   */
+  static std::unique_ptr<QUICApplicationCloseFrame, QUICFrameDeleterFunc> create_application_close_frame(
+    QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr);
+  static std::unique_ptr<QUICApplicationCloseFrame, QUICFrameDeleterFunc> create_application_close_frame(
+    QUICConnectionErrorUPtr error);
+
+  /*
    * Creates a MAX_DATA frame.
    */
   static std::unique_ptr<QUICMaxDataFrame, QUICFrameDeleterFunc> create_max_data_frame(uint64_t maximum_data);
@@ -632,7 +670,7 @@ public:
    * Creates a RST_STREAM frame.
    */
   static std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc> create_rst_stream_frame(QUICStreamId stream_id,
-                                                                                           QUICErrorCode error_code,
+                                                                                           QUICAppErrorCode error_code,
                                                                                            QUICOffset final_offset);
   static std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc> create_rst_stream_frame(QUICStreamErrorUPtr error);
 
@@ -640,7 +678,7 @@ public:
    * Creates a STOP_SENDING frame.
    */
   static std::unique_ptr<QUICStopSendingFrame, QUICFrameDeleterFunc> create_stop_sending_frame(QUICStreamId stream_id,
-                                                                                               QUICErrorCode error_code);
+                                                                                               QUICAppErrorCode error_code);
 
   /*
    * Creates a retransmission frame, which is very special.
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index d78b909..b23609f 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -105,7 +105,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet
   // Negotiate version
   if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) {
     if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) {
-      return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION));
+      return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION));
     }
     if (initial_packet->version()) {
       if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) {
@@ -117,7 +117,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet
         DebugQHS("Version negotiation failed: %x", initial_packet->version());
       }
     } else {
-      return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION));
+      return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION));
     }
   }
   return QUICErrorUPtr(new QUICNoError());
@@ -163,8 +163,7 @@ QUICHandshake::set_transport_parameters(std::shared_ptr<QUICTransportParameters>
   if (tp_in_ch) {
     // Version revalidation
     if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) {
-      this->_client_qc->close(
-        QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::VERSION_NEGOTIATION_ERROR)));
+      this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR)));
       DebugQHS("Enter state_closed");
       SET_HANDLER(&QUICHandshake::state_closed);
       return;
@@ -212,8 +211,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data)
     if (dynamic_cast<QUICConnectionError *>(error.get()) != nullptr) {
       this->_client_qc->close(QUICConnectionErrorUPtr(static_cast<QUICConnectionError *>(error.release())));
     } else {
-      this->_client_qc->close(
-        QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)));
+      this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)));
     }
     DebugQHS("Enter state_closed");
     SET_HANDLER(&QUICHandshake::state_closed);
@@ -241,8 +239,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data)
     if (dynamic_cast<QUICConnectionError *>(error.get()) != nullptr) {
       this->_client_qc->close(QUICConnectionErrorUPtr(static_cast<QUICConnectionError *>(error.release())));
     } else {
-      this->_client_qc->close(
-        QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)));
+      this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)));
     }
     DebugQHS("Enter state_closed");
     SET_HANDLER(&QUICHandshake::state_closed);
@@ -345,7 +342,7 @@ QUICHandshake::_process_client_hello()
 
     return QUICErrorUPtr(new QUICNoError());
   } else {
-    return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED));
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED));
   }
 }
 
@@ -394,7 +391,7 @@ QUICHandshake::_process_client_finished()
 
     return QUICErrorUPtr(new QUICNoError());
   } else {
-    return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED));
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED));
   }
 }
 
diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc
index e769054..797b7b9 100644
--- a/iocore/net/quic/QUICIncomingFrameBuffer.cc
+++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc
@@ -116,17 +116,17 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len,
         // dup fin frame
         return QUICErrorUPtr(new QUICNoError());
       }
-      return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR));
+      return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::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));
+      return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::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));
+    return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR));
   }
 
   this->_max_offset = std::max(offset, this->_max_offset);
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 535b9f4..1017a9f 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -116,8 +116,14 @@ QUICStream::main_event_handler(int event, void *data)
   }
 
   if (error->cls != QUICErrorClass::NONE) {
-    DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast<unsigned int>(error->cls),
-                    QUICDebugNames::error_code(error->code), static_cast<unsigned int>(error->code));
+    if (error->cls == QUICErrorClass::TRANSPORT) {
+      DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls),
+                      static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->trans_error_code),
+                      static_cast<unsigned int>(error->trans_error_code));
+    } else {
+      DebugQUICStream("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls),
+                      static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->app_error_code));
+    }
     if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
       // Stream Error
       QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast<QUICStreamError *>(error.get()));
@@ -295,7 +301,7 @@ QUICStream::recv(const std::shared_ptr<const QUICStreamFrame> frame)
 
   // Check stream state - Do this first before accept the frame
   if (!this->_state.is_allowed_to_receive(*frame)) {
-    return QUICErrorUPtr(new QUICStreamError(this, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_STATE_ERROR));
+    return QUICErrorUPtr(new QUICStreamError(this, QUICTransErrorCode::STREAM_STATE_ERROR));
   }
 
   // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit
diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc
index 6bda170..64190e5 100644
--- a/iocore/net/quic/QUICStreamManager.cc
+++ b/iocore/net/quic/QUICStreamManager.cc
@@ -123,7 +123,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr<const QUICMaxStreamDataFr
   if (stream) {
     return stream->recv(frame);
   } else {
-    return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR));
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR));
   }
 }
 
@@ -134,7 +134,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr<const QUICStreamBlockedFr
   if (stream) {
     return stream->recv(frame);
   } else {
-    return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR));
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR));
   }
 }
 
@@ -143,7 +143,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr<const QUICStreamFrame> &f
 {
   QUICStream *stream = this->_find_or_create_stream(frame->stream_id());
   if (!stream) {
-    return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR));
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR));
   }
 
   QUICApplication *application = this->_app_map->get(frame->stream_id());
@@ -170,7 +170,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr<const QUICRstStreamFrame>
     // TODO Reset the stream
     return QUICErrorUPtr(new QUICNoError());
   } else {
-    return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR));
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR));
   }
 }
 
diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc
index 40c8a02..7427d6a 100644
--- a/iocore/net/quic/QUICTypes.cc
+++ b/iocore/net/quic/QUICTypes.cc
@@ -77,10 +77,16 @@ QUICTypeUtil::read_QUICOffset(const uint8_t *buf, uint8_t len)
   return static_cast<QUICOffset>(read_nbytes_as_uint(buf, len));
 }
 
-QUICErrorCode
-QUICTypeUtil::read_QUICErrorCode(const uint8_t *buf)
+QUICTransErrorCode
+QUICTypeUtil::read_QUICTransErrorCode(const uint8_t *buf)
 {
-  return static_cast<QUICErrorCode>(read_nbytes_as_uint(buf, 4));
+  return static_cast<QUICTransErrorCode>(read_nbytes_as_uint(buf, 2));
+}
+
+QUICAppErrorCode
+QUICTypeUtil::read_QUICAppErrorCode(const uint8_t *buf)
+{
+  return static_cast<QUICAppErrorCode>(read_nbytes_as_uint(buf, 2));
 }
 
 uint64_t
@@ -122,9 +128,15 @@ QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_
 }
 
 void
-QUICTypeUtil::write_QUICErrorCode(QUICErrorCode error_code, uint8_t *buf, size_t *len)
+QUICTypeUtil::write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len)
+{
+  write_uint_as_nbytes(static_cast<uint64_t>(error_code), 2, buf, len);
+}
+
+void
+QUICTypeUtil::write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len)
 {
-  write_uint_as_nbytes(static_cast<uint64_t>(error_code), 4, buf, len);
+  write_uint_as_nbytes(static_cast<uint64_t>(error_code), 2, buf, len);
 }
 
 void
@@ -148,3 +160,9 @@ fnv1a(const uint8_t *data, size_t len, uint8_t *hash)
   }
   return QUICTypeUtil::write_uint_as_nbytes(h, 8, hash, &n);
 }
+
+uint16_t
+QUICError::code()
+{
+  return static_cast<uint16_t>(this->trans_error_code);
+}
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index 5ea6993..2e78939 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -88,7 +88,8 @@ enum class QUICFrameType : int {
   PADDING = 0x00,
   RST_STREAM,
   CONNECTION_CLOSE,
-  MAX_DATA = 0x04,
+  APPLICATION_CLOSE,
+  MAX_DATA,
   MAX_STREAM_DATA,
   MAX_STREAM_ID,
   PING,
@@ -117,47 +118,49 @@ enum class QUICKeyPhase : int {
 
 enum class QUICErrorClass {
   NONE,
-  AQPPLICATION_SPECIFIC,
-  HOST_LOCAL,
-  QUIC_TRANSPORT,
-  CRYPTOGRAPHIC,
+  TRANSPORT,
+  APPLICATION,
 };
 
-enum class QUICErrorCode : uint32_t {
-  APPLICATION_SPECIFIC_ERROR = 0,
-  HOST_LOCAL_ERROR           = 0x40000000,
-  NO_ERROR                   = 0x80000000,
+enum class QUICTransErrorCode : uint16_t {
+  NO_ERROR = 0x00,
   INTERNAL_ERROR,
-  CANCELLED,
-  FLOW_CONTROL_ERROR,
+  FLOW_CONTROL_ERROR = 0x03,
   STREAM_ID_ERROR,
   STREAM_STATE_ERROR,
   FINAL_OFFSET_ERROR,
   FRAME_FORMAT_ERROR,
   TRANSPORT_PARAMETER_ERROR,
   VERSION_NEGOTIATION_ERROR,
-  PROTOCOL_VIOLATION   = 0x8000000A,
-  QUIC_RECEIVED_RST    = 0x80000035,
-  FRAME_ERROR          = 0x80000100,
-  CRYPTOGRAPHIC_ERROR  = 0xC0000000,
-  TLS_HANDSHAKE_FAILED = 0xC000001C,
+  PROTOCOL_VIOLATION   = 0x0A,
+  FRAME_ERROR          = 0x0100, // 0x100 - 0x1FF
+  TLS_HANDSHAKE_FAILED = 0x0201,
   TLS_FATAL_ALERT_GENERATED,
   TLS_FATAL_ALERT_RECEIVED,
-  // TODO Add error codes
 };
 
+// Application Protocol Error Codes defined in application
+using QUICAppErrorCode = uint16_t;
+
 class QUICError
 {
 public:
   virtual ~QUICError() {}
-  QUICErrorClass cls;
-  QUICErrorCode code;
-  const char *msg;
+  uint16_t code();
+
+  QUICErrorClass cls = QUICErrorClass::NONE;
+  union {
+    QUICTransErrorCode trans_error_code = QUICTransErrorCode::NO_ERROR;
+    QUICAppErrorCode app_error_code;
+  };
+  const char *msg = nullptr;
 
 protected:
-  QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, const QUICErrorCode error_code = QUICErrorCode::NO_ERROR,
-            const char *error_msg = nullptr)
-    : cls(error_class), code(error_code), msg(error_msg){};
+  QUICError(){};
+  QUICError(const QUICTransErrorCode error_code, const char *error_msg = nullptr)
+    : cls(QUICErrorClass::TRANSPORT), trans_error_code(error_code), msg(error_msg){};
+  QUICError(const QUICAppErrorCode error_code, const char *error_msg = nullptr)
+    : cls(QUICErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){};
 };
 
 class QUICNoError : public QUICError
@@ -170,8 +173,8 @@ class QUICConnectionError : public QUICError
 {
 public:
   QUICConnectionError() : QUICError() {}
-  QUICConnectionError(const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr)
-    : QUICError(error_class, error_code, error_msg){};
+  QUICConnectionError(const QUICTransErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){};
+  QUICConnectionError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){};
 };
 
 class QUICStream;
@@ -179,8 +182,12 @@ class QUICStream;
 class QUICStreamError : public QUICError
 {
 public:
-  QUICStreamError(QUICStream *s, const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr)
-    : QUICError(error_class, error_code, error_msg), stream(s){};
+  QUICStreamError() : QUICError() {}
+  QUICStreamError(QUICStream *s, const QUICTransErrorCode error_code, const char *error_msg = nullptr)
+    : QUICError(error_code, error_msg), stream(s){};
+  QUICStreamError(QUICStream *s, const QUICAppErrorCode error_code, const char *error_msg = nullptr)
+    : QUICError(error_code, error_msg), stream(s){};
+
   QUICStream *stream;
 };
 
@@ -303,14 +310,16 @@ public:
   static QUICVersion read_QUICVersion(const uint8_t *buf);
   static QUICStreamId read_QUICStreamId(const uint8_t *buf, uint8_t n);
   static QUICOffset read_QUICOffset(const uint8_t *buf, uint8_t n);
-  static QUICErrorCode read_QUICErrorCode(const uint8_t *buf);
+  static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf);
+  static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf);
 
   static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len);
   static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len);
   static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len);
   static void write_QUICStreamId(QUICStreamId stream_id, uint8_t n, uint8_t *buf, size_t *len);
   static void write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_t *len);
-  static void write_QUICErrorCode(QUICErrorCode error_code, uint8_t *buf, size_t *len);
+  static void write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len);
+  static void write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len);
 
   static uint64_t read_nbytes_as_uint(const uint8_t *buf, uint8_t n);
   static void write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len);
diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc
index e98278b..17a9472 100644
--- a/iocore/net/quic/test/test_QUICFlowController.cc
+++ b/iocore/net/quic/test/test_QUICFlowController.cc
@@ -68,7 +68,8 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]")
   error = fc.update(1280);
   CHECK(fc.current_offset() == 1024);
   CHECK(fc.current_limit() == 1024);
-  CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR);
+  CHECK(error->cls == QUICErrorClass::TRANSPORT);
+  CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR);
 
   // MAX_STREAM_DATA
   CHECK(tx.frameCount[static_cast<int>(QUICFrameType::MAX_DATA)] == 0);
@@ -180,7 +181,8 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]")
   error = fc.update(1280);
   CHECK(fc.current_offset() == 1024);
   CHECK(fc.current_limit() == 1024);
-  CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR);
+  CHECK(error->cls == QUICErrorClass::TRANSPORT);
+  CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR);
 
   // MAX_STREAM_DATA
   CHECK(tx.frameCount[static_cast<int>(QUICFrameType::MAX_STREAM_DATA)] == 0);
diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc
index 36f1eee..434ef93 100644
--- a/iocore/net/quic/test/test_QUICFrame.cc
+++ b/iocore/net/quic/test/test_QUICFrame.cc
@@ -32,6 +32,7 @@ TEST_CASE("QUICFrame Type", "[quic]")
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x00")) == QUICFrameType::PADDING);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x01")) == QUICFrameType::RST_STREAM);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x02")) == QUICFrameType::CONNECTION_CLOSE);
+  CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x03")) == QUICFrameType::APPLICATION_CLOSE);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x04")) == QUICFrameType::MAX_DATA);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x05")) == QUICFrameType::MAX_STREAM_DATA);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x06")) == QUICFrameType::MAX_STREAM_ID);
@@ -42,7 +43,6 @@ TEST_CASE("QUICFrame Type", "[quic]")
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x0b")) == QUICFrameType::NEW_CONNECTION_ID);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x0c")) == QUICFrameType::STOP_SENDING);
   // Undefined ragne
-  CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x03")) == QUICFrameType::UNKNOWN);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x0d")) == QUICFrameType::UNKNOWN);
   CHECK(QUICFrame::type(reinterpret_cast<const uint8_t *>("\x9f")) == QUICFrameType::UNKNOWN);
   // Range of ACK
@@ -309,15 +309,15 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]")
   uint8_t buf1[] = {
     0x01,                                          // Type
     0x12, 0x34, 0x56, 0x78,                        // Stream ID
-    0x80, 0x00, 0x00, 0x00,                        // Error Code
+    0x00, 0x01,                                    // Error Code
     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset
   };
   std::shared_ptr<const QUICFrame> frame1 = QUICFrameFactory::create(buf1, sizeof(buf1));
   CHECK(frame1->type() == QUICFrameType::RST_STREAM);
-  CHECK(frame1->size() == 17);
+  CHECK(frame1->size() == 15);
   std::shared_ptr<const QUICRstStreamFrame> rst_stream_frame1 = std::dynamic_pointer_cast<const QUICRstStreamFrame>(frame1);
   CHECK(rst_stream_frame1 != nullptr);
-  CHECK(rst_stream_frame1->error_code() == QUICErrorCode::NO_ERROR);
+  CHECK(rst_stream_frame1->error_code() == 0x0001);
   CHECK(rst_stream_frame1->stream_id() == 0x12345678);
   CHECK(rst_stream_frame1->final_offset() == 0x1122334455667788);
 }
@@ -330,12 +330,12 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]")
   uint8_t expected[] = {
     0x01,                                          // Type
     0x12, 0x34, 0x56, 0x78,                        // Stream ID
-    0x80, 0x00, 0x00, 0x00,                        // Error Code
+    0x00, 0x01,                                    // Error Code
     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset
   };
-  QUICRstStreamFrame rst_stream_frame(0x12345678, QUICErrorCode::NO_ERROR, 0x1122334455667788);
+  QUICRstStreamFrame rst_stream_frame(0x12345678, 0x0001, 0x1122334455667788);
   rst_stream_frame.store(buf, &len);
-  CHECK(len == 17);
+  CHECK(len == 15);
   CHECK(memcmp(buf, expected, len) == 0);
 }
 
@@ -395,33 +395,33 @@ TEST_CASE("Load ConnectionClose Frame", "[quic]")
 {
   uint8_t buf1[] = {
     0x02,                        // Type
-    0x80, 0x00, 0x00, 0x00,      // Error Code
+    0x00, 0x0A,                  // Error Code
     0x00, 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() == 12);
+  CHECK(frame1->size() == 10);
   std::shared_ptr<const QUICConnectionCloseFrame> connectionCloseFrame1 =
     std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame1);
   CHECK(connectionCloseFrame1 != nullptr);
-  CHECK(connectionCloseFrame1->error_code() == QUICErrorCode::NO_ERROR);
+  CHECK(connectionCloseFrame1->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION);
   CHECK(connectionCloseFrame1->reason_phrase_length() == 5);
-  CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 7, 5) == 0);
+  CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 5, 5) == 0);
 
   // No reason phrase
   uint8_t buf2[] = {
-    0x02,                   // Type
-    0x80, 0x00, 0x00, 0x00, // Error Code
-    0x00, 0x00,             // Reason Phrase Length
+    0x02,       // Type
+    0x00, 0x0A, // Error Code
+    0x00, 0x00, // Reason Phrase Length
   };
   std::shared_ptr<const QUICFrame> frame2 = QUICFrameFactory::create(buf2, sizeof(buf1));
   CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE);
-  CHECK(frame2->size() == 7);
+  CHECK(frame2->size() == 5);
   std::shared_ptr<const QUICConnectionCloseFrame> connectionCloseFrame2 =
     std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame2);
   CHECK(connectionCloseFrame2 != nullptr);
-  CHECK(connectionCloseFrame2->error_code() == QUICErrorCode::NO_ERROR);
+  CHECK(connectionCloseFrame2->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION);
   CHECK(connectionCloseFrame2->reason_phrase_length() == 0);
 }
 
@@ -432,23 +432,84 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]")
 
   uint8_t expected1[] = {
     0x02,                        // Type
-    0x80, 0x00, 0x00, 0x00,      // Error Code
+    0x00, 0x0A,                  // Error Code
     0x00, 0x05,                  // Reason Phrase Length
     0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE");
   };
-  QUICConnectionCloseFrame connectionCloseFrame1(QUICErrorCode::NO_ERROR, 5, "ABCDE");
+  QUICConnectionCloseFrame connectionCloseFrame1(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE");
   connectionCloseFrame1.store(buf, &len);
-  CHECK(len == 12);
+  CHECK(len == 10);
   CHECK(memcmp(buf, expected1, len) == 0);
 
   uint8_t expected2[] = {
-    0x02,                   // Type
-    0x80, 0x00, 0x00, 0x00, // Error Code
-    0x00, 0x00,             // Reason Phrase Length
+    0x02,       // Type
+    0x00, 0x0A, // Error Code
+    0x00, 0x00, // Reason Phrase Length
   };
-  QUICConnectionCloseFrame connectionCloseFrame2(QUICErrorCode::NO_ERROR, 0, nullptr);
+  QUICConnectionCloseFrame connectionCloseFrame2(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr);
   connectionCloseFrame2.store(buf, &len);
-  CHECK(len == 7);
+  CHECK(len == 5);
+  CHECK(memcmp(buf, expected2, len) == 0);
+}
+
+TEST_CASE("Load ApplicationClose Frame", "[quic]")
+{
+  uint8_t buf1[] = {
+    0x03,                        // Type
+    0x00, 0x01,                  // Error Code
+    0x00, 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::APPLICATION_CLOSE);
+  CHECK(frame1->size() == 10);
+  std::shared_ptr<const QUICApplicationCloseFrame> applicationCloseFrame1 =
+    std::dynamic_pointer_cast<const QUICApplicationCloseFrame>(frame1);
+  CHECK(applicationCloseFrame1 != nullptr);
+  CHECK(applicationCloseFrame1->error_code() == static_cast<QUICAppErrorCode>(0x01));
+  CHECK(applicationCloseFrame1->reason_phrase_length() == 5);
+  CHECK(memcmp(applicationCloseFrame1->reason_phrase(), buf1 + 5, 5) == 0);
+
+  // No reason phrase
+  uint8_t buf2[] = {
+    0x03,       // Type
+    0x00, 0x01, // Error Code
+    0x00, 0x00, // Reason Phrase Length
+  };
+  std::shared_ptr<const QUICFrame> frame2 = QUICFrameFactory::create(buf2, sizeof(buf1));
+  CHECK(frame2->type() == QUICFrameType::APPLICATION_CLOSE);
+  CHECK(frame2->size() == 5);
+  std::shared_ptr<const QUICApplicationCloseFrame> applicationCloseFrame2 =
+    std::dynamic_pointer_cast<const QUICApplicationCloseFrame>(frame2);
+  CHECK(applicationCloseFrame2 != nullptr);
+  CHECK(applicationCloseFrame2->error_code() == static_cast<QUICAppErrorCode>(0x01));
+  CHECK(applicationCloseFrame2->reason_phrase_length() == 0);
+}
+
+TEST_CASE("Store ApplicationClose Frame", "[quic]")
+{
+  uint8_t buf[65535];
+  size_t len;
+
+  uint8_t expected1[] = {
+    0x03,                        // Type
+    0x00, 0x01,                  // Error Code
+    0x00, 0x05,                  // Reason Phrase Length
+    0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE");
+  };
+  QUICApplicationCloseFrame applicationCloseFrame1(static_cast<QUICAppErrorCode>(0x01), 5, "ABCDE");
+  applicationCloseFrame1.store(buf, &len);
+  CHECK(len == 10);
+  CHECK(memcmp(buf, expected1, len) == 0);
+
+  uint8_t expected2[] = {
+    0x03,       // Type
+    0x00, 0x01, // Error Code
+    0x00, 0x00, // Reason Phrase Length
+  };
+  QUICApplicationCloseFrame applicationCloseFrame2(static_cast<QUICAppErrorCode>(0x01), 0, nullptr);
+  applicationCloseFrame2.store(buf, &len);
+  CHECK(len == 5);
   CHECK(memcmp(buf, expected2, len) == 0);
 }
 
@@ -664,16 +725,16 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]")
   uint8_t buf[] = {
     0x0c,                   // Type
     0x12, 0x34, 0x56, 0x78, // Stream ID
-    0x80, 0x00, 0x00, 0x00, // Error Code
+    0x00, 0x01,             // Error Code
   };
   std::shared_ptr<const QUICFrame> frame = QUICFrameFactory::create(buf, sizeof(buf));
   CHECK(frame->type() == QUICFrameType::STOP_SENDING);
-  CHECK(frame->size() == 9);
+  CHECK(frame->size() == 7);
 
   std::shared_ptr<const QUICStopSendingFrame> stop_sending_frame = std::dynamic_pointer_cast<const QUICStopSendingFrame>(frame);
   CHECK(stop_sending_frame != nullptr);
   CHECK(stop_sending_frame->stream_id() == 0x12345678);
-  CHECK(stop_sending_frame->error_code() == QUICErrorCode::NO_ERROR);
+  CHECK(stop_sending_frame->error_code() == 0x0001);
 }
 
 TEST_CASE("Store STOP_SENDING Frame", "[quic]")
@@ -684,11 +745,11 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]")
   uint8_t expected[] = {
     0x0c,                   // Type
     0x12, 0x34, 0x56, 0x78, // Stream ID
-    0x80, 0x00, 0x00, 0x00, // Error Code
+    0x00, 0x01,             // Error Code
   };
-  QUICStopSendingFrame stop_sending_frame(0x12345678, QUICErrorCode::NO_ERROR);
+  QUICStopSendingFrame stop_sending_frame(0x12345678, static_cast<QUICAppErrorCode>(0x01));
   stop_sending_frame.store(buf, &len);
-  CHECK(len == 9);
+  CHECK(len == 7);
   CHECK(memcmp(buf, expected, len) == 0);
 }
 
@@ -744,18 +805,17 @@ TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]")
 TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", "[quic]")
 {
   std::unique_ptr<QUICConnectionError> error =
-    std::unique_ptr<QUICConnectionError>(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR));
+    std::unique_ptr<QUICConnectionError>(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
   std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> connection_close_frame1 =
     QUICFrameFactory::create_connection_close_frame(std::move(error));
-  CHECK(connection_close_frame1->error_code() == QUICErrorCode::INTERNAL_ERROR);
+  CHECK(connection_close_frame1->error_code() == QUICTransErrorCode::INTERNAL_ERROR);
   CHECK(connection_close_frame1->reason_phrase_length() == 0);
   CHECK(connection_close_frame1->reason_phrase() == nullptr);
 
-  error = std::unique_ptr<QUICConnectionError>(
-    new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR, "test"));
+  error = std::unique_ptr<QUICConnectionError>(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR, "test"));
   std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> connection_close_frame2 =
     QUICFrameFactory::create_connection_close_frame(std::move(error));
-  CHECK(connection_close_frame2->error_code() == QUICErrorCode::INTERNAL_ERROR);
+  CHECK(connection_close_frame2->error_code() == QUICTransErrorCode::INTERNAL_ERROR);
   CHECK(connection_close_frame2->reason_phrase_length() == 4);
   CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0);
 }
@@ -765,10 +825,10 @@ TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]")
   QUICStream stream;
   stream.init(new MockQUICFrameTransmitter(), 0, 0x1234, 0, 0);
   std::unique_ptr<QUICStreamError> error =
-    std::unique_ptr<QUICStreamError>(new QUICStreamError(&stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR));
+    std::unique_ptr<QUICStreamError>(new QUICStreamError(&stream, static_cast<QUICAppErrorCode>(0x01)));
   std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc> rst_stream_frame1 =
     QUICFrameFactory::create_rst_stream_frame(std::move(error));
-  CHECK(rst_stream_frame1->error_code() == QUICErrorCode::INTERNAL_ERROR);
+  CHECK(rst_stream_frame1->error_code() == 0x01);
   CHECK(rst_stream_frame1->stream_id() == 0x1234);
   CHECK(rst_stream_frame1->final_offset() == 0);
 }
diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
index 844607a..a42369b 100644
--- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
+++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
@@ -45,7 +45,7 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]")
   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);
+  CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR);
 
   QUICIncomingFrameBuffer buffer2(stream);
 
@@ -53,13 +53,13 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]")
   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);
+  CHECK(err->trans_error_code == QUICTransErrorCode::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);
+  CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR);
 
   delete stream;
 }
diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc
index 5e63ade..bd2f648 100644
--- a/iocore/net/quic/test/test_QUICStream.cc
+++ b/iocore/net/quic/test/test_QUICStream.cc
@@ -179,7 +179,8 @@ TEST_CASE("QUICStream", "[quic]")
     CHECK(error->cls == QUICErrorClass::NONE);
     // this should exceed the limit
     error = stream->recv(std::make_shared<QUICStreamFrame>(ats_unique_malloc(1024), 1024, stream_id, 8192));
-    CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR);
+    CHECK(error->cls == QUICErrorClass::TRANSPORT);
+    CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR);
   }
 
   SECTION("QUICStream_flow_control_remote", "[quic]")
diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc
index f9490c9..9af5433 100644
--- a/iocore/net/quic/test/test_QUICStreamManager.cc
+++ b/iocore/net/quic/test/test_QUICStreamManager.cc
@@ -53,7 +53,8 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]")
   CHECK(sm.stream_count() == 2);
 
   // RST_STREAM frames create new streams
-  std::shared_ptr<QUICFrame> rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, QUICErrorCode::INTERNAL_ERROR, 0);
+  std::shared_ptr<QUICFrame> rst_stream_frame =
+    QUICFrameFactory::create_rst_stream_frame(2, static_cast<QUICAppErrorCode>(0x01), 0);
   sm.handle_frame(rst_stream_frame);
   CHECK(sm.stream_count() == 3);
 
diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc
index ec30434..2bc3e68 100644
--- a/iocore/net/quic/test/test_QUICStreamState.cc
+++ b/iocore/net/quic/test/test_QUICStreamState.cc
@@ -31,7 +31,7 @@
 TEST_CASE("QUICStreamState_Idle", "[quic]")
 {
   auto stream_frame          = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("foo"), 4, 1, 0);
-  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0);
+  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, static_cast<QUICAppErrorCode>(0x01), 0);
   auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0);
   auto stream_blocked_frame  = QUICFrameFactory::create_stream_blocked_frame(0);
 
@@ -70,7 +70,7 @@ TEST_CASE("QUICStreamState_Open", "[quic]")
 {
   auto stream_frame          = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("foo"), 4, 1, 0);
   auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("bar"), 4, 1, 0, true);
-  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0);
+  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, static_cast<QUICAppErrorCode>(0x01), 0);
 
   // Case1. Send FIN in a STREAM
   QUICStreamState ss1;
@@ -105,7 +105,7 @@ TEST_CASE("QUICStreamState_Half_Closed_Remote", "[quic]")
 {
   auto stream_frame          = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("foo"), 4, 1, 0);
   auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("bar"), 4, 1, 0, true);
-  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0);
+  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, static_cast<QUICAppErrorCode>(0x01), 0);
 
   // Case1. Send FIN in a STREAM
   QUICStreamState ss1;
@@ -126,7 +126,7 @@ TEST_CASE("QUICStreamState_Half_Closed_Local", "[quic]")
 {
   auto stream_frame          = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("foo"), 4, 1, 0);
   auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast<const uint8_t *>("bar"), 4, 1, 0, true);
-  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0);
+  auto rst_stream_frame      = QUICFrameFactory::create_rst_stream_frame(0, static_cast<QUICAppErrorCode>(0x01), 0);
 
   // Case1. Recv FIN in a STREAM
   QUICStreamState ss1;

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