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:
committed by
Facebook GitHub Bot
parent
0678b41ebb
commit
e39bf5f447
@@ -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,
|
||||
};
|
||||
|
||||
@@ -583,6 +583,8 @@ void QuicClientTransport::processPacketData(
|
||||
*conn_, simpleFrame, packetNum, false);
|
||||
break;
|
||||
}
|
||||
case QuicFrame::Type::DatagramFrame:
|
||||
// TODO:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1098,6 +1098,9 @@ void onServerReadDataFromOpen(
|
||||
conn, simpleFrame, packetNum, readData.peer != conn.peerAddress);
|
||||
break;
|
||||
}
|
||||
case QuicFrame::Type::DatagramFrame:
|
||||
isNonProbingPacket = true;
|
||||
// TODO:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user