blob: e5ddb6c5fae55fbfb8bd97864370e50d85f7fdc4 [file] [log] [blame]
/** @file
*
* A brief file description
*
* @section license License
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "QUICStreamState.h"
#include "tscore/ink_assert.h"
// ---------QUICReceiveStreamState -----------
bool
QUICReceiveStreamStateMachine::is_allowed_to_send(const QUICFrame &frame) const
{
return this->is_allowed_to_send(frame.type());
}
bool
QUICReceiveStreamStateMachine::is_allowed_to_send(QUICFrameType type) const
{
if (type != QUICFrameType::STOP_SENDING && type != QUICFrameType::MAX_STREAM_DATA) {
return false;
}
QUICReceiveStreamState state = this->get();
// The receiver only sends MAX_STREAM_DATA in the "Recv" state.
if (type == QUICFrameType::MAX_STREAM_DATA && state == QUICReceiveStreamState::Recv) {
return true;
}
// A receiver can send STOP_SENDING in any state where it has not received a RESET_STREAM frame; that is states other than "Reset
// Recvd" or "Reset Read".
if (type == QUICFrameType::STOP_SENDING && state != QUICReceiveStreamState::ResetRecvd &&
state != QUICReceiveStreamState::ResetRead) {
return true;
}
return false;
}
bool
QUICReceiveStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) const
{
return this->is_allowed_to_receive(frame.type());
}
bool
QUICReceiveStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const
{
// always allow receive these frames.
if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) {
return true;
}
return false;
}
bool
QUICReceiveStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
{
return false;
}
bool
QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame)
{
bool state_changed = false;
// The receiving part of a stream initiated by a peer (types 1 and 3 for a client, or 0 and 2 for a server) is created when the
// first STREAM, STREAM_DATA_BLOCKED, or RESET_STREAM is received for that stream.
QUICReceiveStreamState state = this->get();
QUICFrameType type = frame.type();
if (state == QUICReceiveStreamState::Init &&
(type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) {
state_changed |= this->_set_state(QUICReceiveStreamState::Recv);
}
switch (this->get()) {
case QUICReceiveStreamState::Recv:
if (type == QUICFrameType::STREAM) {
if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
state_changed |= this->_set_state(QUICReceiveStreamState::SizeKnown);
if (this->_in_progress->is_transfer_complete()) {
state_changed |= this->_set_state(QUICReceiveStreamState::DataRecvd);
}
}
} else if (type == QUICFrameType::RESET_STREAM) {
state_changed |= this->_set_state(QUICReceiveStreamState::ResetRecvd);
}
break;
case QUICReceiveStreamState::SizeKnown:
if (type == QUICFrameType::STREAM && this->_in_progress->is_transfer_complete()) {
state_changed |= this->_set_state(QUICReceiveStreamState::DataRecvd);
} else if (type == QUICFrameType::RESET_STREAM) {
state_changed |= this->_set_state(QUICReceiveStreamState::ResetRecvd);
}
break;
case QUICReceiveStreamState::DataRecvd:
if (type == QUICFrameType::STREAM && this->_in_progress->is_transfer_complete()) {
state_changed |= this->_set_state(QUICReceiveStreamState::ResetRecvd);
}
break;
case QUICReceiveStreamState::Init:
case QUICReceiveStreamState::ResetRecvd:
case QUICReceiveStreamState::DataRead:
case QUICReceiveStreamState::ResetRead:
break;
default:
ink_assert(!"Unknown state");
break;
}
return state_changed;
}
bool
QUICReceiveStreamStateMachine::update_on_read()
{
if (this->_in_progress->is_transfer_complete()) {
return this->_set_state(QUICReceiveStreamState::DataRead);
}
return false;
}
bool
QUICReceiveStreamStateMachine::update_on_eos()
{
return this->_set_state(QUICReceiveStreamState::ResetRead);
}
bool
QUICReceiveStreamStateMachine::update(const QUICSendStreamState state)
{
// The receiving part of a stream enters the "Recv" state when the sending part of a bidirectional stream initiated by the
// endpoint (type 0 for a client, type 1 for a server) enters the "Ready" state.
switch (this->get()) {
case QUICReceiveStreamState::Init:
if (state == QUICSendStreamState::Ready) {
return this->_set_state(QUICReceiveStreamState::Recv);
}
break;
default:
break;
}
return false;
}
// ---------- QUICSendStreamState -------------
bool
QUICSendStreamStateMachine::is_allowed_to_send(const QUICFrame &frame) const
{
return this->is_allowed_to_send(frame.type());
}
bool
QUICSendStreamStateMachine::is_allowed_to_send(QUICFrameType type) const
{
if (type != QUICFrameType::STREAM && type != QUICFrameType::STREAM_DATA_BLOCKED && type != QUICFrameType::RESET_STREAM) {
return false;
}
switch (this->get()) {
case QUICSendStreamState::Ready:
if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) {
return true;
}
break;
case QUICSendStreamState::Send:
if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) {
return true;
}
break;
case QUICSendStreamState::DataSent:
if (type == QUICFrameType::RESET_STREAM) {
return true;
}
break;
// A sender MUST NOT send any of these frames from a terminal state ("Data Recvd" or "Reset Recvd").
case QUICSendStreamState::DataRecvd:
case QUICSendStreamState::ResetRecvd:
break;
// A sender MUST NOT send STREAM or STREAM_DATA_BLOCKED after sending a RESET_STREAM; that is, in the terminal states and in the
// "Reset Sent" state.
case QUICSendStreamState::ResetSent:
if (type == QUICFrameType::RESET_STREAM) {
return true;
}
break;
default:
ink_assert("This shouldn't be happen");
break;
}
return false;
}
bool
QUICSendStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) const
{
return this->is_allowed_to_receive(frame.type());
}
bool
QUICSendStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const
{
if (type != QUICFrameType::STOP_SENDING && type != QUICFrameType::MAX_STREAM_DATA) {
return false;
}
// A sender could receive either of these two frames(MAX_STREAM_DATA and STOP_SENDING) in any state as a result of delayed
// delivery of packets.
// PS: Because we need to reply a RESET_STREAM frame. STOP_SENDING frame is accepted in all states. But we
// don't need to do anything for MAX_STREAM_DATA frame when we are in terminal state.
if (type == QUICFrameType::STOP_SENDING) {
return true;
}
switch (this->get()) {
case QUICSendStreamState::Ready:
case QUICSendStreamState::Send:
if (type == QUICFrameType::MAX_STREAM_DATA) {
return true;
}
break;
// "MAX_STREAM_DATA frames might be received until the peer receives the final stream offset. The endpoint can safely ignore
// any MAX_STREAM_DATA frames it receives from its peer for a stream in this state."
case QUICSendStreamState::DataSent:
case QUICSendStreamState::ResetSent:
case QUICSendStreamState::DataRecvd:
case QUICSendStreamState::ResetRecvd:
if (type == QUICFrameType::MAX_STREAM_DATA) {
return true;
}
break;
default:
break;
}
return false;
}
bool
QUICSendStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
{
bool state_changed = false;
QUICSendStreamState state = this->get();
QUICFrameType type = frame.type();
if (state == QUICSendStreamState::Ready &&
(type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) {
state_changed |= this->_set_state(QUICSendStreamState::Send);
}
switch (this->get()) {
case QUICSendStreamState::Send:
if (type == QUICFrameType::STREAM) {
if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
state_changed |= this->_set_state(QUICSendStreamState::DataSent);
}
} else if (type == QUICFrameType::RESET_STREAM) {
state_changed |= this->_set_state(QUICSendStreamState::ResetSent);
}
break;
case QUICSendStreamState::DataSent:
if (type == QUICFrameType::RESET_STREAM) {
state_changed |= this->_set_state(QUICSendStreamState::ResetSent);
}
break;
case QUICSendStreamState::Init:
case QUICSendStreamState::Ready:
case QUICSendStreamState::DataRecvd:
case QUICSendStreamState::ResetSent:
case QUICSendStreamState::ResetRecvd:
break;
default:
ink_assert(!"Unknown state");
break;
}
return state_changed;
}
bool
QUICSendStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame)
{
return false;
}
bool
QUICSendStreamStateMachine::update_on_ack()
{
if (this->_out_progress->is_transfer_complete()) {
return this->_set_state(QUICSendStreamState::DataRecvd);
} else if (this->_out_progress->is_cancelled()) {
return this->_set_state(QUICSendStreamState::ResetRecvd);
}
return false;
}
bool
QUICSendStreamStateMachine::update(const QUICReceiveStreamState state)
{
bool state_changed = false;
// The sending part of a bidirectional stream initiated by a peer (type 0 for a server, type 1 for a client) enters the "Ready"
// state then immediately transitions to the "Send" state if the receiving part enters the "Recv" state (Section 3.2).
switch (this->get()) {
case QUICSendStreamState::Ready:
if (state == QUICReceiveStreamState::Recv) {
state_changed |= this->_set_state(QUICSendStreamState::Send);
}
break;
default:
break;
}
return state_changed;
}
// ---------QUICBidirectionalStreamState -----------
QUICBidirectionalStreamState
QUICBidirectionalStreamStateMachine::get() const
{
QUICSendStreamState s_state = this->_send_stream_state.get();
QUICReceiveStreamState r_state = this->_recv_stream_state.get();
if (s_state == QUICSendStreamState::Ready || r_state == QUICReceiveStreamState::Init) {
return QUICBidirectionalStreamState::Idle;
} else if (s_state == QUICSendStreamState::Ready || s_state == QUICSendStreamState::Send ||
s_state == QUICSendStreamState::DataSent) {
if (r_state == QUICReceiveStreamState::Recv || r_state == QUICReceiveStreamState::SizeKnown) {
return QUICBidirectionalStreamState::Open;
} else if (r_state == QUICReceiveStreamState::DataRecvd || r_state == QUICReceiveStreamState::DataRead) {
return QUICBidirectionalStreamState::HC_R;
} else if (r_state == QUICReceiveStreamState::ResetRecvd || r_state == QUICReceiveStreamState::ResetRead) {
return QUICBidirectionalStreamState::HC_R;
} else {
ink_assert(false);
return QUICBidirectionalStreamState::Invalid;
}
} else if (s_state == QUICSendStreamState::DataRecvd) {
if (r_state == QUICReceiveStreamState::Recv || r_state == QUICReceiveStreamState::SizeKnown) {
return QUICBidirectionalStreamState::HC_L;
} else if (r_state == QUICReceiveStreamState::DataRecvd || r_state == QUICReceiveStreamState::DataRead) {
return QUICBidirectionalStreamState::Closed;
} else if (r_state == QUICReceiveStreamState::ResetRecvd || r_state == QUICReceiveStreamState::ResetRead) {
return QUICBidirectionalStreamState::Closed;
} else {
ink_assert(false);
return QUICBidirectionalStreamState::Invalid;
}
} else if (s_state == QUICSendStreamState::ResetSent || s_state == QUICSendStreamState::ResetRecvd) {
if (r_state == QUICReceiveStreamState::Recv || r_state == QUICReceiveStreamState::SizeKnown) {
return QUICBidirectionalStreamState::HC_L;
} else if (r_state == QUICReceiveStreamState::DataRecvd || r_state == QUICReceiveStreamState::DataRead) {
return QUICBidirectionalStreamState::Closed;
} else if (r_state == QUICReceiveStreamState::ResetRecvd || r_state == QUICReceiveStreamState::ResetRead) {
return QUICBidirectionalStreamState::Closed;
} else {
ink_assert(false);
return QUICBidirectionalStreamState::Invalid;
}
} else {
ink_assert(false);
return QUICBidirectionalStreamState::Invalid;
}
}
bool
QUICBidirectionalStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
{
bool state_changed = false;
// The receiving part of a stream enters the "Recv" state when the sending part of a bidirectional stream initiated by the
// endpoint (type 0 for a client, type 1 for a server) enters the "Ready" state.
state_changed |= this->_send_stream_state.update_with_sending_frame(frame);
// PS: It should not happen because we initialize the send side and read side together. And the SendState has the default state
// "Ready". But to obey the specs, we do this as follow.
if (this->_send_stream_state.get() == QUICSendStreamState::Ready &&
this->_recv_stream_state.get() == QUICReceiveStreamState::Init) {
state_changed |= this->_recv_stream_state.update(this->_send_stream_state.get());
}
return state_changed;
}
bool
QUICBidirectionalStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame)
{
bool state_changed = false;
// The sending part of a bidirectional stream initiated by a peer (type 0 for a server, type 1 for a client) enters the "Ready"
// state then immediately transitions to the "Send" state if the receiving part enters the "Recv" state (Section 3.2).
state_changed |= this->_recv_stream_state.update_with_receiving_frame(frame);
if (this->_send_stream_state.get() == QUICSendStreamState::Ready &&
this->_recv_stream_state.get() == QUICReceiveStreamState::Recv) {
state_changed |= this->_send_stream_state.update(this->_recv_stream_state.get());
}
return state_changed;
}
bool
QUICBidirectionalStreamStateMachine::update_on_ack()
{
return this->_send_stream_state.update_on_ack();
}
bool
QUICBidirectionalStreamStateMachine::update_on_read()
{
return this->_recv_stream_state.update_on_read();
}
bool
QUICBidirectionalStreamStateMachine::update_on_eos()
{
return this->_recv_stream_state.update_on_eos();
}
bool
QUICBidirectionalStreamStateMachine::is_allowed_to_send(const QUICFrame &frame) const
{
return this->is_allowed_to_send(frame.type());
}
bool
QUICBidirectionalStreamStateMachine::is_allowed_to_send(QUICFrameType type) const
{
return this->_send_stream_state.is_allowed_to_send(type) || this->_recv_stream_state.is_allowed_to_send(type);
}
bool
QUICBidirectionalStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) const
{
return this->is_allowed_to_receive(frame.type());
}
bool
QUICBidirectionalStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const
{
return this->_send_stream_state.is_allowed_to_receive(type) || this->_recv_stream_state.is_allowed_to_receive(type);
}