| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 1592a11 commit 53b05e2
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -239,7 +239,8 @@ void Session::Application::ReceiveStreamReset(Stream* stream, | |||
| 239 | 239 | // < 0 (other): fatal error, session already closed | |
| 240 | 240 | ssize_t Session::Application::TryWritePendingDatagram(PathStorage* path, | |
| 241 | 241 | uint8_t* dest, | |
| 242 | - size_t destlen) { | ||
| 242 | + size_t destlen, | ||
| 243 | + uint64_t ts) { | ||
| 243 | 244 | CHECK(session_->HasPendingDatagrams()); | |
| 244 | 245 | auto max_attempts = session_->config().options.max_datagram_send_attempts; | |
| 245 | 246 | ||
@@ -275,7 +276,7 @@ ssize_t Session::Application::TryWritePendingDatagram(PathStorage* path, | |||
| 275 | 276 | dg.id, | |
| 276 | 277 | &dgvec, | |
| 277 | 278 | 1, | |
| 278 | - uv_hrtime()); | ||
| 279 | + ts); | ||
| 279 | 280 | ||
| 280 | 281 | if (accepted) { | |
| 281 | 282 | // Nice, the datagram was accepted! | |
@@ -338,6 +339,13 @@ void Session::Application::SendPendingData() { | |||
| 338 | 339 | // call is dynamically capped by ngtcp2_conn_get_send_quantum(). | |
| 339 | 340 | static constexpr size_t kMaxPackets = 64; | |
| 340 | 341 | Debug(session_, "Application sending pending data"); | |
| 342 | + // Cache the timestamp once for the entire send loop. ngtcp2 does not | ||
| 343 | + // require nanosecond-accurate monotonicity within a single burst — | ||
| 344 | + // a single timestamp per SendPendingData call is what other QUIC | ||
| 345 | + // implementations use (e.g., quiche, msquic). When kernel-level | ||
| 346 | + // packet pacing becomes available via libuv, this timestamp becomes | ||
| 347 | + // the base for computing per-packet transmit timestamps. | ||
| 348 | + const uint64_t ts = uv_hrtime(); | ||
| 341 | 349 | PathStorage path; | |
| 342 | 350 | StreamData stream_data; | |
| 343 | 351 | ||
@@ -441,7 +449,8 @@ void Session::Application::SendPendingData() { | |||
| 441 | 449 | // Awesome, let's write our packet! | |
| 442 | 450 | PacketInfo pi; | |
| 443 | 451 | ssize_t nwrite = WriteVStream( | |
| 444 | - &path, &pi, packet->data(), &ndatalen, packet->length(), stream_data); | ||
| 452 | + &path, &pi, packet->data(), &ndatalen, packet->length(), | ||
| 453 | + stream_data, ts); | ||
| 445 | 454 | ||
| 446 | 455 | // When ndatalen is > 0, that's our indication that stream data was accepted | |
| 447 | 456 | // in to the packet. Yay! | |
@@ -528,7 +537,7 @@ void Session::Application::SendPendingData() { | |||
| 528 | 537 | // if there is one. Otherwise just loop around and keep going. | |
| 529 | 538 | if (session_->HasPendingDatagrams()) { | |
| 530 | 539 | auto result = TryWritePendingDatagram( | |
| 531 | - &path, packet->data(), packet->length()); | ||
| 540 | + &path, packet->data(), packet->length(), ts); | ||
| 532 | 541 | // When result is 0, either the datagram was congestion controlled, | |
| 533 | 542 | // didn't fit in the packet, or was abandoned. Skip and continue. | |
| 534 | 543 | ||
@@ -590,7 +599,7 @@ void Session::Application::SendPendingData() { | |||
| 590 | 599 | return session_->Close(CloseMethod::SILENT); | |
| 591 | 600 | } | |
| 592 | 601 | auto result = | |
| 593 | - TryWritePendingDatagram(&path, packet->data(), packet->length()); | ||
| 602 | + TryWritePendingDatagram(&path, packet->data(), packet->length(), ts); | ||
| 594 | 603 | if (result > 0) { | |
| 595 | 604 | Debug(session_, "Sending datagram packet with %zd bytes", result); | |
| 596 | 605 | enqueue_packet(packet, static_cast<size_t>(result), PacketInfo()); | |
@@ -610,7 +619,8 @@ ssize_t Session::Application::WriteVStream(PathStorage* path, | |||
| 610 | 619 | uint8_t* dest, | |
| 611 | 620 | ssize_t* ndatalen, | |
| 612 | 621 | size_t max_packet_size, | |
| 613 | - const StreamData& stream_data) { | ||
| 622 | + const StreamData& stream_data, | ||
| 623 | + uint64_t ts) { | ||
| 614 | 624 | DCHECK_LE(stream_data.count, kMaxVectorCount); | |
| 615 | 625 | uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE; | |
| 616 | 626 | if (stream_data.fin) flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; | |
@@ -627,7 +637,7 @@ ssize_t Session::Application::WriteVStream(PathStorage* path, | |||
| 627 | 637 | stream_data.id, | |
| 628 | 638 | stream_data, | |
| 629 | 639 | stream_data.count, | |
| 630 | - uv_hrtime()); | ||
| 640 | + ts); | ||
| 631 | 641 | } | |
| 632 | 642 | ||
| 633 | 643 | // ============================================================================ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -267,7 +267,8 @@ class Session::Application : public MemoryRetainer { | |||
| 267 | 267 | // the datagram is either congestion limited or was abandoned | |
| 268 | 268 | ssize_t TryWritePendingDatagram(PathStorage* path, | |
| 269 | 269 | uint8_t* dest, | |
| 270 | - size_t destlen); | ||
| 270 | + size_t destlen, | ||
| 271 | + uint64_t ts); | ||
| 271 | 272 | ||
| 272 | 273 | // Write the given stream_data into the buffer. The PacketInfo out-param | |
| 273 | 274 | // is populated by ngtcp2 with per-packet metadata (e.g., ECN codepoint) | |
@@ -277,7 +278,8 @@ class Session::Application : public MemoryRetainer { | |||
| 277 | 278 | uint8_t* buf, | |
| 278 | 279 | ssize_t* ndatalen, | |
| 279 | 280 | size_t max_packet_size, | |
| 280 | - const StreamData& stream_data); | ||
| 281 | + const StreamData& stream_data, | ||
| 282 | + uint64_t ts); | ||
| 281 | 283 | ||
| 282 | 284 | Session* session_ = nullptr; | |
| 283 | 285 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2112,20 +2112,23 @@ void Session::SetLastError(QuicError&& error) { | |||
| 2112 | 2112 | bool Session::Receive(Store&& store, | |
| 2113 | 2113 | const SocketAddress& local_address, | |
| 2114 | 2114 | const SocketAddress& remote_address, | |
| 2115 | - const PacketInfo& pkt_info) { | ||
| 2115 | + const PacketInfo& pkt_info, | ||
| 2116 | + uint64_t ts) { | ||
| 2116 | 2117 | // Convenience wrapper: reads the packet and immediately triggers | |
| 2117 | 2118 | // SendPendingData. Used by paths that need an immediate response | |
| 2118 | 2119 | // (e.g., Endpoint::Connect for client Initial packets). | |
| 2119 | 2120 | // The hot receive path uses ReadPacket() directly with deferred | |
| 2120 | 2121 | // flush via BindingData's uv_check callback. | |
| 2121 | 2122 | SendPendingDataScope send_scope(this); | |
| 2122 | - return ReadPacket(std::move(store), local_address, remote_address, pkt_info); | ||
| 2123 | + return ReadPacket( | ||
| 2124 | + std::move(store), local_address, remote_address, pkt_info, ts); | ||
| 2123 | 2125 | } | |
| 2124 | 2126 | ||
| 2125 | 2127 | bool Session::ReadPacket(Store&& store, | |
| 2126 | 2128 | const SocketAddress& local_address, | |
| 2127 | 2129 | const SocketAddress& remote_address, | |
| 2128 | - const PacketInfo& pkt_info) { | ||
| 2130 | + const PacketInfo& pkt_info, | ||
| 2131 | + uint64_t ts) { | ||
| 2129 | 2132 | DCHECK(!is_destroyed()); | |
| 2130 | 2133 | impl_->remote_address_ = remote_address; | |
| 2131 | 2134 | ||
@@ -2151,8 +2154,12 @@ bool Session::ReadPacket(Store&& store, | |||
| 2151 | 2154 | // When libuv gains per-packet ECN reporting, the caller should | |
| 2152 | 2155 | // populate pkt_info from the receive metadata before calling | |
| 2153 | 2156 | // ReadPacket(). | |
| 2157 | + // When ts is 0 (the default), call uv_hrtime() here. The batched | ||
| 2158 | + // receive path caches a timestamp and passes it to all ReadPacket() | ||
| 2159 | + // calls in the same I/O burst. | ||
| 2160 | + if (ts == 0) ts = uv_hrtime(); | ||
| 2154 | 2161 | err = ngtcp2_conn_read_pkt( | |
| 2155 | - *this, &path, pkt_info, vec.base, vec.len, uv_hrtime()); | ||
| 2162 | + *this, &path, pkt_info, vec.base, vec.len, ts); | ||
| 2156 | 2163 | } | |
| 2157 | 2164 | if (is_destroyed()) return false; | |
| 2158 | 2165 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -356,7 +356,8 @@ class Session final : public AsyncWrap, private SessionTicket::AppData::Source { | |||
| 356 | 356 | bool Receive(Store&& store, | |
| 357 | 357 | const SocketAddress& local_address, | |
| 358 | 358 | const SocketAddress& remote_address, | |
| 359 | - const PacketInfo& pkt_info = PacketInfo()); | ||
| 359 | + const PacketInfo& pkt_info = PacketInfo(), | ||
| 360 | + uint64_t ts = 0); | ||
| 360 | 361 | ||
| 361 | 362 | // ReadPacket processes a single inbound packet through ngtcp2 without | |
| 362 | 363 | // triggering SendPendingData. This is the building block for batched | |
@@ -366,10 +367,14 @@ class Session final : public AsyncWrap, private SessionTicket::AppData::Source { | |||
| 366 | 367 | // Receive() is kept as a convenience wrapper that calls ReadPacket() | |
| 367 | 368 | // then triggers SendPendingData (for paths like Connect that need | |
| 368 | 369 | // immediate response). | |
| 370 | + // When ts is 0 (the default), uv_hrtime() is called internally. | ||
| 371 | + // The batched receive path caches a timestamp and passes it to all | ||
| 372 | + // ReadPacket() calls in the same I/O burst. | ||
| 369 | 373 | bool ReadPacket(Store&& store, | |
| 370 | 374 | const SocketAddress& local_address, | |
| 371 | 375 | const SocketAddress& remote_address, | |
| 372 | - const PacketInfo& pkt_info = PacketInfo()); | ||
| 376 | + const PacketInfo& pkt_info = PacketInfo(), | ||
| 377 | + uint64_t ts = 0); | ||
| 373 | 378 | ||
| 374 | 379 | // Called by BindingData's flush callback to trigger SendPendingData | |
| 375 | 380 | // on this session. Encapsulates the application() access so that | |
| Back | FazBrowse Home | New Git URL |
0 commit comments