mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-11-07 22:46:22 +03:00
Summary: On loss timer, currently we knock all handshake packets out of the OP list and resend everything. This means miss RTT sampling opportunities during handshake if loss timer fires, and given our initial loss timer is likely not a good fit for many networks, it probably fires a lot. This diff keeps handshake packets in the OP list, and add packet cloning support to handshake packets so we can clone them and send as probes. With this, the handshake alarm is finally removed. PTO will take care of all packet number space. The diff also fixes a bug in the CloningScheduler where we missed cipher overhead setting. That broke a few unit tests once we started to clone handshake packets. The writeProbingDataToSocket API is also changed to support passing a token to it so when we clone Initial, token is added correctly. This is because during packet cloning, we only clone frames. Headers are fresh built. The diff also changed the cloning behavior when there is only one outstanding packet. Currently we clone it twice and send two packets. There is no point of doing that. Now when loss timer fires and when there is only one outstanding packet, we only clone once. The PacketEvent, which was an alias of PacketNumber, is now a real type that has both PacketNumber and PacketNumberSpace to support cloning of handshake packets. I think in the long term we should refactor PacketNumber itself into a real type. Reviewed By: mjoras Differential Revision: D19863693 fbshipit-source-id: e427bb392021445a9388c15e7ea807852ddcbd08
295 lines
8.6 KiB
C++
295 lines
8.6 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.
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <folly/Expected.h>
|
|
#include <folly/io/async/AsyncUDPSocket.h>
|
|
|
|
#include <quic/QuicException.h>
|
|
#include <quic/api/IoBufQuicBatch.h>
|
|
#include <quic/api/QuicPacketScheduler.h>
|
|
#include <quic/api/QuicSocket.h>
|
|
#include <quic/state/StateData.h>
|
|
|
|
// Function to schedule writing data to socket. Return number of packets
|
|
// successfully scheduled
|
|
namespace quic {
|
|
|
|
struct DataPathResult {
|
|
bool buildSuccess{false};
|
|
bool writeSuccess{false};
|
|
folly::Optional<SchedulingResult> result;
|
|
uint64_t encodedSize{0};
|
|
|
|
static DataPathResult makeBuildFailure() {
|
|
return DataPathResult();
|
|
}
|
|
|
|
static DataPathResult makeWriteResult(
|
|
bool writeSuc,
|
|
SchedulingResult&& res,
|
|
uint64_t encodedSizeIn) {
|
|
return DataPathResult(writeSuc, std::move(res), encodedSizeIn);
|
|
}
|
|
|
|
private:
|
|
explicit DataPathResult() = default;
|
|
|
|
explicit DataPathResult(
|
|
bool writeSuc,
|
|
SchedulingResult&& res,
|
|
uint64_t encodedSizeIn)
|
|
: buildSuccess(true),
|
|
writeSuccess(writeSuc),
|
|
result(std::move(res)),
|
|
encodedSize(encodedSizeIn) {}
|
|
};
|
|
|
|
using DataPathFunc = std::function<DataPathResult(
|
|
QuicConnectionStateBase&,
|
|
PacketHeader,
|
|
PacketNumberSpace,
|
|
PacketNum,
|
|
uint64_t,
|
|
QuicPacketScheduler&,
|
|
uint64_t,
|
|
IOBufQuicBatch&,
|
|
const Aead&,
|
|
const PacketNumberCipher&)>;
|
|
|
|
using HeaderBuilder = std::function<PacketHeader(
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
PacketNum packetNum,
|
|
QuicVersion version,
|
|
const std::string& token)>;
|
|
|
|
using WritableBytesFunc =
|
|
std::function<uint64_t(const QuicConnectionStateBase& conn)>;
|
|
|
|
/**
|
|
* Attempts to write data from all frames in the QUIC connection into the UDP
|
|
* socket supplied with the aead and the headerCipher.
|
|
*/
|
|
uint64_t writeQuicDataToSocket(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion version,
|
|
uint64_t packetLimit);
|
|
|
|
/**
|
|
* Writes only the crypto and ack frames to the socket.
|
|
*
|
|
* return the number of packets written to socket.
|
|
*/
|
|
uint64_t writeCryptoAndAckDataToSocket(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
LongHeader::Types packetType,
|
|
Aead& cleartextCipher,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion version,
|
|
uint64_t packetLimit,
|
|
const std::string& token = std::string());
|
|
|
|
/**
|
|
* Writes out all the data streams without writing out crypto streams.
|
|
* This is useful when the crypto stream still needs to be sent in separate
|
|
* packets and cannot use the encryption of the data key.
|
|
*/
|
|
uint64_t writeQuicDataExceptCryptoStreamToSocket(
|
|
folly::AsyncUDPSocket& socket,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion version,
|
|
uint64_t packetLimit);
|
|
|
|
/**
|
|
* Writes frame data including zero rtt data to the socket with the supplied
|
|
* zero rtt cipher.
|
|
*/
|
|
uint64_t writeZeroRttDataToSocket(
|
|
folly::AsyncUDPSocket& socket,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion version,
|
|
uint64_t packetLimit);
|
|
|
|
/**
|
|
* Whether we should and can write data.
|
|
*
|
|
* TODO: We should probably split "should" and "can" into two APIs.
|
|
*/
|
|
WriteDataReason shouldWriteData(const QuicConnectionStateBase& conn);
|
|
bool hasAckDataToWrite(const QuicConnectionStateBase& conn);
|
|
WriteDataReason hasNonAckDataToWrite(const QuicConnectionStateBase& conn);
|
|
|
|
/**
|
|
* Invoked when the written stream data was new stream data.
|
|
*/
|
|
void handleNewStreamDataWritten(
|
|
QuicConnectionStateBase& conn,
|
|
QuicStreamLike& stream,
|
|
uint64_t frameLen,
|
|
bool frameFin,
|
|
PacketNum packetNum,
|
|
PacketNumberSpace packetNumberSpace);
|
|
|
|
/**
|
|
* Invoked when the stream data written was retransmitted data.
|
|
*/
|
|
void handleRetransmissionWritten(
|
|
QuicConnectionStateBase& conn,
|
|
QuicStreamLike& stream,
|
|
uint64_t frameOffset,
|
|
uint64_t frameLen,
|
|
bool frameFin,
|
|
PacketNum packetNum,
|
|
std::deque<StreamBuffer>::iterator lossBufferIter);
|
|
|
|
/**
|
|
* Update the connection and stream state after stream data is written and deal
|
|
* with new data, as well as retranmissions. Returns true if the data sent is
|
|
* new data.
|
|
*/
|
|
bool handleStreamWritten(
|
|
QuicConnectionStateBase& conn,
|
|
QuicStreamLike& stream,
|
|
uint64_t frameOffset,
|
|
uint64_t frameLen,
|
|
bool frameFin,
|
|
PacketNum packetNum,
|
|
PacketNumberSpace packetNumberSpace);
|
|
|
|
/**
|
|
* Update the connection state after sending a new packet.
|
|
*/
|
|
void updateConnection(
|
|
QuicConnectionStateBase& conn,
|
|
folly::Optional<PacketEvent> packetEvent,
|
|
RegularQuicWritePacket packet,
|
|
TimePoint time,
|
|
uint32_t encodedSize);
|
|
|
|
/**
|
|
* Returns the minimum available bytes window out of path validation rate
|
|
* limiting, 0-rtt total bytes sent limiting, and the congestion controller.
|
|
*/
|
|
uint64_t congestionControlWritableBytes(const QuicConnectionStateBase& conn);
|
|
|
|
uint64_t unlimitedWritableBytes(const QuicConnectionStateBase&);
|
|
|
|
void writeCloseCommon(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
PacketHeader&& header,
|
|
folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher);
|
|
|
|
/**
|
|
* Writes a LongHeader packet with a close frame.
|
|
* The close frame type written depends on the type of error in closeDetails.
|
|
*/
|
|
void writeLongClose(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
LongHeader::Types headerType,
|
|
folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion);
|
|
|
|
/**
|
|
* Write a short header packet with a close frame.
|
|
* The close frame type written depends on the type of error in closeDetails.
|
|
*/
|
|
void writeShortClose(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& connId,
|
|
folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher);
|
|
|
|
/**
|
|
* Encrypts the packet header for the header type.
|
|
* This will overwrite the header with the encrypted header form. It will verify
|
|
* whether or not there are enough bytes to sample for the header encryption
|
|
* from the encryptedBody via a CHECK.
|
|
*/
|
|
void encryptPacketHeader(
|
|
HeaderForm headerForm,
|
|
uint8_t* header,
|
|
size_t headerLen,
|
|
const uint8_t* encryptedBody,
|
|
size_t bodyLen,
|
|
const PacketNumberCipher& headerCipher);
|
|
|
|
/**
|
|
* Writes the connections data to the socket using the header
|
|
* builder as well as the scheduler. This will write the amount of
|
|
* data allowed by the writableBytesFunc and will only write a maximum
|
|
* number of packetLimit packets at each invocation.
|
|
*/
|
|
uint64_t writeConnectionDataToSocket(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
HeaderBuilder builder,
|
|
PacketNumberSpace pnSpace,
|
|
QuicPacketScheduler& scheduler,
|
|
const WritableBytesFunc& writableBytesFunc,
|
|
uint64_t packetLimit,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion version,
|
|
const std::string& token = std::string());
|
|
|
|
uint64_t writeProbingDataToSocket(
|
|
folly::AsyncUDPSocket& sock,
|
|
QuicConnectionStateBase& connection,
|
|
const ConnectionId& srcConnId,
|
|
const ConnectionId& dstConnId,
|
|
const HeaderBuilder& builder,
|
|
PacketNumberSpace pnSpace,
|
|
FrameScheduler scheduler,
|
|
uint8_t probesToSend,
|
|
const Aead& aead,
|
|
const PacketNumberCipher& headerCipher,
|
|
QuicVersion version,
|
|
const std::string& token = std::string());
|
|
|
|
HeaderBuilder LongHeaderBuilder(LongHeader::Types packetType);
|
|
HeaderBuilder ShortHeaderBuilder();
|
|
|
|
void maybeSendStreamLimitUpdates(QuicConnectionStateBase& conn);
|
|
|
|
void implicitAckCryptoStream(
|
|
QuicConnectionStateBase& conn,
|
|
EncryptionLevel encryptionLevel);
|
|
void handshakeConfirmed(QuicConnectionStateBase& conn);
|
|
|
|
} // namespace quic
|