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

commit 5f46f5c50a8093536fc242da03b82f46c3035fc6
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed Aug 30 11:38:47 2017 +0900

    Update stream state after sending / receiving frames
---
 iocore/net/quic/QUICFrame.cc                 |  20 ++++-
 iocore/net/quic/QUICFrame.h                  |  12 ++-
 iocore/net/quic/QUICStream.cc                |   2 +-
 iocore/net/quic/QUICStreamState.cc           | 126 +++++++++++++++++++++++++--
 iocore/net/quic/test/test_QUICStreamState.cc | 119 ++++++++++++++++++++++---
 5 files changed, 256 insertions(+), 23 deletions(-)

diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index f0c0b5b..e99eda6 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -70,12 +70,13 @@ QUICFrame::reset(const uint8_t *buf, size_t len)
 // STREAM Frame
 //
 
-QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, 
QUICStreamId stream_id, QUICOffset offset)
+QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, 
QUICStreamId stream_id, QUICOffset offset, bool last)
 {
   this->_data      = data;
   this->_data_len  = data_len;
   this->_stream_id = stream_id;
   this->_offset    = offset;
+  this->_fin       = last;
 }
 
 QUICFrameType
@@ -108,6 +109,11 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool 
include_length_field) con
   buf[0] = static_cast<uint8_t>(QUICFrameType::STREAM);
   *len   = 1;
 
+  // "F" of "11FSSOOD"
+  if (this->has_fin_flag()) {
+    buf[0] += (0x01 << 5);
+  }
+
   // "SS" of "11FSSOOD"
   // use 32 bit length for now
   buf[0] += (0x03 << 3);
@@ -1278,10 +1284,10 @@ QUICFrameFactory::fast_create(const uint8_t *buf, 
size_t len)
 }
 
 std::unique_ptr<QUICStreamFrame, QUICFrameDeleterFunc>
-QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, 
QUICStreamId stream_id, QUICOffset offset)
+QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, 
QUICStreamId stream_id, QUICOffset offset, bool last)
 {
   QUICStreamFrame *frame = quicStreamFrameAllocator.alloc();
-  new (frame) QUICStreamFrame(data, data_len, stream_id, offset);
+  new (frame) QUICStreamFrame(data, data_len, stream_id, offset, last);
   return std::unique_ptr<QUICStreamFrame, QUICFrameDeleterFunc>(frame, 
&QUICFrameDeleter::delete_stream_frame);
 }
 
@@ -1333,6 +1339,14 @@ 
QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id)
   return std::unique_ptr<QUICStreamBlockedFrame, QUICFrameDeleterFunc>(frame, 
&QUICFrameDeleter::delete_stream_blocked_frame);
 }
 
+std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc>
+QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, 
QUICErrorCode error_code, QUICOffset final_offset)
+{
+  QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc();
+  new (frame) QUICRstStreamFrame(error_code, stream_id, final_offset);
+  return std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc>(frame, 
&QUICFrameDeleter::delete_rst_stream_frame);
+}
+
 std::unique_ptr<QUICRetransmissionFrame, QUICFrameDeleterFunc>
 QUICFrameFactory::create_retransmission_frame(std::unique_ptr<QUICFrame, 
QUICFrameDeleterFunc> original_frame,
                                               const QUICPacket 
&original_packet)
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 11fcf03..0272a82 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -58,7 +58,7 @@ class QUICStreamFrame : public QUICFrame
 public:
   QUICStreamFrame() : QUICFrame() {}
   QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {}
-  QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, 
QUICOffset offset);
+  QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, 
QUICOffset offset, bool last = false);
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual void store(uint8_t *buf, size_t *len) const override;
@@ -589,7 +589,8 @@ public:
    * You have to make sure that the data size won't exceed the maximum size of 
QUIC packet.
    */
   static std::unique_ptr<QUICStreamFrame, QUICFrameDeleterFunc> 
create_stream_frame(const uint8_t *data, size_t data_len,
-                                                                               
     QUICStreamId stream_id, QUICOffset offset);
+                                                                               
     QUICStreamId stream_id, QUICOffset offset,
+                                                                               
     bool last = false);
   /*
    * Creates a ACK frame.
    * You shouldn't call this directly but through QUICAckFrameCreator because 
QUICAckFrameCreator manages packet numbers that we
@@ -625,6 +626,13 @@ public:
   static std::unique_ptr<QUICStreamBlockedFrame, QUICFrameDeleterFunc> 
create_stream_blocked_frame(QUICStreamId stream_id);
 
   /*
+   * Creates a RST_STREAM frame.
+   */
+  static std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc> 
create_rst_stream_frame(QUICStreamId stream_id,
+                                                                               
            QUICErrorCode error_code,
+                                                                               
            QUICOffset final_offset);
+
+  /*
    * Creates a retransmission frame, which is very special.
    * This retransmission frame will be used only for retransmission and it's 
not a standard frame type.
    */
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index e77375f..79fd4e8 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -396,7 +396,7 @@ QUICStream::_send()
     total_len += len;
 
     if (!this->_state.is_allowed_to_send(*frame)) {
-      // FIXME: What should we do?
+      Debug(tag, "Canceled sending %s frame due to the stream state", 
QUICDebugNames::frame_type(frame->type()));
       break;
     }
     this->_state.update_with_sent_frame(*frame);
diff --git a/iocore/net/quic/QUICStreamState.cc 
b/iocore/net/quic/QUICStreamState.cc
index eb43130..2f78c3c 100644
--- a/iocore/net/quic/QUICStreamState.cc
+++ b/iocore/net/quic/QUICStreamState.cc
@@ -33,12 +33,52 @@ QUICStreamState::get() const
 bool
 QUICStreamState::is_allowed_to_send(const QUICFrame &frame) const
 {
+  switch (this->_state) {
+  case State::idle:
+    break;
+  case State::open:
+    break;
+  case State::half_closed_local:
+    if (frame.type() == QUICFrameType::STREAM) {
+      return false;
+    }
+    break;
+  case State::half_closed_remote:
+    break;
+  case State::closed:
+    // Once a stream reaches this state, no frames can be sent that mention 
the stream
+    if (frame.type() == QUICFrameType::STREAM) {
+      return false;
+    } else if (frame.type() == QUICFrameType::RST_STREAM) {
+      return false;
+    } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA) {
+      return false;
+    }
+    break;
+  case State::illegal:
+    return false;
+  }
   return true;
 }
 
 bool
 QUICStreamState::is_allowed_to_receive(const QUICFrame &frame) const
 {
+  switch (this->_state) {
+  case State::idle:
+    break;
+  case State::open:
+    break;
+  case State::half_closed_local:
+    break;
+  case State::half_closed_remote:
+    break;
+  case State::closed:
+    // Reordering might cause frames to be received after closing
+    break;
+  case State::illegal:
+    return false;
+  }
   return true;
 }
 
@@ -47,18 +87,46 @@ QUICStreamState::update_with_received_frame(const QUICFrame 
&frame)
 {
   switch (this->_state) {
   case State::idle:
-    this->_set_state(State::open);
-  // fall through
-  case State::open: {
-    if (frame.type() == QUICFrameType::STREAM && dynamic_cast<const 
QUICStreamFrame &>(frame).has_fin_flag()) {
+    if (frame.type() == QUICFrameType::STREAM) {
+      if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
+        this->_set_state(State::half_closed_remote);
+      } else {
+        this->_set_state(State::open);
+      }
+    } else if (frame.type() == QUICFrameType::RST_STREAM) {
       this->_set_state(State::half_closed_remote);
+    } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA || frame.type() 
== QUICFrameType::STREAM_BLOCKED) {
+      this->_set_state(State::open);
+    } else {
+      this->_set_state(State::illegal);
+    }
+    break;
+  case State::open:
+    if (frame.type() == QUICFrameType::STREAM) {
+      if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
+        this->_set_state(State::half_closed_remote);
+      }
     } else if (frame.type() == QUICFrameType::RST_STREAM) {
-      this->_set_state(State::closed);
+      this->_set_state(State::half_closed_remote);
+    } else {
+      this->_set_state(State::illegal);
     }
-  } break;
+    break;
   case State::half_closed_local:
