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

maskit 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 57fe4b2  Send CLOSE_CONNECTION or RST_STREAM when error occurs
57fe4b2 is described below

commit 57fe4b2a4981b7ec3126e2094f854c4e589b0c4a
Author: Masakazu Kitajo <mas...@apache.org>
AuthorDate: Thu Sep 28 17:24:35 2017 +0900

    Send CLOSE_CONNECTION or RST_STREAM when error occurs
---
 iocore/net/P_QUICNetVConnection.h           | 19 +++---
 iocore/net/QUICNetVConnection.cc            | 95 +++++++++++++++++------------
 iocore/net/quic/QUICCongestionController.cc |  4 +-
 iocore/net/quic/QUICCongestionController.h  |  2 +-
 iocore/net/quic/QUICConnection.h            |  2 +-
 iocore/net/quic/QUICFlowController.cc       | 10 +--
 iocore/net/quic/QUICFlowController.h        |  4 +-
 iocore/net/quic/QUICFrame.cc                | 13 ++++
 iocore/net/quic/QUICFrame.h                 |  3 +
 iocore/net/quic/QUICFrameDispatcher.cc      | 10 +--
 iocore/net/quic/QUICFrameDispatcher.h       |  2 +-
 iocore/net/quic/QUICFrameHandler.h          |  4 +-
 iocore/net/quic/QUICHandshake.cc            | 53 +++++++++-------
 iocore/net/quic/QUICHandshake.h             |  8 +--
 iocore/net/quic/QUICLossDetector.cc         |  4 +-
 iocore/net/quic/QUICLossDetector.h          |  2 +-
 iocore/net/quic/QUICStream.cc               | 58 +++++++++++-------
 iocore/net/quic/QUICStream.h                | 11 ++--
 iocore/net/quic/QUICStreamManager.cc        | 28 ++++-----
 iocore/net/quic/QUICStreamManager.h         | 12 ++--
 iocore/net/quic/QUICTypes.h                 | 45 +++++++++++---
 21 files changed, 237 insertions(+), 152 deletions(-)

diff --git a/iocore/net/P_QUICNetVConnection.h 
b/iocore/net/P_QUICNetVConnection.h
index 568e420..7db4cd8 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -177,7 +177,7 @@ public:
   uint32_t pmtu() override;
   NetVConnectionContext_t direction() override;
   SSLNextProtocolSet *next_protocol_set() override;
-  void close(QUICError error) override;
+  void close(QUICConnectionErrorUPtr error) override;
   QUICPacketNumber largest_received_packet_number() override;
   QUICPacketNumber largest_acked_packet_number() override;
 
@@ -191,7 +191,7 @@ public:
 
   // QUICConnection (QUICFrameHandler)
   std::vector<QUICFrameType> interests() override;
-  QUICError handle_frame(std::shared_ptr<const QUICFrame> frame) override;
+  QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame> frame) override;
 
 private:
   std::random_device _rnd;
@@ -240,20 +240,21 @@ private:
   QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool 
retransmittable,
                                QUICPacketType type = 
QUICPacketType::UNINITIALIZED);
 
-  QUICError _recv_and_ack(const uint8_t *payload, uint16_t size, 
QUICPacketNumber packet_numm);
+  QUICErrorUPtr _recv_and_ack(const uint8_t *payload, uint16_t size, 
QUICPacketNumber packet_numm);
 
-  QUICError _state_handshake_process_initial_client_packet(QUICPacketUPtr 
packet);
-  QUICError _state_handshake_process_client_cleartext_packet(QUICPacketUPtr 
packet);
-  QUICError _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr 
packet);
-  QUICError _state_connection_established_process_packet(QUICPacketUPtr 
packet);
-  QUICError _state_common_receive_packet();
-  QUICError _state_common_send_packet();
+  QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr 
packet);
+  QUICErrorUPtr 
_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet);
+  QUICErrorUPtr 
_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet);
+  QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr 
packet);
+  QUICErrorUPtr _state_common_receive_packet();
+  QUICErrorUPtr _state_common_send_packet();
 
   Ptr<ProxyMutex> _packet_transmitter_mutex;
   Ptr<ProxyMutex> _frame_transmitter_mutex;
 
   void _init_flow_control_params(const std::shared_ptr<const 
QUICTransportParameters> &local_tp,
                                  const std::shared_ptr<const 
QUICTransportParameters> &remote_tp);
+  void _handle_error(QUICErrorUPtr error);
 
   QUICStatelessToken _token;
 };
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index c7e1ffb..c0b2848 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -287,7 +287,7 @@ QUICNetVConnection::transmit_frame(QUICFrameUPtr frame)
 }
 
 void
-QUICNetVConnection::close(QUICError error)
+QUICNetVConnection::close(QUICConnectionErrorUPtr error)
 {
   if (this->handler == 
reinterpret_cast<ContinuationHandler>(&QUICNetVConnection::state_connection_closed)
 ||
       this->handler == 
reinterpret_cast<ContinuationHandler>(&QUICNetVConnection::state_connection_closing))
 {
@@ -295,7 +295,7 @@ QUICNetVConnection::close(QUICError error)
   } else {
     DebugQUICCon("Enter state_connection_closing");
     
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing);
-    
this->transmit_frame(QUICFrameFactory::create_connection_close_frame(error.code,
 0, ""));
+    
this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error)));
   }
 }
 
@@ -305,10 +305,10 @@ QUICNetVConnection::interests()
   return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, 
QUICFrameType::MAX_DATA};
 }
 
