1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-25 15:43:13 +03:00

parse and write DATAGRAM Frames

Summary: This diff is the encode and decode support of Datagram frame.

Reviewed By: mjoras, yangchi

Differential Revision: D20983883

fbshipit-source-id: 1a72a87e6ce3601b71fececca872a9d20bf7820e
This commit is contained in:
Luca Niccolini
2021-05-04 10:52:14 -07:00
committed by Facebook GitHub Bot
parent 0678b41ebb
commit e39bf5f447
12 changed files with 121 additions and 8 deletions

View File

@@ -158,6 +158,8 @@ enum class FrameType : uint64_t {
// CONNECTION_CLOSE_APP_ERR frametype is use to indicate application errors
CONNECTION_CLOSE_APP_ERR = 0x1D,
HANDSHAKE_DONE = 0x1E,
DATAGRAM = 0x30,
DATAGRAM_LEN = 0x31,
KNOB = 0x1550,
ACK_FREQUENCY = 0xAF,
};

View File

@@ -583,6 +583,8 @@ void QuicClientTransport::processPacketData(
*conn_, simpleFrame, packetNum, false);
break;
}
case QuicFrame::Type::DatagramFrame:
// TODO:
default:
break;
}

View File

@@ -717,6 +717,29 @@ folly::Expected<RetryToken, TransportErrorCode> parsePlaintextRetryToken(
return RetryToken(connId, *ipAddress, clientPort, timestampInMs);
}
DatagramFrame decodeDatagramFrame(BufQueue& queue, bool hasLen) {
folly::io::Cursor cursor(queue.front());
size_t length = cursor.length();
if (hasLen) {
auto decodeLength = decodeQuicInteger(cursor);
if (!decodeLength) {
throw QuicTransportException(
"Invalid datagram len",
TransportErrorCode::FRAME_ENCODING_ERROR,
FrameType::DATAGRAM_LEN);
}
length = decodeLength->first;
if (cursor.length() < length) {
throw QuicTransportException(
"Invalid datagram frame",
TransportErrorCode::FRAME_ENCODING_ERROR,
FrameType::DATAGRAM_LEN);
}
queue.trimStart(decodeLength->second);
}
return DatagramFrame(length, queue.splitAtMost(length));
}
QuicFrame parseFrame(
BufQueue& queue,
const PacketHeader& header,
@@ -729,10 +752,10 @@ QuicFrame parseFrame(
"Invalid frame-type field", TransportErrorCode::FRAME_ENCODING_ERROR);
}
queue.trimStart(cursor - queue.front());
bool isStream = false;
bool consumedQueue = false;
bool error = false;
SCOPE_EXIT {
if (isStream || error) {
if (consumedQueue || error) {
return;
}
queue.trimStart(cursor - queue.front());
@@ -765,7 +788,7 @@ QuicFrame parseFrame(
case FrameType::STREAM_OFF_FIN:
case FrameType::STREAM_OFF_LEN:
case FrameType::STREAM_OFF_LEN_FIN:
isStream = true;
consumedQueue = true;
return QuicFrame(
decodeStreamFrame(queue, StreamTypeField(frameTypeInt->first)));
case FrameType::MAX_DATA:
@@ -798,6 +821,14 @@ QuicFrame parseFrame(
return QuicFrame(decodeApplicationClose(cursor));
case FrameType::HANDSHAKE_DONE:
return QuicFrame(decodeHandshakeDoneFrame(cursor));
case FrameType::DATAGRAM: {
consumedQueue = true;
return QuicFrame(decodeDatagramFrame(queue, false /* hasLen */));
}
case FrameType::DATAGRAM_LEN: {
consumedQueue = true;
return QuicFrame(decodeDatagramFrame(queue, true /* hasLen */));
}
case FrameType::KNOB:
return QuicFrame(decodeKnobFrame(cursor));
case FrameType::ACK_FREQUENCY:

View File

@@ -136,6 +136,8 @@ HandshakeDoneFrame decodeHandshakeDoneFrame(folly::io::Cursor& cursor);
folly::Expected<RetryToken, TransportErrorCode> parsePlaintextRetryToken(
folly::io::Cursor& cursor);
DatagramFrame decodeDatagramFrame(BufQueue& queue, bool hasLen);
/**
* Parse the Invariant fields in Long Header.
*

View File

@@ -179,6 +179,12 @@ folly::Optional<PacketEvent> PacketRebuilder::rebuildFromPacket(
writeSuccess = ret;
break;
}
case QuicWriteFrame::Type::DatagramFrame:
// Do not clone Datagram frames. If datagram frame is the only frame in
// the packet, notPureAck will be false, and the function will return
// folly::none correctly.
writeSuccess = true;
break;
default: {
bool ret = writeFrame(QuicWriteFrame(frame), builder_) != 0;
notPureAck |= ret;

View File

@@ -671,6 +671,23 @@ size_t writeFrame(QuicWriteFrame&& frame, PacketBuilderInterface& builder) {
case QuicWriteFrame::Type::QuicSimpleFrame: {
return writeSimpleFrame(std::move(*frame.asQuicSimpleFrame()), builder);
}
case QuicWriteFrame::Type::DatagramFrame: {
const DatagramFrame& datagramFrame = *frame.asDatagramFrame();
QuicInteger frameTypeQuicInt(
static_cast<uint8_t>(FrameType::DATAGRAM_LEN));
QuicInteger datagramLenInt(datagramFrame.length);
auto datagramFrameLength = frameTypeQuicInt.getSize() +
datagramFrame.length + datagramLenInt.getSize();
if (packetSpaceCheck(spaceLeft, datagramFrameLength)) {
builder.write(frameTypeQuicInt);
builder.write(datagramLenInt);
builder.insert(std::move(datagramFrame.data), datagramFrame.length);
builder.appendFrame(datagramFrame);
return datagramFrameLength;
}
// no space left in packet
return size_t(0);
}
default: {
// TODO add support for: RETIRE_CONNECTION_ID and NEW_TOKEN frames
auto errorStr = folly::to<std::string>(

View File

@@ -417,6 +417,9 @@ std::string toString(FrameType frame) {
return "APPLICATION_CLOSE";
case FrameType::HANDSHAKE_DONE:
return "HANDSHAKE_DONE";
case FrameType::DATAGRAM:
case FrameType::DATAGRAM_LEN:
return "DATAGRAM";
case FrameType::KNOB:
return "KNOB";
case FrameType::ACK_FREQUENCY:

View File

@@ -585,6 +585,35 @@ struct HandshakeDoneFrame {
}
};
struct DatagramFrame {
size_t length;
BufQueue data;
explicit DatagramFrame(size_t len, Buf buf)
: length(len), data(std::move(buf)) {
CHECK_EQ(length, data.chainLength());
}
// Variant requirement:
DatagramFrame(const DatagramFrame& other)
: length(other.length),
data(other.data.front() ? other.data.front()->clone() : nullptr) {
CHECK_EQ(length, data.chainLength());
}
bool operator==(const DatagramFrame& other) const {
if (length != other.length) {
return false;
}
if (data.empty() && other.data.empty()) {
return true;
}
CHECK(data.front() && other.data.front());
folly::IOBufEqualTo eq;
return eq(*data.front(), *other.data.front());
}
};
// Frame to represent ones we skip
struct NoopFrame {
bool operator==(const NoopFrame&) const {
@@ -649,7 +678,8 @@ DECLARE_VARIANT_TYPE(QuicSimpleFrame, QUIC_SIMPLE_FRAME)
F(ReadNewTokenFrame, __VA_ARGS__) \
F(QuicSimpleFrame, __VA_ARGS__) \
F(PingFrame, __VA_ARGS__) \
F(NoopFrame, __VA_ARGS__)
F(NoopFrame, __VA_ARGS__) \
F(DatagramFrame, __VA_ARGS__)
DECLARE_VARIANT_TYPE(QuicFrame, QUIC_FRAME)
@@ -667,7 +697,8 @@ DECLARE_VARIANT_TYPE(QuicFrame, QUIC_FRAME)
F(WriteCryptoFrame, __VA_ARGS__) \
F(QuicSimpleFrame, __VA_ARGS__) \
F(PingFrame, __VA_ARGS__) \
F(NoopFrame, __VA_ARGS__)
F(NoopFrame, __VA_ARGS__) \
F(DatagramFrame, __VA_ARGS__)
// Types of frames which are written.
DECLARE_VARIANT_TYPE(QuicWriteFrame, QUIC_WRITE_FRAME)

View File

@@ -164,9 +164,10 @@ std::unique_ptr<QLogPacketEvent> BaseQLogger::createPacketEvent(
event->frames.push_back(std::make_unique<ReadNewTokenFrameLog>());
break;
}
case QuicFrame::Type::PingFrame:
case QuicFrame::Type::PingFrame: {
event->frames.push_back(std::make_unique<quic::PingFrameLog>());
break;
}
case QuicFrame::Type::QuicSimpleFrame: {
const auto& simpleFrame = *quicFrame.asQuicSimpleFrame();
addQuicSimpleFrameToEvent(event.get(), simpleFrame);
@@ -175,6 +176,10 @@ std::unique_ptr<QLogPacketEvent> BaseQLogger::createPacketEvent(
case QuicFrame::Type::NoopFrame: {
break;
}
case QuicFrame::Type::DatagramFrame: {
// TODO
break;
}
}
}
if (numPaddingFrames > 0) {
@@ -274,9 +279,17 @@ std::unique_ptr<QLogPacketEvent> BaseQLogger::createPacketEvent(
addQuicSimpleFrameToEvent(event.get(), simpleFrame);
break;
}
default:
case QuicWriteFrame::Type::NoopFrame: {
break;
}
case QuicWriteFrame::Type::DatagramFrame: {
// TODO
break;
}
default: {
break;
}
}
}
if (numPaddingFrames > 0) {
event->frames.push_back(

View File

@@ -73,6 +73,9 @@ folly::StringPiece toQlogString(FrameType frame) {
return "connection_close";
case FrameType::HANDSHAKE_DONE:
return "handshake_done";
case FrameType::DATAGRAM:
case FrameType::DATAGRAM_LEN:
return "datagram";
case FrameType::KNOB:
return "knob";
case FrameType::ACK_FREQUENCY:

View File

@@ -1098,6 +1098,9 @@ void onServerReadDataFromOpen(
conn, simpleFrame, packetNum, readData.peer != conn.peerAddress);
break;
}
case QuicFrame::Type::DatagramFrame:
isNonProbingPacket = true;
// TODO:
default: {
break;
}

View File

@@ -43,7 +43,7 @@ void updateSimpleFrameOnPacketLoss(
/*
* Update the connection state on receipt of the given simple frame.
* Returns true if the frame is not a probing frame
* Returns true if the frame is NOT a probing frame
*/
bool updateSimpleFrameOnPacketReceived(
QuicConnectionStateBase& conn,