/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/quic/packet.h
166 строк
5 KB
James M Snell
quic: add support for future ECN marking
22 май 2026, 00:16
22 май 2026, 00:16
567ac2d
Код
Авторство
О чём код?
#pragma once #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include <ngtcp2/ngtcp2.h> #include <node_sockaddr.h> #include <uv.h> #include <string> #include "arena.h" #include "cid.h" #include "data.h" #include "defs.h" #include "tokens.h" namespace node::quic { class Endpoint; struct PathDescriptor final { uint32_t version; const CID& dcid; const CID& scid; const SocketAddress& local_address; const SocketAddress& remote_address; std::string ToString() const; }; // A Packet encapsulates serialized outbound QUIC data. // // Packets are allocated from an ArenaPool owned by the Endpoint, which // allocates fixed-size slots from contiguous memory blocks. This avoids // heap fragmentation and the overhead of per-packet V8 object allocation. // // Each Packet contains: // - A uv_udp_send_t for the libuv send operation // - A destination socket address // - A data buffer (trailing memory in the arena slot) // // Packets are always encrypted; their content is opaque. We leave it // entirely up to ngtcp2 how to encode QUIC frames into the packet. // // Member layout is ordered so that fields touched on the hot path // (data_, capacity_, length_, listener_) share the first cache line. // The uv_udp_send_t (320 bytes, only touched by libuv) is placed last. class Packet final { public: using Ptr = ArenaPool<Packet>::Ptr; class Listener { public: virtual void PacketDone(int status) = 0; }; // Constructor takes the trailing data buffer and capacity from the // arena slot, plus the listener and destination. The data/capacity // are injected by ArenaPool::AcquireExtra(). Packet(uint8_t* data, size_t capacity, Listener* listener, const SocketAddress& destination); DISALLOW_COPY_AND_MOVE(Packet) // --- Inline accessors (hot path) --- uint8_t* data() { return data_; } const uint8_t* data() const { return data_; } size_t length() const { return length_; } size_t capacity() const { return capacity_; } const SocketAddress& destination() const { return destination_; } const PacketInfo& pkt_info() const { return pkt_info_; } void set_pkt_info(const PacketInfo& pi) { pkt_info_ = pi; } Listener* listener() const { return listener_; } // Redirect the packet to a different endpoint for cross-endpoint sends // (e.g., PATH_RESPONSE on a preferred address path). Updates the // listener (for pending_callbacks accounting) and the destination // (for uv_udp_send targeting). The packet data is unchanged. void Redirect(Listener* listener, const SocketAddress& destination) { listener_ = listener; destination_ = destination; } uv_udp_send_t* req() { return &req_; } operator uv_buf_t() const { return uv_buf_init(reinterpret_cast<char*>(data_), length_); } operator ngtcp2_vec() const { return ngtcp2_vec{data_, length_}; } // Modify the logical size of the packet after ngtcp2 has written // to it. len must be <= capacity(). void Truncate(size_t len) { DCHECK_LE(len, capacity_); length_ = len; } // Recover Packet* from a uv_udp_send_t* in the libuv send callback. static Packet* FromReq(uv_udp_send_t* req) { return ContainerOf(&Packet::req_, req); } // --- Static factory methods --- // These create fully-formed packets for specific QUIC operations. // They acquire from the endpoint's packet pool and return Ptr. // An empty Ptr indicates failure. [[nodiscard]] static Ptr CreateRetryPacket( Endpoint& endpoint, const PathDescriptor& path_descriptor, const TokenSecret& token_secret); [[nodiscard]] static Ptr CreateConnectionClosePacket( Endpoint& endpoint, const SocketAddress& destination, ngtcp2_conn* conn, const QuicError& error); [[nodiscard]] static Ptr CreateImmediateConnectionClosePacket( Endpoint& endpoint, const PathDescriptor& path_descriptor, const QuicError& reason); [[nodiscard]] static Ptr CreateStatelessResetPacket( Endpoint& endpoint, const PathDescriptor& path_descriptor, const TokenSecret& token_secret, size_t source_len); [[nodiscard]] static Ptr CreateVersionNegotiationPacket( Endpoint& endpoint, const PathDescriptor& path_descriptor); // --- Diagnostic label: zero cost in release builds --- #ifdef DEBUG void set_diagnostic_label(const char* label) { diagnostic_label_ = label; } const char* diagnostic_label() const { return diagnostic_label_; } #else void set_diagnostic_label(const char*) {} #endif std::string ToString() const; private: // Hot fields first — all on cache line 0 during the fill loop. uint8_t* data_; size_t capacity_; size_t length_; Listener* listener_; // Touched at send time. PacketInfo pkt_info_; SocketAddress destination_; // Only touched by libuv during uv_udp_send and in the send callback. uv_udp_send_t req_; #ifdef DEBUG const char* diagnostic_label_ = nullptr; #endif }; } // namespace node::quic #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS