| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 80e6bf9 commit 1592a11
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -262,9 +262,12 @@ ssize_t Session::Application::TryWritePendingDatagram(PathStorage* path, | |||
| 262 | 262 | int accepted = 0; | |
| 263 | 263 | int dg_flags = NGTCP2_WRITE_DATAGRAM_FLAG_MORE; | |
| 264 | 264 | ||
| 265 | + // PacketInfo for the datagram path. When libuv gains per-socket ECN | ||
| 266 | + // marking, the value from ngtcp2 should be forwarded to the send path. | ||
| 267 | + PacketInfo dg_pi; | ||
| 265 | 268 | ssize_t dg_nwrite = ngtcp2_conn_writev_datagram(*session_, | |
| 266 | 269 | &path->path, | |
| 267 | - nullptr, | ||
| 270 | + dg_pi, | ||
| 268 | 271 | dest, | |
| 269 | 272 | destlen, | |
| 270 | 273 | &accepted, | |
@@ -390,12 +393,14 @@ void Session::Application::SendPendingData() { | |||
| 390 | 393 | }; | |
| 391 | 394 | ||
| 392 | 395 | // Accumulate a completed packet into the batch. | |
| 393 | - auto enqueue_packet = [&](Packet::Ptr& pkt, size_t len) { | ||
| 394 | - Debug(session_, "Enqueuing packet with %zu bytes into batch", len); | ||
| 395 | - pkt->Truncate(len); | ||
| 396 | - path.CopyTo(&batch_paths[batch_count]); | ||
| 397 | - batch[batch_count++] = std::move(pkt); | ||
| 398 | - }; | ||
| 396 | + auto enqueue_packet = | ||
| 397 | + [&](Packet::Ptr& pkt, size_t len, const PacketInfo& pi) { | ||
| 398 | + Debug(session_, "Enqueuing packet with %zu bytes into batch", len); | ||
| 399 | + pkt->Truncate(len); | ||
| 400 | + pkt->set_pkt_info(pi); | ||
| 401 | + path.CopyTo(&batch_paths[batch_count]); | ||
| 402 | + batch[batch_count++] = std::move(pkt); | ||
| 403 | + }; | ||
| 399 | 404 | ||
| 400 | 405 | // We're going to enter a loop here to prepare and send no more than | |
| 401 | 406 | // max_packet_count packets. | |
@@ -434,8 +439,9 @@ void Session::Application::SendPendingData() { | |||
| 434 | 439 | } | |
| 435 | 440 | ||
| 436 | 441 | // Awesome, let's write our packet! | |
| 442 | + PacketInfo pi; | ||
| 437 | 443 | ssize_t nwrite = WriteVStream( | |
| 438 | - &path, packet->data(), &ndatalen, packet->length(), stream_data); | ||
| 444 | + &path, &pi, packet->data(), &ndatalen, packet->length(), stream_data); | ||
| 439 | 445 | ||
| 440 | 446 | // When ndatalen is > 0, that's our indication that stream data was accepted | |
| 441 | 447 | // in to the packet. Yay! | |
@@ -531,7 +537,7 @@ void Session::Application::SendPendingData() { | |||
| 531 | 537 | if (result > 0) { | |
| 532 | 538 | size_t len = result; | |
| 533 | 539 | Debug(session_, "Sending packet with %zu bytes", len); | |
| 534 | - enqueue_packet(packet, len); | ||
| 540 | + enqueue_packet(packet, len, pi); | ||
| 535 | 541 | if (++packet_send_count == max_packet_count) return; | |
| 536 | 542 | } else if (result < 0) { | |
| 537 | 543 | // Any negative result other than NGTCP2_ERR_WRITE_MORE | |
@@ -568,7 +574,7 @@ void Session::Application::SendPendingData() { | |||
| 568 | 574 | // is the size of the packet we are sending. | |
| 569 | 575 | size_t len = nwrite; | |
| 570 | 576 | Debug(session_, "Sending packet with %zu bytes", len); | |
| 571 | - enqueue_packet(packet, len); | ||
| 577 | + enqueue_packet(packet, len, pi); | ||
| 572 | 578 | if (++packet_send_count == max_packet_count) return; | |
| 573 | 579 | ||
| 574 | 580 | // If there are pending datagrams, try sending them in a fresh packet. | |
@@ -587,7 +593,7 @@ void Session::Application::SendPendingData() { | |||
| 587 | 593 | TryWritePendingDatagram(&path, packet->data(), packet->length()); | |
| 588 | 594 | if (result > 0) { | |
| 589 | 595 | Debug(session_, "Sending datagram packet with %zd bytes", result); | |
| 590 | - enqueue_packet(packet, static_cast<size_t>(result)); | ||
| 596 | + enqueue_packet(packet, static_cast<size_t>(result), PacketInfo()); | ||
| 591 | 597 | if (++packet_send_count == max_packet_count) return; | |
| 592 | 598 | } else if (result < 0 && result != NGTCP2_ERR_WRITE_MORE) { | |
| 593 | 599 | // Fatal error — session already closed by TryWritePendingDatagram. | |
@@ -600,17 +606,20 @@ void Session::Application::SendPendingData() { | |||
| 600 | 606 | } | |
| 601 | 607 | ||
| 602 | 608 | ssize_t Session::Application::WriteVStream(PathStorage* path, | |
| 609 | + PacketInfo* pi, | ||
| 603 | 610 | uint8_t* dest, | |
| 604 | 611 | ssize_t* ndatalen, | |
| 605 | 612 | size_t max_packet_size, | |
| 606 | 613 | const StreamData& stream_data) { | |
| 607 | 614 | DCHECK_LE(stream_data.count, kMaxVectorCount); | |
| 608 | 615 | uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE; | |
| 609 | 616 | if (stream_data.fin) flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; | |
| 617 | + // The PacketInfo out-param is populated by ngtcp2 with the ECN codepoint | ||
| 618 | + // to apply when sending this packet. When libuv gains per-socket ECN | ||
| 619 | + // marking, the value should be forwarded to the send path. | ||
| 610 | 620 | return ngtcp2_conn_writev_stream(*session_, | |
| 611 | 621 | &path->path, | |
| 612 | - // TODO(@jasnell): ECN blocked on libuv | ||
| 613 | - nullptr, | ||
| 622 | + *pi, | ||
| 614 | 623 | dest, | |
| 615 | 624 | max_packet_size, | |
| 616 | 625 | ndatalen, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -269,8 +269,11 @@ class Session::Application : public MemoryRetainer { | |||
| 269 | 269 | uint8_t* dest, | |
| 270 | 270 | size_t destlen); | |
| 271 | 271 | ||
| 272 | - // Write the given stream_data into the buffer. | ||
| 272 | + // Write the given stream_data into the buffer. The PacketInfo out-param | ||
| 273 | + // is populated by ngtcp2 with per-packet metadata (e.g., ECN codepoint) | ||
| 274 | + // that should be applied when sending the packet. | ||
| 273 | 275 | ssize_t WriteVStream(PathStorage* path, | |
| 276 | + PacketInfo* pi, | ||
| 274 | 277 | uint8_t* buf, | |
| 275 | 278 | ssize_t* ndatalen, | |
| 276 | 279 | size_t max_packet_size, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,6 +19,40 @@ namespace node::quic { | |||
| 19 | 19 | template <typename T> | |
| 20 | 20 | concept OneByteType = sizeof(T) == 1; | |
| 21 | 21 | ||
| 22 | + // Lightweight wrapper around ngtcp2_pkt_info. Insulates the Node.js QUIC | ||
| 23 | + // code from the ngtcp2 struct layout and provides a clean API boundary | ||
| 24 | + // for per-packet metadata (currently ECN codepoint; may grow as ngtcp2 | ||
| 25 | + // and libuv evolve). | ||
| 26 | + // | ||
| 27 | + // Default-constructed PacketInfo is zero-initialized, which ngtcp2 treats | ||
| 28 | + // as ECN Not-ECT — identical to passing nullptr for the pkt_info parameter. | ||
| 29 | + class PacketInfo final { | ||
| 30 | + public: | ||
| 31 | + // ECN codepoints as defined by RFC 3168. | ||
| 32 | + enum class Ecn : uint32_t { | ||
| 33 | + NOT_ECT = 0, // Not ECN-Capable Transport | ||
| 34 | + ECT_1 = 1, // ECN-Capable Transport(1) | ||
| 35 | + ECT_0 = 2, // ECN-Capable Transport(0) | ||
| 36 | + CE = 3, // Congestion Experienced | ||
| 37 | + }; | ||
| 38 | + | ||
| 39 | + PacketInfo() : info_{} {} | ||
| 40 | + explicit PacketInfo(const ngtcp2_pkt_info& info) : info_(info) {} | ||
| 41 | + | ||
| 42 | + // ECN codepoint for this packet. When libuv gains per-packet ECN | ||
| 43 | + // reporting, populate via set_ecn() from the receive metadata | ||
| 44 | + // before passing to ReadPacket(). | ||
| 45 | + Ecn ecn() const { return static_cast<Ecn>(info_.ecn); } | ||
| 46 | + void set_ecn(Ecn ecn) { info_.ecn = static_cast<uint32_t>(ecn); } | ||
| 47 | + | ||
| 48 | + // Conversion operators for ngtcp2 API calls. | ||
| 49 | + operator const ngtcp2_pkt_info*() const { return &info_; } | ||
| 50 | + operator ngtcp2_pkt_info*() { return &info_; } | ||
| 51 | + | ||
| 52 | + private: | ||
| 53 | + ngtcp2_pkt_info info_; | ||
| 54 | + }; | ||
| 55 | + | ||
| 22 | 56 | struct Path final : public ngtcp2_path { | |
| 23 | 57 | explicit Path(const SocketAddress& local, const SocketAddress& remote); | |
| 24 | 58 | Path(Path&& other) noexcept = default; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -68,6 +68,8 @@ class Packet final { | |||
| 68 | 68 | size_t length() const { return length_; } | |
| 69 | 69 | size_t capacity() const { return capacity_; } | |
| 70 | 70 | const SocketAddress& destination() const { return destination_; } | |
| 71 | + const PacketInfo& pkt_info() const { return pkt_info_; } | ||
| 72 | + void set_pkt_info(const PacketInfo& pi) { pkt_info_ = pi; } | ||
| 71 | 73 | Listener* listener() const { return listener_; } | |
| 72 | 74 | ||
| 73 | 75 | // Redirect the packet to a different endpoint for cross-endpoint sends | |
@@ -148,6 +150,7 @@ class Packet final { | |||
| 148 | 150 | Listener* listener_; | |
| 149 | 151 | ||
| 150 | 152 | // Touched at send time. | |
| 153 | + PacketInfo pkt_info_; | ||
| 151 | 154 | SocketAddress destination_; | |
| 152 | 155 | ||
| 153 | 156 | // Only touched by libuv during uv_udp_send and in the send callback. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2111,19 +2111,21 @@ void Session::SetLastError(QuicError&& error) { | |||
| 2111 | 2111 | ||
| 2112 | 2112 | bool Session::Receive(Store&& store, | |
| 2113 | 2113 | const SocketAddress& local_address, | |
| 2114 | - const SocketAddress& remote_address) { | ||
| 2114 | + const SocketAddress& remote_address, | ||
| 2115 | + const PacketInfo& pkt_info) { | ||
| 2115 | 2116 | // Convenience wrapper: reads the packet and immediately triggers | |
| 2116 | 2117 | // SendPendingData. Used by paths that need an immediate response | |
| 2117 | 2118 | // (e.g., Endpoint::Connect for client Initial packets). | |
| 2118 | 2119 | // The hot receive path uses ReadPacket() directly with deferred | |
| 2119 | 2120 | // flush via BindingData's uv_check callback. | |
| 2120 | 2121 | SendPendingDataScope send_scope(this); | |
| 2121 | - return ReadPacket(std::move(store), local_address, remote_address); | ||
| 2122 | + return ReadPacket(std::move(store), local_address, remote_address, pkt_info); | ||
| 2122 | 2123 | } | |
| 2123 | 2124 | ||
| 2124 | 2125 | bool Session::ReadPacket(Store&& store, | |
| 2125 | 2126 | const SocketAddress& local_address, | |
| 2126 | - const SocketAddress& remote_address) { | ||
| 2127 | + const SocketAddress& remote_address, | ||
| 2128 | + const PacketInfo& pkt_info) { | ||
| 2127 | 2129 | DCHECK(!is_destroyed()); | |
| 2128 | 2130 | impl_->remote_address_ = remote_address; | |
| 2129 | 2131 | ||
@@ -2145,12 +2147,12 @@ bool Session::ReadPacket(Store&& store, | |||
| 2145 | 2147 | int err; | |
| 2146 | 2148 | { | |
| 2147 | 2149 | NgTcp2CallbackScope callback_scope(this); | |
| 2148 | - // ECN codepoint (ngtcp2_pkt_info.ecn) is not yet populated because | ||
| 2149 | - // libuv does not currently deliver per-packet ECN metadata. When | ||
| 2150 | - // libuv gains ECN receive reporting, the pkt_info should be | ||
| 2151 | - // populated from the per-packet metadata and passed through here. | ||
| 2150 | + // The PacketInfo carries per-packet metadata (currently ECN codepoint). | ||
| 2151 | + // When libuv gains per-packet ECN reporting, the caller should | ||
| 2152 | + // populate pkt_info from the receive metadata before calling | ||
| 2153 | + // ReadPacket(). | ||
| 2152 | 2154 | err = ngtcp2_conn_read_pkt( | |
| 2153 | - *this, &path, nullptr, vec.base, vec.len, uv_hrtime()); | ||
| 2155 | + *this, &path, pkt_info, vec.base, vec.len, uv_hrtime()); | ||
| 2154 | 2156 | } | |
| 2155 | 2157 | if (is_destroyed()) return false; | |
| 2156 | 2158 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -355,7 +355,8 @@ class Session final : public AsyncWrap, private SessionTicket::AppData::Source { | |||
| 355 | 355 | ||
| 356 | 356 | bool Receive(Store&& store, | |
| 357 | 357 | const SocketAddress& local_address, | |
| 358 | - const SocketAddress& remote_address); | ||
| 358 | + const SocketAddress& remote_address, | ||
| 359 | + const PacketInfo& pkt_info = PacketInfo()); | ||
| 359 | 360 | ||
| 360 | 361 | // ReadPacket processes a single inbound packet through ngtcp2 without | |
| 361 | 362 | // triggering SendPendingData. This is the building block for batched | |
@@ -367,7 +368,8 @@ class Session final : public AsyncWrap, private SessionTicket::AppData::Source { | |||
| 367 | 368 | // immediate response). | |
| 368 | 369 | bool ReadPacket(Store&& store, | |
| 369 | 370 | const SocketAddress& local_address, | |
| 370 | - const SocketAddress& remote_address); | ||
| 371 | + const SocketAddress& remote_address, | ||
| 372 | + const PacketInfo& pkt_info = PacketInfo()); | ||
| 371 | 373 | ||
| 372 | 374 | // Called by BindingData's flush callback to trigger SendPendingData | |
| 373 | 375 | // on this session. Encapsulates the application() access so that | |
| Back | FazBrowse Home | New Git URL |
0 commit comments