-QUICError
+QUICErrorUPtr
 QUICNetVConnection::handle_frame(std::shared_ptr<const QUICFrame> frame)
 {
-  QUICError error = QUICError(QUICErrorClass::NONE);
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   switch (frame->type()) {
   case QUICFrameType::MAX_DATA:
@@ -367,7 +367,7 @@ QUICNetVConnection::state_pre_handshake(int event, Event 
*data)
 int
 QUICNetVConnection::state_handshake(int event, Event *data)
 {
-  QUICError error;
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   switch (event) {
   case QUIC_EVENT_PACKET_READ_READY: {
@@ -388,7 +388,7 @@ QUICNetVConnection::state_handshake(int event, Event *data)
       break;
     }
     default:
-      error = QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR);
+      error = QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR));
       break;
     }
 
@@ -414,10 +414,8 @@ QUICNetVConnection::state_handshake(int event, Event *data)
     DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event));
   }
 
-  if (error.cls != QUICErrorClass::NONE) {
-    // TODO: Send error if needed
-    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::NONE) {
+    this->_handle_error(std::move(error));
   }
 
   if (this->_handshake_handler && this->_handshake_handler->is_completed()) {
@@ -440,7 +438,7 @@ QUICNetVConnection::state_handshake(int event, Event *data)
 int
 QUICNetVConnection::state_connection_established(int event, Event *data)
 {
-  QUICError error;
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
   switch (event) {
   case QUIC_EVENT_PACKET_READ_READY: {
     error = this->_state_common_receive_packet();
@@ -465,9 +463,9 @@ QUICNetVConnection::state_connection_established(int event, 
Event *data)
     DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event));
   }
 
-  if (error.cls != QUICErrorClass::NONE) {
-    // TODO: Send error if needed
-    DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast<unsigned 
int>(error.cls), static_cast<unsigned int>(error.code));
+  if (error->cls != QUICErrorClass::NONE) {
+    DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast<unsigned 
int>(error->cls), static_cast<unsigned int>(error->code));
+    this->_handle_error(std::move(error));
   }
 
   return EVENT_CONT;
@@ -476,7 +474,7 @@ QUICNetVConnection::state_connection_established(int event, 
Event *data)
 int
 QUICNetVConnection::state_connection_closing(int event, Event *data)
 {
-  QUICError error;
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
   switch (event) {
   case QUIC_EVENT_PACKET_READ_READY: {
     error = this->_state_common_receive_packet();
@@ -576,64 +574,65 @@ QUICNetVConnection::largest_acked_packet_number()
   return this->_loss_detector->largest_acked_packet_number();
 }
 
-QUICError
+QUICErrorUPtr
 
QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr
 packet)
 {
   if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) {
     DebugQUICCon("Packet size is smaller than the minimum initial client 
packet size");
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR);
+    // Ignore the packet
+    return QUICErrorUPtr(new QUICNoError());
   }
 
   // Start handshake
-  QUICError error = this->_handshake_handler->start(packet.get(), 
&this->_packet_factory);
+  QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), 
&this->_packet_factory);
   if (this->_handshake_handler->is_version_negotiated()) {
     // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing)
     if (packet->has_valid_fnv1a_hash()) {
       bool should_send_ack;
       error = this->_frame_dispatcher->receive_frames(packet->payload(), 
packet->payload_size(), should_send_ack);
-      if (error.cls != QUICErrorClass::NONE) {
+      if (error->cls != QUICErrorClass::NONE) {
         return error;
       }
       error = 
this->_local_flow_controller->update(this->_stream_manager->total_offset_received());
       Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" 
PRIu64,
             static_cast<uint64_t>(this->_quic_connection_id), 
this->_local_flow_controller->current_offset(),
             this->_local_flow_controller->current_limit());
-      if (error.cls != QUICErrorClass::NONE) {
+      if (error->cls != QUICErrorClass::NONE) {
         return error;
       }
     } else {
       DebugQUICCon("Invalid FNV-1a hash value");
-      return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::CRYPTOGRAPHIC_ERROR);
+      // Discard the packet
     }
   }
   return error;
 }
 
-QUICError
+QUICErrorUPtr
 
QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr
 packet)
 {
-  QUICError error = QUICError(QUICErrorClass::NONE);
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   // The payload of this packet contains STREAM frames and could contain 
PADDING and ACK frames
   if (packet->has_valid_fnv1a_hash()) {
     error = this->_recv_and_ack(packet->payload(), packet->payload_size(), 
packet->packet_number());
   } else {
     DebugQUICCon("Invalid FNV-1a hash value");
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::CRYPTOGRAPHIC_ERROR);
+    // Discard the packet
   }
   return error;
 }
 
-QUICError
+QUICErrorUPtr
 
QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr
 packet)
 {
   // TODO: Decrypt the packet
   // decrypt(payload, p);
   // TODO: Not sure what we have to do
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
-QUICError
+QUICErrorUPtr
 
QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr 
packet)
 {
   // TODO: fix size
@@ -650,15 +649,15 @@ 
QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr
   } else {
     DebugQUICCon("CRYPTOGRAPHIC Error");
 
-    return QUICError(QUICErrorClass::CRYPTOGRAPHIC);
+    return QUICConnectionErrorUPtr(new 
QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, 
QUICErrorCode::CRYPTOGRAPHIC_ERROR));
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICNetVConnection::_state_common_receive_packet()
 {
-  QUICError error;
-  QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), 
&QUICPacketDeleter::delete_packet);
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
+  QUICPacketUPtr p    = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), 
&QUICPacketDeleter::delete_packet);
   net_activity(this, this_ethread());
 
   switch (p->type()) {
@@ -667,13 +666,13 @@ QUICNetVConnection::_state_common_receive_packet()
     error = this->_state_connection_established_process_packet(std::move(p));
     break;
   default:
-    error = QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR);
+    error = QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR));
     break;
   }
   return error;
 }
 
