mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-04-18 17:24:03 +03:00
Summary: - as title Reviewed By: lnicco Differential Revision: D33513410 fbshipit-source-id: 282b6f512cf83b9abb7990402661135b658f7bd1
266 lines
8.5 KiB
C++
266 lines
8.5 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and 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/Random.h>
|
|
#include <folly/SocketAddress.h>
|
|
#include <folly/io/SocketOptionMap.h>
|
|
#include <folly/io/async/AsyncUDPSocket.h>
|
|
#include <folly/net/NetOps.h>
|
|
#include <quic/api/QuicTransportBase.h>
|
|
#include <quic/client/state/ClientStateMachine.h>
|
|
#include <quic/common/BufUtil.h>
|
|
#include <quic/state/QuicConnectionStats.h>
|
|
|
|
namespace quic {
|
|
|
|
class ClientHandshakeFactory;
|
|
|
|
class QuicClientTransport
|
|
: public QuicTransportBase,
|
|
public folly::AsyncUDPSocket::ReadCallback,
|
|
public folly::AsyncUDPSocket::ErrMessageCallback,
|
|
public std::enable_shared_from_this<QuicClientTransport> {
|
|
public:
|
|
QuicClientTransport(
|
|
folly::EventBase* evb,
|
|
std::unique_ptr<folly::AsyncUDPSocket> socket,
|
|
std::shared_ptr<ClientHandshakeFactory> handshakeFactory,
|
|
size_t connectionIdSize = 0,
|
|
bool useSplitConnectionCallbacks = false);
|
|
|
|
// Testing only API:
|
|
QuicClientTransport(
|
|
folly::EventBase* evb,
|
|
std::unique_ptr<folly::AsyncUDPSocket> socket,
|
|
std::shared_ptr<ClientHandshakeFactory> handshakeFactory,
|
|
size_t connectionIdSize,
|
|
PacketNum startingPacketNum,
|
|
bool useSplitConnectionCallbacks = false);
|
|
|
|
~QuicClientTransport() override;
|
|
|
|
/**
|
|
* Returns an un-connected QuicClientTransport which is self-owning.
|
|
* The transport is cleaned up when the app calls close() or closeNow() on the
|
|
* transport, or on receiving a terminal ConnectionCallback supplied on
|
|
* start().
|
|
* The transport is self owning in this case is to be able to
|
|
* deal with cases where the app wants to dispose of the transport, however
|
|
* the peer is still sending us packets. If we do not keep the transport alive
|
|
* for this period, the kernel will generate unwanted ICMP echo messages.
|
|
*/
|
|
template <class TransportType = QuicClientTransport>
|
|
static std::shared_ptr<TransportType> newClient(
|
|
folly::EventBase* evb,
|
|
std::unique_ptr<folly::AsyncUDPSocket> sock,
|
|
std::shared_ptr<ClientHandshakeFactory> handshakeFactory,
|
|
size_t connectionIdSize = 0,
|
|
bool useSplitConnectionCallbacks = false) {
|
|
auto client = std::make_shared<TransportType>(
|
|
evb,
|
|
std::move(sock),
|
|
std::move(handshakeFactory),
|
|
connectionIdSize,
|
|
useSplitConnectionCallbacks);
|
|
client->setSelfOwning();
|
|
return client;
|
|
}
|
|
|
|
/**
|
|
* Supply the hostname to use to validate the server. Must be set before
|
|
* start().
|
|
*/
|
|
void setHostname(const std::string& hostname);
|
|
|
|
/**
|
|
* Supplies a new peer address to use for the connection. This must be called
|
|
* at least once before start().
|
|
*/
|
|
void addNewPeerAddress(folly::SocketAddress peerAddress);
|
|
/**
|
|
* Supplies the local address to use for the connection. Calling this is
|
|
* optional. If not called, INADDR_ANY will be used.
|
|
*/
|
|
void setLocalAddress(folly::SocketAddress localAddress);
|
|
void addNewSocket(std::unique_ptr<folly::AsyncUDPSocket> socket);
|
|
void setHappyEyeballsEnabled(bool happyEyeballsEnabled);
|
|
virtual void setHappyEyeballsCachedFamily(sa_family_t cachedFamily);
|
|
|
|
/**
|
|
* Starts the connection.
|
|
*/
|
|
virtual void start(ConnectionCallback* cb);
|
|
|
|
/**
|
|
* Starts the connection with split callbacks.
|
|
*/
|
|
virtual void start(
|
|
ConnectionSetupCallback* connSetupCb,
|
|
ConnectionCallbackNew* connCb);
|
|
|
|
/**
|
|
* Returns whether or not TLS is resumed.
|
|
*/
|
|
bool isTLSResumed() const;
|
|
|
|
// From QuicTransportBase
|
|
void onReadData(
|
|
const folly::SocketAddress& peer,
|
|
NetworkDataSingle&& networkData) override;
|
|
void writeData() override;
|
|
void closeTransport() override;
|
|
void unbindConnection() override;
|
|
bool hasWriteCipher() const override;
|
|
std::shared_ptr<QuicTransportBase> sharedGuard() override;
|
|
|
|
// folly::AsyncUDPSocket::ReadCallback
|
|
void onReadClosed() noexcept override {}
|
|
void onReadError(const folly::AsyncSocketException&) noexcept override;
|
|
|
|
// folly::AsyncUDPSocket::ErrMessageCallback
|
|
void errMessage(const cmsghdr& cmsg) noexcept override;
|
|
void errMessageError(const folly::AsyncSocketException&) noexcept override {}
|
|
|
|
void setSupportedVersions(const std::vector<QuicVersion>& versions) override;
|
|
|
|
/**
|
|
* Set socket options for the underlying socket.
|
|
* Options are being set before and after bind, and not at the time of
|
|
* invoking this function.
|
|
*/
|
|
void setSocketOptions(const folly::SocketOptionMap& options) noexcept {
|
|
socketOptions_ = options;
|
|
}
|
|
|
|
/**
|
|
* Make QuicClient transport self owning.
|
|
*/
|
|
void setSelfOwning();
|
|
|
|
/**
|
|
* Used to set private transport parameters that are not in the
|
|
* TransportParameterId enum.
|
|
* See kCustomTransportParameterThreshold in QuicConstants.h
|
|
*/
|
|
bool setCustomTransportParameter(
|
|
std::unique_ptr<CustomTransportParameter> customParam);
|
|
|
|
void onNetworkSwitch(std::unique_ptr<folly::AsyncUDPSocket> newSock) override;
|
|
|
|
/**
|
|
* Set callback for various transport stats (such as packet received, dropped
|
|
* etc). Since the callback is invoked very frequently, it is
|
|
* important that the implementation is efficient.
|
|
*/
|
|
void setTransportStatsCallback(
|
|
std::shared_ptr<QuicTransportStatsCallback> statsCallback) noexcept;
|
|
|
|
class HappyEyeballsConnAttemptDelayTimeout
|
|
: public folly::HHWheelTimer::Callback {
|
|
public:
|
|
explicit HappyEyeballsConnAttemptDelayTimeout(
|
|
QuicClientTransport* transport)
|
|
: transport_(transport) {}
|
|
|
|
void timeoutExpired() noexcept override {
|
|
transport_->happyEyeballsConnAttemptDelayTimeoutExpired();
|
|
}
|
|
|
|
void callbackCanceled() noexcept override {}
|
|
|
|
private:
|
|
QuicClientTransport* transport_;
|
|
};
|
|
|
|
protected:
|
|
// From AsyncUDPSocket::ReadCallback
|
|
void getReadBuffer(void** buf, size_t* len) noexcept override;
|
|
void onDataAvailable(
|
|
const folly::SocketAddress& server,
|
|
size_t len,
|
|
bool truncated,
|
|
OnDataAvailableParams params) noexcept override;
|
|
bool shouldOnlyNotify() override;
|
|
void onNotifyDataAvailable(folly::AsyncUDPSocket& sock) noexcept override;
|
|
void recvMsg(
|
|
folly::AsyncUDPSocket& sock,
|
|
uint64_t readBufferSize,
|
|
int numPackets,
|
|
NetworkData& networkData,
|
|
folly::Optional<folly::SocketAddress>& server,
|
|
size_t& totalData);
|
|
void recvMmsg(
|
|
folly::AsyncUDPSocket& sock,
|
|
uint64_t readBufferSize,
|
|
int numPackets,
|
|
NetworkData& networkData,
|
|
folly::Optional<folly::SocketAddress>& server,
|
|
size_t& totalData);
|
|
|
|
void processUDPData(
|
|
const folly::SocketAddress& peer,
|
|
NetworkDataSingle&& networkData);
|
|
|
|
void processPacketData(
|
|
const folly::SocketAddress& peer,
|
|
TimePoint receiveTimePoint,
|
|
BufQueue& packetQueue);
|
|
|
|
void startCryptoHandshake();
|
|
|
|
void happyEyeballsConnAttemptDelayTimeoutExpired() noexcept;
|
|
|
|
void handleAckFrame(
|
|
const OutstandingPacket& outstandingPacket,
|
|
const QuicWriteFrame& packetFrame,
|
|
const ReadAckFrame&);
|
|
|
|
Buf readBuffer_;
|
|
folly::Optional<std::string> hostname_;
|
|
HappyEyeballsConnAttemptDelayTimeout happyEyeballsConnAttemptDelayTimeout_;
|
|
|
|
private:
|
|
void setD6DBasePMTUTransportParameter();
|
|
void setD6DRaiseTimeoutTransportParameter();
|
|
void setD6DProbeTimeoutTransportParameter();
|
|
void setSupportedExtensionTransportParameters();
|
|
void adjustGROBuffers();
|
|
void trackDatagramReceived(size_t len);
|
|
|
|
/**
|
|
* Send quic transport knobs defined by transportSettings.knobs to peer. This
|
|
* calls setKnobs() internally.
|
|
*/
|
|
void maybeSendTransportKnobs();
|
|
|
|
void startBase(
|
|
ConnectionCallback* cb,
|
|
ConnectionSetupCallback* connSetupCb,
|
|
ConnectionCallbackNew* connStreamsCb);
|
|
|
|
bool replaySafeNotified_{false};
|
|
// Set it QuicClientTransport is in a self owning mode. This will be cleaned
|
|
// up when the caller invokes a terminal call to the transport.
|
|
std::shared_ptr<QuicClientTransport> selfOwning_;
|
|
bool happyEyeballsEnabled_{false};
|
|
sa_family_t happyEyeballsCachedFamily_{AF_UNSPEC};
|
|
QuicClientConnectionState* clientConn_;
|
|
std::vector<TransportParameter> customTransportParameters_;
|
|
folly::SocketOptionMap socketOptions_;
|
|
std::shared_ptr<QuicTransportStatsCallback> statsCallback_;
|
|
// Same value as conn_->transportSettings.numGROBuffers_ if the kernel
|
|
// supports GRO. otherwise kDefaultNumGROBuffers
|
|
uint32_t numGROBuffers_{kDefaultNumGROBuffers};
|
|
RecvmmsgStorage recvmmsgStorage_;
|
|
// We will only send transport knobs once, this flag keeps track of it
|
|
bool transportKnobsSent_{false};
|
|
};
|
|
} // namespace quic
|