1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-24 04:01:07 +03:00
Files
mvfst/quic/state/SimpleFrameFunctions.cpp
Matt Joras 003f012cb7 TODO comment cleanup.
Summary:
These are either no longer relevant, are unlikely to be done, or are spculative enough that they don't deserve code space.

Hope here is to make our search for TODOs higher signal.

Reviewed By: lnicco

Differential Revision: D29769792

fbshipit-source-id: 7cfa62cdc15e72d8b7b0cd5dbb5913ea3ca3dc5a
2021-07-20 10:27:32 -07:00

274 lines
10 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 <quic/QuicConstants.h>
#include <quic/state/QuicStateFunctions.h>
#include <quic/state/QuicStreamFunctions.h>
#include <quic/state/stream/StreamSendHandlers.h>
namespace quic {
void sendSimpleFrame(QuicConnectionStateBase& conn, QuicSimpleFrame frame) {
conn.pendingEvents.frames.emplace_back(std::move(frame));
}
folly::Optional<QuicSimpleFrame> updateSimpleFrameOnPacketClone(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& frame) {
switch (frame.type()) {
case QuicSimpleFrame::Type::StopSendingFrame:
if (!conn.streamManager->streamExists(
frame.asStopSendingFrame()->streamId)) {
return folly::none;
}
return QuicSimpleFrame(frame);
case QuicSimpleFrame::Type::PathChallengeFrame:
// Path validation timer expired, path validation failed;
// or a different path validation was scheduled
if (!conn.outstandingPathValidation ||
*frame.asPathChallengeFrame() != *conn.outstandingPathValidation) {
return folly::none;
}
return QuicSimpleFrame(frame);
case QuicSimpleFrame::Type::PathResponseFrame:
// Do not clone PATH_RESPONSE to avoid buffering
return folly::none;
case QuicSimpleFrame::Type::NewConnectionIdFrame:
case QuicSimpleFrame::Type::MaxStreamsFrame:
case QuicSimpleFrame::Type::HandshakeDoneFrame:
case QuicSimpleFrame::Type::KnobFrame:
case QuicSimpleFrame::Type::AckFrequencyFrame:
case QuicSimpleFrame::Type::RetireConnectionIdFrame:
// TODO junqiw
return QuicSimpleFrame(frame);
}
folly::assume_unreachable();
}
void updateSimpleFrameOnPacketSent(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& simpleFrame) {
switch (simpleFrame.type()) {
case QuicSimpleFrame::Type::PathChallengeFrame:
conn.outstandingPathValidation =
std::move(conn.pendingEvents.pathChallenge);
conn.pendingEvents.schedulePathValidationTimeout = true;
// Start the clock to measure Rtt
conn.pathChallengeStartTime = Clock::now();
break;
default: {
auto& frames = conn.pendingEvents.frames;
auto itr = std::find(frames.begin(), frames.end(), simpleFrame);
CHECK(itr != frames.end());
frames.erase(itr);
break;
}
}
}
void updateSimpleFrameOnPacketLoss(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& frame) {
switch (frame.type()) {
case QuicSimpleFrame::Type::StopSendingFrame: {
const StopSendingFrame& stopSendingFrame = *frame.asStopSendingFrame();
if (conn.streamManager->streamExists(stopSendingFrame.streamId)) {
conn.pendingEvents.frames.push_back(stopSendingFrame);
}
break;
}
case QuicSimpleFrame::Type::PathChallengeFrame: {
const PathChallengeFrame& pathChallenge = *frame.asPathChallengeFrame();
if (conn.outstandingPathValidation &&
pathChallenge == *conn.outstandingPathValidation) {
conn.pendingEvents.pathChallenge = pathChallenge;
}
break;
}
case QuicSimpleFrame::Type::PathResponseFrame: {
// Do not retransmit PATH_RESPONSE to avoid buffering
break;
}
case QuicSimpleFrame::Type::HandshakeDoneFrame: {
const auto& handshakeDoneFrame = *frame.asHandshakeDoneFrame();
conn.pendingEvents.frames.push_back(handshakeDoneFrame);
break;
}
case QuicSimpleFrame::Type::NewConnectionIdFrame:
case QuicSimpleFrame::Type::MaxStreamsFrame:
case QuicSimpleFrame::Type::RetireConnectionIdFrame:
case QuicSimpleFrame::Type::KnobFrame:
case QuicSimpleFrame::Type::AckFrequencyFrame:
conn.pendingEvents.frames.push_back(frame);
break;
}
}
bool updateSimpleFrameOnPacketReceived(
QuicConnectionStateBase& conn,
const QuicSimpleFrame& frame,
PacketNum /*packetNum*/,
bool fromChangedPeerAddress) {
switch (frame.type()) {
case QuicSimpleFrame::Type::StopSendingFrame: {
const StopSendingFrame& stopSending = *frame.asStopSendingFrame();
auto stream = conn.streamManager->getStream(stopSending.streamId);
if (stream) {
sendStopSendingSMHandler(*stream, stopSending);
}
return true;
}
case QuicSimpleFrame::Type::PathChallengeFrame: {
bool rotatedId = conn.retireAndSwitchPeerConnectionIds();
if (!rotatedId) {
throw QuicTransportException(
"No more connection ids to use for new path.",
TransportErrorCode::INVALID_MIGRATION);
}
const PathChallengeFrame& pathChallenge = *frame.asPathChallengeFrame();
conn.pendingEvents.frames.emplace_back(
PathResponseFrame(pathChallenge.pathData));
return false;
}
case QuicSimpleFrame::Type::PathResponseFrame: {
const PathResponseFrame& pathResponse = *frame.asPathResponseFrame();
// Ignore the response if outstandingPathValidation is none or
// the path data doesn't match what's in outstandingPathValidation
if (fromChangedPeerAddress || !conn.outstandingPathValidation ||
pathResponse.pathData != conn.outstandingPathValidation->pathData) {
return false;
}
if (conn.qLogger) {
conn.qLogger->addPathValidationEvent(true);
}
// TODO update source token,
conn.outstandingPathValidation = folly::none;
conn.pendingEvents.schedulePathValidationTimeout = false;
// stop the clock to measure init rtt
std::chrono::microseconds sampleRtt =
std::chrono::duration_cast<std::chrono::microseconds>(
Clock::now() - conn.pathChallengeStartTime);
updateRtt(conn, sampleRtt, 0us);
return false;
}
case QuicSimpleFrame::Type::NewConnectionIdFrame: {
const NewConnectionIdFrame& newConnectionId =
*frame.asNewConnectionIdFrame();
// TODO vchynaro Ensure we ignore smaller subsequent retirePriorTos
// than the largest seen so far.
if (newConnectionId.retirePriorTo > newConnectionId.sequenceNumber) {
throw QuicTransportException(
"Retire prior to greater than sequence number",
TransportErrorCode::PROTOCOL_VIOLATION);
}
for (const auto& existingPeerConnIdData : conn.peerConnectionIds) {
if (existingPeerConnIdData.connId == newConnectionId.connectionId) {
if (existingPeerConnIdData.sequenceNumber !=
newConnectionId.sequenceNumber) {
throw QuicTransportException(
"Repeated connection id with different sequence number.",
TransportErrorCode::PROTOCOL_VIOLATION);
} else {
// No-op on repeated conn id.
return false;
}
}
}
// PeerConnectionIds holds ALL peer's connection ids
// (initial + NEW_CONNECTION_ID).
// If using 0-len peer cid then this would be the only element.
auto peerConnId =
(conn.nodeType == QuicNodeType::Client ? conn.serverConnectionId
: conn.clientConnectionId);
if (!peerConnId || peerConnId->size() == 0) {
throw QuicTransportException(
"Endpoint is already using 0-len connection ids.",
TransportErrorCode::PROTOCOL_VIOLATION);
}
// TODO vchynaro Implement retire_prior_to logic
// selfActiveConnectionIdLimit represents the active_connection_id_limit
// transport parameter which is the maximum amount of connection ids
// provided by NEW_CONNECTION_ID frames. We add 1 to represent the initial
// cid.
if (conn.peerConnectionIds.size() ==
conn.transportSettings.selfActiveConnectionIdLimit + 1) {
// Unspec'd as of d-23 if a server doesn't respect the
// active_connection_id_limit. Ignore frame.
return false;
}
conn.peerConnectionIds.emplace_back(
newConnectionId.connectionId,
newConnectionId.sequenceNumber,
newConnectionId.token);
return false;
}
case QuicSimpleFrame::Type::MaxStreamsFrame: {
const MaxStreamsFrame& maxStreamsFrame = *frame.asMaxStreamsFrame();
if (maxStreamsFrame.isForBidirectionalStream()) {
conn.streamManager->setMaxLocalBidirectionalStreams(
maxStreamsFrame.maxStreams);
} else {
conn.streamManager->setMaxLocalUnidirectionalStreams(
maxStreamsFrame.maxStreams);
}
return true;
}
case QuicSimpleFrame::Type::RetireConnectionIdFrame: {
return true;
}
case QuicSimpleFrame::Type::HandshakeDoneFrame: {
if (conn.nodeType == QuicNodeType::Server) {
throw QuicTransportException(
"Received HANDSHAKE_DONE from client.",
TransportErrorCode::PROTOCOL_VIOLATION,
FrameType::HANDSHAKE_DONE);
}
// Mark the handshake confirmed in the handshake layer before doing
// any dropping, as this gives us a chance to process ACKs in this
// packet.
conn.handshakeLayer->handshakeConfirmed();
return true;
}
case QuicSimpleFrame::Type::KnobFrame: {
const KnobFrame& knobFrame = *frame.asKnobFrame();
conn.pendingEvents.knobs.emplace_back(
knobFrame.knobSpace, knobFrame.id, knobFrame.blob->clone());
return true;
}
case QuicSimpleFrame::Type::AckFrequencyFrame: {
if (!conn.transportSettings.minAckDelay.hasValue()) {
return true;
}
const auto ackFrequencyFrame = frame.asAckFrequencyFrame();
auto& ackState = conn.ackStates.appDataAckState;
if (!ackState.ackFrequencySequenceNumber ||
ackFrequencyFrame->sequenceNumber >
ackState.ackFrequencySequenceNumber.value()) {
ackState.tolerance = ackFrequencyFrame->packetTolerance;
ackState.ignoreReorder = ackFrequencyFrame->ignoreOrder;
conn.ackStates.maxAckDelay =
std::chrono::microseconds(std::max<uint64_t>(
conn.transportSettings.minAckDelay->count(),
ackFrequencyFrame->updateMaxAckDelay));
}
return true;
}
}
folly::assume_unreachable();
}
} // namespace quic