-QUICError
+QUICErrorUPtr
 QUICNetVConnection::_state_common_send_packet()
 {
   this->_packetize_frames();
@@ -688,19 +687,19 @@ QUICNetVConnection::_state_common_send_packet()
 
   net_activity(this, this_ethread());
 
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
 // Schedule sending BLOCKED frame when offset exceed the limit
 bool
 QUICNetVConnection::_is_send_frame_avail_more_than(uint32_t size)
 {
-  QUICError error = 
this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent()
 + size) / 1024);
+  QUICErrorUPtr error = 
this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent()
 + size) / 1024);
   Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" 
PRIu64,
         static_cast<uint64_t>(this->_quic_connection_id), 
this->_remote_flow_controller->current_offset(),
         this->_remote_flow_controller->current_limit());
 
-  if (error.cls != QUICErrorClass::NONE) {
+  if (error->cls != QUICErrorClass::NONE) {
     // Flow Contoroller blocked sending STREAM frame
     return false;
   }
@@ -792,7 +791,7 @@ QUICNetVConnection::_packetize_frames()
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, 
QUICPacketNumber packet_num)
 {
   if (packet_num > this->_largest_received_packet_number) {
@@ -801,17 +800,17 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, 
uint16_t size, QUICPac
 
   bool should_send_ack;
 
-  QUICError error;
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   error = this->_frame_dispatcher->receive_frames(payload, size, 
should_send_ack);
-  if (error.cls != QUICErrorClass::NONE) {
+  if (error->cls != QUICErrorClass::NONE) {
     return error;
   }
 
   error = 
this->_local_flow_controller->update(this->_stream_manager->total_offset_received());
   Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" 
PRIu64, static_cast<uint64_t>(this->_quic_connection_id),
         this->_local_flow_controller->current_offset(), 
this->_local_flow_controller->current_limit());
-  if (error.cls != QUICErrorClass::NONE) {
+  if (error->cls != QUICErrorClass::NONE) {
     return error;
   }
   // this->_local_flow_controller->forward_limit();
@@ -872,3 +871,19 @@ QUICNetVConnection::_init_flow_control_params(const 
std::shared_ptr<const QUICTr
         static_cast<uint64_t>(this->_quic_connection_id), 
this->_remote_flow_controller->current_offset(),
         this->_remote_flow_controller->current_limit());
 }
+
+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 (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
+    // Stream Error
+    QUICStreamError *serror = static_cast<QUICStreamError *>(error.release());
+    serror->stream->reset(QUICStreamErrorUPtr(serror));
+  } else {
+    // Connection Error
+    QUICConnectionError *cerror = static_cast<QUICConnectionError 
*>(error.release());
+    this->close(QUICConnectionErrorUPtr(cerror));
+  }
+}
diff --git a/iocore/net/quic/QUICCongestionController.cc 
b/iocore/net/quic/QUICCongestionController.cc
index 19939fe..4a0ea79 100644
--- a/iocore/net/quic/QUICCongestionController.cc
+++ b/iocore/net/quic/QUICCongestionController.cc
@@ -31,10 +31,10 @@ QUICCongestionController::interests()
   return {QUICFrameType::ACK, QUICFrameType::STREAM};
 }
 
-QUICError
+QUICErrorUPtr
 QUICCongestionController::handle_frame(std::shared_ptr<const QUICFrame> frame)
 {
-  QUICError error = QUICError(QUICErrorClass::NONE);
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   switch (frame->type()) {
   case QUICFrameType::STREAM:
diff --git a/iocore/net/quic/QUICCongestionController.h 
b/iocore/net/quic/QUICCongestionController.h
index cf8191b..d44b9bf 100644
--- a/iocore/net/quic/QUICCongestionController.h
+++ b/iocore/net/quic/QUICCongestionController.h
@@ -31,7 +31,7 @@ class QUICCongestionController : public QUICFrameHandler
 {
 public:
   virtual std::vector<QUICFrameType> interests() override;
-  virtual QUICError handle_frame(std::shared_ptr<const QUICFrame>) override;
+  virtual QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame>) 
override;
 
 private:
 };
diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h
index 6901819..e0bb194 100644
--- a/iocore/net/quic/QUICConnection.h
+++ b/iocore/net/quic/QUICConnection.h
@@ -55,7 +55,7 @@ public:
   virtual uint32_t pmtu()                                   = 0;
   virtual NetVConnectionContext_t direction()               = 0;
   virtual SSLNextProtocolSet *next_protocol_set()           = 0;
-  virtual void close(QUICError error)                       = 0;
+  virtual void close(QUICConnectionErrorUPtr error)         = 0;
   virtual QUICPacketNumber largest_received_packet_number() = 0;
   virtual QUICPacketNumber largest_acked_packet_number()    = 0;
 };
diff --git a/iocore/net/quic/QUICFlowController.cc 
b/iocore/net/quic/QUICFlowController.cc
index e0dcbec..18deeea 100644
--- a/iocore/net/quic/QUICFlowController.cc
+++ b/iocore/net/quic/QUICFlowController.cc
@@ -40,18 +40,18 @@ QUICFlowController::current_limit()
   return this->_limit;
 }
 
