1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-27 03:41:14 +03:00

Use custom variant type for write frames

Summary:
Use the custom variant type for write frames as well, now that
we use them for read frames.

Reviewed By: mjoras

Differential Revision: D17776862

fbshipit-source-id: 47093146d0f1565c22e5393ed012c70e2e23d279
This commit is contained in:
Subodh Iyengar
2019-10-07 22:41:31 -07:00
committed by Facebook Github Bot
parent 233346268e
commit 68c332acb1
22 changed files with 1201 additions and 994 deletions

View File

@@ -53,108 +53,128 @@ folly::Optional<PacketEvent> PacketRebuilder::rebuildFromPacket(
iter != packet.packet.frames.cend();
iter++) {
const QuicWriteFrame& frame = *iter;
writeSuccess = folly::variant_match(
frame,
[&](const WriteAckFrame& ackFrame) {
auto& packetHeader = builder_.getPacketHeader();
uint64_t ackDelayExponent =
(packetHeader.getHeaderForm() == HeaderForm::Long)
? kDefaultAckDelayExponent
: conn_.transportSettings.ackDelayExponent;
AckFrameMetaData meta(
ackFrame.ackBlocks, ackFrame.ackDelay, ackDelayExponent);
auto ackWriteResult = writeAckFrame(meta, builder_);
return ackWriteResult.hasValue();
},
[&](const WriteStreamFrame& streamFrame) {
auto stream = conn_.streamManager->getStream(streamFrame.streamId);
if (stream && retransmittable(*stream)) {
auto streamData = cloneRetransmissionBuffer(streamFrame, stream);
auto bufferLen =
streamData ? streamData->computeChainDataLength() : 0;
auto dataLen = writeStreamFrameHeader(
builder_,
streamFrame.streamId,
streamFrame.offset,
bufferLen,
bufferLen,
streamFrame.fin);
bool ret = dataLen.hasValue() && *dataLen == streamFrame.len;
if (ret) {
writeStreamFrameData(builder_, std::move(streamData), *dataLen);
notPureAck = true;
return true;
}
return false;
switch (frame.type()) {
case QuicWriteFrame::Type::WriteAckFrame_E: {
const WriteAckFrame& ackFrame = *frame.asWriteAckFrame();
auto& packetHeader = builder_.getPacketHeader();
uint64_t ackDelayExponent =
(packetHeader.getHeaderForm() == HeaderForm::Long)
? kDefaultAckDelayExponent
: conn_.transportSettings.ackDelayExponent;
AckFrameMetaData meta(
ackFrame.ackBlocks, ackFrame.ackDelay, ackDelayExponent);
auto ackWriteResult = writeAckFrame(meta, builder_);
writeSuccess = ackWriteResult.hasValue();
break;
}
case QuicWriteFrame::Type::WriteStreamFrame_E: {
const WriteStreamFrame& streamFrame = *frame.asWriteStreamFrame();
auto stream = conn_.streamManager->getStream(streamFrame.streamId);
if (stream && retransmittable(*stream)) {
auto streamData = cloneRetransmissionBuffer(streamFrame, stream);
auto bufferLen =
streamData ? streamData->computeChainDataLength() : 0;
auto dataLen = writeStreamFrameHeader(
builder_,
streamFrame.streamId,
streamFrame.offset,
bufferLen,
bufferLen,
streamFrame.fin);
bool ret = dataLen.hasValue() && *dataLen == streamFrame.len;
if (ret) {
writeStreamFrameData(builder_, std::move(streamData), *dataLen);
notPureAck = true;
writeSuccess = true;
break;
}
// If a stream is already Closed, we should not clone and resend this
// stream data. But should we abort the cloning of this packet and
// move on to the next packet? I'm gonna err on the aggressive side
// for now and call it success.
return true;
},
[&](const WriteCryptoFrame& cryptoFrame) {
// initialStream and handshakeStream can only be in handshake packet,
// so they are not clonable
CHECK(!packet.isHandshake);
// key update not supported
DCHECK(
packet.packet.header.getProtectionType() ==
ProtectionType::KeyPhaseZero);
auto& stream = conn_.cryptoState->oneRttStream;
auto buf = cloneCryptoRetransmissionBuffer(cryptoFrame, stream);
writeSuccess = false;
break;
}
// If a stream is already Closed, we should not clone and resend this
// stream data. But should we abort the cloning of this packet and
// move on to the next packet? I'm gonna err on the aggressive side
// for now and call it success.
writeSuccess = true;
break;
}
case QuicWriteFrame::Type::WriteCryptoFrame_E: {
const WriteCryptoFrame& cryptoFrame = *frame.asWriteCryptoFrame();
// initialStream and handshakeStream can only be in handshake packet,
// so they are not clonable
CHECK(!packet.isHandshake);
// key update not supported
DCHECK(
packet.packet.header.getProtectionType() ==
ProtectionType::KeyPhaseZero);
auto& stream = conn_.cryptoState->oneRttStream;
auto buf = cloneCryptoRetransmissionBuffer(cryptoFrame, stream);
// No crypto data found to be cloned, just skip
if (!buf) {
return true;
}
auto cryptoWriteResult =
writeCryptoFrame(cryptoFrame.offset, std::move(buf), builder_);
bool ret = cryptoWriteResult.hasValue() &&
cryptoWriteResult->offset == cryptoFrame.offset &&
cryptoWriteResult->len == cryptoFrame.len;
notPureAck |= ret;
return ret;
},
[&](const MaxDataFrame&) {
shouldWriteWindowUpdate = true;
auto ret = 0 != writeFrame(generateMaxDataFrame(conn_), builder_);
windowUpdateWritten |= ret;
notPureAck |= ret;
return true;
},
[&](const MaxStreamDataFrame& maxStreamDataFrame) {
auto stream =
conn_.streamManager->getStream(maxStreamDataFrame.streamId);
if (!stream || !stream->shouldSendFlowControl()) {
return true;
}
shouldWriteWindowUpdate = true;
auto ret =
0 != writeFrame(generateMaxStreamDataFrame(*stream), builder_);
windowUpdateWritten |= ret;
notPureAck |= ret;
return true;
},
[&](const PaddingFrame& paddingFrame) {
return writeFrame(paddingFrame, builder_) != 0;
},
[&](const QuicSimpleFrame& simpleFrame) {
auto updatedSimpleFrame =
updateSimpleFrameOnPacketClone(conn_, simpleFrame);
if (!updatedSimpleFrame) {
return true;
}
bool ret =
writeSimpleFrame(std::move(*updatedSimpleFrame), builder_) != 0;
notPureAck |= ret;
return ret;
},
[&](const auto& otherFrame) {
bool ret = writeFrame(otherFrame, builder_) != 0;
notPureAck |= ret;
return ret;
});
// No crypto data found to be cloned, just skip
if (!buf) {
writeSuccess = true;
break;
}
auto cryptoWriteResult =
writeCryptoFrame(cryptoFrame.offset, std::move(buf), builder_);
bool ret = cryptoWriteResult.hasValue() &&
cryptoWriteResult->offset == cryptoFrame.offset &&
cryptoWriteResult->len == cryptoFrame.len;
notPureAck |= ret;
writeSuccess = ret;
break;
}
case QuicWriteFrame::Type::MaxDataFrame_E: {
shouldWriteWindowUpdate = true;
auto ret = 0 != writeFrame(generateMaxDataFrame(conn_), builder_);
windowUpdateWritten |= ret;
notPureAck |= ret;
writeSuccess = true;
break;
}
case QuicWriteFrame::Type::MaxStreamDataFrame_E: {
const MaxStreamDataFrame& maxStreamDataFrame =
*frame.asMaxStreamDataFrame();
auto stream =
conn_.streamManager->getStream(maxStreamDataFrame.streamId);
if (!stream || !stream->shouldSendFlowControl()) {
writeSuccess = true;
break;
}
shouldWriteWindowUpdate = true;
auto ret =
0 != writeFrame(generateMaxStreamDataFrame(*stream), builder_);
windowUpdateWritten |= ret;
notPureAck |= ret;
writeSuccess = true;
break;
}
case QuicWriteFrame::Type::PaddingFrame_E: {
const PaddingFrame& paddingFrame = *frame.asPaddingFrame();
writeSuccess = writeFrame(paddingFrame, builder_) != 0;
break;
}
case QuicWriteFrame::Type::QuicSimpleFrame_E: {
const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame();
auto updatedSimpleFrame =
updateSimpleFrameOnPacketClone(conn_, simpleFrame);
if (!updatedSimpleFrame) {
writeSuccess = true;
break;
}
bool ret =
writeSimpleFrame(std::move(*updatedSimpleFrame), builder_) != 0;
notPureAck |= ret;
writeSuccess = ret;
break;
}
default: {
bool ret = writeFrame(QuicWriteFrame(frame), builder_) != 0;
notPureAck |= ret;
writeSuccess = ret;
break;
}
}
if (!writeSuccess) {
return folly::none;
}