+    if (frame.type() == QUICFrameType::STREAM) {
+      if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
+        this->_set_state(State::closed);
+      }
+    } else if (frame.type() == QUICFrameType::RST_STREAM) {
+      this->_set_state(State::closed);
+    } else {
+      this->_set_state(State::illegal);
+    }
+    break;
   case State::half_closed_remote:
+    break;
   case State::closed:
+    break;
   case State::illegal:
     // Once we get illegal state, no way to recover it
     break;
@@ -70,6 +138,52 @@ QUICStreamState::update_with_received_frame(const QUICFrame 
&frame)
 void
 QUICStreamState::update_with_sent_frame(const QUICFrame &frame)
 {
+  switch (this->_state) {
+  case State::idle:
+    if (frame.type() == QUICFrameType::STREAM) {
+      if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
+        this->_set_state(State::half_closed_local);
+      } else {
+        this->_set_state(State::open);
+      }
+    } else if (frame.type() == QUICFrameType::RST_STREAM) {
+      this->_set_state(State::half_closed_local);
+    } else {
+      this->_set_state(State::illegal);
+    }
+    break;
+  case State::open:
+    if (frame.type() == QUICFrameType::STREAM) {
+      if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
+        this->_set_state(State::half_closed_local);
+      }
+    } else if (frame.type() == QUICFrameType::RST_STREAM) {
+      this->_set_state(State::half_closed_local);
+    } else {
+      this->_set_state(State::illegal);
+    }
+    break;
+  case State::half_closed_local:
+    break;
+  case State::half_closed_remote:
+    if (frame.type() == QUICFrameType::STREAM) {
+      if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
+        this->_set_state(State::closed);
+      }
+    } else if (frame.type() == QUICFrameType::RST_STREAM) {
+      this->_set_state(State::closed);
+    } else {
+      this->_set_state(State::illegal);
+    }
+    break;
+  case State::closed:
+    break;
+  case State::illegal:
+    // Once we get illegal state, no way to recover it
+    break;
+  default:
+    break;
+  }
 }
 
 void
diff --git a/iocore/net/quic/test/test_QUICStreamState.cc 
b/iocore/net/quic/test/test_QUICStreamState.cc
index 353cffd..a771f66 100644
--- a/iocore/net/quic/test/test_QUICStreamState.cc
+++ b/iocore/net/quic/test/test_QUICStreamState.cc
@@ -28,20 +28,117 @@
 #include "quic/QUICFrame.h"
 #include "quic/QUICStreamState.h"
 
-TEST_CASE("QUICStreamState_Update", "[quic]")
+TEST_CASE("QUICStreamState_Idle", "[quic]")
 {
-  QUICStreamState ss;
+  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::QUIC_TRANSPORT_ERROR, 0);
+  auto max_stream_data_frame = 
QUICFrameFactory::create_max_stream_data_frame(0, 0);
+  auto stream_blocked_frame  = 
QUICFrameFactory::create_stream_blocked_frame(0);
 
-  std::shared_ptr<const QUICStreamFrame> streamFrame =
-    std::make_shared<const QUICStreamFrame>(reinterpret_cast<const uint8_t 
*>("foo"), 4, 1, 0);
-  std::shared_ptr<const QUICRstStreamFrame> rstStreamFrame =
-    std::make_shared<const 
QUICRstStreamFrame>(QUICErrorCode::QUIC_TRANSPORT_ERROR, 0, 0);
+  // Case1. Send STREAM
+  QUICStreamState ss1;
+  ss1.update_with_sent_frame(*stream_frame);
+  CHECK(ss1.get() == QUICStreamState::State::open);
 
-  CHECK(ss.get() == QUICStreamState::State::idle);
+  // Case2. Send RST_STREAM
+  QUICStreamState ss2;
+  ss2.update_with_sent_frame(*rst_stream_frame);
+  CHECK(ss2.get() == QUICStreamState::State::half_closed_local);
 
-  ss.update_with_received_frame(*streamFrame);
-  CHECK(ss.get() == QUICStreamState::State::open);
+  // Case3. Recv STREAM
+  QUICStreamState ss3;
+  ss3.update_with_received_frame(*stream_frame);
+  CHECK(ss3.get() == QUICStreamState::State::open);
 