-QUICError
+QUICErrorUPtr
 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 QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::FLOW_CONTROL_ERROR);
+      return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::FLOW_CONTROL_ERROR));
     }
     this->_offset = offset;
   }
 
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
 void
@@ -81,10 +81,10 @@ QUICRemoteFlowController::forward_limit(QUICOffset offset)
   this->_blocked = false;
 }
 
-QUICError
+QUICErrorUPtr
 QUICRemoteFlowController::update(QUICOffset offset)
 {
-  QUICError error = QUICFlowController::update(offset);
+  QUICErrorUPtr error = QUICFlowController::update(offset);
 
   // Assume flow control is not initialized if the limit was 0
   if (this->_limit == 0) {
diff --git a/iocore/net/quic/QUICFlowController.h 
b/iocore/net/quic/QUICFlowController.h
index 9badb74..d195728 100644
--- a/iocore/net/quic/QUICFlowController.h
+++ b/iocore/net/quic/QUICFlowController.h
@@ -33,7 +33,7 @@ class QUICFlowController
 public:
   QUICOffset current_offset();
   QUICOffset current_limit();
-  virtual QUICError update(QUICOffset offset);
+  virtual QUICErrorUPtr update(QUICOffset offset);
   virtual void forward_limit(QUICOffset limit);
   void set_threshold(uint64_t threshold);
 
@@ -51,7 +51,7 @@ class QUICRemoteFlowController : public QUICFlowController
 {
 public:
   QUICRemoteFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : 
QUICFlowController(initial_limit, tx) {}
-  QUICError update(QUICOffset offset) override;
+  QUICErrorUPtr update(QUICOffset offset) override;
   void forward_limit(QUICOffset limit) override;
 
 private:
diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 48405bd..0db9d8c 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -22,6 +22,7 @@
  */
 
 #include "QUICFrame.h"
+#include "QUICStream.h"
 
 ClassAllocator<QUICStreamFrame> 
quicStreamFrameAllocator("quicStreamFrameAllocator");
 ClassAllocator<QUICAckFrame> quicAckFrameAllocator("quicAckFrameAllocator");
@@ -1333,6 +1334,12 @@ 
QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16
   return std::unique_ptr<QUICConnectionCloseFrame, 
QUICFrameDeleterFunc>(frame, &QUICFrameDeleter::delete_connection_close_frame);
 }
 
+std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc>
+QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error)
+{
+  return QUICFrameFactory::create_connection_close_frame(error->code, 
strlen(error->msg), error->msg);
+}
+
 std::unique_ptr<QUICMaxDataFrame, QUICFrameDeleterFunc>
 QUICFrameFactory::create_max_data_frame(uint64_t maximum_data)
 {
@@ -1373,6 +1380,12 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId 
stream_id, QUICErrorCode
   return std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc>(frame, 
&QUICFrameDeleter::delete_rst_stream_frame);
 }
 
+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());
+}
+
 std::unique_ptr<QUICStopSendingFrame, QUICFrameDeleterFunc>
 QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, 
QUICErrorCode error_code)
 {
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index ba7841c..15c098c 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -603,6 +603,8 @@ public:
    */
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> 
create_connection_close_frame(
     QUICErrorCode error_code, uint16_t reason_phrase_length, const char 
*reason_phrase);
+  static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> 
create_connection_close_frame(
+    QUICConnectionErrorUPtr error);
 
   /*
    * Creates a MAX_DATA frame.
@@ -631,6 +633,7 @@ public:
   static std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc> 
create_rst_stream_frame(QUICStreamId stream_id,
                                                                                
            QUICErrorCode error_code,
                                                                                
            QUICOffset final_offset);
+  static std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc> 
create_rst_stream_frame(QUICStreamErrorUPtr error);
 
   /*
    * Creates a STOP_SENDING frame.
diff --git a/iocore/net/quic/QUICFrameDispatcher.cc 
b/iocore/net/quic/QUICFrameDispatcher.cc
index 5b87cd1..c23fff1 100644
--- a/iocore/net/quic/QUICFrameDispatcher.cc
+++ b/iocore/net/quic/QUICFrameDispatcher.cc
@@ -43,13 +43,13 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler)
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, 
bool &should_send_ack)
 {
   std::shared_ptr<const QUICFrame> frame(nullptr);
-  uint16_t cursor = 0;
-  should_send_ack = false;
-  QUICError error = QUICError(QUICErrorClass::NONE);
+  uint16_t cursor     = 0;
+  should_send_ack     = false;
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   while (cursor < size) {
     frame = this->_frame_factory.fast_create(payload + cursor, size - cursor);
@@ -72,7 +72,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, 
uint16_t size, bool
     for (auto h : handlers) {
       error = h->handle_frame(frame);
       // TODO: is there any case to continue this loop even if error?
-      if (error.cls != QUICErrorClass::NONE) {
+      if (error->cls != QUICErrorClass::NONE) {
         return error;
       }
     }
diff --git a/iocore/net/quic/QUICFrameDispatcher.h 
b/iocore/net/quic/QUICFrameDispatcher.h
index 0c61f39..397f0d3 100644
--- a/iocore/net/quic/QUICFrameDispatcher.h
+++ b/iocore/net/quic/QUICFrameDispatcher.h
@@ -33,7 +33,7 @@ public:
   /*
    * Returns true if ACK frame should be sent
    */
-  QUICError receive_frames(const uint8_t *payload, uint16_t size, bool 
&should_send_ack);
+  QUICErrorUPtr receive_frames(const uint8_t *payload, uint16_t size, bool 
&should_send_ack);
 
   void add_handler(QUICFrameHandler *handler);
 
diff --git a/iocore/net/quic/QUICFrameHandler.h 
b/iocore/net/quic/QUICFrameHandler.h
index 0f2a27f..e857513 100644
--- a/iocore/net/quic/QUICFrameHandler.h
+++ b/iocore/net/quic/QUICFrameHandler.h
@@ -30,6 +30,6 @@ class QUICFrameHandler
 {
 public:
   virtual ~QUICFrameHandler(){};
-  virtual std::vector<QUICFrameType> interests()                         = 0;
-  virtual QUICError handle_frame(std::shared_ptr<const QUICFrame> frame) = 0;
+  virtual std::vector<QUICFrameType> interests()                             = 
0;
+  virtual QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame> frame) = 
0;
 };
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index daa47aa..7c34690 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -72,13 +72,13 @@ QUICHandshake::~QUICHandshake()
   SSL_free(this->_ssl);
 }
 
