1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-04-18 17:24:03 +03:00
mvfst/quic/client/QuicClientTransport.h
Hani Damlaj 00e67c1bf9 mvfst License Header Update
Reviewed By: lnicco

Differential Revision: D33587012

fbshipit-source-id: 972eb440f0156c9c04aa6e8787561b18295c1a97
2022-01-18 13:56:12 -08:00

265 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