/* * 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 #include #include #include #include namespace quic { class DSRPacketizationRequestSender; class QuicSocket : virtual public QuicSocketLite { public: /** * Sets the functions that mvfst will invoke to validate early data params * and encode early data params to NewSessionTicket. * It's up to the application's responsibility to make sure captured objects * (if any) are alive when the functions are called. * * validator: * On server side: * Called during handshake while negotiating early data. * @param alpn * The negotiated ALPN. Optional because it may be absent from * ClientHello. * @param appParams * The encoded and encrypted application parameters from PSK. * @return * Whether application accepts parameters from resumption state for * 0-RTT. * On client side: * Called when transport is applying psk from cache. * @param alpn * The ALPN client is going to use for this connection. Optional * because client may not set ALPN. * @param appParams * The encoded (not encrypted) application parameter from local cache. * @return * Whether application will attempt early data based on the cached * application parameters. This is useful when client updates to use a * new binary but still reads PSK from an old cache. Client may choose * to not attempt 0-RTT at all given client thinks server will likely * reject it. * * getter: * On server side: * Called when transport is writing NewSessionTicket. * @return * The encoded application parameters that will be included in * NewSessionTicket. * On client side: * Called when client receives NewSessionTicket and is going to write to * cache. * @return * Encoded application parameters that will be written to cache. */ virtual void setEarlyDataAppParamsFunctions( folly::Function< bool(const Optional& alpn, const Buf& appParams) const> validator, folly::Function getter) = 0; virtual ~QuicSocket() override = default; /** * ===== Generic Socket Methods ===== */ /** * Get the QUIC Client Connection ID */ virtual Optional getClientConnectionId() const = 0; /** * Get the QUIC Server Connection ID */ virtual Optional getServerConnectionId() const = 0; /** * Get the original Quic Server Connection ID chosen by client */ FOLLY_NODISCARD virtual Optional getClientChosenDestConnectionId() const = 0; virtual bool replaySafe() const = 0; /** * Close this socket gracefully, by waiting for all the streams to be idle * first. */ virtual void closeGracefully() = 0; /** * Returns the current offset already read or written by the application on * the given stream. */ virtual folly::Expected getStreamReadOffset( StreamId id) const = 0; virtual folly::Expected getStreamWriteOffset( StreamId id) const = 0; /** * Returns the amount of data buffered by the transport waiting to be written */ virtual folly::Expected getStreamWriteBufferedBytes( StreamId id) const = 0; /** * Returns the current flow control windows for the connection. * Use getStreamFlowControl for stream flow control window. */ virtual folly::Expected getConnectionFlowControl() const = 0; /** * Returns the minimum of current send flow control window and available * buffer space. */ virtual folly::Expected getMaxWritableOnStream( StreamId id) const = 0; /** * Sets the flow control window for the connection. * Use setStreamFlowControlWindow for per Stream flow control. */ virtual folly::Expected setConnectionFlowControlWindow(uint64_t windowSize) = 0; /** * Sets the flow control window for the stream. * Use setConnectionFlowControlWindow for connection flow control. */ virtual folly::Expected setStreamFlowControlWindow(StreamId id, uint64_t windowSize) = 0; /** * Get stream priority. */ virtual folly::Expected getStreamPriority( StreamId id) = 0; /** * Convenience function that sets the read callbacks of all streams to be * nullptr. */ virtual void unsetAllReadCallbacks() = 0; /** * Convenience function that sets the read callbacks of all streams to be * nullptr. */ virtual void unsetAllPeekCallbacks() = 0; /** * Convenience function that cancels delivery callbacks of all streams. */ virtual void unsetAllDeliveryCallbacks() = 0; /** * Pause/Resume read callback being triggered when data is available. */ virtual folly::Expected pauseRead( StreamId id) = 0; virtual folly::Expected resumeRead( StreamId id) = 0; /** * ===== Peek/Consume API ===== */ /** * Usage: * class Application { * void onNewBidirectionalStream(StreamId id) { * socket_->setPeekCallback(id, this); * } * * virtual void onDataAvailable( * StreamId id, * const folly::Range& peekData) noexcept override * { * auto amount = tryInterpret(peekData); * if (amount) { * socket_->consume(id, amount); * } * } * }; */ virtual folly::Expected setPeekCallback( StreamId id, PeekCallback* cb) = 0; /** * Pause/Resume peek callback being triggered when data is available. */ virtual folly::Expected pausePeek( StreamId id) = 0; virtual folly::Expected resumePeek( StreamId id) = 0; /** * Peek at the given stream. * * The return value is Expected. If the value hasError(), then a read error * occurred and it can be obtained with error(). If the value hasValue(), * indicates that peekCallback has been called. * * The range that is passed to callback is only valid until callback returns, * If caller need to preserve data that range points to - that data has to * be copied. * * Calling peek() when there is no data/eof to deliver will return an * EAGAIN-like error code. */ virtual folly::Expected peek( StreamId id, const folly::Function&) const>& peekCallback) = 0; /** * Consumes data on the given stream, starting from currentReadOffset * * The return value is Expected. If the value hasError(), then a read error * occurred and it can be obtained with error(). * * @offset - represents start of consumed range. * Current implementation returns error and currentReadOffset if offset != * currentReadOffset * * Calling consume() when there is no data/eof to deliver * will return an EAGAIN-like error code. * */ virtual folly:: Expected>> consume(StreamId id, uint64_t offset, size_t amount) = 0; /** * Equivalent of calling consume(id, stream->currentReadOffset, amount); */ virtual folly::Expected consume( StreamId id, size_t amount) = 0; /** * Create a bidirectional stream group. */ virtual folly::Expected createBidirectionalStreamGroup() = 0; /** * Create a unidirectional stream group. */ virtual folly::Expected createUnidirectionalStreamGroup() = 0; /** * Same as createBidirectionalStream(), but creates a stream in a group. */ virtual folly::Expected createBidirectionalStreamInGroup(StreamGroupId groupId) = 0; /** * Same as createBidirectionalStream(), but creates a stream in a group. */ virtual folly::Expected createUnidirectionalStreamInGroup(StreamGroupId groupId) = 0; /** * Returns whether a stream ID represents a client-initiated stream. */ virtual bool isClientStream(StreamId stream) noexcept = 0; /** * Returns whether a stream ID represents a server-initiated stream. */ virtual bool isServerStream(StreamId stream) noexcept = 0; /** * Returns directionality (unidirectional or bidirectional) of a stream by ID. */ virtual StreamDirectionality getStreamDirectionality( StreamId stream) noexcept = 0; /** * 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. * * If the registration fails, the callback (ByteEventCallback* cb) will NEVER * be invoked for anything. If the registration succeeds, the callback is * guaranteed to receive an onByteEventRegistered() notification. */ virtual folly::Expected registerTxCallback( const StreamId id, const uint64_t offset, ByteEventCallback* cb) = 0; /** * 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. */ virtual void resetNonControlStreams( ApplicationErrorCode error, folly::StringPiece errorMsg) = 0; /** * Helper method to check a generic error for an Application error, and reset * the stream with the reciprocal error. * * Returns true if the error was an ApplicationErrorCode, and the stream was * reset. */ virtual folly::Expected maybeResetStreamFromReadError(StreamId id, QuicErrorCode error) = 0; /** * Set the ping callback */ virtual folly::Expected setPingCallback( PingCallback* cb) = 0; /** * Send a ping to the peer. When the ping is acknowledged by the peer or * times out, the transport will invoke the callback. */ virtual void sendPing(std::chrono::milliseconds pingTimeout) = 0; /** * Detaches the eventbase from the socket. This must be called from the * eventbase of socket. * Normally this is invoked by an app when the connection is idle, i.e. * there are no "active" streams on the connection, however an app might * think that all the streams are closed because it wrote the FIN * to the QuicSocket, however the QuicSocket might not have delivered the FIN * to the peer yet. Apps SHOULD use the delivery callback to make sure that * all writes for the closed stream are finished before detaching the * connection from the eventbase. */ virtual void detachEventBase() = 0; /** * Attaches an eventbase to the socket. This must be called from the * eventbase that needs to be attached and the caller must make sure that * there is no eventbase already attached to the socket. */ virtual void attachEventBase(std::shared_ptr evb) = 0; /** * Returns whether or not the eventbase can currently be detached from the * socket. */ virtual bool isDetachable() = 0; /** * ===== Datagram API ===== * * Datagram support is experimental. Currently there isn't delivery callback * or loss notification support for Datagram. */ /** * Set the read callback for Datagrams */ virtual folly::Expected setDatagramCallback( DatagramCallback* cb) = 0; /** * Returns the maximum allowed Datagram payload size. * 0 means Datagram is not supported */ FOLLY_NODISCARD virtual uint16_t getDatagramSizeLimit() const = 0; /** * 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. */ virtual WriteResult writeDatagram(Buf buf) = 0; /** * Returns the currently available received Datagrams. * Returns all datagrams if atMost is 0. */ virtual folly::Expected, LocalErrorCode> readDatagrams(size_t atMost = 0) = 0; /** * Returns the currently available received Datagram IOBufs. * Returns all datagrams if atMost is 0. */ virtual folly::Expected, LocalErrorCode> readDatagramBufs( size_t atMost = 0) = 0; /** * Sets a retransmission policy on a stream group. */ virtual folly::Expected setStreamGroupRetransmissionPolicy( StreamGroupId groupId, std::optional policy) noexcept = 0; }; } // namespace quic