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/09/01 07:49:10 UTC
[trafficserver] 01/05: Update stream state after sending /
receiving frames
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 <ma...@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" <co...@trafficserver.apache.org>.