mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-08-09 20:42:44 +03:00
Split stream state machine into send and receive state machines
Summary: This is step 1 for removing reset on reset, since the send side may need to transition to waiting for a reset ack while the read side is an any state. Reviewed By: lnicco Differential Revision: D15075849 fbshipit-source-id: 1e094942a8a1ca9a01d4161cd6309b4136a9cfbf
This commit is contained in:
committed by
Facebook Github Bot
parent
5c9c0821ff
commit
90e5e1b3f1
@@ -1801,7 +1801,7 @@ folly::Expected<folly::Unit, LocalErrorCode> QuicTransportBase::resetStream(
|
||||
return folly::makeUnexpected(LocalErrorCode::STREAM_CLOSED);
|
||||
}
|
||||
// Invoke state machine
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
*conn_, *stream, StreamEvents::SendReset(errorCode));
|
||||
for (auto pendingResetIt = conn_->pendingEvents.resets.begin();
|
||||
closeState_ == CloseState::OPEN &&
|
||||
|
@@ -281,7 +281,8 @@ class TestQuicTransport
|
||||
|
||||
void closeStream(StreamId id) {
|
||||
QuicStreamState* stream = conn_->streamManager->getStream(id);
|
||||
stream->state = StreamStates::Closed{};
|
||||
stream->send.state = StreamSendStates::Closed();
|
||||
stream->recv.state = StreamReceiveStates::Closed();
|
||||
conn_->streamManager->addClosed(id);
|
||||
|
||||
auto deliveryCb = deliveryCallbacks_.find(id);
|
||||
|
@@ -775,7 +775,7 @@ TEST_F(QuicTransportTest, RstStream) {
|
||||
auto stream =
|
||||
transport_->getConnectionState().streamManager->findStream(streamId);
|
||||
ASSERT_TRUE(stream);
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream->send));
|
||||
EXPECT_TRUE(stream->retransmissionBuffer.empty());
|
||||
EXPECT_TRUE(stream->writeBuffer.empty());
|
||||
EXPECT_FALSE(stream->writable());
|
||||
@@ -1245,7 +1245,7 @@ TEST_F(QuicTransportTest, RstWrittenStream) {
|
||||
}
|
||||
EXPECT_TRUE(foundReset);
|
||||
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream->send));
|
||||
EXPECT_TRUE(stream->retransmissionBuffer.empty());
|
||||
EXPECT_TRUE(stream->writeBuffer.empty());
|
||||
EXPECT_FALSE(stream->writable());
|
||||
@@ -1311,7 +1311,7 @@ TEST_F(QuicTransportTest, WriteAfterSendRst) {
|
||||
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
|
||||
loopForWrites();
|
||||
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream->send));
|
||||
EXPECT_TRUE(stream->retransmissionBuffer.empty());
|
||||
EXPECT_TRUE(stream->writeBuffer.empty());
|
||||
EXPECT_FALSE(stream->writable());
|
||||
|
@@ -355,7 +355,7 @@ void QuicClientTransport::processPacketData(
|
||||
auto stream =
|
||||
conn_->streamManager->getStream(frame.streamId);
|
||||
if (stream) {
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
*conn_, *stream, StreamEvents::RstAck(frame));
|
||||
}
|
||||
},
|
||||
@@ -368,7 +368,7 @@ void QuicClientTransport::processPacketData(
|
||||
<< " closed=" << (ackedStream == nullptr) << " "
|
||||
<< *this;
|
||||
if (ackedStream) {
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
*conn_,
|
||||
*ackedStream,
|
||||
StreamEvents::AckStreamFrame(frame));
|
||||
@@ -398,7 +398,7 @@ void QuicClientTransport::processPacketData(
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
invokeStreamStateMachine(*conn_, *stream, std::move(frame));
|
||||
invokeStreamReceiveStateMachine(*conn_, *stream, std::move(frame));
|
||||
},
|
||||
[&](ReadCryptoFrame& cryptoFrame) {
|
||||
pktHasRetransmittableData = true;
|
||||
@@ -425,7 +425,7 @@ void QuicClientTransport::processPacketData(
|
||||
<< *conn_;
|
||||
return;
|
||||
}
|
||||
invokeStreamStateMachine(*conn_, *stream, std::move(frame));
|
||||
invokeStreamReceiveStateMachine(*conn_, *stream, std::move(frame));
|
||||
},
|
||||
[&](MaxDataFrame& connWindowUpdate) {
|
||||
VLOG(10) << "Client received max data offset="
|
||||
|
@@ -82,6 +82,7 @@ void ClientInvalidStateHandler(QuicClientConnectionState& state);
|
||||
|
||||
struct QuicClientStateMachine {
|
||||
using StateData = QuicClientConnectionState;
|
||||
using UserData = QuicClientConnectionState;
|
||||
static constexpr auto InvalidEventHandler = &ClientInvalidStateHandler;
|
||||
};
|
||||
|
||||
|
@@ -43,10 +43,8 @@ class PacketRebuilder {
|
||||
PacketEvent cloneOutstandingPacket(OutstandingPacket& packet);
|
||||
|
||||
bool retransmittable(const QuicStreamState& stream) const {
|
||||
return matchesStates<
|
||||
StreamStateData,
|
||||
StreamStates::Open,
|
||||
StreamStates::HalfClosedRemote>(stream.state);
|
||||
return matchesStates<StreamSendStateData, StreamSendStates::Open>(
|
||||
stream.send.state);
|
||||
}
|
||||
|
||||
Buf cloneCryptoRetransmissionBuffer(
|
||||
|
@@ -175,7 +175,7 @@ TEST_F(QuicPacketRebuilderTest, RebuildAfterResetStream) {
|
||||
ASSERT_EQ(1, packet1.packet.frames.size());
|
||||
|
||||
// Then we reset the stream
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
conn,
|
||||
*stream,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
|
@@ -75,7 +75,8 @@ PacketNum rstStreamAndSendPacket(
|
||||
auto aead = createNoOpAead();
|
||||
auto headerCipher = createNoOpHeaderCipher();
|
||||
auto version = conn.version.value_or(*conn.originalVersion);
|
||||
invokeStreamStateMachine(conn, stream, StreamEvents::SendReset(errorCode));
|
||||
invokeStreamSendStateMachine(
|
||||
conn, stream, StreamEvents::SendReset(errorCode));
|
||||
writeQuicDataToSocket(
|
||||
sock,
|
||||
conn,
|
||||
|
@@ -262,7 +262,8 @@ TEST_F(QuicFlowControlTest, DontSendStreamWindowUpdateTwice) {
|
||||
TEST_F(QuicFlowControlTest, DontSendStreamWindowUpdateOnRemoteHalfClosed) {
|
||||
StreamId id = 3;
|
||||
QuicStreamState stream(id, conn_);
|
||||
stream.state = StreamStates::HalfClosedRemote();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
// Should not send window update
|
||||
maybeSendStreamWindowUpdate(stream, Clock::now());
|
||||
EXPECT_FALSE(conn_.streamManager->pendingWindowUpdate(stream.id));
|
||||
@@ -476,7 +477,8 @@ TEST_F(QuicFlowControlTest, LostStreamWindowUpdateHalfClosedRemote) {
|
||||
stream.currentReadOffset = 300;
|
||||
stream.flowControlState.windowSize = 500;
|
||||
stream.flowControlState.advertisedMaxOffset = 400;
|
||||
stream.state = StreamStates::HalfClosedRemote();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
|
||||
// Should not send window update
|
||||
onStreamWindowUpdateLost(stream);
|
||||
|
@@ -443,7 +443,7 @@ TEST_F(QuicLossFunctionsTest, TestMarkPacketLossAfterStreamReset) {
|
||||
*stream1,
|
||||
*buf,
|
||||
true);
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
*conn,
|
||||
*stream1,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
|
@@ -690,7 +690,7 @@ void onServerReadDataFromOpen(
|
||||
auto ackedStream =
|
||||
conn.streamManager->getStream(frame.streamId);
|
||||
if (ackedStream) {
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
conn,
|
||||
*ackedStream,
|
||||
StreamEvents::AckStreamFrame(frame));
|
||||
@@ -708,7 +708,7 @@ void onServerReadDataFromOpen(
|
||||
auto stream =
|
||||
conn.streamManager->getStream(frame.streamId);
|
||||
if (stream) {
|
||||
invokeStreamStateMachine(
|
||||
invokeStreamSendStateMachine(
|
||||
conn, *stream, StreamEvents::RstAck(frame));
|
||||
}
|
||||
},
|
||||
@@ -734,7 +734,7 @@ void onServerReadDataFromOpen(
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
invokeStreamStateMachine(conn, *stream, frame);
|
||||
invokeStreamReceiveStateMachine(conn, *stream, frame);
|
||||
},
|
||||
[&](ReadCryptoFrame& cryptoFrame) {
|
||||
pktHasRetransmittableData = true;
|
||||
@@ -763,7 +763,7 @@ void onServerReadDataFromOpen(
|
||||
// Ignore data from closed streams that we don't have the
|
||||
// state for any more.
|
||||
if (stream) {
|
||||
invokeStreamStateMachine(conn, *stream, frame);
|
||||
invokeStreamReceiveStateMachine(conn, *stream, frame);
|
||||
}
|
||||
},
|
||||
[&](MaxDataFrame& connWindowUpdate) {
|
||||
|
@@ -177,4 +177,3 @@ void onConnectionMigration(
|
||||
QuicServerConnectionState& conn,
|
||||
const folly::SocketAddress& newPeerAddress);
|
||||
} // namespace quic
|
||||
|
||||
|
@@ -1079,7 +1079,8 @@ TEST_F(QuicServerTransportTest, TestOpenAckStreamFrame) {
|
||||
EXPECT_EQ(
|
||||
stream->retransmissionBuffer.size(),
|
||||
originalRetransSize - buffersInPacket1);
|
||||
EXPECT_TRUE(isState<StreamStates::Open>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::Open>(stream->send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
|
||||
// Dup ack
|
||||
auto packet2 = createAckPacket(
|
||||
@@ -1092,7 +1093,8 @@ TEST_F(QuicServerTransportTest, TestOpenAckStreamFrame) {
|
||||
EXPECT_EQ(
|
||||
stream->retransmissionBuffer.size(),
|
||||
originalRetransSize - buffersInPacket1);
|
||||
EXPECT_TRUE(isState<StreamStates::Open>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::Open>(stream->send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
|
||||
IntervalSet<PacketNum> acks2 = {{packetNum1, lastPacketNum}};
|
||||
auto packet3 = createAckPacket(
|
||||
@@ -1103,7 +1105,8 @@ TEST_F(QuicServerTransportTest, TestOpenAckStreamFrame) {
|
||||
deliverData(packetToBuf(packet3));
|
||||
|
||||
EXPECT_EQ(stream->retransmissionBuffer.size(), 0);
|
||||
EXPECT_TRUE(isState<StreamStates::Open>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::Open>(stream->send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
|
||||
auto empty = IOBuf::create(0);
|
||||
server->writeChain(streamId, std::move(empty), true, false);
|
||||
@@ -1123,7 +1126,8 @@ TEST_F(QuicServerTransportTest, TestOpenAckStreamFrame) {
|
||||
acks3,
|
||||
PacketNumberSpace::AppData);
|
||||
deliverData(packetToBuf(packet4));
|
||||
EXPECT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicServerTransportTest, RecvRstStreamFrameNonexistClientStream) {
|
||||
@@ -3018,7 +3022,8 @@ TEST_P(
|
||||
0 /* cipherOverhead */,
|
||||
0 /* largestAcked */,
|
||||
std::make_pair(
|
||||
LongHeader::Types::ZeroRtt, server->getConn().supportedVersions[0])));
|
||||
LongHeader::Types::ZeroRtt, server->getConn().supportedVersions[0]),
|
||||
false));
|
||||
deliverData(std::move(packetData), false);
|
||||
if (GetParam().acceptZeroRtt) {
|
||||
if (!GetParam().chloSync) {
|
||||
@@ -3049,7 +3054,9 @@ TEST_P(
|
||||
streamId,
|
||||
*data,
|
||||
0 /* cipherOverhead */,
|
||||
0 /* largestAcked */));
|
||||
0 /* largestAcked */,
|
||||
folly::none,
|
||||
false));
|
||||
deliverData(std::move(packetData));
|
||||
EXPECT_EQ(server->getConn().streamManager->streamCount(), 0);
|
||||
EXPECT_EQ(server->getConn().pendingOneRttData->size(), 1);
|
||||
@@ -3076,7 +3083,8 @@ TEST_P(
|
||||
0 /* cipherOverhead */,
|
||||
0 /* largestAcked */,
|
||||
std::make_pair(
|
||||
LongHeader::Types::ZeroRtt, server->getConn().supportedVersions[0])));
|
||||
LongHeader::Types::ZeroRtt, server->getConn().supportedVersions[0]),
|
||||
false));
|
||||
deliverData(std::move(packetData), false);
|
||||
if (GetParam().acceptZeroRtt) {
|
||||
if (!GetParam().chloSync) {
|
||||
|
@@ -113,10 +113,8 @@ void onRecvMinStreamDataFrame(
|
||||
PacketNum packetNum) {
|
||||
if (isReceivingStream(stream->conn.nodeType, stream->id) ||
|
||||
(isSendingStream(stream->conn.nodeType, stream->id) &&
|
||||
!matchesStates<
|
||||
StreamStateData,
|
||||
StreamStates::Open,
|
||||
StreamStates::HalfClosedRemote>(stream->state))) {
|
||||
!matchesStates<StreamSendStateData, StreamSendStates::Open>(
|
||||
stream->send.state))) {
|
||||
throw QuicTransportException(
|
||||
"MinStreamDataFrame on receiving-only stream or "
|
||||
"sending-only stream but not opened",
|
||||
|
@@ -36,11 +36,20 @@ void updateRtt(
|
||||
std::chrono::microseconds ackDelay);
|
||||
|
||||
template <typename Event>
|
||||
void invokeStreamStateMachine(
|
||||
void invokeStreamSendStateMachine(
|
||||
QuicConnectionStateBase&,
|
||||
QuicStreamState& stream,
|
||||
Event event) {
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(event));
|
||||
invokeHandler<StreamSendStateMachine>(stream.send, std::move(event), stream);
|
||||
}
|
||||
|
||||
template <typename Event>
|
||||
void invokeStreamReceiveStateMachine(
|
||||
QuicConnectionStateBase&,
|
||||
QuicStreamState& stream,
|
||||
Event event) {
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, std::move(event), stream);
|
||||
}
|
||||
|
||||
bool isConnectionPaced(const QuicConnectionStateBase& conn) noexcept;
|
||||
|
@@ -305,9 +305,8 @@ void QuicStreamManager::removeClosedStream(StreamId streamId) {
|
||||
return;
|
||||
}
|
||||
VLOG(10) << "Removing closed stream=" << streamId;
|
||||
bool matchClosedState =
|
||||
matchesStates<StreamStateData, StreamStates::Closed>(it->second.state);
|
||||
DCHECK(matchClosedState);
|
||||
bool inTerminalStates = it->second.inTerminalStates();
|
||||
DCHECK(inTerminalStates);
|
||||
readableStreams_.erase(streamId);
|
||||
peekableStreams_.erase(streamId);
|
||||
writableStreams_.erase(streamId);
|
||||
|
@@ -129,7 +129,7 @@ bool updateSimpleFrameOnPacketReceived(
|
||||
[&](const StopSendingFrame& frame) {
|
||||
auto stream = conn.streamManager->getStream(frame.streamId);
|
||||
if (stream) {
|
||||
invokeStreamStateMachine(conn, *stream, frame);
|
||||
invokeStreamSendStateMachine(conn, *stream, frame);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
@@ -32,6 +32,13 @@ QuicStreamState::QuicStreamState(StreamId idIn, QuicConnectionStateBase& connIn)
|
||||
: isLocalStream(connIn.nodeType, idIn)
|
||||
? conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote
|
||||
: conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiLocal;
|
||||
if (isUnidirectionalStream(idIn)) {
|
||||
if (isLocalStream(connIn.nodeType, idIn)) {
|
||||
recv.state = StreamReceiveStates::Invalid();
|
||||
} else {
|
||||
send.state = StreamSendStates::Invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const QuicConnectionStateBase& st) {
|
||||
|
@@ -28,6 +28,7 @@ namespace quic {
|
||||
* 2. Create a Machine type with an alias of StateData
|
||||
* struct Machine {
|
||||
* using StateData = StateDataType;
|
||||
* using UserData = UserDataType;
|
||||
* constexpr auto InvalidEventHandler = &InvalidEventHandler;
|
||||
* }
|
||||
* 3. Create types for each state
|
||||
@@ -101,7 +102,10 @@ struct HandlerBase {
|
||||
class Handler<machine, state, event> \
|
||||
: public HandlerBase<machine, state, event, ##__VA_ARGS__> { \
|
||||
public: \
|
||||
static void handle(typename machine::StateData& data, event evt); \
|
||||
static void handle( \
|
||||
typename machine::StateData& data, \
|
||||
event evt, \
|
||||
typename machine::UserData& userData); \
|
||||
};
|
||||
|
||||
#define QUIC_DECLARE_STATE_HANDLER_T(state, event, ...) \
|
||||
@@ -109,7 +113,10 @@ struct HandlerBase {
|
||||
class Handler<Machine, state, event> \
|
||||
: public HandlerBase<Machine, state, event, ##__VA_ARGS__> { \
|
||||
public: \
|
||||
static void handle(typename Machine::StateData& data, event evt); \
|
||||
static void handle( \
|
||||
typename Machine::StateData& data, \
|
||||
event evt, \
|
||||
typename Machine::UserData&); \
|
||||
template <class NewState> \
|
||||
static void transit(typename Machine::StateData& data) { \
|
||||
HandlerBase<Machine, state, event, ##__VA_ARGS__>::template transit< \
|
||||
@@ -123,28 +130,39 @@ struct HandlerBase {
|
||||
*/
|
||||
template <class Machine, class State, class Event>
|
||||
struct Handler : public HandlerBase<Machine, State, Event> {
|
||||
static void handle(typename Machine::StateData& data, Event /*event*/) {
|
||||
Machine::InvalidEventHandler(data);
|
||||
static void handle(
|
||||
typename Machine::StateData& /*state*/,
|
||||
Event /*event*/,
|
||||
typename Machine::UserData& userData) {
|
||||
Machine::InvalidEventHandler(userData);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Machine, class Event>
|
||||
struct state_visitor : public boost::static_visitor<> {
|
||||
explicit state_visitor(Event event, typename Machine::StateData& data)
|
||||
: event_(std::move(event)), data_(data) {}
|
||||
explicit state_visitor(
|
||||
Event event,
|
||||
typename Machine::StateData& data,
|
||||
typename Machine::UserData& userData)
|
||||
: event_(std::move(event)), data_(data), userData_(userData) {}
|
||||
|
||||
template <class State>
|
||||
void operator()(const State& /*state*/) {
|
||||
Handler<Machine, State, Event>::handle(data_, std::move(event_));
|
||||
Handler<Machine, State, Event>::handle(data_, std::move(event_), userData_);
|
||||
}
|
||||
|
||||
Event event_;
|
||||
typename Machine::StateData& data_;
|
||||
typename Machine::UserData& userData_;
|
||||
};
|
||||
|
||||
template <class Machine, class Event>
|
||||
void invokeHandler(typename Machine::StateData& data, Event event) {
|
||||
auto visitor = state_visitor<Machine, Event>(std::move(event), data);
|
||||
void invokeHandler(
|
||||
typename Machine::StateData& data,
|
||||
Event event,
|
||||
typename Machine::UserData& userData) {
|
||||
auto visitor =
|
||||
state_visitor<Machine, Event>(std::move(event), data, userData);
|
||||
return boost::apply_visitor(visitor, data.state);
|
||||
}
|
||||
}
|
||||
|
@@ -81,38 +81,57 @@ struct QuicStreamLike {
|
||||
|
||||
struct QuicConnectionStateBase;
|
||||
|
||||
struct StreamStates {
|
||||
// The stream is open
|
||||
struct StreamSendStates {
|
||||
// Ready, Send and FinSent are collapsed into Open
|
||||
struct Open {};
|
||||
|
||||
// The stream has closed its write
|
||||
struct HalfClosedLocal {};
|
||||
// RST has been sent
|
||||
struct ResetSent {};
|
||||
|
||||
// The stream has closed read.
|
||||
struct HalfClosedRemote {};
|
||||
|
||||
// The stream is waiting for the ack of the reset stream
|
||||
struct WaitingForRstAck {};
|
||||
|
||||
// The stream is now closed.
|
||||
// All data acked or RST acked. Collapsed Data Received and Reset Received
|
||||
struct Closed {};
|
||||
|
||||
// Used for peer initiated unidirectional streams
|
||||
struct Invalid {};
|
||||
};
|
||||
|
||||
using StreamStateData = boost::variant<
|
||||
StreamStates::Open,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamStates::Closed>;
|
||||
struct StreamReceiveStates {
|
||||
// Renamed Receive to Open
|
||||
struct Open {};
|
||||
|
||||
inline std::string streamStateToString(const StreamStateData& state) {
|
||||
// All data or rst received
|
||||
struct Closed {};
|
||||
|
||||
// Used for self-initiated unidirectional streams
|
||||
struct Invalid {};
|
||||
};
|
||||
|
||||
using StreamSendStateData = boost::variant<
|
||||
StreamSendStates::Open,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamSendStates::Closed,
|
||||
StreamSendStates::Invalid>;
|
||||
|
||||
using StreamReceiveStateData = boost::variant<
|
||||
StreamReceiveStates::Open,
|
||||
StreamReceiveStates::Closed,
|
||||
StreamReceiveStates::Invalid>;
|
||||
|
||||
inline std::string streamStateToString(const StreamSendStateData& state) {
|
||||
return folly::variant_match(
|
||||
state,
|
||||
[](const StreamStates::Open&) { return "Open"; },
|
||||
[](const StreamStates::HalfClosedLocal&) { return "HalfClosedLocal"; },
|
||||
[](const StreamStates::HalfClosedRemote&) { return "HalfClosedRemote"; },
|
||||
[](const StreamStates::WaitingForRstAck&) { return "WaitingForRstAck"; },
|
||||
[](const StreamStates::Closed&) { return "Closed"; });
|
||||
[](const StreamSendStates::Open&) { return "Open"; },
|
||||
[](const StreamSendStates::ResetSent&) { return "ResetSent"; },
|
||||
[](const StreamSendStates::Closed&) { return "Closed"; },
|
||||
[](const StreamSendStates::Invalid&) { return "Invalid"; });
|
||||
}
|
||||
|
||||
inline std::string streamStateToString(const StreamReceiveStateData& state) {
|
||||
return folly::variant_match(
|
||||
state,
|
||||
[](const StreamReceiveStates::Open&) { return "Open"; },
|
||||
[](const StreamReceiveStates::Closed&) { return "Closed"; },
|
||||
[](const StreamReceiveStates::Invalid&) { return "Invalid"; });
|
||||
}
|
||||
|
||||
struct QuicStreamState : public QuicStreamLike {
|
||||
@@ -145,7 +164,12 @@ struct QuicStreamState : public QuicStreamLike {
|
||||
folly::Optional<QuicErrorCode> streamWriteError;
|
||||
|
||||
// State machine data
|
||||
StreamStateData state{StreamStates::Open()};
|
||||
struct Send {
|
||||
StreamSendStateData state{StreamSendStates::Open()};
|
||||
} send;
|
||||
struct Recv {
|
||||
StreamReceiveStateData state{StreamReceiveStates::Open()};
|
||||
} recv;
|
||||
|
||||
// The packet number of the latest packet that contains a MaxStreamDataFrame
|
||||
// sent out by us.
|
||||
@@ -167,20 +191,29 @@ struct QuicStreamState : public QuicStreamLike {
|
||||
// lastHolbTime indicates whether the stream is HOL blocked at the moment.
|
||||
uint32_t holbCount{0};
|
||||
|
||||
// Returns true if both send and receive state machines are in a terminal
|
||||
// state
|
||||
bool inTerminalStates() const {
|
||||
return matchesStates<
|
||||
StreamSendStateData,
|
||||
StreamSendStates::Closed,
|
||||
StreamSendStates::Invalid>(send.state) &&
|
||||
matchesStates<
|
||||
StreamReceiveStateData,
|
||||
StreamReceiveStates::Closed,
|
||||
StreamReceiveStates::Invalid>(recv.state);
|
||||
}
|
||||
|
||||
// If the stream is still writable.
|
||||
bool writable() const {
|
||||
return matchesStates<
|
||||
StreamStateData,
|
||||
StreamStates::Open,
|
||||
StreamStates::HalfClosedRemote>(state) &&
|
||||
return matchesStates<StreamSendStateData, StreamSendStates::Open>(
|
||||
send.state) &&
|
||||
!finalWriteOffset.hasValue();
|
||||
}
|
||||
|
||||
bool shouldSendFlowControl() const {
|
||||
return matchesStates<
|
||||
StreamStateData,
|
||||
StreamStates::Open,
|
||||
StreamStates::HalfClosedLocal>(state);
|
||||
return matchesStates<StreamReceiveStateData, StreamReceiveStates::Open>(
|
||||
recv.state);
|
||||
}
|
||||
|
||||
bool hasWritableData() const {
|
||||
|
@@ -12,16 +12,21 @@
|
||||
#include <quic/state/stream/StreamStateFunctions.h>
|
||||
|
||||
namespace quic {
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Closed, ReadStreamFrame>::handle(
|
||||
template <typename Event>
|
||||
void invokeStreamSendStateMachine(
|
||||
QuicConnectionStateBase&,
|
||||
QuicStreamState& stream,
|
||||
ReadStreamFrame frame) {
|
||||
if (isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"ReadStreamFrame on unidirectional sending stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
Event event);
|
||||
|
||||
inline void Handler<
|
||||
StreamReceiveStateMachine,
|
||||
StreamReceiveStates::Closed,
|
||||
ReadStreamFrame>::
|
||||
handle(
|
||||
QuicStreamState::Recv& state,
|
||||
ReadStreamFrame frame,
|
||||
QuicStreamState& stream) {
|
||||
CHECK(!isSendingStream(stream.conn.nodeType, stream.id));
|
||||
VLOG_IF(10, frame.fin) << "Closed: Received data with fin"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
appendDataToReadBuffer(
|
||||
@@ -29,64 +34,64 @@ Handler<StreamStateMachine, StreamStates::Closed, ReadStreamFrame>::handle(
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Closed, StopSendingFrame>::handle(
|
||||
QuicStreamState& stream,
|
||||
StopSendingFrame /* frame */) {
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"StopSendingFrame on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
Handler<StreamSendStateMachine, StreamSendStates::Closed, StopSendingFrame>::
|
||||
handle(
|
||||
QuicStreamState::Send& /*state*/,
|
||||
StopSendingFrame /*frame*/,
|
||||
QuicStreamState& /*stream*/) {
|
||||
// no-op, we're already done sending
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Closed, RstStreamFrame>::handle(
|
||||
QuicStreamState& stream,
|
||||
RstStreamFrame rst) {
|
||||
if (isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"RstStreamFrame on unidirectional sending stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
inline void Handler<
|
||||
StreamReceiveStateMachine,
|
||||
StreamReceiveStates::Closed,
|
||||
RstStreamFrame>::
|
||||
handle(
|
||||
QuicStreamState::Recv& state,
|
||||
RstStreamFrame rst,
|
||||
QuicStreamState& stream) {
|
||||
// TODO: Remove
|
||||
invokeStreamSendStateMachine(
|
||||
stream.conn,
|
||||
stream,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::NO_ERROR));
|
||||
// This will check whether the reset is still consistent with the stream.
|
||||
onResetQuicStream(stream, std::move(rst));
|
||||
}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StreamEvents::AckStreamFrame>::
|
||||
handle(QuicStreamState& stream, StreamEvents::AckStreamFrame /*ack*/) {
|
||||
// do nothing here, we're done with handling our write data.
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"AckStreamFrame on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
handle(
|
||||
QuicStreamState::Send& /*state*/,
|
||||
StreamEvents::AckStreamFrame /*ack*/,
|
||||
QuicStreamState& stream) {
|
||||
DCHECK(stream.retransmissionBuffer.empty());
|
||||
DCHECK(stream.writeBuffer.empty());
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Closed, StreamEvents::RstAck>::handle(
|
||||
QuicStreamState& stream,
|
||||
StreamEvents::RstAck /*ack*/) {
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"RstAck on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
inline void Handler<
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StreamEvents::RstAck>::
|
||||
handle(
|
||||
QuicStreamState::Send& /*state*/,
|
||||
StreamEvents::RstAck /*ack*/,
|
||||
QuicStreamState& /*stream*/) {
|
||||
// Just discard the ack if we are already in Closed state.
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Closed, StreamEvents::SendReset>::
|
||||
handle(QuicStreamState& stream, StreamEvents::SendReset) {
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"SendReset on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
inline void Handler<
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StreamEvents::SendReset>::
|
||||
handle(
|
||||
QuicStreamState::Send& state,
|
||||
StreamEvents::SendReset,
|
||||
QuicStreamState& stream) {
|
||||
// TODO: remove this as a valid state transition
|
||||
LOG(ERROR) << "Ignoring SendReset from closed state. This may be a bug";
|
||||
// Discard the send reset.
|
||||
}
|
||||
} // namespace quic
|
||||
|
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
// override-include-guard
|
||||
|
||||
#include <quic/state/stream/StreamStateFunctions.h>
|
||||
|
||||
namespace quic {
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::HalfClosedLocal, RstStreamFrame>::
|
||||
handle(QuicStreamState& stream, RstStreamFrame rst) {
|
||||
// We transition before invoking onResetQuicStream so that reset stream
|
||||
// can use the state to make decisions.
|
||||
VLOG(10) << "HalfClosedLocal: Received reset, transition to closed"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
transit<StreamStates::Closed>(stream);
|
||||
onResetQuicStream(stream, std::move(rst));
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::HalfClosedLocal, ReadStreamFrame>::
|
||||
handle(QuicStreamState& stream, ReadStreamFrame frame) {
|
||||
VLOG_IF(10, frame.fin) << "HalfClosedLocal: Received data with fin"
|
||||
<< " stream=" << stream.id
|
||||
<< " offset=" << frame.offset
|
||||
<< " readOffset=" << stream.currentReadOffset << " "
|
||||
<< stream.conn;
|
||||
appendDataToReadBuffer(
|
||||
stream, StreamBuffer(std::move(frame.data), frame.offset, frame.fin));
|
||||
if (isAllDataReceived(stream)) {
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
VLOG(10) << "HalfClosedLocal: Transition to closed"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
transit<StreamStates::Closed>(stream);
|
||||
}
|
||||
stream.conn.streamManager->updateReadableStreams(stream);
|
||||
}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamEvents::AckStreamFrame>::
|
||||
handle(QuicStreamState& stream, StreamEvents::AckStreamFrame /*ack*/) {
|
||||
// do nothing here, we already got acks for all the bytes till fin.
|
||||
DCHECK(stream.retransmissionBuffer.empty());
|
||||
DCHECK(stream.writeBuffer.empty());
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::HalfClosedLocal, StopSendingFrame>::
|
||||
handle(QuicStreamState& /*stream*/, StopSendingFrame /*frame*/) {}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamEvents::SendReset>::
|
||||
handle(QuicStreamState& stream, StreamEvents::SendReset rst) {
|
||||
resetQuicStream(stream, rst.errorCode);
|
||||
appendPendingStreamReset(stream.conn, stream, rst.errorCode);
|
||||
// Move the state machine:
|
||||
VLOG(10) << "HalfClosedLocal: Transition to WaitingForRstAck"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
transit<StreamStates::WaitingForRstAck>(stream);
|
||||
}
|
||||
} // namespace quic
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
// override-include-guard
|
||||
|
||||
#include <quic/QuicException.h>
|
||||
#include <quic/state/stream/StreamStateFunctions.h>
|
||||
|
||||
namespace quic {
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::HalfClosedRemote, ReadStreamFrame>::
|
||||
handle(QuicStreamState& stream, ReadStreamFrame frame) {
|
||||
VLOG_IF(10, frame.fin) << "HalfClosedRemote: Received data with fin"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
appendDataToReadBuffer(
|
||||
stream, StreamBuffer(std::move(frame.data), frame.offset, frame.fin));
|
||||
}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StreamEvents::AckStreamFrame>::
|
||||
handle(QuicStreamState& stream, StreamEvents::AckStreamFrame ack) {
|
||||
// Clean up the acked buffers from the retransmissionBuffer.
|
||||
auto ackedBuffer = std::lower_bound(
|
||||
stream.retransmissionBuffer.begin(),
|
||||
stream.retransmissionBuffer.end(),
|
||||
ack.ackedFrame.offset,
|
||||
[](const auto& buffer, const auto& offset) {
|
||||
return buffer.offset < offset;
|
||||
});
|
||||
|
||||
if (ackedBuffer != stream.retransmissionBuffer.end()) {
|
||||
// Since the StreamFrames that are ACKed are computed from the outstanding
|
||||
// packets, we always know that the retransmission buffer corresponds to
|
||||
// 1 buffer in the retranmission buffer.
|
||||
CHECK_EQ(ackedBuffer->offset, ack.ackedFrame.offset);
|
||||
CHECK_EQ(ackedBuffer->data.chainLength(), ack.ackedFrame.len);
|
||||
|
||||
VLOG(10) << "HalfClosedRemote: stream data acked stream=" << stream.id
|
||||
<< " offset=" << ackedBuffer->offset
|
||||
<< " len=" << ackedBuffer->data.chainLength()
|
||||
<< " eof=" << ackedBuffer->eof << " " << stream.conn;
|
||||
stream.retransmissionBuffer.erase(ackedBuffer);
|
||||
} else {
|
||||
VLOG(10) << __func__ << ": offset " << ack.ackedFrame.offset
|
||||
<< " no longer in retransmissionBuffer";
|
||||
}
|
||||
|
||||
// This stream may be able to invoke some deliveryCallbacks:
|
||||
stream.conn.streamManager->addDeliverable(stream.id);
|
||||
|
||||
// Check for whether or not we have ACKed all bytes until our FIN.
|
||||
if (allBytesTillFinAcked(stream)) {
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
VLOG(10) << "HalfClosedRemote: Transition to closed stream=" << stream.id
|
||||
<< " " << stream.conn;
|
||||
transit<StreamStates::Closed>(stream);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::HalfClosedRemote, StopSendingFrame>::
|
||||
handle(QuicStreamState& stream, StopSendingFrame frame) {
|
||||
stream.conn.streamManager->addStopSending(stream.id, frame.errorCode);
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::HalfClosedRemote, RstStreamFrame>::
|
||||
handle(QuicStreamState& stream, RstStreamFrame rst) {
|
||||
// We transit before invoking onResetQuicStream because it will check the
|
||||
// state of the stream for flow control.
|
||||
transit<StreamStates::WaitingForRstAck>(stream);
|
||||
onResetQuicStream(stream, std::move(rst));
|
||||
// TODO: remove.
|
||||
appendPendingStreamReset(
|
||||
stream.conn, stream, GenericApplicationErrorCode::NO_ERROR);
|
||||
}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StreamEvents::SendReset>::
|
||||
handle(QuicStreamState& stream, StreamEvents::SendReset rst) {
|
||||
resetQuicStream(stream, rst.errorCode);
|
||||
appendPendingStreamReset(stream.conn, stream, rst.errorCode);
|
||||
// Move the state machine:
|
||||
transit<StreamStates::WaitingForRstAck>(stream);
|
||||
}
|
||||
} // namespace quic
|
@@ -9,95 +9,92 @@
|
||||
// override-include-guard
|
||||
|
||||
#include <quic/state/QuicStreamUtilities.h>
|
||||
#include <quic/state/stream/StreamStateFunctions.h>
|
||||
|
||||
namespace quic {
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Open, ReadStreamFrame>::handle(
|
||||
template <typename Event>
|
||||
void invokeStreamSendStateMachine(
|
||||
QuicConnectionStateBase&,
|
||||
QuicStreamState& stream,
|
||||
ReadStreamFrame frame) {
|
||||
if (isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"ReadStreamFrame on unidirectional sending stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
Event event);
|
||||
inline void
|
||||
Handler<StreamReceiveStateMachine, StreamReceiveStates::Open, ReadStreamFrame>::
|
||||
handle(
|
||||
QuicStreamState::Recv& state,
|
||||
ReadStreamFrame frame,
|
||||
QuicStreamState& stream) {
|
||||
VLOG_IF(10, frame.fin) << "Open: Received data with fin"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
appendDataToReadBuffer(
|
||||
stream, StreamBuffer(std::move(frame.data), frame.offset, frame.fin));
|
||||
if (isAllDataReceived(stream)) {
|
||||
if (isUnidirectionalStream(stream.id)) {
|
||||
VLOG(10) << "Open: Transition to Closed"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
transit<StreamStates::Closed>(stream);
|
||||
} else {
|
||||
VLOG(10) << "Open: Transition to HalfClosedRemote"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
transit<StreamStates::HalfClosedRemote>(stream);
|
||||
transit<StreamReceiveStates::Closed>(state);
|
||||
if (stream.inTerminalStates()) {
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
}
|
||||
}
|
||||
stream.conn.streamManager->updateReadableStreams(stream);
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Open, StopSendingFrame>::handle(
|
||||
QuicStreamState& stream,
|
||||
StopSendingFrame frame) {
|
||||
if (isBidirectionalStream(stream.id) ||
|
||||
isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
Handler<StreamSendStateMachine, StreamSendStates::Open, StopSendingFrame>::
|
||||
handle(
|
||||
QuicStreamState::Send& state,
|
||||
StopSendingFrame frame,
|
||||
QuicStreamState& stream) {
|
||||
CHECK(
|
||||
isBidirectionalStream(stream.id) ||
|
||||
isSendingStream(stream.conn.nodeType, stream.id));
|
||||
stream.conn.streamManager->addStopSending(stream.id, frame.errorCode);
|
||||
} else {
|
||||
throw QuicTransportException(
|
||||
"StopSendingFrame on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Open, RstStreamFrame>::handle(
|
||||
QuicStreamState& stream,
|
||||
RstStreamFrame rst) {
|
||||
if (isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"RstStreamFrame on unidirectional sending stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
// We transit before invoking onResetQuicStream because it will check the
|
||||
// state of the stream for flow control.
|
||||
transit<StreamStates::WaitingForRstAck>(stream);
|
||||
onResetQuicStream(stream, std::move(rst));
|
||||
if (isBidirectionalStream(stream.id)) {
|
||||
Handler<StreamReceiveStateMachine, StreamReceiveStates::Open, RstStreamFrame>::
|
||||
handle(
|
||||
QuicStreamState::Recv& state,
|
||||
RstStreamFrame rst,
|
||||
QuicStreamState& stream) {
|
||||
if (matchesStates<StreamSendStateData, StreamSendStates::Open>(
|
||||
stream.send.state)) {
|
||||
// TODO: remove.
|
||||
appendPendingStreamReset(
|
||||
stream.conn, stream, GenericApplicationErrorCode::NO_ERROR);
|
||||
} else {
|
||||
transit<StreamStates::Closed>(stream);
|
||||
invokeStreamSendStateMachine(
|
||||
stream.conn,
|
||||
stream,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::NO_ERROR));
|
||||
}
|
||||
// We transit the receive state machine to Closed before invoking
|
||||
// onResetQuicStream because it will check the state of the stream for flow
|
||||
// control.
|
||||
transit<StreamReceiveStates::Closed>(state);
|
||||
if (stream.inTerminalStates()) {
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
}
|
||||
onResetQuicStream(stream, std::move(rst));
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Open, StreamEvents::SendReset>::
|
||||
handle(QuicStreamState& stream, StreamEvents::SendReset rst) {
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"SendReset on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
inline void Handler<
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Open,
|
||||
StreamEvents::SendReset>::
|
||||
handle(
|
||||
QuicStreamState::Send& state,
|
||||
StreamEvents::SendReset rst,
|
||||
QuicStreamState& stream) {
|
||||
resetQuicStream(stream, rst.errorCode);
|
||||
appendPendingStreamReset(stream.conn, stream, rst.errorCode);
|
||||
// Move the state machine:
|
||||
transit<StreamStates::WaitingForRstAck>(stream);
|
||||
transit<StreamSendStates::ResetSent>(state);
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::Open, StreamEvents::AckStreamFrame>::
|
||||
handle(QuicStreamState& stream, StreamEvents::AckStreamFrame ack) {
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"AckStreamFrame on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
inline void Handler<
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Open,
|
||||
StreamEvents::AckStreamFrame>::
|
||||
handle(
|
||||
QuicStreamState::Send& state,
|
||||
StreamEvents::AckStreamFrame ack,
|
||||
QuicStreamState& stream) {
|
||||
// Clean up the acked buffers from the retransmissionBuffer.
|
||||
|
||||
auto ackedBuffer = std::lower_bound(
|
||||
@@ -129,10 +126,9 @@ Handler<StreamStateMachine, StreamStates::Open, StreamEvents::AckStreamFrame>::
|
||||
|
||||
// Check for whether or not we have ACKed all bytes until our FIN.
|
||||
if (allBytesTillFinAcked(stream)) {
|
||||
if (isUnidirectionalStream(stream.id)) {
|
||||
transit<StreamStates::Closed>(stream);
|
||||
} else {
|
||||
transit<StreamStates::HalfClosedLocal>(stream);
|
||||
transit<StreamSendStates::Closed>(state);
|
||||
if (stream.inTerminalStates()) {
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,219 +40,171 @@ struct StreamEvents {
|
||||
|
||||
// Transition the stream to an error state if there is an invalid state
|
||||
// transition.
|
||||
inline void StreamStateMachineInvalidHandler(const QuicStreamState& state) {
|
||||
inline void StreamSendStateMachineInvalidHandler(const QuicStreamState& state) {
|
||||
throw QuicTransportException(
|
||||
folly::to<std::string>(
|
||||
"Invalid transition from state=",
|
||||
folly::variant_match(
|
||||
state.state,
|
||||
[](const StreamStates::Open&) { return "Open"; },
|
||||
[](const StreamStates::HalfClosedLocal&) {
|
||||
return "HalfClosedLocal";
|
||||
},
|
||||
[](const StreamStates::HalfClosedRemote&) {
|
||||
return "HalfClosedRemote";
|
||||
},
|
||||
[](const StreamStates::WaitingForRstAck&) {
|
||||
return "WaitingForRstAck";
|
||||
},
|
||||
[](const StreamStates::Closed&) { return "Closed"; })),
|
||||
state.send.state,
|
||||
[](const StreamSendStates::Open&) { return "Open"; },
|
||||
[](const StreamSendStates::ResetSent&) { return "ResetSent"; },
|
||||
[](const StreamSendStates::Closed&) { return "Closed"; },
|
||||
[](const StreamSendStates::Invalid&) { return "Invalid"; })),
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
|
||||
struct StreamStateMachine {
|
||||
using StateData = QuicStreamState;
|
||||
static constexpr auto InvalidEventHandler = &StreamStateMachineInvalidHandler;
|
||||
struct StreamSendStateMachine {
|
||||
using StateData = QuicStreamState::Send;
|
||||
using UserData = QuicStreamState;
|
||||
static constexpr auto InvalidEventHandler =
|
||||
&StreamSendStateMachineInvalidHandler;
|
||||
};
|
||||
|
||||
// Transition the stream to an error state if there is an invalid state
|
||||
// transition.
|
||||
inline void StreamReceiveStateMachineInvalidHandler(
|
||||
const QuicStreamState& state) {
|
||||
throw QuicTransportException(
|
||||
folly::to<std::string>(
|
||||
"Invalid transition from state=",
|
||||
folly::variant_match(
|
||||
state.recv.state,
|
||||
[](const StreamReceiveStates::Open&) { return "Open"; },
|
||||
[](const StreamReceiveStates::Closed&) { return "Closed"; },
|
||||
[](const StreamReceiveStates::Invalid&) { return "Invalid"; })),
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
|
||||
struct StreamReceiveStateMachine {
|
||||
using StateData = QuicStreamState::Recv;
|
||||
using UserData = QuicStreamState;
|
||||
static constexpr auto InvalidEventHandler =
|
||||
&StreamReceiveStateMachineInvalidHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
* Welcome to the stream state machine, we got fun and games.
|
||||
*
|
||||
* ACK = Ack of stream frame.
|
||||
* This is a simplified version of the state machines defined in the transport
|
||||
* specification. The "Invalid" state is used for unidirectional streams that
|
||||
* do not have that half (eg: an ingress uni stream is in send state Invalid)
|
||||
*
|
||||
* Send State Machine
|
||||
* ==================
|
||||
*
|
||||
* [ Initial State ]
|
||||
* |
|
||||
* | Send Stream
|
||||
* |
|
||||
* v
|
||||
* Send::Open ---------------+
|
||||
* | |
|
||||
* | Ack all bytes | Send RST
|
||||
* | ti FIN |
|
||||
* v v
|
||||
* Send::Closed <------ ResetSent
|
||||
* RST
|
||||
* Acked
|
||||
*
|
||||
*
|
||||
* Stream / ACK Stream/ ACK
|
||||
* |--| |----|
|
||||
* | v All bytes till FIN | v All bytes till FIN
|
||||
* Open ---------------------> HalfClosedRemote ------------------------|
|
||||
* | | recv | acked |
|
||||
* | | | |
|
||||
* | | SendReset / Reset | |
|
||||
* | ----------------------------| | |
|
||||
* | | | |
|
||||
* | All bytes till FIN acked | | |
|
||||
* | | | |
|
||||
* | | | |
|
||||
* | Stream / ACK | | SendReset / |
|
||||
* | |---| | | Reset |
|
||||
* v | v SendReset v v RstAck v
|
||||
* HalfClosedLocal --------------> WaitingForRstAck---------------------|
|
||||
* | | ^ |
|
||||
* | |---| |
|
||||
* | Reset / Stream / ACK / Reset / SendReset |
|
||||
* | All bytes till FIN recv |
|
||||
* |--------------------------------------------------------------> Closed
|
||||
* | ^
|
||||
* |---|
|
||||
* Stream /
|
||||
* Reset /
|
||||
* RstAck /
|
||||
* Ack /
|
||||
* SendReset
|
||||
* Receive State Machine
|
||||
* =====================
|
||||
*
|
||||
* [ Initial State ]
|
||||
* |
|
||||
* | Stream
|
||||
* |
|
||||
* v
|
||||
* Receive::Open -----------+
|
||||
* | |
|
||||
* | Receive all | Receive RST
|
||||
* | bytes til FIN |
|
||||
* v |
|
||||
* Receive::Closed <---------+
|
||||
*
|
||||
*/
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Open,
|
||||
StreamReceiveStateMachine,
|
||||
StreamReceiveStates::Open,
|
||||
ReadStreamFrame,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StreamStates::Closed);
|
||||
StreamReceiveStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Open,
|
||||
StreamReceiveStateMachine,
|
||||
StreamReceiveStates::Open,
|
||||
RstStreamFrame,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamStates::Closed);
|
||||
StreamReceiveStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Open,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Open,
|
||||
StreamEvents::SendReset,
|
||||
StreamStates::WaitingForRstAck);
|
||||
StreamSendStates::ResetSent);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Open,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Open,
|
||||
StreamEvents::AckStreamFrame,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamStates::Closed);
|
||||
StreamSendStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Open,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Open,
|
||||
StopSendingFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
RstStreamFrame,
|
||||
StreamStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
ReadStreamFrame,
|
||||
StreamStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamEvents::AckStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StopSendingFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedLocal,
|
||||
StreamEvents::SendReset,
|
||||
StreamStates::WaitingForRstAck);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
ReadStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StreamEvents::AckStreamFrame,
|
||||
StreamStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StopSendingFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
StreamEvents::SendReset,
|
||||
StreamStates::WaitingForRstAck);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::HalfClosedRemote,
|
||||
RstStreamFrame,
|
||||
StreamStates::WaitingForRstAck);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
ReadStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamEvents::AckStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StopSendingFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
RstStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamEvents::RstAck,
|
||||
StreamStates::Closed);
|
||||
StreamSendStates::Closed);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamEvents::SendReset);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamReceiveStateMachine,
|
||||
StreamReceiveStates::Closed,
|
||||
ReadStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StreamEvents::RstAck);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StreamEvents::AckStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StopSendingFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamReceiveStateMachine,
|
||||
StreamReceiveStates::Closed,
|
||||
RstStreamFrame);
|
||||
|
||||
QUIC_DECLARE_STATE_HANDLER(
|
||||
StreamStateMachine,
|
||||
StreamStates::Closed,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::Closed,
|
||||
StreamEvents::SendReset);
|
||||
} // namespace quic
|
||||
|
||||
#include <quic/state/stream/StreamClosedHandlers.h>
|
||||
#include <quic/state/stream/StreamHalfClosedLocalHandlers.h>
|
||||
#include <quic/state/stream/StreamHalfClosedRemoteHandlers.h>
|
||||
#include <quic/state/stream/StreamOpenHandlers.h>
|
||||
#include <quic/state/stream/StreamWaitingForRstAckHandlers.h>
|
||||
|
@@ -12,25 +12,20 @@
|
||||
|
||||
namespace quic {
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::WaitingForRstAck, ReadStreamFrame>::
|
||||
handle(QuicStreamState& stream, ReadStreamFrame frame) {
|
||||
if (isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"ReadStreamFrame on unidirectional sending stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
VLOG_IF(10, frame.fin) << "WaitingForRstAck: Received data with fin"
|
||||
<< " stream=" << stream.id << " " << stream.conn;
|
||||
appendDataToReadBuffer(
|
||||
stream, StreamBuffer(std::move(frame.data), frame.offset, frame.fin));
|
||||
}
|
||||
template <typename Event>
|
||||
void invokeStreamReceiveStateMachine(
|
||||
QuicConnectionStateBase&,
|
||||
QuicStreamState& stream,
|
||||
Event event);
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamEvents::AckStreamFrame>::
|
||||
handle(QuicStreamState& stream, StreamEvents::AckStreamFrame /*ack*/) {
|
||||
handle(
|
||||
QuicStreamState::Send& /*state*/,
|
||||
StreamEvents::AckStreamFrame /*ack*/,
|
||||
QuicStreamState& stream) {
|
||||
// do nothing here. We should have already dumped the stream state before
|
||||
// we got here.
|
||||
DCHECK(stream.retransmissionBuffer.empty());
|
||||
@@ -38,43 +33,46 @@ inline void Handler<
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::WaitingForRstAck, StopSendingFrame>::
|
||||
handle(QuicStreamState& stream, StopSendingFrame /*frame*/) {
|
||||
if (isReceivingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"StopSendingFrame on unidirectional receiving stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Handler<StreamStateMachine, StreamStates::WaitingForRstAck, RstStreamFrame>::
|
||||
handle(QuicStreamState& stream, RstStreamFrame rst) {
|
||||
if (isSendingStream(stream.conn.nodeType, stream.id)) {
|
||||
throw QuicTransportException(
|
||||
"RstStreamFrame on unidirectional sending stream",
|
||||
TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
// This will make sure all the states are consistent between resets.
|
||||
onResetQuicStream(stream, std::move(rst));
|
||||
Handler<StreamSendStateMachine, StreamSendStates::ResetSent, StopSendingFrame>::
|
||||
handle(
|
||||
QuicStreamState::Send& /*state*/,
|
||||
StopSendingFrame /*frame*/,
|
||||
QuicStreamState& /*stream*/) {
|
||||
// no-op, we already sent a reset
|
||||
}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamEvents::RstAck>::
|
||||
handle(QuicStreamState& stream, StreamEvents::RstAck /*ack*/) {
|
||||
handle(
|
||||
QuicStreamState::Send& state,
|
||||
StreamEvents::RstAck /*ack*/,
|
||||
QuicStreamState& stream) {
|
||||
VLOG(10) << "ResetSent: Transition to closed stream=" << stream.id << " "
|
||||
<< stream.conn;
|
||||
transit<StreamSendStates::Closed>(state);
|
||||
if (matchesStates<StreamReceiveStateData, StreamReceiveStates::Open>(
|
||||
stream.recv.state)) {
|
||||
// Terminate the ingress state machine until we remove rst on rst
|
||||
invokeStreamReceiveStateMachine(
|
||||
stream.conn,
|
||||
stream,
|
||||
RstStreamFrame(stream.id, GenericApplicationErrorCode::NO_ERROR, 0));
|
||||
}
|
||||
if (stream.inTerminalStates()) {
|
||||
stream.conn.streamManager->addClosed(stream.id);
|
||||
VLOG(10) << "WaitingForRstAck: Transition to closed stream=" << stream.id
|
||||
<< " " << stream.conn;
|
||||
transit<StreamStates::Closed>(stream);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Handler<
|
||||
StreamStateMachine,
|
||||
StreamStates::WaitingForRstAck,
|
||||
StreamSendStateMachine,
|
||||
StreamSendStates::ResetSent,
|
||||
StreamEvents::SendReset>::
|
||||
handle(QuicStreamState& /*stream*/, StreamEvents::SendReset) {
|
||||
handle(
|
||||
QuicStreamState::Send& /*state*/,
|
||||
StreamEvents::SendReset,
|
||||
QuicStreamState& /*stream*/) {
|
||||
// do nothing.
|
||||
}
|
||||
} // namespace quic
|
||||
|
@@ -36,8 +36,10 @@ TEST_F(StreamStateFunctionsTests, SanityTest) {
|
||||
auto currentReadOffset = stream.currentReadOffset;
|
||||
EXPECT_TRUE(stream.writable());
|
||||
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream);
|
||||
// Something are cleared:
|
||||
EXPECT_TRUE(stream.writeBuffer.empty());
|
||||
EXPECT_TRUE(stream.retransmissionBuffer.empty());
|
||||
|
@@ -27,10 +27,13 @@ void verifyStreamReset(
|
||||
const QuicStreamState& stream,
|
||||
uint64_t readOffsetExpected) {
|
||||
EXPECT_TRUE(stream.readBuffer.empty());
|
||||
// AHF
|
||||
EXPECT_TRUE(stream.retransmissionBuffer.empty());
|
||||
EXPECT_TRUE(stream.writeBuffer.empty());
|
||||
|
||||
EXPECT_TRUE(stream.finalReadOffset.hasValue());
|
||||
EXPECT_EQ(readOffsetExpected, stream.finalReadOffset.value());
|
||||
// AHF
|
||||
EXPECT_FALSE(stream.writable());
|
||||
}
|
||||
|
||||
@@ -65,10 +68,11 @@ TEST_F(QuicOpenStateTest, ReadStreamDataNotFin) {
|
||||
bool fin = false;
|
||||
ReadStreamFrame frame(id, offset, fin);
|
||||
frame.data = IOBuf::copyBuffer("hey");
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(frame));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, std::move(frame), stream);
|
||||
EXPECT_TRUE(stream.hasReadableData());
|
||||
EXPECT_TRUE(stream.hasPeekableData());
|
||||
EXPECT_TRUE(isState<StreamStates::Open>(stream));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Open>(stream.recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicOpenStateTest, ReadInvalidData) {
|
||||
@@ -81,15 +85,17 @@ TEST_F(QuicOpenStateTest, ReadInvalidData) {
|
||||
// EOF in middle of stream
|
||||
ReadStreamFrame frame1(id, offset1, fin1);
|
||||
frame1.data = IOBuf::copyBuffer("hey");
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(frame1));
|
||||
EXPECT_TRUE(isState<StreamStates::Open>(stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, std::move(frame1), stream);
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Open>(stream.recv));
|
||||
|
||||
uint64_t offset2 = 1;
|
||||
bool fin2 = true;
|
||||
ReadStreamFrame frame2(id, offset2, fin2);
|
||||
frame2.data = IOBuf::copyBuffer("e");
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(frame2)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, std::move(frame2), stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -99,7 +105,8 @@ TEST_F(QuicOpenStateTest, InvalidEvent) {
|
||||
QuicStreamState stream(id, *conn);
|
||||
RstStreamFrame frame(1, GenericApplicationErrorCode::UNKNOWN, 0);
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, StreamEvents::RstAck(frame)),
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send, StreamEvents::RstAck(frame), stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -113,8 +120,9 @@ TEST_F(QuicOpenStateTest, ReceiveStreamFrameWithFIN) {
|
||||
ReadStreamFrame receivedStreamFrame(stream->id, 100, true);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(*stream, std::move(receivedStreamFrame));
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedRemote>(*stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream->recv, std::move(receivedStreamFrame), *stream);
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Closed>(stream->recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicOpenStateTest, ReceiveStreamFrameWithFINReadbuffHole) {
|
||||
@@ -127,8 +135,9 @@ TEST_F(QuicOpenStateTest, ReceiveStreamFrameWithFINReadbuffHole) {
|
||||
ReadStreamFrame receivedStreamFrame(stream->id, 200, true);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(*stream, std::move(receivedStreamFrame));
|
||||
ASSERT_TRUE(isState<StreamStates::Open>(*stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream->recv, std::move(receivedStreamFrame), *stream);
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicOpenStateTest, ReceiveStreamFrameWithoutFIN) {
|
||||
@@ -141,28 +150,32 @@ TEST_F(QuicOpenStateTest, ReceiveStreamFrameWithoutFIN) {
|
||||
ReadStreamFrame receivedStreamFrame(stream->id, 100, false);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(*stream, std::move(receivedStreamFrame));
|
||||
ASSERT_TRUE(isState<StreamStates::Open>(*stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream->recv, std::move(receivedStreamFrame), *stream);
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
}
|
||||
|
||||
class QuicWaitingForRstAckStateTest : public Test {};
|
||||
class QuicResetSentStateTest : public Test {};
|
||||
|
||||
TEST_F(QuicWaitingForRstAckStateTest, RstAck) {
|
||||
TEST_F(QuicResetSentStateTest, RstAck) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
stream.currentReadOffset = 0xABCD;
|
||||
stream.finalWriteOffset = 0xACDC;
|
||||
stream.readBuffer.emplace_back(
|
||||
folly::IOBuf::copyBuffer("One more thing"), 0xABCD, false);
|
||||
RstStreamFrame frame(id, GenericApplicationErrorCode::UNKNOWN, 0);
|
||||
invokeHandler<StreamStateMachine>(stream, StreamEvents::RstAck(frame));
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send, StreamEvents::RstAck(frame), stream);
|
||||
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
EXPECT_FALSE(stream.finalReadOffset);
|
||||
EXPECT_FALSE(stream.readBuffer.empty());
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
// AHF
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
// EXPECT_FALSE(stream.finalReadOffset);
|
||||
// EXPECT_FALSE(stream.readBuffer.empty());
|
||||
}
|
||||
|
||||
class QuicClosedStateTest : public Test {};
|
||||
@@ -171,10 +184,11 @@ TEST_F(QuicClosedStateTest, RstAck) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
RstStreamFrame frame(id, GenericApplicationErrorCode::UNKNOWN, 0);
|
||||
invokeHandler<StreamStateMachine>(stream, StreamEvents::RstAck(frame));
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send, StreamEvents::RstAck(frame), stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
}
|
||||
|
||||
TEST_F(QuicOpenStateTest, AckStream) {
|
||||
@@ -204,11 +218,11 @@ TEST_F(QuicOpenStateTest, AckStream) {
|
||||
->packet.frames.front());
|
||||
|
||||
StreamEvents::AckStreamFrame ack(streamFrame);
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
}
|
||||
|
||||
TEST_F(QuicOpenStateTest, AckStreamAfterSkip) {
|
||||
@@ -245,11 +259,13 @@ TEST_F(QuicOpenStateTest, AckStreamAfterSkip) {
|
||||
EXPECT_TRUE(stream->retransmissionBuffer.empty());
|
||||
|
||||
StreamEvents::AckStreamFrame ack(streamFrame);
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
}
|
||||
|
||||
class QuicHalfClosedLocalStateTest : public Test {};
|
||||
@@ -258,45 +274,54 @@ TEST_F(QuicHalfClosedLocalStateTest, ReceiveStreamFrameWithFIN) {
|
||||
auto conn = createConn();
|
||||
|
||||
auto stream = conn->streamManager->createNextBidirectionalStream().value();
|
||||
stream->state = StreamStates::HalfClosedLocal();
|
||||
stream->send.state = StreamSendStates::Closed();
|
||||
stream->recv.state = StreamReceiveStates::Open();
|
||||
stream->currentReadOffset = 100;
|
||||
|
||||
// We received FIN and everything:
|
||||
ReadStreamFrame receivedStreamFrame(stream->id, 100, true);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(*stream, std::move(receivedStreamFrame));
|
||||
ASSERT_TRUE(isState<StreamStates::Closed>(*stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream->recv, std::move(receivedStreamFrame), *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Closed>(stream->recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicHalfClosedLocalStateTest, ReceiveStreamFrameWithFINReadbuffHole) {
|
||||
auto conn = createConn();
|
||||
|
||||
auto stream = conn->streamManager->createNextBidirectionalStream().value();
|
||||
stream->state = StreamStates::HalfClosedLocal();
|
||||
stream->send.state = StreamSendStates::Closed();
|
||||
stream->recv.state = StreamReceiveStates::Open();
|
||||
stream->currentReadOffset = 100;
|
||||
|
||||
// We received FIN, but we havn't received anything between 100 and 200:
|
||||
ReadStreamFrame receivedStreamFrame(stream->id, 200, true);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(*stream, std::move(receivedStreamFrame));
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream->recv, std::move(receivedStreamFrame), *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicHalfClosedLocalStateTest, ReceiveStreamFrameWithoutFIN) {
|
||||
auto conn = createConn();
|
||||
|
||||
auto stream = conn->streamManager->createNextBidirectionalStream().value();
|
||||
stream->state = StreamStates::HalfClosedLocal();
|
||||
stream->send.state = StreamSendStates::Closed();
|
||||
stream->recv.state = StreamReceiveStates::Open();
|
||||
stream->currentReadOffset = 100;
|
||||
|
||||
// We haven't received FIN:
|
||||
ReadStreamFrame receivedStreamFrame(stream->id, 100, false);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(*stream, std::move(receivedStreamFrame));
|
||||
ASSERT_TRUE(isState<StreamStates::HalfClosedLocal>(*stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream->recv, std::move(receivedStreamFrame), *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Open>(stream->recv));
|
||||
}
|
||||
|
||||
class QuicHalfClosedRemoteStateTest : public Test {};
|
||||
@@ -310,7 +335,8 @@ TEST_F(QuicHalfClosedRemoteStateTest, AckStream) {
|
||||
folly::Optional<ConnectionId> serverChosenConnId =
|
||||
connIdAlgo->encodeConnectionId(params);
|
||||
auto stream = conn->streamManager->createNextBidirectionalStream().value();
|
||||
stream->state = StreamStates::HalfClosedRemote();
|
||||
stream->send.state = StreamSendStates::Open();
|
||||
stream->recv.state = StreamReceiveStates::Closed();
|
||||
|
||||
EventBase evb;
|
||||
auto sock = std::make_unique<folly::test::MockAsyncUDPSocket>(&evb);
|
||||
@@ -333,11 +359,11 @@ TEST_F(QuicHalfClosedRemoteStateTest, AckStream) {
|
||||
->packet.frames.front());
|
||||
|
||||
StreamEvents::AckStreamFrame ack(streamFrame);
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::Closed>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::Closed>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
}
|
||||
|
||||
TEST_F(QuicHalfClosedRemoteStateTest, AckStreamAfterSkip) {
|
||||
@@ -349,7 +375,8 @@ TEST_F(QuicHalfClosedRemoteStateTest, AckStreamAfterSkip) {
|
||||
folly::Optional<ConnectionId> serverChosenConnId =
|
||||
connIdAlgo->encodeConnectionId(params);
|
||||
auto stream = conn->streamManager->createNextBidirectionalStream().value();
|
||||
stream->state = StreamStates::HalfClosedRemote();
|
||||
stream->send.state = StreamSendStates::Open();
|
||||
stream->recv.state = StreamReceiveStates::Closed();
|
||||
|
||||
EventBase evb;
|
||||
auto sock = std::make_unique<folly::test::MockAsyncUDPSocket>(&evb);
|
||||
@@ -379,11 +406,13 @@ TEST_F(QuicHalfClosedRemoteStateTest, AckStreamAfterSkip) {
|
||||
EXPECT_TRUE(stream->retransmissionBuffer.empty());
|
||||
|
||||
StreamEvents::AckStreamFrame ack(streamFrame);
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::Closed>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Closed>(stream->recv));
|
||||
|
||||
invokeHandler<StreamStateMachine>(*stream, ack);
|
||||
ASSERT_TRUE(isState<StreamStates::Closed>(*stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream->send, ack, *stream);
|
||||
ASSERT_TRUE(isState<StreamSendStates::Closed>(stream->send));
|
||||
ASSERT_TRUE(isState<StreamReceiveStates::Closed>(stream->recv));
|
||||
}
|
||||
|
||||
class QuicSendResetTest : public Test {};
|
||||
@@ -392,47 +421,61 @@ TEST_F(QuicSendResetTest, FromOpen) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
}
|
||||
|
||||
TEST_F(QuicSendResetTest, FromHalfCloseRemote) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedRemote();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
}
|
||||
|
||||
TEST_F(QuicSendResetTest, FromHalfCloseLocal) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedLocal();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream);
|
||||
|
||||
// You cannot send a reset after FIN has been acked
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
}
|
||||
|
||||
TEST_F(QuicSendResetTest, FromClosed) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream);
|
||||
}
|
||||
|
||||
TEST_F(QuicSendResetTest, FromWaitingForRstAck) {
|
||||
TEST_F(QuicSendResetTest, FromResetSent) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN));
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream);
|
||||
}
|
||||
|
||||
class QuicRecvResetTest : public Test {};
|
||||
@@ -443,8 +486,9 @@ TEST_F(QuicRecvResetTest, FromOpen) {
|
||||
StreamId rstStream = 1;
|
||||
QuicStreamState stream(id, *conn);
|
||||
RstStreamFrame rst(rstStream, GenericApplicationErrorCode::UNKNOWN, 100);
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(rst));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(stream.recv, std::move(rst), stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 100);
|
||||
}
|
||||
|
||||
@@ -456,7 +500,8 @@ TEST_F(QuicRecvResetTest, FromOpenReadEOFMismatch) {
|
||||
RstStreamFrame rst(1, GenericApplicationErrorCode::UNKNOWN, 100);
|
||||
stream.finalReadOffset = 1024;
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(rst)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, std::move(rst), stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -464,10 +509,14 @@ TEST_F(QuicRecvResetTest, FromHalfClosedRemoteNoReadOffsetYet) {
|
||||
StreamId id = 5;
|
||||
auto conn = createConn();
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedRemote();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 100));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 100),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 100);
|
||||
}
|
||||
|
||||
@@ -475,11 +524,15 @@ TEST_F(QuicRecvResetTest, FromHalfClosedRemoteReadOffsetMatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedRemote();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
stream.finalReadOffset = 1024;
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1024));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1024),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 1024);
|
||||
}
|
||||
|
||||
@@ -487,11 +540,14 @@ TEST_F(QuicRecvResetTest, FromHalfClosedRemoteReadOffsetMismatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedRemote();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
stream.finalReadOffset = 1024;
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 100)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 100),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -499,10 +555,14 @@ TEST_F(QuicRecvResetTest, FromHalfClosedLocal) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedLocal();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200));
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 200);
|
||||
}
|
||||
|
||||
@@ -510,46 +570,60 @@ TEST_F(QuicRecvResetTest, FromHalfClosedLocalReadEOFMismatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::HalfClosedLocal();
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
stream.finalReadOffset = 2014;
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
TEST_F(QuicRecvResetTest, FromWaitingForRstAckNoReadOffsetYet) {
|
||||
TEST_F(QuicRecvResetTest, FromResetSentNoReadOffsetYet) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 200);
|
||||
}
|
||||
|
||||
TEST_F(QuicRecvResetTest, FromWaitingForRstAckOffsetMatch) {
|
||||
TEST_F(QuicRecvResetTest, FromResetSentOffsetMatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
stream.finalReadOffset = 200;
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200));
|
||||
EXPECT_TRUE(isState<StreamStates::WaitingForRstAck>(stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::ResetSent>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 200);
|
||||
}
|
||||
|
||||
TEST_F(QuicRecvResetTest, FromWaitingForRstAckOffsetMismatch) {
|
||||
TEST_F(QuicRecvResetTest, FromResetSentOffsetMismatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
stream.finalReadOffset = 300;
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -557,10 +631,14 @@ TEST_F(QuicRecvResetTest, FromClosedNoReadOffsetYet) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200));
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 200),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 200);
|
||||
}
|
||||
|
||||
@@ -568,11 +646,15 @@ TEST_F(QuicRecvResetTest, FromClosedOffsetMatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
stream.finalReadOffset = 1234;
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234));
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
verifyStreamReset(stream, 1234);
|
||||
}
|
||||
|
||||
@@ -580,12 +662,14 @@ TEST_F(QuicRecvResetTest, FromClosedOffsetMismatch) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 5;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Closed();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
stream.finalReadOffset = 123;
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -595,9 +679,11 @@ TEST_F(QuicUnidirectionalStreamTest, OpenInvalidReadStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, ReadStreamFrame(id, 1, false)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, ReadStreamFrame(id, 1, false), stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -605,11 +691,13 @@ TEST_F(QuicUnidirectionalStreamTest, OpenInvalidRstStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -617,11 +705,13 @@ TEST_F(QuicUnidirectionalStreamTest, OpenInvalidSendReset) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN)),
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -629,20 +719,25 @@ TEST_F(QuicUnidirectionalStreamTest, OpenInvalidAckStreamFrame) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
StreamEvents::AckStreamFrame ack(WriteStreamFrame(id, 0, 0, false));
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, ack), QuicTransportException);
|
||||
invokeHandler<StreamSendStateMachine>(stream.send, ack, stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, OpenInvalidStopSending) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StopSendingFrame(id, GenericApplicationErrorCode::UNKNOWN)),
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StopSendingFrame(id, GenericApplicationErrorCode::UNKNOWN),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -650,9 +745,11 @@ TEST_F(QuicUnidirectionalStreamTest, ClosedInvalidReadStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, ReadStreamFrame(id, 1, false)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, ReadStreamFrame(id, 1, false), stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -660,11 +757,13 @@ TEST_F(QuicUnidirectionalStreamTest, ClosedInvalidRstStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -672,11 +771,13 @@ TEST_F(QuicUnidirectionalStreamTest, ClosedInvalidSendReset) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN)),
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StreamEvents::SendReset(GenericApplicationErrorCode::UNKNOWN),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -684,20 +785,25 @@ TEST_F(QuicUnidirectionalStreamTest, ClosedInvalidAckStreamFrame) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
StreamEvents::AckStreamFrame ack(WriteStreamFrame(id, 0, 0, false));
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, ack), QuicTransportException);
|
||||
invokeHandler<StreamSendStateMachine>(stream.send, ack, stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, ClosedInvalidStopSending) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Closed();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Closed();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StopSendingFrame(id, GenericApplicationErrorCode::UNKNOWN)),
|
||||
invokeHandler<StreamSendStateMachine>(
|
||||
stream.send,
|
||||
StopSendingFrame(id, GenericApplicationErrorCode::UNKNOWN),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
@@ -705,23 +811,30 @@ TEST_F(QuicUnidirectionalStreamTest, OpenReadStreamFin) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
stream.currentReadOffset = 100;
|
||||
ReadStreamFrame receivedStreamFrame(stream.id, 100, true);
|
||||
receivedStreamFrame.data = folly::IOBuf::create(10);
|
||||
receivedStreamFrame.data->append(10);
|
||||
invokeHandler<StreamStateMachine>(stream, std::move(receivedStreamFrame));
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, std::move(receivedStreamFrame), stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Invalid>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, OpenRstStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::Open();
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234));
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
stream.send.state = StreamSendStates::Invalid();
|
||||
stream.recv.state = StreamReceiveStates::Open();
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234),
|
||||
stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Invalid>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Closed>(stream.recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, OpenFinalAckStreamFrame) {
|
||||
@@ -729,48 +842,44 @@ TEST_F(QuicUnidirectionalStreamTest, OpenFinalAckStreamFrame) {
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
WriteStreamFrame streamFrame(id, 1, 1, false);
|
||||
stream.state = StreamStates::Open();
|
||||
stream.send.state = StreamSendStates::Open();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
stream.finalWriteOffset = 1;
|
||||
stream.currentWriteOffset = 2;
|
||||
auto buf = folly::IOBuf::create(1);
|
||||
buf->append(1);
|
||||
stream.retransmissionBuffer.emplace_back(std::move(buf), 1, false);
|
||||
StreamEvents::AckStreamFrame ack(streamFrame);
|
||||
invokeHandler<StreamStateMachine>(stream, ack);
|
||||
EXPECT_TRUE(isState<StreamStates::Closed>(stream));
|
||||
invokeHandler<StreamSendStateMachine>(stream.send, ack, stream);
|
||||
EXPECT_TRUE(isState<StreamSendStates::Closed>(stream.send));
|
||||
EXPECT_TRUE(isState<StreamReceiveStates::Invalid>(stream.recv));
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, WaitingForRstAckInvalidReadStream) {
|
||||
TEST_F(QuicUnidirectionalStreamTest, ResetSentInvalidReadStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(stream, ReadStreamFrame(id, 1, false)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv, ReadStreamFrame(id, 1, false), stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, WaitingForRstAckInvalidRstStream) {
|
||||
TEST_F(QuicUnidirectionalStreamTest, ResetSentInvalidRstStream) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b111;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
stream.send.state = StreamSendStates::ResetSent();
|
||||
stream.recv.state = StreamReceiveStates::Invalid();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234)),
|
||||
invokeHandler<StreamReceiveStateMachine>(
|
||||
stream.recv,
|
||||
RstStreamFrame(1, GenericApplicationErrorCode::UNKNOWN, 1234),
|
||||
stream),
|
||||
QuicTransportException);
|
||||
}
|
||||
|
||||
TEST_F(QuicUnidirectionalStreamTest, WaitingForRstAckInvalidStopSending) {
|
||||
auto conn = createConn();
|
||||
StreamId id = 0b110;
|
||||
QuicStreamState stream(id, *conn);
|
||||
stream.state = StreamStates::WaitingForRstAck();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<StreamStateMachine>(
|
||||
stream, StopSendingFrame(id, GenericApplicationErrorCode::UNKNOWN)),
|
||||
QuicTransportException);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace quic
|
||||
|
@@ -194,7 +194,8 @@ TEST_F(QPRFunctionsTest, RecvMinStreamDataFrameShrinkBuffer) {
|
||||
|
||||
TEST_F(QPRFunctionsTest, RecvMinStreamDataFrameOnUnidirectionalStream) {
|
||||
auto stream = conn.streamManager->createNextUnidirectionalStream().value();
|
||||
stream->state = StreamStates::Closed{};
|
||||
stream->send.state = StreamSendStates::Closed{};
|
||||
stream->recv.state = StreamReceiveStates::Closed{};
|
||||
PacketNum packetNum(10);
|
||||
MinStreamDataFrame frame(
|
||||
stream->id, stream->flowControlState.peerAdvertisedMaxOffset + 100, 100);
|
||||
|
@@ -345,10 +345,11 @@ TEST_F(QuicStateFunctionsTest, TestInvokeStreamStateMachineConnectionError) {
|
||||
RstStreamFrame rst(1, GenericApplicationErrorCode::UNKNOWN, 100);
|
||||
stream.finalReadOffset = 1024;
|
||||
EXPECT_THROW(
|
||||
invokeStreamStateMachine(conn, stream, std::move(rst)),
|
||||
invokeStreamReceiveStateMachine(conn, stream, std::move(rst)),
|
||||
QuicTransportException);
|
||||
bool matches = matchesStates<StreamStateData, StreamStates::WaitingForRstAck>(
|
||||
stream.state);
|
||||
bool matches =
|
||||
matchesStates<StreamSendStateData, StreamSendStates::ResetSent>(
|
||||
stream.send.state);
|
||||
EXPECT_TRUE(matches);
|
||||
}
|
||||
|
||||
@@ -361,9 +362,10 @@ TEST_F(QuicStateFunctionsTest, InvokeResetDoesNotSendFlowControl) {
|
||||
stream.flowControlState.windowSize = 100;
|
||||
conn.flowControlState.advertisedMaxOffset = 100;
|
||||
conn.flowControlState.windowSize = 100;
|
||||
invokeStreamStateMachine(conn, stream, std::move(rst));
|
||||
bool matches = matchesStates<StreamStateData, StreamStates::WaitingForRstAck>(
|
||||
stream.state);
|
||||
invokeStreamReceiveStateMachine(conn, stream, std::move(rst));
|
||||
bool matches =
|
||||
matchesStates<StreamSendStateData, StreamSendStates::ResetSent>(
|
||||
stream.send.state);
|
||||
EXPECT_TRUE(matches);
|
||||
EXPECT_FALSE(conn.streamManager->hasWindowUpdates());
|
||||
EXPECT_TRUE(conn.pendingEvents.connWindowUpdate);
|
||||
@@ -376,13 +378,13 @@ TEST_F(QuicStateFunctionsTest, TestInvokeStreamStateMachineStreamError) {
|
||||
QuicStreamState stream(1, conn);
|
||||
RstStreamFrame rst(1, GenericApplicationErrorCode::UNKNOWN, 100);
|
||||
try {
|
||||
invokeStreamStateMachine(conn, stream, StreamEvents::RstAck(rst));
|
||||
invokeStreamSendStateMachine(conn, stream, StreamEvents::RstAck(rst));
|
||||
ADD_FAILURE();
|
||||
} catch (QuicTransportException& ex) {
|
||||
EXPECT_EQ(ex.errorCode(), TransportErrorCode::STREAM_STATE_ERROR);
|
||||
}
|
||||
bool matches =
|
||||
matchesStates<StreamStateData, StreamStates::Open>(stream.state);
|
||||
bool matches = matchesStates<StreamSendStateData, StreamSendStates::Open>(
|
||||
stream.send.state);
|
||||
EXPECT_TRUE(matches);
|
||||
}
|
||||
|
||||
|
@@ -1518,7 +1518,8 @@ TEST_F(QuicStreamFunctionsTest, RemovedClosedState) {
|
||||
conn.streamManager->queueWindowUpdate(streamId);
|
||||
conn.streamManager->addStopSending(
|
||||
streamId, GenericApplicationErrorCode::UNKNOWN);
|
||||
stream->state = StreamStates::Closed{};
|
||||
stream->send.state = StreamSendStates::Closed{};
|
||||
stream->recv.state = StreamReceiveStates::Closed{};
|
||||
conn.streamManager->removeClosedStream(streamId);
|
||||
EXPECT_FALSE(conn.streamManager->streamExists(streamId));
|
||||
EXPECT_TRUE(conn.streamManager->readableStreams().empty());
|
||||
@@ -1594,8 +1595,8 @@ TEST_F(QuicServerStreamFunctionsTest, ServerGetCloseBothDirections) {
|
||||
conn.streamManager->createStream(serverBiStream).value();
|
||||
EXPECT_EQ(conn.streamManager->getStream(serverBiStream)->id, serverBiStream);
|
||||
StreamId serverUniStream = 0x0B;
|
||||
conn.streamManager->createStream(serverUniStream).value()->state =
|
||||
StreamStates::Closed{};
|
||||
auto stream = conn.streamManager->createStream(serverUniStream).value();
|
||||
stream->send.state = StreamSendStates::Closed{};
|
||||
|
||||
conn.streamManager->removeClosedStream(serverUniStream);
|
||||
EXPECT_TRUE(
|
||||
@@ -1679,7 +1680,10 @@ TEST_F(QuicStreamFunctionsTest, StreamExists) {
|
||||
EXPECT_FALSE(conn.streamManager->streamExists(peerStream));
|
||||
EXPECT_FALSE(conn.streamManager->streamExists(peerAutoOpened));
|
||||
|
||||
conn.streamManager->getStream(peerStream)->state = StreamStates::Closed{};
|
||||
conn.streamManager->getStream(peerStream)->send.state =
|
||||
StreamSendStates::Closed{};
|
||||
conn.streamManager->getStream(peerStream)->recv.state =
|
||||
StreamReceiveStates::Closed{};
|
||||
EXPECT_TRUE(conn.streamManager->streamExists(localStream));
|
||||
EXPECT_TRUE(conn.streamManager->streamExists(localAutoOpened));
|
||||
EXPECT_FALSE(conn.streamManager->streamExists(notOpenedLocal));
|
||||
|
@@ -41,6 +41,7 @@ void ThrowExceptionHandler(const ConnectionState&) {
|
||||
|
||||
struct TestMachine {
|
||||
using StateData = ConnectionState;
|
||||
using UserData = ConnectionState;
|
||||
static auto constexpr InvalidEventHandler = &ThrowExceptionHandler;
|
||||
};
|
||||
|
||||
@@ -51,14 +52,16 @@ QUIC_DECLARE_STATE_HANDLER(TestMachine, State2, Event2, State1, State3);
|
||||
// The handlers
|
||||
void Handler<TestMachine, State1, Event1>::handle(
|
||||
ConnectionState& connState,
|
||||
Event1 /*event*/) {
|
||||
Event1 /*event*/,
|
||||
TestMachine::UserData&) {
|
||||
connState.visitedState1Event1 = true;
|
||||
transit<State2>(connState);
|
||||
}
|
||||
|
||||
void Handler<TestMachine, State1, Event2>::handle(
|
||||
ConnectionState& connState,
|
||||
Event2 /*event*/) {
|
||||
Event2 /*event*/,
|
||||
TestMachine::UserData&) {
|
||||
connState.visitedState1Event2 = true;
|
||||
transit<State3>(connState);
|
||||
// transit<State1>(connState); This will fail to compile because it
|
||||
@@ -67,7 +70,8 @@ void Handler<TestMachine, State1, Event2>::handle(
|
||||
|
||||
void Handler<TestMachine, State2, Event2>::handle(
|
||||
ConnectionState& connState,
|
||||
Event2 /*event*/) {
|
||||
Event2 /*event*/,
|
||||
TestMachine::UserData&) {
|
||||
connState.visitedState2Event2 = true;
|
||||
transit<State3>(connState);
|
||||
}
|
||||
@@ -83,6 +87,7 @@ struct ConnectionStateT {
|
||||
template <typename T>
|
||||
struct TestMachineT {
|
||||
using StateData = ConnectionStateT<T>;
|
||||
using UserData = ConnectionStateT<T>;
|
||||
static void InvalidEventHandler(ConnectionStateT<T>& /*s*/) {
|
||||
throw InvalidHandlerException("invalid state in template machine");
|
||||
}
|
||||
@@ -95,7 +100,8 @@ QUIC_DECLARE_STATE_HANDLER_T(State2, Event2, State3);
|
||||
template <typename Machine>
|
||||
void Handler<Machine, State1, Event1>::handle(
|
||||
typename Machine::StateData& s,
|
||||
Event1) {
|
||||
Event1,
|
||||
typename Machine::UserData&) {
|
||||
s.visitedState1Event1 = true;
|
||||
transit<State2>(s);
|
||||
}
|
||||
@@ -103,7 +109,8 @@ void Handler<Machine, State1, Event1>::handle(
|
||||
template <typename Machine>
|
||||
void Handler<Machine, State1, Event2>::handle(
|
||||
typename Machine::StateData& s,
|
||||
Event2) {
|
||||
Event2,
|
||||
typename Machine::UserData&) {
|
||||
s.visitedState1Event2 = true;
|
||||
transit<State3>(s);
|
||||
}
|
||||
@@ -111,7 +118,8 @@ void Handler<Machine, State1, Event2>::handle(
|
||||
template <typename Machine>
|
||||
void Handler<Machine, State2, Event2>::handle(
|
||||
typename Machine::StateData& s,
|
||||
Event2) {
|
||||
Event2,
|
||||
typename Machine::UserData&) {
|
||||
s.visitedState2Event2 = true;
|
||||
transit<State3>(s);
|
||||
}
|
||||
@@ -126,7 +134,7 @@ class StateMachineTest : public Test {
|
||||
|
||||
TEST_F(StateMachineTest, TestTransitions) {
|
||||
state.state = State1();
|
||||
invokeHandler<TestMachine>(state, Event1());
|
||||
invokeHandler<TestMachine>(state, Event1(), state);
|
||||
EXPECT_TRUE(state.visitedState1Event1);
|
||||
EXPECT_FALSE(state.visitedState1Event2);
|
||||
EXPECT_FALSE(state.visitedState2Event2);
|
||||
@@ -134,7 +142,7 @@ TEST_F(StateMachineTest, TestTransitions) {
|
||||
// check that the state is correct.
|
||||
boost::get<State2>(state.state);
|
||||
|
||||
invokeHandler<TestMachine>(state, Event2());
|
||||
invokeHandler<TestMachine>(state, Event2(), state);
|
||||
|
||||
EXPECT_TRUE(state.visitedState1Event1);
|
||||
EXPECT_FALSE(state.visitedState1Event2);
|
||||
@@ -146,19 +154,20 @@ TEST_F(StateMachineTest, TestTransitions) {
|
||||
TEST_F(StateMachineTest, TestInvalid) {
|
||||
state.state = State2();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<TestMachine>(state, Event1()), InvalidHandlerException);
|
||||
invokeHandler<TestMachine>(state, Event1(), state),
|
||||
InvalidHandlerException);
|
||||
}
|
||||
|
||||
TEST_F(StateMachineTest, TestTemplateTransitions) {
|
||||
stateT.state = State1();
|
||||
invokeHandler<TestMachineT<int>>(stateT, Event1());
|
||||
invokeHandler<TestMachineT<int>>(stateT, Event1(), stateT);
|
||||
EXPECT_TRUE(stateT.visitedState1Event1);
|
||||
EXPECT_FALSE(stateT.visitedState1Event2);
|
||||
EXPECT_FALSE(stateT.visitedState2Event2);
|
||||
|
||||
boost::get<State2>(stateT.state);
|
||||
|
||||
invokeHandler<TestMachineT<int>>(stateT, Event2());
|
||||
invokeHandler<TestMachineT<int>>(stateT, Event2(), stateT);
|
||||
|
||||
EXPECT_TRUE(stateT.visitedState1Event1);
|
||||
EXPECT_FALSE(stateT.visitedState1Event2);
|
||||
@@ -170,7 +179,7 @@ TEST_F(StateMachineTest, TestTemplateTransitions) {
|
||||
TEST_F(StateMachineTest, TestTemplateInvalid) {
|
||||
stateT.state = State2();
|
||||
EXPECT_THROW(
|
||||
invokeHandler<TestMachineT<int>>(stateT, Event1()),
|
||||
invokeHandler<TestMachineT<int>>(stateT, Event1(), stateT),
|
||||
InvalidHandlerException);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user