-  ss.update_with_received_frame(*rstStreamFrame);
-  CHECK(ss.get() == QUICStreamState::State::closed);
+  // Case4. Recv RST_STREAM
+  QUICStreamState ss4;
+  ss4.update_with_received_frame(*rst_stream_frame);
+  CHECK(ss4.get() == QUICStreamState::State::half_closed_remote);
+
+  // Case5. Recv MAX_STREAM_DATA
+  QUICStreamState ss5;
+  ss5.update_with_received_frame(*max_stream_data_frame);
+  CHECK(ss5.get() == QUICStreamState::State::open);
+
+  // Case6. Recv STREAM_BLOCKED
+  QUICStreamState ss6;
+  ss6.update_with_received_frame(*stream_blocked_frame);
+  CHECK(ss6.get() == QUICStreamState::State::open);
+}
+
+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::QUIC_TRANSPORT_ERROR, 0);
+
+  // Case1. Send FIN in a STREAM
+  QUICStreamState ss1;
+  ss1.update_with_sent_frame(*stream_frame); // OPEN
+  CHECK(ss1.get() == QUICStreamState::State::open);
+  ss1.update_with_sent_frame(*stream_frame_with_fin);
+  CHECK(ss1.get() == QUICStreamState::State::half_closed_local);
+
+  // Case2. Send RST_STREAM
+  QUICStreamState ss2;
+  ss2.update_with_sent_frame(*stream_frame); // OPEN
+  CHECK(ss2.get() == QUICStreamState::State::open);
+  ss2.update_with_sent_frame(*rst_stream_frame);
+  CHECK(ss2.get() == QUICStreamState::State::half_closed_local);
+
+  // Case3. Recv FIN in a STREAM
+  QUICStreamState ss3;
+  ss3.update_with_received_frame(*stream_frame); // OPEN
+  CHECK(ss3.get() == QUICStreamState::State::open);
+  ss3.update_with_received_frame(*stream_frame_with_fin);
+  CHECK(ss3.get() == QUICStreamState::State::half_closed_remote);
+
+  // Case4. Recv RST_STREAM
+  QUICStreamState ss4;
+  ss4.update_with_received_frame(*stream_frame); // OPEN
+  CHECK(ss4.get() == QUICStreamState::State::open);
+  ss4.update_with_received_frame(*rst_stream_frame);
+  CHECK(ss4.get() == QUICStreamState::State::half_closed_remote);
+}
+
+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::QUIC_TRANSPORT_ERROR, 0);
+
+  // Case1. Send FIN in a STREAM
+  QUICStreamState ss1;
+  ss1.update_with_received_frame(*stream_frame_with_fin); // HALF CLOSED REMOTE
+  CHECK(ss1.get() == QUICStreamState::State::half_closed_remote);
+  ss1.update_with_sent_frame(*stream_frame_with_fin);
+  CHECK(ss1.get() == QUICStreamState::State::closed);
+
+  // Case2. Send RST
+  QUICStreamState ss2;
+  ss2.update_with_received_frame(*stream_frame_with_fin); // HALF CLOSED REMOTE
+  CHECK(ss2.get() == QUICStreamState::State::half_closed_remote);
+  ss2.update_with_sent_frame(*rst_stream_frame);
+  CHECK(ss2.get() == QUICStreamState::State::closed);
+}
+
+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::QUIC_TRANSPORT_ERROR, 0);
+
+  // Case1. Recv FIN in a STREAM
+  QUICStreamState ss1;
+  ss1.update_with_sent_frame(*stream_frame_with_fin); // HALF CLOSED LOCAL
+  CHECK(ss1.get() == QUICStreamState::State::half_closed_local);
+  ss1.update_with_received_frame(*stream_frame_with_fin);
+  CHECK(ss1.get() == QUICStreamState::State::closed);
+
+  // Case2. Recv RST
+  QUICStreamState ss2;
+  ss2.update_with_sent_frame(*stream_frame_with_fin); // HALF CLOSED LOCAL
+  CHECK(ss2.get() == QUICStreamState::State::half_closed_local);
+  ss2.update_with_received_frame(*rst_stream_frame);
+  CHECK(ss2.get() == QUICStreamState::State::closed);
 }

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to