-QUICError
+QUICErrorUPtr
 QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory 
*packet_factory)
 {
   // Negotiate version
   if (this->_version_negotiator->status() == 
QUICVersionNegotiationStatus::NOT_NEGOTIATED) {
     if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) {
-      return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR);
+      return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::PROTOCOL_VIOLATION));
     }
     if (initial_packet->version()) {
       if (this->_version_negotiator->negotiate(initial_packet) == 
QUICVersionNegotiationStatus::NEGOTIATED) {
@@ -90,10 +90,10 @@ QUICHandshake::start(const QUICPacket *initial_packet, 
QUICPacketFactory *packet
         Debug(tag, "Version negotiation failed: %x", 
initial_packet->version());
       }
     } else {
-      return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR);
+      return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::PROTOCOL_VIOLATION));
     }
   }
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
 bool
@@ -136,7 +136,8 @@ 
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({QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::VERSION_NEGOTIATION_ERROR});
+      this->_client_qc->close(
+        QUICConnectionErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::VERSION_NEGOTIATION_ERROR)));
       Debug(tag, "Enter state_closed");
       SET_HANDLER(&QUICHandshake::state_closed);
       return;
@@ -168,7 +169,7 @@ QUICHandshake::remote_transport_parameters()
 int
 QUICHandshake::state_read_client_hello(int event, Event *data)
 {
-  QUICError error;
+  QUICErrorUPtr error;
   switch (event) {
   case VC_EVENT_READ_READY:
   case VC_EVENT_READ_COMPLETE: {
@@ -180,8 +181,13 @@ QUICHandshake::state_read_client_hello(int event, Event 
*data)
     break;
   }
 
-  if (error.cls != QUICErrorClass::NONE) {
-    this->_client_qc->close(error);
+  if (error->cls != QUICErrorClass::NONE) {
+    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)));
+    }
     Debug(tag, "Enter state_closed");
     SET_HANDLER(&QUICHandshake::state_closed);
   }
@@ -192,7 +198,7 @@ QUICHandshake::state_read_client_hello(int event, Event 
*data)
 int
 QUICHandshake::state_read_client_finished(int event, Event *data)
 {
-  QUICError error;
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
   switch (event) {
   case VC_EVENT_READ_READY:
   case VC_EVENT_READ_COMPLETE: {
@@ -204,8 +210,13 @@ QUICHandshake::state_read_client_finished(int event, Event 
*data)
     break;
   }
 
-  if (error.cls != QUICErrorClass::NONE) {
-    this->_client_qc->close(error);
+  if (error->cls != QUICErrorClass::NONE) {
+    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)));
+    }
     Debug(tag, "Enter state_closed");
     SET_HANDLER(&QUICHandshake::state_closed);
   }
@@ -267,7 +278,7 @@ QUICHandshake::_load_local_transport_parameters()
   this->_local_transport_parameters = 
std::unique_ptr<QUICTransportParameters>(tp);
 }
 
-QUICError
+QUICErrorUPtr
 QUICHandshake::_process_client_hello()
 {
   QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE);
@@ -279,7 +290,7 @@ QUICHandshake::_process_client_hello()
 
   if (msg_len <= 0) {
     Debug(tag, "No message");
-    return QUICError(QUICErrorClass::NONE);
+    return QUICErrorUPtr(new QUICNoError());
   }
 
   // ----- DEBUG ----->
@@ -305,13 +316,13 @@ QUICHandshake::_process_client_hello()
     stream_io->write_reenable();
     stream_io->read_reenable();
 
-    return QUICError(QUICErrorClass::NONE);
+    return QUICErrorUPtr(new QUICNoError());
   } else {
-    return QUICError(QUICErrorClass::CRYPTOGRAPHIC, 
QUICErrorCode::TLS_HANDSHAKE_FAILED);
+    return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, 
QUICErrorCode::TLS_HANDSHAKE_FAILED));
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICHandshake::_process_client_finished()
 {
   QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE);
@@ -323,7 +334,7 @@ QUICHandshake::_process_client_finished()
 
   if (msg_len <= 0) {
     Debug(tag, "No message");
-    return QUICError(QUICErrorClass::NONE);
+    return QUICErrorUPtr(new QUICNoError());
   }
 
   // ----- DEBUG ----->
