/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include namespace quic { /** * Base class for the QUIC Transport. Implements common behavior for both * clients and servers. QuicTransportBase assumes the following: * 1. It is intended to be sub-classed and used via the subclass directly. * 2. Assumes that the sub-class manages its ownership via a shared_ptr. * This is needed in order for QUIC to be able to live beyond the lifetime * of the object that holds it to send graceful close messages to the peer. */ class QuicTransportBase : public QuicSocket, public QuicTransportBaseLite, QuicStreamPrioritiesObserver { public: QuicTransportBase( std::shared_ptr evb, std::unique_ptr socket, bool useConnectionEndWithErrorCallback = false); ~QuicTransportBase() override; void setPacingTimer(QuicTimer::SharedPtr pacingTimer) noexcept; Optional getClientConnectionId() const override; Optional getServerConnectionId() const override; Optional getClientChosenDestConnectionId() const override; const std::shared_ptr getQLogger() const; // QuicSocket interface bool replaySafe() const override; void closeGracefully() override; folly::Expected getStreamReadOffset( StreamId id) const override; folly::Expected getStreamWriteOffset( StreamId id) const override; folly::Expected getStreamWriteBufferedBytes( StreamId id) const override; folly::Expected getConnectionFlowControl() const override; folly::Expected getMaxWritableOnStream( StreamId id) const override; folly::Expected setConnectionFlowControlWindow( uint64_t windowSize) override; folly::Expected setStreamFlowControlWindow( StreamId id, uint64_t windowSize) override; void unsetAllReadCallbacks() override; void unsetAllPeekCallbacks() override; void unsetAllDeliveryCallbacks() override; folly::Expected pauseRead(StreamId id) override; folly::Expected resumeRead(StreamId id) override; folly::Expected setPeekCallback( StreamId id, PeekCallback* cb) override; folly::Expected pausePeek(StreamId id) override; folly::Expected resumePeek(StreamId id) override; folly::Expected peek( StreamId id, const folly::Function&) const>& peekCallback) override; folly::Expected consume( StreamId id, size_t amount) override; folly::Expected>> consume(StreamId id, uint64_t offset, size_t amount) override; folly::Expected createBidirectionalStreamGroup() override; folly::Expected createUnidirectionalStreamGroup() override; folly::Expected createBidirectionalStreamInGroup( StreamGroupId groupId) override; folly::Expected createUnidirectionalStreamInGroup( StreamGroupId groupId) override; bool isClientStream(StreamId stream) noexcept override; bool isServerStream(StreamId stream) noexcept override; StreamDirectionality getStreamDirectionality( StreamId stream) noexcept override; folly::Expected maybeResetStreamFromReadError( StreamId id, QuicErrorCode error) override; folly::Expected setPingCallback( PingCallback* cb) override; void sendPing(std::chrono::milliseconds pingTimeout) override; const QuicConnectionStateBase* getState() const override { return conn_.get(); } virtual void setAckRxTimestampsEnabled(bool enableAckRxTimestamps); void setEarlyDataAppParamsFunctions( folly::Function&, const Buf&) const> validator, folly::Function getter) final; bool isDetachable() override; void detachEventBase() override; void attachEventBase(std::shared_ptr evb) override; // Subclass API. folly::Expected getStreamPriority( StreamId id) override; /** * Register a callback to be invoked when the stream offset was transmitted. * * Currently, an offset is considered "transmitted" if it has been written to * to the underlying UDP socket, indicating that it has passed through * congestion control and pacing. In the future, this callback may be * triggered by socket/NIC software or hardware timestamps. */ folly::Expected registerTxCallback( const StreamId id, const uint64_t offset, ByteEventCallback* cb) override; /** * Reset or send a stop sending on all non-control streams. Leaves the * connection otherwise unmodified. Note this will also trigger the * onStreamWriteError and readError callbacks immediately. */ void resetNonControlStreams( ApplicationErrorCode error, folly::StringPiece errorMsg) override; /* * Set the background mode priority threshold and the target bw utilization * factor to use when in background mode. * * If all streams have equal or lower priority compares to the threshold * (value >= threshold), the connection is considered to be in background * mode. */ void setBackgroundModeParameters( PriorityLevel maxBackgroundPriority, float backgroundUtilizationFactor); /* * Disable background mode by clearing all related parameters. */ void clearBackgroundModeParameters(); virtual void setQLogger(std::shared_ptr qLogger); void setLoopDetectorCallback(std::shared_ptr callback) { conn_->loopDetectorCallback = std::move(callback); } /** * Set the read callback for Datagrams */ folly::Expected setDatagramCallback( DatagramCallback* cb) override; /** * Returns the maximum allowed Datagram payload size. * 0 means Datagram is not supported */ FOLLY_NODISCARD uint16_t getDatagramSizeLimit() const override; /** * Writes a Datagram frame. If buf is larger than the size limit returned by * getDatagramSizeLimit(), or if the write buffer is full, buf will simply be * dropped, and a LocalErrorCode will be returned to caller. */ folly::Expected writeDatagram(Buf buf) override; /** * Returns the currently available received Datagrams. * Returns all datagrams if atMost is 0. */ folly::Expected, LocalErrorCode> readDatagrams( size_t atMost = 0) override; /** * Returns the currently available received Datagram IOBufs. * Returns all datagrams if atMost is 0. */ folly::Expected, LocalErrorCode> readDatagramBufs( size_t atMost = 0) override; /** * Set control messages to be sent for socket_ write, note that it's for this * specific transport and does not change the other sockets sharing the same * fd. */ void setCmsgs(const folly::SocketCmsgMap& options); void appendCmsgs(const folly::SocketCmsgMap& options); /** * Sets the policy per stream group id. * If policy == std::nullopt, the policy is removed for corresponding stream * group id (reset to the default rtx policy). */ folly::Expected setStreamGroupRetransmissionPolicy( StreamGroupId groupId, std::optional policy) noexcept override; [[nodiscard]] const folly:: F14FastMap& getStreamGroupRetransmissionPolicies() const { return conn_->retransmissionPolicies; } [[nodiscard]] QuicAsyncUDPSocket* getUdpSocket() const { return socket_.get(); } protected: /* * Observe changes in stream priorities and handle background mode. * * Implements the QuicStreamPrioritiesObserver interface */ void onStreamPrioritiesChange() override; folly::Expected pauseOrResumeRead( StreamId id, bool resume); folly::Expected pauseOrResumePeek( StreamId id, bool resume); folly::Expected setPeekCallbackInternal( StreamId id, PeekCallback* cb) noexcept; void schedulePingTimeout( PingCallback* callback, std::chrono::milliseconds pingTimeout); bool handshakeDoneNotified_{false}; uint64_t qlogRefcnt_{0}; // Priority level threshold for background streams // If all streams have equal or lower priority to the threshold // (value >= threshold), the connection is considered to be in background // mode. Optional backgroundPriorityThreshold_; Optional backgroundUtilizationFactor_; private: /** * Helper to check if using custom retransmission profiles is feasible. * Custom retransmission profiles are only applicable when stream groups are * enabled, i.e. advertisedMaxStreamGroups in transport settings is > 0. */ [[nodiscard]] bool checkCustomRetransmissionProfilesEnabled() const; }; } // namespace quic