quic/server/QuicServerTransport.h (132 lines of code) (raw):

/* * 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 <quic/api/QuicTransportBase.h> #include <quic/api/QuicTransportFunctions.h> #include <quic/codec/ConnectionIdAlgo.h> #include <quic/common/TransportKnobs.h> #include <quic/congestion_control/CongestionControllerFactory.h> #include <quic/server/handshake/ServerTransportParametersExtension.h> #include <quic/server/state/ServerConnectionIdRejector.h> #include <quic/server/state/ServerStateMachine.h> #include <quic/state/QuicTransportStatsCallback.h> #include <folly/io/async/AsyncTransportCertificate.h> #include <fizz/record/Types.h> namespace quic { struct CipherInfo { TrafficKey trafficKey; fizz::CipherSuite cipherSuite; Buf packetProtectionKey; }; class QuicServerTransport : public QuicTransportBase, public ServerHandshake::HandshakeCallback, public std::enable_shared_from_this<QuicServerTransport> { public: using Ptr = std::shared_ptr<QuicServerTransport>; using SourceIdentity = std::pair<folly::SocketAddress, ConnectionId>; class RoutingCallback { public: virtual ~RoutingCallback() = default; // Called when a connection id is available virtual void onConnectionIdAvailable( Ptr transport, ConnectionId id) noexcept = 0; // Called when a connecton id is bound and ip address should not // be used any more for routing. virtual void onConnectionIdBound(Ptr transport) noexcept = 0; // Called when the connection is finished and needs to be Unbound. virtual void onConnectionUnbound( QuicServerTransport* transport, const SourceIdentity& address, const std::vector<ConnectionIdData>& connectionIdData) noexcept = 0; }; class HandshakeFinishedCallback { public: virtual ~HandshakeFinishedCallback() = default; virtual void onHandshakeFinished() noexcept = 0; virtual void onHandshakeUnfinished() noexcept = 0; }; static QuicServerTransport::Ptr make( folly::EventBase* evb, std::unique_ptr<folly::AsyncUDPSocket> sock, ConnectionSetupCallback* connSetupCb, ConnectionCallback* connStreamsCb, std::shared_ptr<const fizz::server::FizzServerContext> ctx, bool useConnectionEndWithErrorCallback = false); QuicServerTransport( folly::EventBase* evb, std::unique_ptr<folly::AsyncUDPSocket> sock, ConnectionSetupCallback* connSetupCb, ConnectionCallback* connStreamsCb, std::shared_ptr<const fizz::server::FizzServerContext> ctx, std::unique_ptr<CryptoFactory> cryptoFactory = nullptr, bool useConnectionEndWithErrorCallback = false); // Testing only API: QuicServerTransport( folly::EventBase* evb, std::unique_ptr<folly::AsyncUDPSocket> sock, ConnectionSetupCallback* connSetupCb, ConnectionCallback* connStreamsCb, std::shared_ptr<const fizz::server::FizzServerContext> ctx, std::unique_ptr<CryptoFactory> cryptoFactory, PacketNum startingPacketNum); ~QuicServerTransport() override; virtual void setRoutingCallback(RoutingCallback* callback) noexcept; virtual void setHandshakeFinishedCallback( HandshakeFinishedCallback* callback) noexcept; virtual void setOriginalPeerAddress(const folly::SocketAddress& addr); virtual void setServerConnectionIdParams( ServerConnectionIdParams params) noexcept; /** * Set callback for various transport stats (such as packet received, dropped * etc). */ virtual void setTransportStatsCallback( QuicTransportStatsCallback* statsCallback) noexcept; /** * Set ConnectionIdAlgo implementation to encode and decode ConnectionId with * various info, such as routing related info. */ virtual void setConnectionIdAlgo(ConnectionIdAlgo* connIdAlgo) noexcept; void setServerConnectionIdRejector( ServerConnectionIdRejector* connIdRejector) noexcept; virtual void setClientConnectionId(const ConnectionId& clientConnectionId); void setClientChosenDestConnectionId(const ConnectionId& serverCid); // 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; QuicConnectionStats getConnectionsStats() const override; const fizz::server::FizzServerContext& getCtx() { return *ctx_; } virtual void accept(); virtual void setBufAccessor(BufAccessor* bufAccessor); #ifdef CCP_ENABLED /* * This function must be called with an initialized ccp_datapath (via * libccp:ccp_init) before starting any connections using the CCP congestion * control algorithm. See further notes on this struct in the header file. */ void setCcpDatapath(struct ccp_datapath* datapath); #endif const std::shared_ptr<const folly::AsyncTransportCertificate> getPeerCertificate() const override; virtual CipherInfo getOneRttCipherInfo() const; protected: // From ServerHandshake::HandshakeCallback virtual void onCryptoEventAvailable() noexcept override; void onTransportKnobs(Buf knobBlob) override; void handleTransportKnobParams(const TransportKnobParams& params); // Made it protected for testing purpose void registerTransportKnobParamHandler( uint64_t paramId, std::function<void(QuicServerTransport*, uint64_t)>&& handler); private: void processPendingData(bool async); void maybeNotifyTransportReady(); void maybeNotifyConnectionIdBound(); void maybeWriteNewSessionTicket(); void maybeIssueConnectionIds(); void maybeNotifyHandshakeFinished(); bool hasReadCipher() const; void maybeStartD6DProbing(); void registerAllTransportKnobParamHandlers(); private: RoutingCallback* routingCb_{nullptr}; HandshakeFinishedCallback* handshakeFinishedCb_{nullptr}; std::shared_ptr<const fizz::server::FizzServerContext> ctx_; bool notifiedRouting_{false}; bool notifiedConnIdBound_{false}; bool newSessionTicketWritten_{false}; bool connectionIdsIssued_{false}; QuicServerConnectionState* serverConn_; std::unordered_map< uint64_t, std::function<void(QuicServerTransport*, uint64_t)>> transportKnobParamHandlers_; }; } // namespace quic