@@ -353,13 +364,13 @@ QUICHandshake::_process_client_finished()
     stream_io->write_reenable();
     stream_io->read_reenable();
 
-    return QUICError(QUICErrorClass::NONE);
+    return QUICErrorUPtr(new QUICNoError());
   } else {
-    return QUICError(QUICErrorClass::CRYPTOGRAPHIC, 
QUICErrorCode::TLS_HANDSHAKE_FAILED);
+    return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, 
QUICErrorCode::TLS_HANDSHAKE_FAILED));
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICHandshake::_process_handshake_complete()
 {
   QUICCrypto *crypto = this->_crypto;
@@ -371,5 +382,5 @@ QUICHandshake::_process_handshake_complete()
     Debug(tag, "Failed to export Keying Materials");
   }
 
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h
index 5d0060a..d74344f 100644
--- a/iocore/net/quic/QUICHandshake.h
+++ b/iocore/net/quic/QUICHandshake.h
@@ -53,7 +53,7 @@ public:
   QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessToken 
token);
   ~QUICHandshake();
 
-  QUICError start(const QUICPacket *initial_packet, QUICPacketFactory 
*packet_factory);
+  QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory 
*packet_factory);
 
   // States
   int state_read_client_hello(int event, Event *data);
@@ -84,9 +84,9 @@ private:
 
   void _load_local_transport_parameters();
 
-  QUICError _process_client_hello();
-  QUICError _process_client_finished();
-  QUICError _process_handshake_complete();
+  QUICErrorUPtr _process_client_hello();
+  QUICErrorUPtr _process_client_finished();
+  QUICErrorUPtr _process_handshake_complete();
 
   QUICStatelessToken _token;
 };
diff --git a/iocore/net/quic/QUICLossDetector.cc 
b/iocore/net/quic/QUICLossDetector.cc
index 1662fa7..33d923d 100644
--- a/iocore/net/quic/QUICLossDetector.cc
+++ b/iocore/net/quic/QUICLossDetector.cc
@@ -81,10 +81,10 @@ QUICLossDetector::interests()
   return {QUICFrameType::ACK};
 }
 
-QUICError
+QUICErrorUPtr
 QUICLossDetector::handle_frame(std::shared_ptr<const QUICFrame> frame)
 {
-  QUICError error = QUICError(QUICErrorClass::NONE);
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   switch (frame->type()) {
   case QUICFrameType::ACK:
diff --git a/iocore/net/quic/QUICLossDetector.h 
b/iocore/net/quic/QUICLossDetector.h
index 5b52b55..7313694 100644
--- a/iocore/net/quic/QUICLossDetector.h
+++ b/iocore/net/quic/QUICLossDetector.h
@@ -46,7 +46,7 @@ public:
   int event_handler(int event, Event *edata);
 
   std::vector<QUICFrameType> interests() override;
-  virtual QUICError handle_frame(std::shared_ptr<const QUICFrame>) override;
+  virtual QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame>) 
override;
   void on_packet_sent(QUICPacketUPtr packet);
   QUICPacketNumber largest_acked_packet_number();
 
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 1a9cff2..dd41ff3 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -70,11 +70,18 @@ QUICStream::id()
   return this->_id;
 }
 
+QUICOffset
+QUICStream::final_offset()
+{
+  // TODO Return final offset
+  return 0;
+}
+
 int
 QUICStream::main_event_handler(int event, void *data)
 {
   DebugQUICStream("%s", QUICDebugNames::vc_event(event));
-  QUICError error;
+  QUICErrorUPtr error = std::unique_ptr<QUICError>(new QUICNoError());
 
   switch (event) {
   case VC_EVENT_READ_READY:
@@ -104,10 +111,17 @@ QUICStream::main_event_handler(int event, void *data)
     ink_assert(false);
   }
 
-  if (error.cls != QUICErrorClass::NONE) {
-    // TODO Send error if needed
-    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::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 (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
+      // Stream Error
+      QUICStreamErrorUPtr serror = 
QUICStreamErrorUPtr(static_cast<QUICStreamError *>(error.get()));
+      this->reset(std::move(serror));
+    } else {
+      // Connection Error
+      // TODO Close connection (Does this really happen?)
+    }
   }
 
   return EVENT_CONT;
@@ -281,7 +295,7 @@ QUICStream::_reorder_data()
  * If the reordering or writting operation is heavy, split out them to read 
function,
  * which is called by application via do_io_read() or reenable().
  */
-QUICError
+QUICErrorUPtr
 QUICStream::recv(const std::shared_ptr<const QUICStreamFrame> frame)
 {
   ink_assert(_id == frame->stream_id());
@@ -289,23 +303,22 @@ 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)) {
-    this->reset();
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::INTERNAL_ERROR);
+    return QUICErrorUPtr(new QUICStreamError(this, 
QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_STATE_ERROR));
   }
 
   // Flow Control - Even if it's allowed to receive on the state, it may 
exceed the limit
-  QUICError error = this->_local_flow_controller->update(frame->offset() + 
frame->data_length());
+  QUICErrorUPtr error = this->_local_flow_controller->update(frame->offset() + 
frame->data_length());
   Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" 
PRIu64, this->_id,
         QUICDebugNames::stream_state(this->_state), 
this->_local_flow_controller->current_offset(),
         this->_local_flow_controller->current_limit());
