trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mas...@apache.org
Subject [trafficserver] 01/05: Update stream state after sending / receiving frames
Date Fri, 01 Sep 2017 07:49:10 GMT
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 <maskit@apache.org>
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
"commits@trafficserver.apache.org" <commits@trafficserver.apache.org>.

Mime
View raw message