1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-09 20:42:44 +03:00
Files
mvfst/quic/state/SimpleFrameFunctions.cpp
Matt Joras 72e677df33 Send windowed stream limit updates
Summary:
Implement sending stream limit updates in a windowed fashion, so that as a peer exhausts its streams we will grant it additional credit. This is implemented by having the stream manager check if an update is needed on removing streams, and the api layer potentially sending an update after it initiates the check for closed streams.

This also makes some driveby changes to use `std::lower_bound` instead of `std::find` for the sorted collections in the stream manager.

Reviewed By: yangchi

Differential Revision: D16808229

fbshipit-source-id: f6e3460d43e4d165e362164be00c0cec27cf1e79
2019-09-18 11:33:03 -07:00

199 lines
6.8 KiB
C++

/*
* 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.
*
*/
#include "SimpleFrameFunctions.h"
#include <boost/variant/get.hpp>
#include <quic/state/QuicStateFunctions.h>
#include <quic/state/QuicStreamFunctions.h>
namespace quic {
void sendSimpleFrame(QuicConnectionStateBase& conn, QuicSimpleFrame frame) {
conn.pendingEvents.frames.emplace_back(std::move(frame));
}
void updateSimpleFrameOnAck(
QuicConnectionStateBase& /*conn*/,
const QuicSimpleFrame& /*frame*/) {
// TODO implement.
}
folly::Optional<QuicSimpleFrame> updateSimpleFrameOnPacketClone(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& frame) {
return folly::variant_match(
frame,
[&](const StopSendingFrame& frame) -> folly::Optional<QuicSimpleFrame> {
if (!conn.streamManager->streamExists(frame.streamId)) {
return folly::none;
}
return QuicSimpleFrame(frame);
},
[&](const MinStreamDataFrame& frame) -> folly::Optional<QuicSimpleFrame> {
if (!conn.streamManager->streamExists(frame.streamId)) {
return folly::none;
}
return QuicSimpleFrame(frame);
},
[&](const ExpiredStreamDataFrame& frame)
-> folly::Optional<QuicSimpleFrame> {
if (!conn.streamManager->streamExists(frame.streamId)) {
return folly::none;
}
return QuicSimpleFrame(frame);
},
[&](const PathChallengeFrame& frame) -> folly::Optional<QuicSimpleFrame> {
// Path validation timer expired, path validation failed;
// or a different path validation was scheduled
if (!conn.outstandingPathValidation ||
frame != *conn.outstandingPathValidation) {
return folly::none;
}
return QuicSimpleFrame(frame);
},
[&](const PathResponseFrame&) -> folly::Optional<QuicSimpleFrame> {
// Do not clone PATH_RESPONSE to avoid buffering
return folly::none;
},
[&](const NewConnectionIdFrame& frame)
-> folly::Optional<QuicSimpleFrame> {
return QuicSimpleFrame(frame);
},
[&](const MaxStreamsFrame& frame) -> folly::Optional<QuicSimpleFrame> {
return QuicSimpleFrame(frame);
});
}
void updateSimpleFrameOnPacketSent(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& simpleFrame) {
folly::variant_match(
simpleFrame,
[&](const PathChallengeFrame&) {
conn.outstandingPathValidation =
std::move(conn.pendingEvents.pathChallenge);
conn.pendingEvents.schedulePathValidationTimeout = true;
},
[&](const QuicSimpleFrame& frame) {
auto& frames = conn.pendingEvents.frames;
auto itr =
find_if(frames.begin(), frames.end(), [&](QuicSimpleFrame& f) {
return folly::variant_match(frame, [&](auto& vFrame) {
auto fptr = boost::get<decltype(vFrame)>(&f);
return fptr != nullptr && *fptr == vFrame;
});
});
CHECK(itr != frames.end());
frames.erase(itr);
});
}
void updateSimpleFrameOnPacketLoss(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& frameIn) {
folly::variant_match(
frameIn,
[&](const StopSendingFrame& frame) {
if (conn.streamManager->streamExists(frame.streamId)) {
conn.pendingEvents.frames.push_back(frame);
}
},
[&](const MinStreamDataFrame& frame) {
auto stream = conn.streamManager->getStream(frame.streamId);
if (stream && stream->conn.partialReliabilityEnabled) {
advanceCurrentReceiveOffset(stream, frame.minimumStreamOffset);
}
},
[&](const ExpiredStreamDataFrame& frame) {
auto stream = conn.streamManager->getStream(frame.streamId);
if (stream && stream->conn.partialReliabilityEnabled) {
advanceMinimumRetransmittableOffset(
stream, frame.minimumStreamOffset);
}
},
[&](const PathChallengeFrame& frame) {
if (conn.outstandingPathValidation &&
frame == *conn.outstandingPathValidation) {
conn.pendingEvents.pathChallenge = frame;
}
},
[&](const PathResponseFrame&) {
// Do not retransmit PATH_RESPONSE to avoid buffering
},
[&](const NewConnectionIdFrame& frame) {
conn.pendingEvents.frames.push_back(frame);
},
[&](const MaxStreamsFrame& frame) {
conn.pendingEvents.frames.push_back(frame);
});
}
bool updateSimpleFrameOnPacketReceived(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& frameIn,
PacketNum packetNum,
bool fromChangedPeerAddress) {
return folly::variant_match(
frameIn,
[&](const StopSendingFrame& frame) {
auto stream = conn.streamManager->getStream(frame.streamId);
if (stream) {
invokeStreamSendStateMachine(conn, *stream, frame);
}
return true;
},
[&](const MinStreamDataFrame& frame) {
auto stream = conn.streamManager->getStream(frame.streamId);
if (stream && stream->conn.partialReliabilityEnabled) {
onRecvMinStreamDataFrame(stream, frame, packetNum);
}
return true;
},
[&](const ExpiredStreamDataFrame& frame) {
auto stream = conn.streamManager->getStream(frame.streamId);
if (stream && stream->conn.partialReliabilityEnabled) {
onRecvExpiredStreamDataFrame(stream, frame);
}
return true;
},
[&](const PathChallengeFrame& frame) {
conn.pendingEvents.frames.emplace_back(
PathResponseFrame(frame.pathData));
return false;
},
[&](const PathResponseFrame& frame) {
// Ignore the response if outstandingPathValidation is none or
// the path data doesn't match what's in outstandingPathValidation
if (fromChangedPeerAddress || !conn.outstandingPathValidation ||
frame.pathData != conn.outstandingPathValidation->pathData) {
return false;
}
// TODO update source token,
conn.outstandingPathValidation = folly::none;
conn.pendingEvents.schedulePathValidationTimeout = false;
conn.writableBytesLimit = folly::none;
return false;
},
[&](const NewConnectionIdFrame&) {
// TODO junqiw
return false;
},
[&](const MaxStreamsFrame& maxStreamsFrame) {
if (maxStreamsFrame.isForBidirectionalStream()) {
conn.streamManager->setMaxLocalBidirectionalStreams(
maxStreamsFrame.maxStreams);
} else {
conn.streamManager->setMaxLocalUnidirectionalStreams(
maxStreamsFrame.maxStreams);
}
return true;
});
}
} // namespace quic