-  if (error.cls != QUICErrorClass::NONE) {
+  if (error->cls != QUICErrorClass::NONE) {
     return error;
   }
 
   // Reordering - Some frames may be delayed or be dropped
   if (this->_recv_offset > frame->offset()) {
     // Do nothing. Just ignore STREAM frame.
-    return QUICError(QUICErrorClass::NONE);
+    return QUICErrorUPtr(new QUICNoError());
   } else if (this->_recv_offset == frame->offset()) {
     this->_write_to_read_vio(frame);
     this->_reorder_data();
@@ -315,10 +328,10 @@ QUICStream::recv(const std::shared_ptr<const 
QUICStreamFrame> frame)
     this->_received_stream_frame_buffer.insert(std::make_pair(frame->offset(), 
frame));
   }
 
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
-QUICError
+QUICErrorUPtr
 QUICStream::recv(const std::shared_ptr<const QUICMaxStreamDataFrame> frame)
 {
   this->_remote_flow_controller->forward_limit(frame->maximum_stream_data());
@@ -328,25 +341,26 @@ QUICStream::recv(const std::shared_ptr<const 
QUICMaxStreamDataFrame> frame)
 
   this->reenable(&this->_write_vio);
 
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
-QUICError
+QUICErrorUPtr
 QUICStream::recv(const std::shared_ptr<const QUICStreamBlockedFrame> frame)
 {
   // STREAM_BLOCKED frames are for debugging. Nothing to do here.
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
 /**
  * @brief Send STREAM DATA from _response_buffer
  */
-QUICError
+QUICErrorUPtr
 QUICStream::_send()
 {
   SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
 
-  QUICError error;
+  QUICErrorUPtr error = std::unique_ptr<QUICError>(new QUICNoError());
+
   IOBufferReader *reader = this->_write_vio.get_reader();
   int64_t bytes_avail    = reader->read_avail();
   int64_t total_len      = 0;
@@ -366,11 +380,11 @@ QUICStream::_send()
       }
     }
 
-    QUICError error = this->_remote_flow_controller->update(this->_send_offset 
+ len);
+    error = this->_remote_flow_controller->update(this->_send_offset + len);
     Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" 
PRIu64, this->_id,
           QUICDebugNames::stream_state(this->_state), 
this->_remote_flow_controller->current_offset(),
           this->_remote_flow_controller->current_limit());
-    if (error.cls != QUICErrorClass::NONE) {
+    if (error->cls != QUICErrorClass::NONE) {
       break;
     }
 
@@ -394,9 +408,9 @@ QUICStream::_send()
 }
 
 void
-QUICStream::reset()
+QUICStream::reset(QUICStreamErrorUPtr error)
 {
-  // TODO: Create a RST_STREAM frame and pass it to Stream Manager
+  
this->_tx->transmit_frame(QUICFrameFactory::create_rst_stream_frame(std::move(error)));
 }
 
 void
diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h
index d8b476c..bdb78ae 100644
--- a/iocore/net/quic/QUICStream.h
+++ b/iocore/net/quic/QUICStream.h
@@ -52,6 +52,7 @@ public:
   int main_event_handler(int event, void *data);
 
   QUICStreamId id();
+  QUICOffset final_offset();
 
   // Implement VConnection interface.
   VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf 
= nullptr) override;
@@ -60,11 +61,11 @@ public:
   void do_io_shutdown(ShutdownHowTo_t howto) override;
   void reenable(VIO *vio) override;
 
-  QUICError recv(const std::shared_ptr<const QUICStreamFrame> frame);
-  QUICError recv(const std::shared_ptr<const QUICMaxStreamDataFrame> frame);
-  QUICError recv(const std::shared_ptr<const QUICStreamBlockedFrame> frame);
+  QUICErrorUPtr recv(const std::shared_ptr<const QUICStreamFrame> frame);
+  QUICErrorUPtr recv(const std::shared_ptr<const QUICMaxStreamDataFrame> 
frame);
+  QUICErrorUPtr recv(const std::shared_ptr<const QUICStreamBlockedFrame> 
frame);
 
-  void reset();
+  void reset(QUICStreamErrorUPtr error);
   void shutdown();
 
   size_t nbytes_to_read();
@@ -77,7 +78,7 @@ public:
 private:
   QUICStreamState _state;
 
-  QUICError _send();
+  QUICErrorUPtr _send();
 
   void _write_to_read_vio(const std::shared_ptr<const QUICStreamFrame> &);
   void _reorder_data();
diff --git a/iocore/net/quic/QUICStreamManager.cc 
b/iocore/net/quic/QUICStreamManager.cc
index ba322ff..2832328 100644
--- a/iocore/net/quic/QUICStreamManager.cc
+++ b/iocore/net/quic/QUICStreamManager.cc
@@ -85,10 +85,10 @@ QUICStreamManager::set_max_stream_id(QUICStreamId id)
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICStreamManager::handle_frame(std::shared_ptr<const QUICFrame> frame)
 {
-  QUICError error = QUICError(QUICErrorClass::NONE);
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
 
   switch (frame->type()) {
   case QUICFrameType::MAX_STREAM_DATA:
@@ -116,34 +116,34 @@ QUICStreamManager::handle_frame(std::shared_ptr<const 
QUICFrame> frame)
   return error;
 }
 
-QUICError
+QUICErrorUPtr
 QUICStreamManager::_handle_frame(const std::shared_ptr<const 
QUICMaxStreamDataFrame> &frame)
 {
   QUICStream *stream = this->_find_or_create_stream(frame->stream_id());
   if (stream) {
     return stream->recv(frame);
   } else {
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR);
+    return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR));
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICStreamManager::_handle_frame(const std::shared_ptr<const 
QUICStreamBlockedFrame> &frame)
 {
   QUICStream *stream = this->_find_or_create_stream(frame->stream_id());
   if (stream) {
     return stream->recv(frame);
   } else {
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR);
+    return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR));
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICStreamManager::_handle_frame(const std::shared_ptr<const QUICStreamFrame> 
&frame)
 {
   QUICStream *stream = this->_find_or_create_stream(frame->stream_id());
   if (!stream) {
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR);
+    return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR));
   }
 
   QUICApplication *application = this->_app_map->get(frame->stream_id());
@@ -153,7 +153,7 @@ QUICStreamManager::_handle_frame(const 
std::shared_ptr<const QUICStreamFrame> &f
   }
 
   size_t nbytes_to_read = stream->nbytes_to_read();
-  QUICError error       = stream->recv(frame);
+  QUICErrorUPtr error   = stream->recv(frame);
   // Prevent trigger read events multiple times
   if (nbytes_to_read == 0) {
     this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream);
@@ -162,23 +162,23 @@ QUICStreamManager::_handle_frame(const 
std::shared_ptr<const QUICStreamFrame> &f
   return error;
 }
 
-QUICError
+QUICErrorUPtr
 QUICStreamManager::_handle_frame(const std::shared_ptr<const 
QUICRstStreamFrame> &frame)
 {
   QUICStream *stream = this->_find_or_create_stream(frame->stream_id());
   if (stream) {
     // TODO Reset the stream
-    return QUICError(QUICErrorClass::NONE);
+    return QUICErrorUPtr(new QUICNoError());
   } else {
-    return QUICError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR);
+    return QUICErrorUPtr(new 
QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, 
QUICErrorCode::STREAM_ID_ERROR));
   }
 }
 
-QUICError
+QUICErrorUPtr
 QUICStreamManager::_handle_frame(const std::shared_ptr<const 
QUICMaxStreamIdFrame> &frame)
 {
   this->_remote_maximum_stream_id = frame->maximum_stream_id();
-  return QUICError(QUICErrorClass::NONE);
+  return QUICErrorUPtr(new QUICNoError());
 }
 
 QUICStream *
diff --git a/iocore/net/quic/QUICStreamManager.h 
b/iocore/net/quic/QUICStreamManager.h
index 2f664ca..b6ad75f 100644
--- a/iocore/net/quic/QUICStreamManager.h
+++ b/iocore/net/quic/QUICStreamManager.h
@@ -53,16 +53,16 @@ public:
 
   // QUICFrameHandler
   virtual std::vector<QUICFrameType> interests() override;
-  virtual QUICError handle_frame(std::shared_ptr<const QUICFrame>) override;
+  virtual QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame>) 
override;
 
 private:
   QUICStream *_find_or_create_stream(QUICStreamId stream_id);
   QUICStream *_find_stream(QUICStreamId id);
-  QUICError _handle_frame(const std::shared_ptr<const QUICStreamFrame> &);
-  QUICError _handle_frame(const std::shared_ptr<const QUICRstStreamFrame> &);
-  QUICError _handle_frame(const std::shared_ptr<const QUICMaxStreamDataFrame> 
&);
-  QUICError _handle_frame(const std::shared_ptr<const QUICStreamBlockedFrame> 
&);
-  QUICError _handle_frame(const std::shared_ptr<const QUICMaxStreamIdFrame> &);
+  QUICErrorUPtr _handle_frame(const std::shared_ptr<const QUICStreamFrame> &);
+  QUICErrorUPtr _handle_frame(const std::shared_ptr<const QUICRstStreamFrame> 
&);
+  QUICErrorUPtr _handle_frame(const std::shared_ptr<const 
QUICMaxStreamDataFrame> &);
+  QUICErrorUPtr _handle_frame(const std::shared_ptr<const 
QUICStreamBlockedFrame> &);
+  QUICErrorUPtr _handle_frame(const std::shared_ptr<const 
QUICMaxStreamIdFrame> &);
 
   QUICFrameTransmitter *_tx                                 = nullptr;
   QUICApplicationMap *_app_map                              = nullptr;
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index f3773c3..c2673d9 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -146,20 +146,47 @@ enum class QUICErrorCode : uint32_t {
   // TODO Add error codes
 };
 
-struct QUICError {
-  QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, const 
QUICErrorCode error_code = QUICErrorCode::NO_ERROR,
-            const char *err_msg = nullptr)
-  {
-    cls  = error_class;
-    code = error_code;
-    msg  = err_msg;
-  };
-
+class QUICError
+{
+public:
+  virtual ~QUICError() {}
   QUICErrorClass cls;
   QUICErrorCode code;
   const char *msg;
+
+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){};
+};
+
+class QUICNoError : public QUICError
+{
+public:
+  QUICNoError() : QUICError() {}
+};
+
+class QUICConnectionError : public QUICError
+{
+public:
+  QUICConnectionError(const QUICErrorClass error_class, const QUICErrorCode 
error_code, const char *error_msg = nullptr)
+    : QUICError(error_class, error_code, error_msg){};
 };
 
+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){};
+  QUICStream *stream;
+};
+
+using QUICErrorUPtr           = std::unique_ptr<QUICError>;
+using QUICConnectionErrorUPtr = std::unique_ptr<QUICConnectionError>;
+using QUICStreamErrorUPtr     = std::unique_ptr<QUICStreamError>;
+
 class QUICStatelessToken
 {
 public:

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

Reply via email to