deploy: 4c90a9ebd0d24bc4e4b9d8ceb5764ee93bfac8bf

This commit is contained in:
Frando
2026-05-06 12:49:00 +00:00
parent fad3b3e3f5
commit c811d6a7e2
14 changed files with 850 additions and 852 deletions
+1 -1
View File
@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Documentation for Rustdoc"><title>Help</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-ca0dd0c4.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="noq_perf" data-themes="" data-resource-suffix="" data-rustdoc-version="1.92.0-nightly (b6f0945e4 2025-10-08)" data-channel="nightly" data-search-js="search-8d3311b9.js" data-stringdex-js="stringdex-828709d0.js" data-settings-js="settings-c38705f0.js" ><script src="./static.files/storage-e2aeef58.js"></script><script defer src="./static.files/main-ce535bd0.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-263c88ec.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">All</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.92.0-nightly</span></h2></div><div class="version">(b6f0945e4 2025-10-08)</div><h2 class="location">Help</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content"><div class="main-heading"><h1>Rustdoc help</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section><p>You need to enable JavaScript to use keyboard commands or search.</p><p>For more information, browse the <a href="https://doc.rust-lang.org/nightly/rustdoc/">rustdoc handbook</a>.</p></section></noscript></section></div></main></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Documentation for Rustdoc"><title>Help</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-ca0dd0c4.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="data_transfer" data-themes="" data-resource-suffix="" data-rustdoc-version="1.92.0-nightly (b6f0945e4 2025-10-08)" data-channel="nightly" data-search-js="search-8d3311b9.js" data-stringdex-js="stringdex-828709d0.js" data-settings-js="settings-c38705f0.js" ><script src="./static.files/storage-e2aeef58.js"></script><script defer src="./static.files/main-ce535bd0.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-263c88ec.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">All</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.92.0-nightly</span></h2></div><div class="version">(b6f0945e4 2025-10-08)</div><h2 class="location">Help</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content"><div class="main-heading"><h1>Rustdoc help</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section><p>You need to enable JavaScript to use keyboard commands or search.</p><p>For more information, browse the <a href="https://doc.rust-lang.org/nightly/rustdoc/">rustdoc handbook</a>.</p></section></noscript></section></div></main></body></html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Settings of Rustdoc"><title>Settings</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-ca0dd0c4.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="noq_perf" data-themes="" data-resource-suffix="" data-rustdoc-version="1.92.0-nightly (b6f0945e4 2025-10-08)" data-channel="nightly" data-search-js="search-8d3311b9.js" data-stringdex-js="stringdex-828709d0.js" data-settings-js="settings-c38705f0.js" ><script src="./static.files/storage-e2aeef58.js"></script><script defer src="./static.files/main-ce535bd0.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-263c88ec.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">All</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.92.0-nightly</span></h2></div><div class="version">(b6f0945e4 2025-10-08)</div><h2 class="location">Settings</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content"><div class="main-heading"><h1>Rustdoc settings</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section>You need to enable JavaScript be able to update your settings.</section></noscript><script defer src="./static.files/settings-c38705f0.js"></script></section></div></main></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Settings of Rustdoc"><title>Settings</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-ca0dd0c4.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="data_transfer" data-themes="" data-resource-suffix="" data-rustdoc-version="1.92.0-nightly (b6f0945e4 2025-10-08)" data-channel="nightly" data-search-js="search-8d3311b9.js" data-stringdex-js="stringdex-828709d0.js" data-settings-js="settings-c38705f0.js" ><script src="./static.files/storage-e2aeef58.js"></script><script defer src="./static.files/main-ce535bd0.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-263c88ec.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">All</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.92.0-nightly</span></h2></div><div class="version">(b6f0945e4 2025-10-08)</div><h2 class="location">Settings</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content"><div class="main-heading"><h1>Rustdoc settings</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section>You need to enable JavaScript be able to update your settings.</section></noscript><script defer src="./static.files/settings-c38705f0.js"></script></section></div></main></body></html>
+476 -491
View File
@@ -24,7 +24,7 @@
<a href=#24 id=24 data-nosnippet>24</a> ConnectionEvent, Duration, Instant, Path, VarInt,
<a href=#25 id=25 data-nosnippet>25</a> endpoint::ensure_ipv6,
<a href=#26 id=26 data-nosnippet>26</a> mutex::{Mutex, MutexGuard},
<a href=#27 id=27 data-nosnippet>27</a> path::OpenPath,
<a href=#27 id=27 data-nosnippet>27</a> path::{OpenPath, PathRef, PathRefOwner},
<a href=#28 id=28 data-nosnippet>28</a> recv_stream::RecvStream,
<a href=#29 id=29 data-nosnippet>29</a> runtime::{AsyncTimer, Runtime, UdpSender},
<a href=#30 id=30 data-nosnippet>30</a> send_stream::SendStream,
@@ -1413,493 +1413,478 @@
<a href=#1413 id=1413 data-nosnippet>1413</a> </span>open_path: FxHashMap&lt;PathId, watch::Sender&lt;<span class="prelude-ty">Result</span>&lt;(), PathError&gt;&gt;&gt;,
<a href=#1414 id=1414 data-nosnippet>1414</a> <span class="doccomment">/// Tracks reference counts for paths.
<a href=#1415 id=1415 data-nosnippet>1415</a> ///
<a href=#1416 id=1416 data-nosnippet>1416</a> /// I.e. how many [`Path`] and [`WeakPathHandle`] structs are alive for a path. Each
<a href=#1417 id=1417 data-nosnippet>1417</a> /// entry's [`PathRef`] holds an [`AtomicUsize`] so that cloning or dropping a [`Path`]
<a href=#1418 id=1418 data-nosnippet>1418</a> /// or [`WeakPathHandle`] does not need to lock this state.
<a href=#1419 id=1419 data-nosnippet>1419</a> ///
<a href=#1420 id=1420 data-nosnippet>1420</a> /// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#1421 id=1421 data-nosnippet>1421</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) path_refs: FxHashMap&lt;PathId, Arc&lt;PathRef&gt;&gt;,
<a href=#1422 id=1422 data-nosnippet>1422</a> <span class="doccomment">/// Final path stats for discarded paths.
<a href=#1423 id=1423 data-nosnippet>1423</a> ///
<a href=#1424 id=1424 data-nosnippet>1424</a> /// We only insert entries if the discarded path has a non-zero reference count in [`Self::path_refs`].
<a href=#1425 id=1425 data-nosnippet>1425</a> /// When the last reference to a path is dropped its entry is removed from both maps.
<a href=#1426 id=1426 data-nosnippet>1426</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) final_path_stats: FxHashMap&lt;PathId, PathStats&gt;,
<a href=#1427 id=1427 data-nosnippet>1427</a> <span class="kw">pub</span>(<span class="kw">crate</span>) path_events: tokio::sync::broadcast::Sender&lt;PathEvent&gt;,
<a href=#1428 id=1428 data-nosnippet>1428</a> sender: Pin&lt;Box&lt;<span class="kw">dyn </span>UdpSender&gt;&gt;,
<a href=#1429 id=1429 data-nosnippet>1429</a> <span class="kw">pub</span>(<span class="kw">crate</span>) runtime: Arc&lt;<span class="kw">dyn </span>Runtime&gt;,
<a href=#1430 id=1430 data-nosnippet>1430</a> send_buffer: Vec&lt;u8&gt;,
<a href=#1431 id=1431 data-nosnippet>1431</a> <span class="doccomment">/// We buffer a transmit when the underlying I/O would block
<a href=#1432 id=1432 data-nosnippet>1432</a> </span>buffered_transmit: <span class="prelude-ty">Option</span>&lt;proto::Transmit&gt;,
<a href=#1433 id=1433 data-nosnippet>1433</a> <span class="doccomment">/// Our last external address reported by the peer. When multipath is enabled, this will be the
<a href=#1434 id=1434 data-nosnippet>1434</a> /// last report across all paths.
<a href=#1435 id=1435 data-nosnippet>1435</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) observed_external_addr: watch::Sender&lt;<span class="prelude-ty">Option</span>&lt;SocketAddr&gt;&gt;,
<a href=#1436 id=1436 data-nosnippet>1436</a> <span class="kw">pub</span>(<span class="kw">crate</span>) nat_traversal_updates: tokio::sync::broadcast::Sender&lt;n0_nat_traversal::Event&gt;,
<a href=#1437 id=1437 data-nosnippet>1437</a> on_closed: Vec&lt;oneshot::Sender&lt;Closed&gt;&gt;,
<a href=#1438 id=1438 data-nosnippet>1438</a>}
<a href=#1439 id=1439 data-nosnippet>1439</a>
<a href=#1440 id=1440 data-nosnippet>1440</a><span class="kw">impl </span>State {
<a href=#1441 id=1441 data-nosnippet>1441</a> <span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#1442 id=1442 data-nosnippet>1442</a> </span><span class="kw">fn </span>new(
<a href=#1443 id=1443 data-nosnippet>1443</a> inner: proto::Connection,
<a href=#1444 id=1444 data-nosnippet>1444</a> handle: ConnectionHandle,
<a href=#1445 id=1445 data-nosnippet>1445</a> endpoint_events: mpsc::UnboundedSender&lt;(ConnectionHandle, EndpointEvent)&gt;,
<a href=#1446 id=1446 data-nosnippet>1446</a> conn_events: mpsc::UnboundedReceiver&lt;ConnectionEvent&gt;,
<a href=#1447 id=1447 data-nosnippet>1447</a> on_handshake_data: oneshot::Sender&lt;()&gt;,
<a href=#1448 id=1448 data-nosnippet>1448</a> on_connected: oneshot::Sender&lt;bool&gt;,
<a href=#1449 id=1449 data-nosnippet>1449</a> sender: Pin&lt;Box&lt;<span class="kw">dyn </span>UdpSender&gt;&gt;,
<a href=#1450 id=1450 data-nosnippet>1450</a> runtime: Arc&lt;<span class="kw">dyn </span>Runtime&gt;,
<a href=#1451 id=1451 data-nosnippet>1451</a> ) -&gt; <span class="self">Self </span>{
<a href=#1452 id=1452 data-nosnippet>1452</a> <span class="self">Self </span>{
<a href=#1453 id=1453 data-nosnippet>1453</a> inner,
<a href=#1454 id=1454 data-nosnippet>1454</a> driver: <span class="prelude-val">None</span>,
<a href=#1455 id=1455 data-nosnippet>1455</a> handle,
<a href=#1456 id=1456 data-nosnippet>1456</a> on_handshake_data: <span class="prelude-val">Some</span>(on_handshake_data),
<a href=#1457 id=1457 data-nosnippet>1457</a> on_connected: <span class="prelude-val">Some</span>(on_connected),
<a href=#1458 id=1458 data-nosnippet>1458</a> connected: <span class="bool-val">false</span>,
<a href=#1459 id=1459 data-nosnippet>1459</a> handshake_confirmed: <span class="bool-val">false</span>,
<a href=#1460 id=1460 data-nosnippet>1460</a> timer: <span class="prelude-val">None</span>,
<a href=#1461 id=1461 data-nosnippet>1461</a> timer_deadline: <span class="prelude-val">None</span>,
<a href=#1462 id=1462 data-nosnippet>1462</a> conn_events,
<a href=#1463 id=1463 data-nosnippet>1463</a> endpoint_events,
<a href=#1464 id=1464 data-nosnippet>1464</a> blocked_writers: FxHashMap::default(),
<a href=#1465 id=1465 data-nosnippet>1465</a> blocked_readers: FxHashMap::default(),
<a href=#1466 id=1466 data-nosnippet>1466</a> stopped: FxHashMap::default(),
<a href=#1467 id=1467 data-nosnippet>1467</a> open_path: FxHashMap::default(),
<a href=#1468 id=1468 data-nosnippet>1468</a> error: <span class="prelude-val">None</span>,
<a href=#1469 id=1469 data-nosnippet>1469</a> sender,
<a href=#1470 id=1470 data-nosnippet>1470</a> runtime,
<a href=#1471 id=1471 data-nosnippet>1471</a> send_buffer: Vec::new(),
<a href=#1472 id=1472 data-nosnippet>1472</a> buffered_transmit: <span class="prelude-val">None</span>,
<a href=#1473 id=1473 data-nosnippet>1473</a> path_events: tokio::sync::broadcast::channel(<span class="number">32</span>).<span class="number">0</span>,
<a href=#1474 id=1474 data-nosnippet>1474</a> observed_external_addr: watch::Sender::new(<span class="prelude-val">None</span>),
<a href=#1475 id=1475 data-nosnippet>1475</a> nat_traversal_updates: tokio::sync::broadcast::channel(<span class="number">32</span>).<span class="number">0</span>,
<a href=#1476 id=1476 data-nosnippet>1476</a> on_closed: Vec::new(),
<a href=#1477 id=1477 data-nosnippet>1477</a> final_path_stats: Default::default(),
<a href=#1478 id=1478 data-nosnippet>1478</a> path_refs: Default::default(),
<a href=#1479 id=1479 data-nosnippet>1479</a> }
<a href=#1480 id=1480 data-nosnippet>1480</a> }
<a href=#1481 id=1481 data-nosnippet>1481</a>
<a href=#1482 id=1482 data-nosnippet>1482</a> <span class="kw">fn </span>drive_transmit(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; io::Result&lt;bool&gt; {
<a href=#1483 id=1483 data-nosnippet>1483</a> <span class="kw">let </span>now = <span class="self">self</span>.runtime.now();
<a href=#1484 id=1484 data-nosnippet>1484</a> <span class="kw">let </span><span class="kw-2">mut </span>transmits = <span class="number">0</span>;
<a href=#1485 id=1485 data-nosnippet>1485</a>
<a href=#1486 id=1486 data-nosnippet>1486</a> <span class="kw">let </span>max_datagrams = <span class="self">self
<a href=#1487 id=1487 data-nosnippet>1487</a> </span>.sender
<a href=#1488 id=1488 data-nosnippet>1488</a> .max_transmit_segments()
<a href=#1489 id=1489 data-nosnippet>1489</a> .min(MAX_TRANSMIT_SEGMENTS);
<a href=#1490 id=1490 data-nosnippet>1490</a>
<a href=#1491 id=1491 data-nosnippet>1491</a> <span class="kw">loop </span>{
<a href=#1492 id=1492 data-nosnippet>1492</a> <span class="comment">// Retry the last transmit, or get a new one.
<a href=#1493 id=1493 data-nosnippet>1493</a> </span><span class="kw">let </span>t = <span class="kw">match </span><span class="self">self</span>.buffered_transmit.take() {
<a href=#1494 id=1494 data-nosnippet>1494</a> <span class="prelude-val">Some</span>(t) =&gt; t,
<a href=#1495 id=1495 data-nosnippet>1495</a> <span class="prelude-val">None </span>=&gt; {
<a href=#1496 id=1496 data-nosnippet>1496</a> <span class="self">self</span>.send_buffer.clear();
<a href=#1497 id=1497 data-nosnippet>1497</a> <span class="kw">match </span><span class="self">self
<a href=#1498 id=1498 data-nosnippet>1498</a> </span>.inner
<a href=#1499 id=1499 data-nosnippet>1499</a> .poll_transmit(now, max_datagrams, <span class="kw-2">&amp;mut </span><span class="self">self</span>.send_buffer)
<a href=#1500 id=1500 data-nosnippet>1500</a> {
<a href=#1501 id=1501 data-nosnippet>1501</a> <span class="prelude-val">Some</span>(t) =&gt; {
<a href=#1502 id=1502 data-nosnippet>1502</a> transmits += <span class="kw">match </span>t.segment_size {
<a href=#1503 id=1503 data-nosnippet>1503</a> <span class="prelude-val">None </span>=&gt; <span class="number">1</span>,
<a href=#1504 id=1504 data-nosnippet>1504</a> <span class="prelude-val">Some</span>(s) =&gt; t.size.div_ceil(s), <span class="comment">// round up
<a href=#1505 id=1505 data-nosnippet>1505</a> </span>};
<a href=#1506 id=1506 data-nosnippet>1506</a> t
<a href=#1507 id=1507 data-nosnippet>1507</a> }
<a href=#1508 id=1508 data-nosnippet>1508</a> <span class="prelude-val">None </span>=&gt; <span class="kw">break</span>,
<a href=#1509 id=1509 data-nosnippet>1509</a> }
<a href=#1510 id=1510 data-nosnippet>1510</a> }
<a href=#1511 id=1511 data-nosnippet>1511</a> };
<a href=#1512 id=1512 data-nosnippet>1512</a>
<a href=#1513 id=1513 data-nosnippet>1513</a> <span class="kw">let </span>len = t.size;
<a href=#1514 id=1514 data-nosnippet>1514</a> <span class="kw">match </span><span class="self">self
<a href=#1515 id=1515 data-nosnippet>1515</a> </span>.sender
<a href=#1516 id=1516 data-nosnippet>1516</a> .as_mut()
<a href=#1517 id=1517 data-nosnippet>1517</a> .poll_send(<span class="kw-2">&amp;</span>udp_transmit(<span class="kw-2">&amp;</span>t, <span class="kw-2">&amp;</span><span class="self">self</span>.send_buffer[..len]), cx)
<a href=#1518 id=1518 data-nosnippet>1518</a> {
<a href=#1519 id=1519 data-nosnippet>1519</a> Poll::Pending =&gt; {
<a href=#1520 id=1520 data-nosnippet>1520</a> <span class="self">self</span>.buffered_transmit = <span class="prelude-val">Some</span>(t);
<a href=#1521 id=1521 data-nosnippet>1521</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="bool-val">false</span>);
<a href=#1522 id=1522 data-nosnippet>1522</a> }
<a href=#1523 id=1523 data-nosnippet>1523</a> Poll::Ready(<span class="prelude-val">Err</span>(e)) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(e),
<a href=#1524 id=1524 data-nosnippet>1524</a> Poll::Ready(<span class="prelude-val">Ok</span>(())) =&gt; {}
<a href=#1525 id=1525 data-nosnippet>1525</a> }
<a href=#1526 id=1526 data-nosnippet>1526</a>
<a href=#1527 id=1527 data-nosnippet>1527</a> <span class="kw">if </span>transmits &gt;= MAX_TRANSMIT_DATAGRAMS {
<a href=#1528 id=1528 data-nosnippet>1528</a> <span class="comment">// TODO: What isn't ideal here yet is that if we don't poll all
<a href=#1529 id=1529 data-nosnippet>1529</a> // datagrams that could be sent we don't go into the `app_limited`
<a href=#1530 id=1530 data-nosnippet>1530</a> // state and CWND continues to grow until we get here the next time.
<a href=#1531 id=1531 data-nosnippet>1531</a> // See https://github.com/quinn-rs/quinn/issues/1126
<a href=#1532 id=1532 data-nosnippet>1532</a> </span><span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="bool-val">true</span>);
<a href=#1533 id=1533 data-nosnippet>1533</a> }
<a href=#1534 id=1534 data-nosnippet>1534</a> }
<a href=#1535 id=1535 data-nosnippet>1535</a>
<a href=#1536 id=1536 data-nosnippet>1536</a> <span class="prelude-val">Ok</span>(<span class="bool-val">false</span>)
<a href=#1537 id=1537 data-nosnippet>1537</a> }
<a href=#1538 id=1538 data-nosnippet>1538</a>
<a href=#1539 id=1539 data-nosnippet>1539</a> <span class="kw">fn </span>forward_endpoint_events(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#1540 id=1540 data-nosnippet>1540</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(event) = <span class="self">self</span>.inner.poll_endpoint_events() {
<a href=#1541 id=1541 data-nosnippet>1541</a> <span class="comment">// If the endpoint driver is gone, noop.
<a href=#1542 id=1542 data-nosnippet>1542</a> </span><span class="kw">let _ </span>= <span class="self">self</span>.endpoint_events.send((<span class="self">self</span>.handle, event));
<a href=#1543 id=1543 data-nosnippet>1543</a> }
<a href=#1544 id=1544 data-nosnippet>1544</a> }
<a href=#1545 id=1545 data-nosnippet>1545</a>
<a href=#1546 id=1546 data-nosnippet>1546</a> <span class="doccomment">/// If this returns `Err`, the endpoint is dead, so the driver should exit immediately.
<a href=#1547 id=1547 data-nosnippet>1547</a> </span><span class="kw">fn </span>process_conn_events(
<a href=#1548 id=1548 data-nosnippet>1548</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#1549 id=1549 data-nosnippet>1549</a> shared: <span class="kw-2">&amp;</span>Shared,
<a href=#1550 id=1550 data-nosnippet>1550</a> cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
<a href=#1551 id=1551 data-nosnippet>1551</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;(), ConnectionError&gt; {
<a href=#1552 id=1552 data-nosnippet>1552</a> <span class="kw">loop </span>{
<a href=#1553 id=1553 data-nosnippet>1553</a> <span class="kw">match </span><span class="self">self</span>.conn_events.poll_recv(cx) {
<a href=#1554 id=1554 data-nosnippet>1554</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::Rebind(sender))) =&gt; {
<a href=#1555 id=1555 data-nosnippet>1555</a> <span class="self">self</span>.sender = sender;
<a href=#1556 id=1556 data-nosnippet>1556</a> <span class="self">self</span>.inner.handle_network_change(<span class="prelude-val">None</span>, <span class="self">self</span>.runtime.now());
<a href=#1557 id=1557 data-nosnippet>1557</a> }
<a href=#1558 id=1558 data-nosnippet>1558</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::LocalAddressChanged(hint))) =&gt; {
<a href=#1559 id=1559 data-nosnippet>1559</a> <span class="self">self</span>.inner
<a href=#1560 id=1560 data-nosnippet>1560</a> .handle_network_change(hint.as_deref().map(|x| x <span class="kw">as _</span>), <span class="self">self</span>.runtime.now());
<a href=#1561 id=1561 data-nosnippet>1561</a> }
<a href=#1562 id=1562 data-nosnippet>1562</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::Proto(event))) =&gt; {
<a href=#1563 id=1563 data-nosnippet>1563</a> <span class="self">self</span>.inner.handle_event(event);
<a href=#1564 id=1564 data-nosnippet>1564</a> }
<a href=#1565 id=1565 data-nosnippet>1565</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::Close { reason, error_code })) =&gt; {
<a href=#1566 id=1566 data-nosnippet>1566</a> <span class="self">self</span>.close(error_code, reason, shared);
<a href=#1567 id=1567 data-nosnippet>1567</a> }
<a href=#1568 id=1568 data-nosnippet>1568</a> Poll::Ready(<span class="prelude-val">None</span>) =&gt; {
<a href=#1569 id=1569 data-nosnippet>1569</a> <span class="kw">return </span><span class="prelude-val">Err</span>(ConnectionError::TransportError(TransportError::new(
<a href=#1570 id=1570 data-nosnippet>1570</a> TransportErrorCode::INTERNAL_ERROR,
<a href=#1571 id=1571 data-nosnippet>1571</a> <span class="string">"endpoint driver future was dropped"</span>.to_string(),
<a href=#1572 id=1572 data-nosnippet>1572</a> )));
<a href=#1573 id=1573 data-nosnippet>1573</a> }
<a href=#1574 id=1574 data-nosnippet>1574</a> Poll::Pending =&gt; {
<a href=#1575 id=1575 data-nosnippet>1575</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#1576 id=1576 data-nosnippet>1576</a> }
<a href=#1577 id=1577 data-nosnippet>1577</a> }
<a href=#1578 id=1578 data-nosnippet>1578</a> }
<a href=#1579 id=1579 data-nosnippet>1579</a> }
<a href=#1580 id=1580 data-nosnippet>1580</a>
<a href=#1581 id=1581 data-nosnippet>1581</a> <span class="kw">fn </span>forward_app_events(<span class="kw-2">&amp;mut </span><span class="self">self</span>, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1582 id=1582 data-nosnippet>1582</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(event) = <span class="self">self</span>.inner.poll() {
<a href=#1583 id=1583 data-nosnippet>1583</a> <span class="kw">use </span>proto::Event::<span class="kw-2">*</span>;
<a href=#1584 id=1584 data-nosnippet>1584</a> <span class="kw">match </span>event {
<a href=#1585 id=1585 data-nosnippet>1585</a> HandshakeDataReady =&gt; {
<a href=#1586 id=1586 data-nosnippet>1586</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_handshake_data.take() {
<a href=#1587 id=1587 data-nosnippet>1587</a> <span class="kw">let _ </span>= x.send(());
<a href=#1588 id=1588 data-nosnippet>1588</a> }
<a href=#1589 id=1589 data-nosnippet>1589</a> }
<a href=#1590 id=1590 data-nosnippet>1590</a> Connected =&gt; {
<a href=#1591 id=1591 data-nosnippet>1591</a> <span class="self">self</span>.connected = <span class="bool-val">true</span>;
<a href=#1592 id=1592 data-nosnippet>1592</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_connected.take() {
<a href=#1593 id=1593 data-nosnippet>1593</a> <span class="comment">// We don't care if the on-connected future was dropped
<a href=#1594 id=1594 data-nosnippet>1594</a> </span><span class="kw">let _ </span>= x.send(<span class="self">self</span>.inner.accepted_0rtt());
<a href=#1595 id=1595 data-nosnippet>1595</a> }
<a href=#1596 id=1596 data-nosnippet>1596</a> <span class="kw">if </span><span class="self">self</span>.inner.side().is_client() &amp;&amp; !<span class="self">self</span>.inner.accepted_0rtt() {
<a href=#1597 id=1597 data-nosnippet>1597</a> <span class="comment">// Wake up rejected 0-RTT streams so they can fail immediately with
<a href=#1598 id=1598 data-nosnippet>1598</a> // `ZeroRttRejected` errors.
<a href=#1599 id=1599 data-nosnippet>1599</a> </span>wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers);
<a href=#1600 id=1600 data-nosnippet>1600</a> wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_readers);
<a href=#1601 id=1601 data-nosnippet>1601</a> wake_all_notify(<span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped);
<a href=#1602 id=1602 data-nosnippet>1602</a> }
<a href=#1603 id=1603 data-nosnippet>1603</a> }
<a href=#1604 id=1604 data-nosnippet>1604</a> HandshakeConfirmed =&gt; {
<a href=#1605 id=1605 data-nosnippet>1605</a> <span class="self">self</span>.handshake_confirmed = <span class="bool-val">true</span>;
<a href=#1606 id=1606 data-nosnippet>1606</a> shared.handshake_confirmed.notify_waiters();
<a href=#1607 id=1607 data-nosnippet>1607</a> }
<a href=#1608 id=1608 data-nosnippet>1608</a> ConnectionLost { reason } =&gt; {
<a href=#1609 id=1609 data-nosnippet>1609</a> <span class="self">self</span>.terminate(reason, shared);
<a href=#1610 id=1610 data-nosnippet>1610</a> }
<a href=#1611 id=1611 data-nosnippet>1611</a> Stream(StreamEvent::Writable { id }) =&gt; wake_stream(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers),
<a href=#1612 id=1612 data-nosnippet>1612</a> Stream(StreamEvent::Opened { dir: Dir::Uni }) =&gt; {
<a href=#1613 id=1613 data-nosnippet>1613</a> shared.stream_incoming[Dir::Uni <span class="kw">as </span>usize].notify_waiters();
<a href=#1614 id=1614 data-nosnippet>1614</a> }
<a href=#1615 id=1615 data-nosnippet>1615</a> Stream(StreamEvent::Opened { dir: Dir::Bi }) =&gt; {
<a href=#1616 id=1616 data-nosnippet>1616</a> shared.stream_incoming[Dir::Bi <span class="kw">as </span>usize].notify_waiters();
<a href=#1617 id=1617 data-nosnippet>1617</a> }
<a href=#1618 id=1618 data-nosnippet>1618</a> DatagramReceived =&gt; {
<a href=#1619 id=1619 data-nosnippet>1619</a> shared.datagram_received.notify_waiters();
<a href=#1620 id=1620 data-nosnippet>1620</a> }
<a href=#1621 id=1621 data-nosnippet>1621</a> DatagramsUnblocked =&gt; {
<a href=#1622 id=1622 data-nosnippet>1622</a> shared.datagrams_unblocked.notify_waiters();
<a href=#1623 id=1623 data-nosnippet>1623</a> }
<a href=#1624 id=1624 data-nosnippet>1624</a> Stream(StreamEvent::Readable { id }) =&gt; wake_stream(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_readers),
<a href=#1625 id=1625 data-nosnippet>1625</a> Stream(StreamEvent::Available { dir }) =&gt; {
<a href=#1626 id=1626 data-nosnippet>1626</a> <span class="comment">// Might mean any number of streams are ready, so we wake up everyone
<a href=#1627 id=1627 data-nosnippet>1627</a> </span>shared.stream_budget_available[dir <span class="kw">as </span>usize].notify_waiters();
<a href=#1628 id=1628 data-nosnippet>1628</a> }
<a href=#1629 id=1629 data-nosnippet>1629</a> Stream(StreamEvent::Finished { id }) =&gt; wake_stream_notify(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped),
<a href=#1630 id=1630 data-nosnippet>1630</a> Stream(StreamEvent::Stopped { id, .. }) =&gt; {
<a href=#1631 id=1631 data-nosnippet>1631</a> wake_stream_notify(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped);
<a href=#1632 id=1632 data-nosnippet>1632</a> wake_stream(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers);
<a href=#1633 id=1633 data-nosnippet>1633</a> }
<a href=#1634 id=1634 data-nosnippet>1634</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::ObservedAddr { addr: observed, .. }) =&gt; {
<a href=#1635 id=1635 data-nosnippet>1635</a> <span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1636 id=1636 data-nosnippet>1636</a> <span class="self">self</span>.observed_external_addr.send_if_modified(|addr| {
<a href=#1637 id=1637 data-nosnippet>1637</a> <span class="kw">let </span>old = addr.replace(observed);
<a href=#1638 id=1638 data-nosnippet>1638</a> old != <span class="kw-2">*</span>addr
<a href=#1639 id=1639 data-nosnippet>1639</a> });
<a href=#1640 id=1640 data-nosnippet>1640</a> }
<a href=#1641 id=1641 data-nosnippet>1641</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::Opened { id }) =&gt; {
<a href=#1642 id=1642 data-nosnippet>1642</a> <span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1643 id=1643 data-nosnippet>1643</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sender) = <span class="self">self</span>.open_path.remove(<span class="kw-2">&amp;</span>id) {
<a href=#1644 id=1644 data-nosnippet>1644</a> sender.send_modify(|value| <span class="kw-2">*</span>value = <span class="prelude-val">Ok</span>(()));
<a href=#1645 id=1645 data-nosnippet>1645</a> }
<a href=#1646 id=1646 data-nosnippet>1646</a> }
<a href=#1647 id=1647 data-nosnippet>1647</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::Discarded { id, <span class="kw-2">ref </span>path_stats }) =&gt; {
<a href=#1648 id=1648 data-nosnippet>1648</a> <span class="kw">if </span><span class="self">self</span>.path_refs.contains_key(<span class="kw-2">&amp;</span>id) {
<a href=#1649 id=1649 data-nosnippet>1649</a> <span class="self">self</span>.final_path_stats.insert(id, <span class="kw-2">*</span>path_stats.clone());
<a href=#1650 id=1650 data-nosnippet>1650</a> }
<a href=#1651 id=1651 data-nosnippet>1651</a> <span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1652 id=1652 data-nosnippet>1652</a> }
<a href=#1653 id=1653 data-nosnippet>1653</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::Abandoned { id, .. }) =&gt; {
<a href=#1654 id=1654 data-nosnippet>1654</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sender) = <span class="self">self</span>.open_path.remove(<span class="kw-2">&amp;</span>id) {
<a href=#1655 id=1655 data-nosnippet>1655</a> <span class="comment">// We don't care for the reason why this path was closed here, because semantically
<a href=#1656 id=1656 data-nosnippet>1656</a> // all close reasons for a path that has not yet been opened equals to `ValidationFailed`.
<a href=#1657 id=1657 data-nosnippet>1657</a> // With the noq API, there is no way to application-close a not-yet-opened path, so
<a href=#1658 id=1658 data-nosnippet>1658</a> // `ApplicationClosed` cannot occur. And all other variants will only occur for paths
<a href=#1659 id=1659 data-nosnippet>1659</a> // that have already been opened.
<a href=#1660 id=1660 data-nosnippet>1660</a> // The previous iteration of this code had another event `PathEvent::LocallyClosed` which
<a href=#1661 id=1661 data-nosnippet>1661</a> // contained a `PathError`, but that was only ever set to `ValidationFailed`.
<a href=#1662 id=1662 data-nosnippet>1662</a> </span><span class="kw">let </span>error = PathError::ValidationFailed;
<a href=#1663 id=1663 data-nosnippet>1663</a> sender.send_modify(|value| <span class="kw-2">*</span>value = <span class="prelude-val">Err</span>(error));
<a href=#1664 id=1664 data-nosnippet>1664</a> }
<a href=#1665 id=1665 data-nosnippet>1665</a> <span class="comment">// this will happen also for already opened paths
<a href=#1666 id=1666 data-nosnippet>1666</a> </span><span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1667 id=1667 data-nosnippet>1667</a> }
<a href=#1668 id=1668 data-nosnippet>1668</a> Path(evt @ PathEvent::RemoteStatus { .. }) =&gt; {
<a href=#1669 id=1669 data-nosnippet>1669</a> <span class="self">self</span>.path_events.send(evt).ok();
<a href=#1670 id=1670 data-nosnippet>1670</a> }
<a href=#1671 id=1671 data-nosnippet>1671</a> NatTraversal(update) =&gt; {
<a href=#1672 id=1672 data-nosnippet>1672</a> <span class="self">self</span>.nat_traversal_updates.send(update).ok();
<a href=#1673 id=1673 data-nosnippet>1673</a> }
<a href=#1674 id=1674 data-nosnippet>1674</a> }
<a href=#1675 id=1675 data-nosnippet>1675</a> }
<a href=#1676 id=1676 data-nosnippet>1676</a> }
<a href=#1677 id=1677 data-nosnippet>1677</a>
<a href=#1678 id=1678 data-nosnippet>1678</a> <span class="kw">fn </span>drive_timer(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; bool {
<a href=#1679 id=1679 data-nosnippet>1679</a> <span class="comment">// Check whether we need to (re)set the timer. If so, we must poll again to ensure the
<a href=#1680 id=1680 data-nosnippet>1680</a> // timer is registered with the runtime (and check whether it's already
<a href=#1681 id=1681 data-nosnippet>1681</a> // expired).
<a href=#1682 id=1682 data-nosnippet>1682</a> </span><span class="kw">match </span><span class="self">self</span>.inner.poll_timeout() {
<a href=#1683 id=1683 data-nosnippet>1683</a> <span class="prelude-val">Some</span>(deadline) =&gt; {
<a href=#1684 id=1684 data-nosnippet>1684</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(delay) = <span class="kw-2">&amp;mut </span><span class="self">self</span>.timer {
<a href=#1685 id=1685 data-nosnippet>1685</a> <span class="comment">// There is no need to reset the tokio timer if the deadline
<a href=#1686 id=1686 data-nosnippet>1686</a> // did not change
<a href=#1687 id=1687 data-nosnippet>1687</a> </span><span class="kw">if </span><span class="self">self
<a href=#1688 id=1688 data-nosnippet>1688</a> </span>.timer_deadline
<a href=#1689 id=1689 data-nosnippet>1689</a> .map(|current_deadline| current_deadline != deadline)
<a href=#1690 id=1690 data-nosnippet>1690</a> .unwrap_or(<span class="bool-val">true</span>)
<a href=#1691 id=1691 data-nosnippet>1691</a> {
<a href=#1692 id=1692 data-nosnippet>1692</a> delay.as_mut().reset(deadline);
<a href=#1693 id=1693 data-nosnippet>1693</a> }
<a href=#1694 id=1694 data-nosnippet>1694</a> } <span class="kw">else </span>{
<a href=#1695 id=1695 data-nosnippet>1695</a> <span class="self">self</span>.timer = <span class="prelude-val">Some</span>(<span class="self">self</span>.runtime.new_timer(deadline));
<a href=#1696 id=1696 data-nosnippet>1696</a> }
<a href=#1697 id=1697 data-nosnippet>1697</a> <span class="comment">// Store the actual expiration time of the timer
<a href=#1698 id=1698 data-nosnippet>1698</a> </span><span class="self">self</span>.timer_deadline = <span class="prelude-val">Some</span>(deadline);
<a href=#1699 id=1699 data-nosnippet>1699</a> }
<a href=#1700 id=1700 data-nosnippet>1700</a> <span class="prelude-val">None </span>=&gt; {
<a href=#1701 id=1701 data-nosnippet>1701</a> <span class="self">self</span>.timer_deadline = <span class="prelude-val">None</span>;
<a href=#1702 id=1702 data-nosnippet>1702</a> <span class="kw">return </span><span class="bool-val">false</span>;
<a href=#1703 id=1703 data-nosnippet>1703</a> }
<a href=#1704 id=1704 data-nosnippet>1704</a> }
<a href=#1705 id=1705 data-nosnippet>1705</a>
<a href=#1706 id=1706 data-nosnippet>1706</a> <span class="kw">if </span><span class="self">self</span>.timer_deadline.is_none() {
<a href=#1707 id=1707 data-nosnippet>1707</a> <span class="kw">return </span><span class="bool-val">false</span>;
<a href=#1708 id=1708 data-nosnippet>1708</a> }
<a href=#1709 id=1709 data-nosnippet>1709</a>
<a href=#1710 id=1710 data-nosnippet>1710</a> <span class="kw">let </span>delay = <span class="self">self
<a href=#1711 id=1711 data-nosnippet>1711</a> </span>.timer
<a href=#1712 id=1712 data-nosnippet>1712</a> .as_mut()
<a href=#1713 id=1713 data-nosnippet>1713</a> .expect(<span class="string">"timer must exist in this state"</span>)
<a href=#1714 id=1714 data-nosnippet>1714</a> .as_mut();
<a href=#1715 id=1715 data-nosnippet>1715</a> <span class="kw">if </span>delay.poll(cx).is_pending() {
<a href=#1716 id=1716 data-nosnippet>1716</a> <span class="comment">// Since there wasn't a timeout event, there is nothing new
<a href=#1717 id=1717 data-nosnippet>1717</a> // for the connection to do
<a href=#1718 id=1718 data-nosnippet>1718</a> </span><span class="kw">return </span><span class="bool-val">false</span>;
<a href=#1719 id=1719 data-nosnippet>1719</a> }
<a href=#1720 id=1720 data-nosnippet>1720</a>
<a href=#1721 id=1721 data-nosnippet>1721</a> <span class="comment">// A timer expired, so the caller needs to check for
<a href=#1722 id=1722 data-nosnippet>1722</a> // new transmits, which might cause new timers to be set.
<a href=#1723 id=1723 data-nosnippet>1723</a> </span><span class="self">self</span>.inner.handle_timeout(<span class="self">self</span>.runtime.now());
<a href=#1724 id=1724 data-nosnippet>1724</a> <span class="self">self</span>.timer_deadline = <span class="prelude-val">None</span>;
<a href=#1725 id=1725 data-nosnippet>1725</a> <span class="bool-val">true
<a href=#1726 id=1726 data-nosnippet>1726</a> </span>}
<a href=#1727 id=1727 data-nosnippet>1727</a>
<a href=#1728 id=1728 data-nosnippet>1728</a> <span class="doccomment">/// Wake up a blocked `Driver` task to process I/O
<a href=#1729 id=1729 data-nosnippet>1729</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>wake(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#1730 id=1730 data-nosnippet>1730</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.driver.take() {
<a href=#1731 id=1731 data-nosnippet>1731</a> x.wake();
<a href=#1732 id=1732 data-nosnippet>1732</a> }
<a href=#1733 id=1733 data-nosnippet>1733</a> }
<a href=#1734 id=1734 data-nosnippet>1734</a>
<a href=#1735 id=1735 data-nosnippet>1735</a> <span class="doccomment">/// Used to wake up all blocked futures when the connection becomes closed for any reason
<a href=#1736 id=1736 data-nosnippet>1736</a> </span><span class="kw">fn </span>terminate(<span class="kw-2">&amp;mut </span><span class="self">self</span>, reason: ConnectionError, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1737 id=1737 data-nosnippet>1737</a> <span class="self">self</span>.error = <span class="prelude-val">Some</span>(reason.clone());
<a href=#1738 id=1738 data-nosnippet>1738</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_handshake_data.take() {
<a href=#1739 id=1739 data-nosnippet>1739</a> <span class="kw">let _ </span>= x.send(());
<a href=#1740 id=1740 data-nosnippet>1740</a> }
<a href=#1741 id=1741 data-nosnippet>1741</a> wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers);
<a href=#1742 id=1742 data-nosnippet>1742</a> wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_readers);
<a href=#1743 id=1743 data-nosnippet>1743</a> shared.stream_budget_available[Dir::Uni <span class="kw">as </span>usize].notify_waiters();
<a href=#1744 id=1744 data-nosnippet>1744</a> shared.stream_budget_available[Dir::Bi <span class="kw">as </span>usize].notify_waiters();
<a href=#1745 id=1745 data-nosnippet>1745</a> shared.stream_incoming[Dir::Uni <span class="kw">as </span>usize].notify_waiters();
<a href=#1746 id=1746 data-nosnippet>1746</a> shared.stream_incoming[Dir::Bi <span class="kw">as </span>usize].notify_waiters();
<a href=#1747 id=1747 data-nosnippet>1747</a> shared.datagram_received.notify_waiters();
<a href=#1748 id=1748 data-nosnippet>1748</a> shared.datagrams_unblocked.notify_waiters();
<a href=#1749 id=1749 data-nosnippet>1749</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_connected.take() {
<a href=#1750 id=1750 data-nosnippet>1750</a> <span class="kw">let _ </span>= x.send(<span class="bool-val">false</span>);
<a href=#1751 id=1751 data-nosnippet>1751</a> }
<a href=#1752 id=1752 data-nosnippet>1752</a> shared.handshake_confirmed.notify_waiters();
<a href=#1753 id=1753 data-nosnippet>1753</a> wake_all_notify(<span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped);
<a href=#1754 id=1754 data-nosnippet>1754</a> shared.closed.notify_waiters();
<a href=#1755 id=1755 data-nosnippet>1755</a>
<a href=#1756 id=1756 data-nosnippet>1756</a> <span class="comment">// Send to the registered on_closed futures.
<a href=#1757 id=1757 data-nosnippet>1757</a> </span><span class="kw">if </span>!<span class="self">self</span>.on_closed.is_empty() {
<a href=#1758 id=1758 data-nosnippet>1758</a> <span class="kw">let </span>closed = Closed::new(<span class="self">self</span>, reason);
<a href=#1759 id=1759 data-nosnippet>1759</a> <span class="kw">for </span>tx <span class="kw">in </span><span class="self">self</span>.on_closed.drain(..) {
<a href=#1760 id=1760 data-nosnippet>1760</a> tx.send(closed.clone()).ok();
<a href=#1761 id=1761 data-nosnippet>1761</a> }
<a href=#1762 id=1762 data-nosnippet>1762</a> }
<a href=#1763 id=1763 data-nosnippet>1763</a> }
<a href=#1764 id=1764 data-nosnippet>1764</a>
<a href=#1765 id=1765 data-nosnippet>1765</a> <span class="kw">fn </span>close(<span class="kw-2">&amp;mut </span><span class="self">self</span>, error_code: VarInt, reason: Bytes, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1766 id=1766 data-nosnippet>1766</a> <span class="self">self</span>.inner.close(<span class="self">self</span>.runtime.now(), error_code, reason);
<a href=#1767 id=1767 data-nosnippet>1767</a> <span class="self">self</span>.terminate(ConnectionError::LocallyClosed, shared);
<a href=#1768 id=1768 data-nosnippet>1768</a> <span class="self">self</span>.wake();
<a href=#1769 id=1769 data-nosnippet>1769</a> }
<a href=#1770 id=1770 data-nosnippet>1770</a>
<a href=#1771 id=1771 data-nosnippet>1771</a> <span class="doccomment">/// Close for a reason other than the application's explicit request
<a href=#1772 id=1772 data-nosnippet>1772</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>implicit_close(<span class="kw-2">&amp;mut </span><span class="self">self</span>, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1773 id=1773 data-nosnippet>1773</a> <span class="self">self</span>.close(<span class="number">0u32</span>.into(), Bytes::new(), shared);
<a href=#1774 id=1774 data-nosnippet>1774</a> }
<a href=#1775 id=1775 data-nosnippet>1775</a>
<a href=#1776 id=1776 data-nosnippet>1776</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>check_0rtt(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), ()&gt; {
<a href=#1777 id=1777 data-nosnippet>1777</a> <span class="kw">if </span><span class="self">self</span>.inner.is_handshaking()
<a href=#1778 id=1778 data-nosnippet>1778</a> || <span class="self">self</span>.inner.accepted_0rtt()
<a href=#1779 id=1779 data-nosnippet>1779</a> || <span class="self">self</span>.inner.side().is_server()
<a href=#1780 id=1780 data-nosnippet>1780</a> {
<a href=#1781 id=1781 data-nosnippet>1781</a> <span class="prelude-val">Ok</span>(())
<a href=#1782 id=1782 data-nosnippet>1782</a> } <span class="kw">else </span>{
<a href=#1783 id=1783 data-nosnippet>1783</a> <span class="prelude-val">Err</span>(())
<a href=#1784 id=1784 data-nosnippet>1784</a> }
<a href=#1785 id=1785 data-nosnippet>1785</a> }
<a href=#1786 id=1786 data-nosnippet>1786</a>
<a href=#1787 id=1787 data-nosnippet>1787</a> <span class="doccomment">/// Returns [`PathStats`] for a path, if available.
<a href=#1788 id=1788 data-nosnippet>1788</a> ///
<a href=#1789 id=1789 data-nosnippet>1789</a> /// This gets the stats from [`proto::Connection`]. If that returns `None`
<a href=#1790 id=1790 data-nosnippet>1790</a> /// it gets them from `Self::final_path_stats` instead.
<a href=#1791 id=1791 data-nosnippet>1791</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>path_stats(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path_id: PathId) -&gt; <span class="prelude-ty">Option</span>&lt;PathStats&gt; {
<a href=#1792 id=1792 data-nosnippet>1792</a> <span class="self">self</span>.inner
<a href=#1793 id=1793 data-nosnippet>1793</a> .path_stats(path_id)
<a href=#1794 id=1794 data-nosnippet>1794</a> .or_else(|| <span class="self">self</span>.final_path_stats.get(<span class="kw-2">&amp;</span>path_id).copied())
<a href=#1795 id=1795 data-nosnippet>1795</a> }
<a href=#1796 id=1796 data-nosnippet>1796</a>
<a href=#1797 id=1797 data-nosnippet>1797</a> <span class="doccomment">/// Acquire a [`PathRef`] for a path id, bumping its reference counter by 1.
<a href=#1798 id=1798 data-nosnippet>1798</a> ///
<a href=#1799 id=1799 data-nosnippet>1799</a> /// The returned [`Arc`] is shared with the entry stored in [`Self::path_refs`].
<a href=#1800 id=1800 data-nosnippet>1800</a> /// Callers must own the returned reference for the lifetime of the [`Path`] or
<a href=#1801 id=1801 data-nosnippet>1801</a> /// [`WeakPathHandle`] it backs, and decrement the counter on drop.
<a href=#1802 id=1802 data-nosnippet>1802</a> ///
<a href=#1803 id=1803 data-nosnippet>1803</a> /// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#1804 id=1804 data-nosnippet>1804</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>acquire_path_ref(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path_id: PathId) -&gt; Arc&lt;PathRef&gt; {
<a href=#1805 id=1805 data-nosnippet>1805</a> <span class="kw">let </span>path_ref = <span class="self">self</span>.path_refs.entry(path_id).or_default().clone();
<a href=#1806 id=1806 data-nosnippet>1806</a> path_ref.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#1807 id=1807 data-nosnippet>1807</a> path_ref
<a href=#1808 id=1808 data-nosnippet>1808</a> }
<a href=#1809 id=1809 data-nosnippet>1809</a>}
<a href=#1810 id=1810 data-nosnippet>1810</a>
<a href=#1811 id=1811 data-nosnippet>1811</a><span class="doccomment">/// Reference counter for live [`Path`] and [`WeakPathHandle`] handles for a single path id.
<a href=#1812 id=1812 data-nosnippet>1812</a>///
<a href=#1813 id=1813 data-nosnippet>1813</a>/// The counter is stored as an [`AtomicUsize`] so that cloning or dropping a [`Path`] or
<a href=#1814 id=1814 data-nosnippet>1814</a>/// [`WeakPathHandle`] only needs to bump or decrement an atomic, instead of locking the
<a href=#1815 id=1815 data-nosnippet>1815</a>/// connection state. The state lock is taken only when allocating the entry (on first
<a href=#1816 id=1816 data-nosnippet>1816</a>/// construction) or when the count drops to zero, so the entry can be removed and any
<a href=#1817 id=1817 data-nosnippet>1817</a>/// cached final path stats can be released.
<a href=#1818 id=1818 data-nosnippet>1818</a>///
<a href=#1819 id=1819 data-nosnippet>1819</a>/// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#1820 id=1820 data-nosnippet>1820</a></span><span class="attr">#[derive(Debug, Default)]
<a href=#1821 id=1821 data-nosnippet>1821</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>PathRef {
<a href=#1822 id=1822 data-nosnippet>1822</a> <span class="kw">pub</span>(<span class="kw">crate</span>) ref_count: AtomicUsize,
<a href=#1823 id=1823 data-nosnippet>1823</a>}
<a href=#1824 id=1824 data-nosnippet>1824</a>
<a href=#1825 id=1825 data-nosnippet>1825</a><span class="kw">impl </span>Drop <span class="kw">for </span>State {
<a href=#1826 id=1826 data-nosnippet>1826</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#1827 id=1827 data-nosnippet>1827</a> <span class="kw">if </span>!<span class="self">self</span>.inner.is_drained() {
<a href=#1828 id=1828 data-nosnippet>1828</a> <span class="comment">// Ensure the endpoint can tidy up
<a href=#1829 id=1829 data-nosnippet>1829</a> </span><span class="kw">let _ </span>= <span class="self">self
<a href=#1830 id=1830 data-nosnippet>1830</a> </span>.endpoint_events
<a href=#1831 id=1831 data-nosnippet>1831</a> .send((<span class="self">self</span>.handle, proto::EndpointEvent::drained()));
<a href=#1832 id=1832 data-nosnippet>1832</a> }
<a href=#1833 id=1833 data-nosnippet>1833</a>
<a href=#1834 id=1834 data-nosnippet>1834</a> <span class="kw">if </span>!<span class="self">self</span>.on_closed.is_empty()
<a href=#1835 id=1835 data-nosnippet>1835</a> &amp;&amp; <span class="kw">let </span><span class="prelude-val">Some</span>(reason) = <span class="self">self</span>.error.clone()
<a href=#1836 id=1836 data-nosnippet>1836</a> {
<a href=#1837 id=1837 data-nosnippet>1837</a> <span class="comment">// Ensure that all on_closed oneshot senders are triggered before dropping.
<a href=#1838 id=1838 data-nosnippet>1838</a> </span><span class="kw">let </span>closed = Closed::new(<span class="self">self</span>, reason);
<a href=#1839 id=1839 data-nosnippet>1839</a> <span class="kw">for </span>tx <span class="kw">in </span><span class="self">self</span>.on_closed.drain(..) {
<a href=#1840 id=1840 data-nosnippet>1840</a> tx.send(closed.clone()).ok();
<a href=#1841 id=1841 data-nosnippet>1841</a> }
<a href=#1842 id=1842 data-nosnippet>1842</a> }
<a href=#1843 id=1843 data-nosnippet>1843</a> }
<a href=#1844 id=1844 data-nosnippet>1844</a>}
<a href=#1845 id=1845 data-nosnippet>1845</a>
<a href=#1846 id=1846 data-nosnippet>1846</a><span class="kw">impl </span>fmt::Debug <span class="kw">for </span>State {
<a href=#1847 id=1847 data-nosnippet>1847</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#1848 id=1848 data-nosnippet>1848</a> f.debug_struct(<span class="string">"State"</span>).field(<span class="string">"inner"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner).finish()
<a href=#1849 id=1849 data-nosnippet>1849</a> }
<a href=#1850 id=1850 data-nosnippet>1850</a>}
<a href=#1851 id=1851 data-nosnippet>1851</a>
<a href=#1852 id=1852 data-nosnippet>1852</a><span class="kw">fn </span>wake_stream(stream_id: StreamId, wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Waker&gt;) {
<a href=#1853 id=1853 data-nosnippet>1853</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(waker) = wakers.remove(<span class="kw-2">&amp;</span>stream_id) {
<a href=#1854 id=1854 data-nosnippet>1854</a> waker.wake();
<a href=#1855 id=1855 data-nosnippet>1855</a> }
<a href=#1856 id=1856 data-nosnippet>1856</a>}
<a href=#1857 id=1857 data-nosnippet>1857</a>
<a href=#1858 id=1858 data-nosnippet>1858</a><span class="kw">fn </span>wake_all(wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Waker&gt;) {
<a href=#1859 id=1859 data-nosnippet>1859</a> wakers.drain().for_each(|(<span class="kw">_</span>, waker)| waker.wake())
<a href=#1860 id=1860 data-nosnippet>1860</a>}
<a href=#1861 id=1861 data-nosnippet>1861</a>
<a href=#1862 id=1862 data-nosnippet>1862</a><span class="kw">fn </span>wake_stream_notify(stream_id: StreamId, wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Arc&lt;Notify&gt;&gt;) {
<a href=#1863 id=1863 data-nosnippet>1863</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(notify) = wakers.remove(<span class="kw-2">&amp;</span>stream_id) {
<a href=#1864 id=1864 data-nosnippet>1864</a> notify.notify_waiters()
<a href=#1865 id=1865 data-nosnippet>1865</a> }
<a href=#1866 id=1866 data-nosnippet>1866</a>}
<a href=#1867 id=1867 data-nosnippet>1867</a>
<a href=#1868 id=1868 data-nosnippet>1868</a><span class="kw">fn </span>wake_all_notify(wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Arc&lt;Notify&gt;&gt;) {
<a href=#1869 id=1869 data-nosnippet>1869</a> wakers
<a href=#1870 id=1870 data-nosnippet>1870</a> .drain()
<a href=#1871 id=1871 data-nosnippet>1871</a> .for_each(|(<span class="kw">_</span>, notify)| notify.notify_waiters())
<a href=#1872 id=1872 data-nosnippet>1872</a>}
<a href=#1873 id=1873 data-nosnippet>1873</a>
<a href=#1874 id=1874 data-nosnippet>1874</a><span class="doccomment">/// Errors that can arise when sending a datagram
<a href=#1875 id=1875 data-nosnippet>1875</a></span><span class="attr">#[derive(Debug, Error, Clone, Eq, PartialEq)]
<a href=#1876 id=1876 data-nosnippet>1876</a></span><span class="kw">pub enum </span>SendDatagramError {
<a href=#1877 id=1877 data-nosnippet>1877</a> <span class="doccomment">/// The peer does not support receiving datagram frames
<a href=#1878 id=1878 data-nosnippet>1878</a> </span><span class="attr">#[error(<span class="string">"datagrams not supported by peer"</span>)]
<a href=#1879 id=1879 data-nosnippet>1879</a> </span>UnsupportedByPeer,
<a href=#1880 id=1880 data-nosnippet>1880</a> <span class="doccomment">/// Datagram support is disabled locally
<a href=#1881 id=1881 data-nosnippet>1881</a> </span><span class="attr">#[error(<span class="string">"datagram support disabled"</span>)]
<a href=#1882 id=1882 data-nosnippet>1882</a> </span>Disabled,
<a href=#1883 id=1883 data-nosnippet>1883</a> <span class="doccomment">/// The datagram is larger than the connection can currently accommodate
<a href=#1884 id=1884 data-nosnippet>1884</a> ///
<a href=#1885 id=1885 data-nosnippet>1885</a> /// Indicates that the path MTU minus overhead or the limit advertised by the peer has been
<a href=#1886 id=1886 data-nosnippet>1886</a> /// exceeded.
<a href=#1887 id=1887 data-nosnippet>1887</a> </span><span class="attr">#[error(<span class="string">"datagram too large"</span>)]
<a href=#1888 id=1888 data-nosnippet>1888</a> </span>TooLarge,
<a href=#1889 id=1889 data-nosnippet>1889</a> <span class="doccomment">/// The connection was lost
<a href=#1890 id=1890 data-nosnippet>1890</a> </span><span class="attr">#[error(<span class="string">"connection lost"</span>)]
<a href=#1891 id=1891 data-nosnippet>1891</a> </span>ConnectionLost(<span class="attr">#[from] </span>ConnectionError),
<a href=#1892 id=1892 data-nosnippet>1892</a>}
<a href=#1893 id=1893 data-nosnippet>1893</a>
<a href=#1894 id=1894 data-nosnippet>1894</a><span class="doccomment">/// The maximum amount of datagrams which will be produced in a single `drive_transmit` call
<a href=#1895 id=1895 data-nosnippet>1895</a>///
<a href=#1896 id=1896 data-nosnippet>1896</a>/// This limits the amount of CPU resources consumed by datagram generation,
<a href=#1897 id=1897 data-nosnippet>1897</a>/// and allows other tasks (like receiving ACKs) to run in between.
<a href=#1898 id=1898 data-nosnippet>1898</a></span><span class="kw">const </span>MAX_TRANSMIT_DATAGRAMS: usize = <span class="number">20</span>;
<a href=#1899 id=1899 data-nosnippet>1899</a>
<a href=#1900 id=1900 data-nosnippet>1900</a><span class="doccomment">/// The maximum amount of datagrams that are sent in a single transmit
<a href=#1901 id=1901 data-nosnippet>1901</a>///
<a href=#1902 id=1902 data-nosnippet>1902</a>/// This can be lower than the maximum platform capabilities, to avoid excessive
<a href=#1903 id=1903 data-nosnippet>1903</a>/// memory allocations when calling `poll_transmit()`. Benchmarks have shown
<a href=#1904 id=1904 data-nosnippet>1904</a>/// that numbers around 10 are a good compromise.
<a href=#1905 id=1905 data-nosnippet>1905</a></span><span class="kw">const </span>MAX_TRANSMIT_SEGMENTS: NonZeroUsize = NonZeroUsize::new(<span class="number">10</span>).expect(<span class="string">"known"</span>);</code></pre></div></section></main></body></html>
<a href=#1416 id=1416 data-nosnippet>1416</a> /// I.e. how many [`Path`] and [`WeakPathHandle`] structs are alive for a path.
<a href=#1417 id=1417 data-nosnippet>1417</a> /// Each entry's [`PathRefOwner`] holds an [`AtomicUsize`] so that cloning or
<a href=#1418 id=1418 data-nosnippet>1418</a> /// dropping a [`PathRef`] (held by [`Path`] or [`WeakPathHandle`]) does not need
<a href=#1419 id=1419 data-nosnippet>1419</a> /// to lock this state.
<a href=#1420 id=1420 data-nosnippet>1420</a> ///
<a href=#1421 id=1421 data-nosnippet>1421</a> /// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#1422 id=1422 data-nosnippet>1422</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) path_refs: FxHashMap&lt;PathId, PathRefOwner&gt;,
<a href=#1423 id=1423 data-nosnippet>1423</a> <span class="doccomment">/// Final path stats for discarded paths.
<a href=#1424 id=1424 data-nosnippet>1424</a> ///
<a href=#1425 id=1425 data-nosnippet>1425</a> /// We only insert entries if the discarded path has a non-zero reference count in [`Self::path_refs`].
<a href=#1426 id=1426 data-nosnippet>1426</a> /// When the last reference to a path is dropped its entry is removed from both maps.
<a href=#1427 id=1427 data-nosnippet>1427</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) final_path_stats: FxHashMap&lt;PathId, PathStats&gt;,
<a href=#1428 id=1428 data-nosnippet>1428</a> <span class="kw">pub</span>(<span class="kw">crate</span>) path_events: tokio::sync::broadcast::Sender&lt;PathEvent&gt;,
<a href=#1429 id=1429 data-nosnippet>1429</a> sender: Pin&lt;Box&lt;<span class="kw">dyn </span>UdpSender&gt;&gt;,
<a href=#1430 id=1430 data-nosnippet>1430</a> <span class="kw">pub</span>(<span class="kw">crate</span>) runtime: Arc&lt;<span class="kw">dyn </span>Runtime&gt;,
<a href=#1431 id=1431 data-nosnippet>1431</a> send_buffer: Vec&lt;u8&gt;,
<a href=#1432 id=1432 data-nosnippet>1432</a> <span class="doccomment">/// We buffer a transmit when the underlying I/O would block
<a href=#1433 id=1433 data-nosnippet>1433</a> </span>buffered_transmit: <span class="prelude-ty">Option</span>&lt;proto::Transmit&gt;,
<a href=#1434 id=1434 data-nosnippet>1434</a> <span class="doccomment">/// Our last external address reported by the peer. When multipath is enabled, this will be the
<a href=#1435 id=1435 data-nosnippet>1435</a> /// last report across all paths.
<a href=#1436 id=1436 data-nosnippet>1436</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) observed_external_addr: watch::Sender&lt;<span class="prelude-ty">Option</span>&lt;SocketAddr&gt;&gt;,
<a href=#1437 id=1437 data-nosnippet>1437</a> <span class="kw">pub</span>(<span class="kw">crate</span>) nat_traversal_updates: tokio::sync::broadcast::Sender&lt;n0_nat_traversal::Event&gt;,
<a href=#1438 id=1438 data-nosnippet>1438</a> on_closed: Vec&lt;oneshot::Sender&lt;Closed&gt;&gt;,
<a href=#1439 id=1439 data-nosnippet>1439</a>}
<a href=#1440 id=1440 data-nosnippet>1440</a>
<a href=#1441 id=1441 data-nosnippet>1441</a><span class="kw">impl </span>State {
<a href=#1442 id=1442 data-nosnippet>1442</a> <span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#1443 id=1443 data-nosnippet>1443</a> </span><span class="kw">fn </span>new(
<a href=#1444 id=1444 data-nosnippet>1444</a> inner: proto::Connection,
<a href=#1445 id=1445 data-nosnippet>1445</a> handle: ConnectionHandle,
<a href=#1446 id=1446 data-nosnippet>1446</a> endpoint_events: mpsc::UnboundedSender&lt;(ConnectionHandle, EndpointEvent)&gt;,
<a href=#1447 id=1447 data-nosnippet>1447</a> conn_events: mpsc::UnboundedReceiver&lt;ConnectionEvent&gt;,
<a href=#1448 id=1448 data-nosnippet>1448</a> on_handshake_data: oneshot::Sender&lt;()&gt;,
<a href=#1449 id=1449 data-nosnippet>1449</a> on_connected: oneshot::Sender&lt;bool&gt;,
<a href=#1450 id=1450 data-nosnippet>1450</a> sender: Pin&lt;Box&lt;<span class="kw">dyn </span>UdpSender&gt;&gt;,
<a href=#1451 id=1451 data-nosnippet>1451</a> runtime: Arc&lt;<span class="kw">dyn </span>Runtime&gt;,
<a href=#1452 id=1452 data-nosnippet>1452</a> ) -&gt; <span class="self">Self </span>{
<a href=#1453 id=1453 data-nosnippet>1453</a> <span class="self">Self </span>{
<a href=#1454 id=1454 data-nosnippet>1454</a> inner,
<a href=#1455 id=1455 data-nosnippet>1455</a> driver: <span class="prelude-val">None</span>,
<a href=#1456 id=1456 data-nosnippet>1456</a> handle,
<a href=#1457 id=1457 data-nosnippet>1457</a> on_handshake_data: <span class="prelude-val">Some</span>(on_handshake_data),
<a href=#1458 id=1458 data-nosnippet>1458</a> on_connected: <span class="prelude-val">Some</span>(on_connected),
<a href=#1459 id=1459 data-nosnippet>1459</a> connected: <span class="bool-val">false</span>,
<a href=#1460 id=1460 data-nosnippet>1460</a> handshake_confirmed: <span class="bool-val">false</span>,
<a href=#1461 id=1461 data-nosnippet>1461</a> timer: <span class="prelude-val">None</span>,
<a href=#1462 id=1462 data-nosnippet>1462</a> timer_deadline: <span class="prelude-val">None</span>,
<a href=#1463 id=1463 data-nosnippet>1463</a> conn_events,
<a href=#1464 id=1464 data-nosnippet>1464</a> endpoint_events,
<a href=#1465 id=1465 data-nosnippet>1465</a> blocked_writers: FxHashMap::default(),
<a href=#1466 id=1466 data-nosnippet>1466</a> blocked_readers: FxHashMap::default(),
<a href=#1467 id=1467 data-nosnippet>1467</a> stopped: FxHashMap::default(),
<a href=#1468 id=1468 data-nosnippet>1468</a> open_path: FxHashMap::default(),
<a href=#1469 id=1469 data-nosnippet>1469</a> error: <span class="prelude-val">None</span>,
<a href=#1470 id=1470 data-nosnippet>1470</a> sender,
<a href=#1471 id=1471 data-nosnippet>1471</a> runtime,
<a href=#1472 id=1472 data-nosnippet>1472</a> send_buffer: Vec::new(),
<a href=#1473 id=1473 data-nosnippet>1473</a> buffered_transmit: <span class="prelude-val">None</span>,
<a href=#1474 id=1474 data-nosnippet>1474</a> path_events: tokio::sync::broadcast::channel(<span class="number">32</span>).<span class="number">0</span>,
<a href=#1475 id=1475 data-nosnippet>1475</a> observed_external_addr: watch::Sender::new(<span class="prelude-val">None</span>),
<a href=#1476 id=1476 data-nosnippet>1476</a> nat_traversal_updates: tokio::sync::broadcast::channel(<span class="number">32</span>).<span class="number">0</span>,
<a href=#1477 id=1477 data-nosnippet>1477</a> on_closed: Vec::new(),
<a href=#1478 id=1478 data-nosnippet>1478</a> final_path_stats: Default::default(),
<a href=#1479 id=1479 data-nosnippet>1479</a> path_refs: Default::default(),
<a href=#1480 id=1480 data-nosnippet>1480</a> }
<a href=#1481 id=1481 data-nosnippet>1481</a> }
<a href=#1482 id=1482 data-nosnippet>1482</a>
<a href=#1483 id=1483 data-nosnippet>1483</a> <span class="kw">fn </span>drive_transmit(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; io::Result&lt;bool&gt; {
<a href=#1484 id=1484 data-nosnippet>1484</a> <span class="kw">let </span>now = <span class="self">self</span>.runtime.now();
<a href=#1485 id=1485 data-nosnippet>1485</a> <span class="kw">let </span><span class="kw-2">mut </span>transmits = <span class="number">0</span>;
<a href=#1486 id=1486 data-nosnippet>1486</a>
<a href=#1487 id=1487 data-nosnippet>1487</a> <span class="kw">let </span>max_datagrams = <span class="self">self
<a href=#1488 id=1488 data-nosnippet>1488</a> </span>.sender
<a href=#1489 id=1489 data-nosnippet>1489</a> .max_transmit_segments()
<a href=#1490 id=1490 data-nosnippet>1490</a> .min(MAX_TRANSMIT_SEGMENTS);
<a href=#1491 id=1491 data-nosnippet>1491</a>
<a href=#1492 id=1492 data-nosnippet>1492</a> <span class="kw">loop </span>{
<a href=#1493 id=1493 data-nosnippet>1493</a> <span class="comment">// Retry the last transmit, or get a new one.
<a href=#1494 id=1494 data-nosnippet>1494</a> </span><span class="kw">let </span>t = <span class="kw">match </span><span class="self">self</span>.buffered_transmit.take() {
<a href=#1495 id=1495 data-nosnippet>1495</a> <span class="prelude-val">Some</span>(t) =&gt; t,
<a href=#1496 id=1496 data-nosnippet>1496</a> <span class="prelude-val">None </span>=&gt; {
<a href=#1497 id=1497 data-nosnippet>1497</a> <span class="self">self</span>.send_buffer.clear();
<a href=#1498 id=1498 data-nosnippet>1498</a> <span class="kw">match </span><span class="self">self
<a href=#1499 id=1499 data-nosnippet>1499</a> </span>.inner
<a href=#1500 id=1500 data-nosnippet>1500</a> .poll_transmit(now, max_datagrams, <span class="kw-2">&amp;mut </span><span class="self">self</span>.send_buffer)
<a href=#1501 id=1501 data-nosnippet>1501</a> {
<a href=#1502 id=1502 data-nosnippet>1502</a> <span class="prelude-val">Some</span>(t) =&gt; {
<a href=#1503 id=1503 data-nosnippet>1503</a> transmits += <span class="kw">match </span>t.segment_size {
<a href=#1504 id=1504 data-nosnippet>1504</a> <span class="prelude-val">None </span>=&gt; <span class="number">1</span>,
<a href=#1505 id=1505 data-nosnippet>1505</a> <span class="prelude-val">Some</span>(s) =&gt; t.size.div_ceil(s), <span class="comment">// round up
<a href=#1506 id=1506 data-nosnippet>1506</a> </span>};
<a href=#1507 id=1507 data-nosnippet>1507</a> t
<a href=#1508 id=1508 data-nosnippet>1508</a> }
<a href=#1509 id=1509 data-nosnippet>1509</a> <span class="prelude-val">None </span>=&gt; <span class="kw">break</span>,
<a href=#1510 id=1510 data-nosnippet>1510</a> }
<a href=#1511 id=1511 data-nosnippet>1511</a> }
<a href=#1512 id=1512 data-nosnippet>1512</a> };
<a href=#1513 id=1513 data-nosnippet>1513</a>
<a href=#1514 id=1514 data-nosnippet>1514</a> <span class="kw">let </span>len = t.size;
<a href=#1515 id=1515 data-nosnippet>1515</a> <span class="kw">match </span><span class="self">self
<a href=#1516 id=1516 data-nosnippet>1516</a> </span>.sender
<a href=#1517 id=1517 data-nosnippet>1517</a> .as_mut()
<a href=#1518 id=1518 data-nosnippet>1518</a> .poll_send(<span class="kw-2">&amp;</span>udp_transmit(<span class="kw-2">&amp;</span>t, <span class="kw-2">&amp;</span><span class="self">self</span>.send_buffer[..len]), cx)
<a href=#1519 id=1519 data-nosnippet>1519</a> {
<a href=#1520 id=1520 data-nosnippet>1520</a> Poll::Pending =&gt; {
<a href=#1521 id=1521 data-nosnippet>1521</a> <span class="self">self</span>.buffered_transmit = <span class="prelude-val">Some</span>(t);
<a href=#1522 id=1522 data-nosnippet>1522</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="bool-val">false</span>);
<a href=#1523 id=1523 data-nosnippet>1523</a> }
<a href=#1524 id=1524 data-nosnippet>1524</a> Poll::Ready(<span class="prelude-val">Err</span>(e)) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(e),
<a href=#1525 id=1525 data-nosnippet>1525</a> Poll::Ready(<span class="prelude-val">Ok</span>(())) =&gt; {}
<a href=#1526 id=1526 data-nosnippet>1526</a> }
<a href=#1527 id=1527 data-nosnippet>1527</a>
<a href=#1528 id=1528 data-nosnippet>1528</a> <span class="kw">if </span>transmits &gt;= MAX_TRANSMIT_DATAGRAMS {
<a href=#1529 id=1529 data-nosnippet>1529</a> <span class="comment">// TODO: What isn't ideal here yet is that if we don't poll all
<a href=#1530 id=1530 data-nosnippet>1530</a> // datagrams that could be sent we don't go into the `app_limited`
<a href=#1531 id=1531 data-nosnippet>1531</a> // state and CWND continues to grow until we get here the next time.
<a href=#1532 id=1532 data-nosnippet>1532</a> // See https://github.com/quinn-rs/quinn/issues/1126
<a href=#1533 id=1533 data-nosnippet>1533</a> </span><span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="bool-val">true</span>);
<a href=#1534 id=1534 data-nosnippet>1534</a> }
<a href=#1535 id=1535 data-nosnippet>1535</a> }
<a href=#1536 id=1536 data-nosnippet>1536</a>
<a href=#1537 id=1537 data-nosnippet>1537</a> <span class="prelude-val">Ok</span>(<span class="bool-val">false</span>)
<a href=#1538 id=1538 data-nosnippet>1538</a> }
<a href=#1539 id=1539 data-nosnippet>1539</a>
<a href=#1540 id=1540 data-nosnippet>1540</a> <span class="kw">fn </span>forward_endpoint_events(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#1541 id=1541 data-nosnippet>1541</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(event) = <span class="self">self</span>.inner.poll_endpoint_events() {
<a href=#1542 id=1542 data-nosnippet>1542</a> <span class="comment">// If the endpoint driver is gone, noop.
<a href=#1543 id=1543 data-nosnippet>1543</a> </span><span class="kw">let _ </span>= <span class="self">self</span>.endpoint_events.send((<span class="self">self</span>.handle, event));
<a href=#1544 id=1544 data-nosnippet>1544</a> }
<a href=#1545 id=1545 data-nosnippet>1545</a> }
<a href=#1546 id=1546 data-nosnippet>1546</a>
<a href=#1547 id=1547 data-nosnippet>1547</a> <span class="doccomment">/// If this returns `Err`, the endpoint is dead, so the driver should exit immediately.
<a href=#1548 id=1548 data-nosnippet>1548</a> </span><span class="kw">fn </span>process_conn_events(
<a href=#1549 id=1549 data-nosnippet>1549</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#1550 id=1550 data-nosnippet>1550</a> shared: <span class="kw-2">&amp;</span>Shared,
<a href=#1551 id=1551 data-nosnippet>1551</a> cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
<a href=#1552 id=1552 data-nosnippet>1552</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;(), ConnectionError&gt; {
<a href=#1553 id=1553 data-nosnippet>1553</a> <span class="kw">loop </span>{
<a href=#1554 id=1554 data-nosnippet>1554</a> <span class="kw">match </span><span class="self">self</span>.conn_events.poll_recv(cx) {
<a href=#1555 id=1555 data-nosnippet>1555</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::Rebind(sender))) =&gt; {
<a href=#1556 id=1556 data-nosnippet>1556</a> <span class="self">self</span>.sender = sender;
<a href=#1557 id=1557 data-nosnippet>1557</a> <span class="self">self</span>.inner.handle_network_change(<span class="prelude-val">None</span>, <span class="self">self</span>.runtime.now());
<a href=#1558 id=1558 data-nosnippet>1558</a> }
<a href=#1559 id=1559 data-nosnippet>1559</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::LocalAddressChanged(hint))) =&gt; {
<a href=#1560 id=1560 data-nosnippet>1560</a> <span class="self">self</span>.inner
<a href=#1561 id=1561 data-nosnippet>1561</a> .handle_network_change(hint.as_deref().map(|x| x <span class="kw">as _</span>), <span class="self">self</span>.runtime.now());
<a href=#1562 id=1562 data-nosnippet>1562</a> }
<a href=#1563 id=1563 data-nosnippet>1563</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::Proto(event))) =&gt; {
<a href=#1564 id=1564 data-nosnippet>1564</a> <span class="self">self</span>.inner.handle_event(event);
<a href=#1565 id=1565 data-nosnippet>1565</a> }
<a href=#1566 id=1566 data-nosnippet>1566</a> Poll::Ready(<span class="prelude-val">Some</span>(ConnectionEvent::Close { reason, error_code })) =&gt; {
<a href=#1567 id=1567 data-nosnippet>1567</a> <span class="self">self</span>.close(error_code, reason, shared);
<a href=#1568 id=1568 data-nosnippet>1568</a> }
<a href=#1569 id=1569 data-nosnippet>1569</a> Poll::Ready(<span class="prelude-val">None</span>) =&gt; {
<a href=#1570 id=1570 data-nosnippet>1570</a> <span class="kw">return </span><span class="prelude-val">Err</span>(ConnectionError::TransportError(TransportError::new(
<a href=#1571 id=1571 data-nosnippet>1571</a> TransportErrorCode::INTERNAL_ERROR,
<a href=#1572 id=1572 data-nosnippet>1572</a> <span class="string">"endpoint driver future was dropped"</span>.to_string(),
<a href=#1573 id=1573 data-nosnippet>1573</a> )));
<a href=#1574 id=1574 data-nosnippet>1574</a> }
<a href=#1575 id=1575 data-nosnippet>1575</a> Poll::Pending =&gt; {
<a href=#1576 id=1576 data-nosnippet>1576</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#1577 id=1577 data-nosnippet>1577</a> }
<a href=#1578 id=1578 data-nosnippet>1578</a> }
<a href=#1579 id=1579 data-nosnippet>1579</a> }
<a href=#1580 id=1580 data-nosnippet>1580</a> }
<a href=#1581 id=1581 data-nosnippet>1581</a>
<a href=#1582 id=1582 data-nosnippet>1582</a> <span class="kw">fn </span>forward_app_events(<span class="kw-2">&amp;mut </span><span class="self">self</span>, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1583 id=1583 data-nosnippet>1583</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(event) = <span class="self">self</span>.inner.poll() {
<a href=#1584 id=1584 data-nosnippet>1584</a> <span class="kw">use </span>proto::Event::<span class="kw-2">*</span>;
<a href=#1585 id=1585 data-nosnippet>1585</a> <span class="kw">match </span>event {
<a href=#1586 id=1586 data-nosnippet>1586</a> HandshakeDataReady =&gt; {
<a href=#1587 id=1587 data-nosnippet>1587</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_handshake_data.take() {
<a href=#1588 id=1588 data-nosnippet>1588</a> <span class="kw">let _ </span>= x.send(());
<a href=#1589 id=1589 data-nosnippet>1589</a> }
<a href=#1590 id=1590 data-nosnippet>1590</a> }
<a href=#1591 id=1591 data-nosnippet>1591</a> Connected =&gt; {
<a href=#1592 id=1592 data-nosnippet>1592</a> <span class="self">self</span>.connected = <span class="bool-val">true</span>;
<a href=#1593 id=1593 data-nosnippet>1593</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_connected.take() {
<a href=#1594 id=1594 data-nosnippet>1594</a> <span class="comment">// We don't care if the on-connected future was dropped
<a href=#1595 id=1595 data-nosnippet>1595</a> </span><span class="kw">let _ </span>= x.send(<span class="self">self</span>.inner.accepted_0rtt());
<a href=#1596 id=1596 data-nosnippet>1596</a> }
<a href=#1597 id=1597 data-nosnippet>1597</a> <span class="kw">if </span><span class="self">self</span>.inner.side().is_client() &amp;&amp; !<span class="self">self</span>.inner.accepted_0rtt() {
<a href=#1598 id=1598 data-nosnippet>1598</a> <span class="comment">// Wake up rejected 0-RTT streams so they can fail immediately with
<a href=#1599 id=1599 data-nosnippet>1599</a> // `ZeroRttRejected` errors.
<a href=#1600 id=1600 data-nosnippet>1600</a> </span>wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers);
<a href=#1601 id=1601 data-nosnippet>1601</a> wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_readers);
<a href=#1602 id=1602 data-nosnippet>1602</a> wake_all_notify(<span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped);
<a href=#1603 id=1603 data-nosnippet>1603</a> }
<a href=#1604 id=1604 data-nosnippet>1604</a> }
<a href=#1605 id=1605 data-nosnippet>1605</a> HandshakeConfirmed =&gt; {
<a href=#1606 id=1606 data-nosnippet>1606</a> <span class="self">self</span>.handshake_confirmed = <span class="bool-val">true</span>;
<a href=#1607 id=1607 data-nosnippet>1607</a> shared.handshake_confirmed.notify_waiters();
<a href=#1608 id=1608 data-nosnippet>1608</a> }
<a href=#1609 id=1609 data-nosnippet>1609</a> ConnectionLost { reason } =&gt; {
<a href=#1610 id=1610 data-nosnippet>1610</a> <span class="self">self</span>.terminate(reason, shared);
<a href=#1611 id=1611 data-nosnippet>1611</a> }
<a href=#1612 id=1612 data-nosnippet>1612</a> Stream(StreamEvent::Writable { id }) =&gt; wake_stream(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers),
<a href=#1613 id=1613 data-nosnippet>1613</a> Stream(StreamEvent::Opened { dir: Dir::Uni }) =&gt; {
<a href=#1614 id=1614 data-nosnippet>1614</a> shared.stream_incoming[Dir::Uni <span class="kw">as </span>usize].notify_waiters();
<a href=#1615 id=1615 data-nosnippet>1615</a> }
<a href=#1616 id=1616 data-nosnippet>1616</a> Stream(StreamEvent::Opened { dir: Dir::Bi }) =&gt; {
<a href=#1617 id=1617 data-nosnippet>1617</a> shared.stream_incoming[Dir::Bi <span class="kw">as </span>usize].notify_waiters();
<a href=#1618 id=1618 data-nosnippet>1618</a> }
<a href=#1619 id=1619 data-nosnippet>1619</a> DatagramReceived =&gt; {
<a href=#1620 id=1620 data-nosnippet>1620</a> shared.datagram_received.notify_waiters();
<a href=#1621 id=1621 data-nosnippet>1621</a> }
<a href=#1622 id=1622 data-nosnippet>1622</a> DatagramsUnblocked =&gt; {
<a href=#1623 id=1623 data-nosnippet>1623</a> shared.datagrams_unblocked.notify_waiters();
<a href=#1624 id=1624 data-nosnippet>1624</a> }
<a href=#1625 id=1625 data-nosnippet>1625</a> Stream(StreamEvent::Readable { id }) =&gt; wake_stream(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_readers),
<a href=#1626 id=1626 data-nosnippet>1626</a> Stream(StreamEvent::Available { dir }) =&gt; {
<a href=#1627 id=1627 data-nosnippet>1627</a> <span class="comment">// Might mean any number of streams are ready, so we wake up everyone
<a href=#1628 id=1628 data-nosnippet>1628</a> </span>shared.stream_budget_available[dir <span class="kw">as </span>usize].notify_waiters();
<a href=#1629 id=1629 data-nosnippet>1629</a> }
<a href=#1630 id=1630 data-nosnippet>1630</a> Stream(StreamEvent::Finished { id }) =&gt; wake_stream_notify(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped),
<a href=#1631 id=1631 data-nosnippet>1631</a> Stream(StreamEvent::Stopped { id, .. }) =&gt; {
<a href=#1632 id=1632 data-nosnippet>1632</a> wake_stream_notify(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped);
<a href=#1633 id=1633 data-nosnippet>1633</a> wake_stream(id, <span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers);
<a href=#1634 id=1634 data-nosnippet>1634</a> }
<a href=#1635 id=1635 data-nosnippet>1635</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::ObservedAddr { addr: observed, .. }) =&gt; {
<a href=#1636 id=1636 data-nosnippet>1636</a> <span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1637 id=1637 data-nosnippet>1637</a> <span class="self">self</span>.observed_external_addr.send_if_modified(|addr| {
<a href=#1638 id=1638 data-nosnippet>1638</a> <span class="kw">let </span>old = addr.replace(observed);
<a href=#1639 id=1639 data-nosnippet>1639</a> old != <span class="kw-2">*</span>addr
<a href=#1640 id=1640 data-nosnippet>1640</a> });
<a href=#1641 id=1641 data-nosnippet>1641</a> }
<a href=#1642 id=1642 data-nosnippet>1642</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::Opened { id }) =&gt; {
<a href=#1643 id=1643 data-nosnippet>1643</a> <span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1644 id=1644 data-nosnippet>1644</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sender) = <span class="self">self</span>.open_path.remove(<span class="kw-2">&amp;</span>id) {
<a href=#1645 id=1645 data-nosnippet>1645</a> sender.send_modify(|value| <span class="kw-2">*</span>value = <span class="prelude-val">Ok</span>(()));
<a href=#1646 id=1646 data-nosnippet>1646</a> }
<a href=#1647 id=1647 data-nosnippet>1647</a> }
<a href=#1648 id=1648 data-nosnippet>1648</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::Discarded { id, <span class="kw-2">ref </span>path_stats }) =&gt; {
<a href=#1649 id=1649 data-nosnippet>1649</a> <span class="kw">if </span><span class="self">self</span>.path_refs.contains_key(<span class="kw-2">&amp;</span>id) {
<a href=#1650 id=1650 data-nosnippet>1650</a> <span class="self">self</span>.final_path_stats.insert(id, <span class="kw-2">*</span>path_stats.clone());
<a href=#1651 id=1651 data-nosnippet>1651</a> }
<a href=#1652 id=1652 data-nosnippet>1652</a> <span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1653 id=1653 data-nosnippet>1653</a> }
<a href=#1654 id=1654 data-nosnippet>1654</a> Path(<span class="kw-2">ref </span>evt @ PathEvent::Abandoned { id, .. }) =&gt; {
<a href=#1655 id=1655 data-nosnippet>1655</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sender) = <span class="self">self</span>.open_path.remove(<span class="kw-2">&amp;</span>id) {
<a href=#1656 id=1656 data-nosnippet>1656</a> <span class="comment">// We don't care for the reason why this path was closed here, because semantically
<a href=#1657 id=1657 data-nosnippet>1657</a> // all close reasons for a path that has not yet been opened equals to `ValidationFailed`.
<a href=#1658 id=1658 data-nosnippet>1658</a> // With the noq API, there is no way to application-close a not-yet-opened path, so
<a href=#1659 id=1659 data-nosnippet>1659</a> // `ApplicationClosed` cannot occur. And all other variants will only occur for paths
<a href=#1660 id=1660 data-nosnippet>1660</a> // that have already been opened.
<a href=#1661 id=1661 data-nosnippet>1661</a> // The previous iteration of this code had another event `PathEvent::LocallyClosed` which
<a href=#1662 id=1662 data-nosnippet>1662</a> // contained a `PathError`, but that was only ever set to `ValidationFailed`.
<a href=#1663 id=1663 data-nosnippet>1663</a> </span><span class="kw">let </span>error = PathError::ValidationFailed;
<a href=#1664 id=1664 data-nosnippet>1664</a> sender.send_modify(|value| <span class="kw-2">*</span>value = <span class="prelude-val">Err</span>(error));
<a href=#1665 id=1665 data-nosnippet>1665</a> }
<a href=#1666 id=1666 data-nosnippet>1666</a> <span class="comment">// this will happen also for already opened paths
<a href=#1667 id=1667 data-nosnippet>1667</a> </span><span class="self">self</span>.path_events.send(evt.clone()).ok();
<a href=#1668 id=1668 data-nosnippet>1668</a> }
<a href=#1669 id=1669 data-nosnippet>1669</a> Path(evt @ PathEvent::RemoteStatus { .. }) =&gt; {
<a href=#1670 id=1670 data-nosnippet>1670</a> <span class="self">self</span>.path_events.send(evt).ok();
<a href=#1671 id=1671 data-nosnippet>1671</a> }
<a href=#1672 id=1672 data-nosnippet>1672</a> NatTraversal(update) =&gt; {
<a href=#1673 id=1673 data-nosnippet>1673</a> <span class="self">self</span>.nat_traversal_updates.send(update).ok();
<a href=#1674 id=1674 data-nosnippet>1674</a> }
<a href=#1675 id=1675 data-nosnippet>1675</a> }
<a href=#1676 id=1676 data-nosnippet>1676</a> }
<a href=#1677 id=1677 data-nosnippet>1677</a> }
<a href=#1678 id=1678 data-nosnippet>1678</a>
<a href=#1679 id=1679 data-nosnippet>1679</a> <span class="kw">fn </span>drive_timer(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; bool {
<a href=#1680 id=1680 data-nosnippet>1680</a> <span class="comment">// Check whether we need to (re)set the timer. If so, we must poll again to ensure the
<a href=#1681 id=1681 data-nosnippet>1681</a> // timer is registered with the runtime (and check whether it's already
<a href=#1682 id=1682 data-nosnippet>1682</a> // expired).
<a href=#1683 id=1683 data-nosnippet>1683</a> </span><span class="kw">match </span><span class="self">self</span>.inner.poll_timeout() {
<a href=#1684 id=1684 data-nosnippet>1684</a> <span class="prelude-val">Some</span>(deadline) =&gt; {
<a href=#1685 id=1685 data-nosnippet>1685</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(delay) = <span class="kw-2">&amp;mut </span><span class="self">self</span>.timer {
<a href=#1686 id=1686 data-nosnippet>1686</a> <span class="comment">// There is no need to reset the tokio timer if the deadline
<a href=#1687 id=1687 data-nosnippet>1687</a> // did not change
<a href=#1688 id=1688 data-nosnippet>1688</a> </span><span class="kw">if </span><span class="self">self
<a href=#1689 id=1689 data-nosnippet>1689</a> </span>.timer_deadline
<a href=#1690 id=1690 data-nosnippet>1690</a> .map(|current_deadline| current_deadline != deadline)
<a href=#1691 id=1691 data-nosnippet>1691</a> .unwrap_or(<span class="bool-val">true</span>)
<a href=#1692 id=1692 data-nosnippet>1692</a> {
<a href=#1693 id=1693 data-nosnippet>1693</a> delay.as_mut().reset(deadline);
<a href=#1694 id=1694 data-nosnippet>1694</a> }
<a href=#1695 id=1695 data-nosnippet>1695</a> } <span class="kw">else </span>{
<a href=#1696 id=1696 data-nosnippet>1696</a> <span class="self">self</span>.timer = <span class="prelude-val">Some</span>(<span class="self">self</span>.runtime.new_timer(deadline));
<a href=#1697 id=1697 data-nosnippet>1697</a> }
<a href=#1698 id=1698 data-nosnippet>1698</a> <span class="comment">// Store the actual expiration time of the timer
<a href=#1699 id=1699 data-nosnippet>1699</a> </span><span class="self">self</span>.timer_deadline = <span class="prelude-val">Some</span>(deadline);
<a href=#1700 id=1700 data-nosnippet>1700</a> }
<a href=#1701 id=1701 data-nosnippet>1701</a> <span class="prelude-val">None </span>=&gt; {
<a href=#1702 id=1702 data-nosnippet>1702</a> <span class="self">self</span>.timer_deadline = <span class="prelude-val">None</span>;
<a href=#1703 id=1703 data-nosnippet>1703</a> <span class="kw">return </span><span class="bool-val">false</span>;
<a href=#1704 id=1704 data-nosnippet>1704</a> }
<a href=#1705 id=1705 data-nosnippet>1705</a> }
<a href=#1706 id=1706 data-nosnippet>1706</a>
<a href=#1707 id=1707 data-nosnippet>1707</a> <span class="kw">if </span><span class="self">self</span>.timer_deadline.is_none() {
<a href=#1708 id=1708 data-nosnippet>1708</a> <span class="kw">return </span><span class="bool-val">false</span>;
<a href=#1709 id=1709 data-nosnippet>1709</a> }
<a href=#1710 id=1710 data-nosnippet>1710</a>
<a href=#1711 id=1711 data-nosnippet>1711</a> <span class="kw">let </span>delay = <span class="self">self
<a href=#1712 id=1712 data-nosnippet>1712</a> </span>.timer
<a href=#1713 id=1713 data-nosnippet>1713</a> .as_mut()
<a href=#1714 id=1714 data-nosnippet>1714</a> .expect(<span class="string">"timer must exist in this state"</span>)
<a href=#1715 id=1715 data-nosnippet>1715</a> .as_mut();
<a href=#1716 id=1716 data-nosnippet>1716</a> <span class="kw">if </span>delay.poll(cx).is_pending() {
<a href=#1717 id=1717 data-nosnippet>1717</a> <span class="comment">// Since there wasn't a timeout event, there is nothing new
<a href=#1718 id=1718 data-nosnippet>1718</a> // for the connection to do
<a href=#1719 id=1719 data-nosnippet>1719</a> </span><span class="kw">return </span><span class="bool-val">false</span>;
<a href=#1720 id=1720 data-nosnippet>1720</a> }
<a href=#1721 id=1721 data-nosnippet>1721</a>
<a href=#1722 id=1722 data-nosnippet>1722</a> <span class="comment">// A timer expired, so the caller needs to check for
<a href=#1723 id=1723 data-nosnippet>1723</a> // new transmits, which might cause new timers to be set.
<a href=#1724 id=1724 data-nosnippet>1724</a> </span><span class="self">self</span>.inner.handle_timeout(<span class="self">self</span>.runtime.now());
<a href=#1725 id=1725 data-nosnippet>1725</a> <span class="self">self</span>.timer_deadline = <span class="prelude-val">None</span>;
<a href=#1726 id=1726 data-nosnippet>1726</a> <span class="bool-val">true
<a href=#1727 id=1727 data-nosnippet>1727</a> </span>}
<a href=#1728 id=1728 data-nosnippet>1728</a>
<a href=#1729 id=1729 data-nosnippet>1729</a> <span class="doccomment">/// Wake up a blocked `Driver` task to process I/O
<a href=#1730 id=1730 data-nosnippet>1730</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>wake(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#1731 id=1731 data-nosnippet>1731</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.driver.take() {
<a href=#1732 id=1732 data-nosnippet>1732</a> x.wake();
<a href=#1733 id=1733 data-nosnippet>1733</a> }
<a href=#1734 id=1734 data-nosnippet>1734</a> }
<a href=#1735 id=1735 data-nosnippet>1735</a>
<a href=#1736 id=1736 data-nosnippet>1736</a> <span class="doccomment">/// Used to wake up all blocked futures when the connection becomes closed for any reason
<a href=#1737 id=1737 data-nosnippet>1737</a> </span><span class="kw">fn </span>terminate(<span class="kw-2">&amp;mut </span><span class="self">self</span>, reason: ConnectionError, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1738 id=1738 data-nosnippet>1738</a> <span class="self">self</span>.error = <span class="prelude-val">Some</span>(reason.clone());
<a href=#1739 id=1739 data-nosnippet>1739</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_handshake_data.take() {
<a href=#1740 id=1740 data-nosnippet>1740</a> <span class="kw">let _ </span>= x.send(());
<a href=#1741 id=1741 data-nosnippet>1741</a> }
<a href=#1742 id=1742 data-nosnippet>1742</a> wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_writers);
<a href=#1743 id=1743 data-nosnippet>1743</a> wake_all(<span class="kw-2">&amp;mut </span><span class="self">self</span>.blocked_readers);
<a href=#1744 id=1744 data-nosnippet>1744</a> shared.stream_budget_available[Dir::Uni <span class="kw">as </span>usize].notify_waiters();
<a href=#1745 id=1745 data-nosnippet>1745</a> shared.stream_budget_available[Dir::Bi <span class="kw">as </span>usize].notify_waiters();
<a href=#1746 id=1746 data-nosnippet>1746</a> shared.stream_incoming[Dir::Uni <span class="kw">as </span>usize].notify_waiters();
<a href=#1747 id=1747 data-nosnippet>1747</a> shared.stream_incoming[Dir::Bi <span class="kw">as </span>usize].notify_waiters();
<a href=#1748 id=1748 data-nosnippet>1748</a> shared.datagram_received.notify_waiters();
<a href=#1749 id=1749 data-nosnippet>1749</a> shared.datagrams_unblocked.notify_waiters();
<a href=#1750 id=1750 data-nosnippet>1750</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(x) = <span class="self">self</span>.on_connected.take() {
<a href=#1751 id=1751 data-nosnippet>1751</a> <span class="kw">let _ </span>= x.send(<span class="bool-val">false</span>);
<a href=#1752 id=1752 data-nosnippet>1752</a> }
<a href=#1753 id=1753 data-nosnippet>1753</a> shared.handshake_confirmed.notify_waiters();
<a href=#1754 id=1754 data-nosnippet>1754</a> wake_all_notify(<span class="kw-2">&amp;mut </span><span class="self">self</span>.stopped);
<a href=#1755 id=1755 data-nosnippet>1755</a> shared.closed.notify_waiters();
<a href=#1756 id=1756 data-nosnippet>1756</a>
<a href=#1757 id=1757 data-nosnippet>1757</a> <span class="comment">// Send to the registered on_closed futures.
<a href=#1758 id=1758 data-nosnippet>1758</a> </span><span class="kw">if </span>!<span class="self">self</span>.on_closed.is_empty() {
<a href=#1759 id=1759 data-nosnippet>1759</a> <span class="kw">let </span>closed = Closed::new(<span class="self">self</span>, reason);
<a href=#1760 id=1760 data-nosnippet>1760</a> <span class="kw">for </span>tx <span class="kw">in </span><span class="self">self</span>.on_closed.drain(..) {
<a href=#1761 id=1761 data-nosnippet>1761</a> tx.send(closed.clone()).ok();
<a href=#1762 id=1762 data-nosnippet>1762</a> }
<a href=#1763 id=1763 data-nosnippet>1763</a> }
<a href=#1764 id=1764 data-nosnippet>1764</a> }
<a href=#1765 id=1765 data-nosnippet>1765</a>
<a href=#1766 id=1766 data-nosnippet>1766</a> <span class="kw">fn </span>close(<span class="kw-2">&amp;mut </span><span class="self">self</span>, error_code: VarInt, reason: Bytes, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1767 id=1767 data-nosnippet>1767</a> <span class="self">self</span>.inner.close(<span class="self">self</span>.runtime.now(), error_code, reason);
<a href=#1768 id=1768 data-nosnippet>1768</a> <span class="self">self</span>.terminate(ConnectionError::LocallyClosed, shared);
<a href=#1769 id=1769 data-nosnippet>1769</a> <span class="self">self</span>.wake();
<a href=#1770 id=1770 data-nosnippet>1770</a> }
<a href=#1771 id=1771 data-nosnippet>1771</a>
<a href=#1772 id=1772 data-nosnippet>1772</a> <span class="doccomment">/// Close for a reason other than the application's explicit request
<a href=#1773 id=1773 data-nosnippet>1773</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>implicit_close(<span class="kw-2">&amp;mut </span><span class="self">self</span>, shared: <span class="kw-2">&amp;</span>Shared) {
<a href=#1774 id=1774 data-nosnippet>1774</a> <span class="self">self</span>.close(<span class="number">0u32</span>.into(), Bytes::new(), shared);
<a href=#1775 id=1775 data-nosnippet>1775</a> }
<a href=#1776 id=1776 data-nosnippet>1776</a>
<a href=#1777 id=1777 data-nosnippet>1777</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>check_0rtt(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), ()&gt; {
<a href=#1778 id=1778 data-nosnippet>1778</a> <span class="kw">if </span><span class="self">self</span>.inner.is_handshaking()
<a href=#1779 id=1779 data-nosnippet>1779</a> || <span class="self">self</span>.inner.accepted_0rtt()
<a href=#1780 id=1780 data-nosnippet>1780</a> || <span class="self">self</span>.inner.side().is_server()
<a href=#1781 id=1781 data-nosnippet>1781</a> {
<a href=#1782 id=1782 data-nosnippet>1782</a> <span class="prelude-val">Ok</span>(())
<a href=#1783 id=1783 data-nosnippet>1783</a> } <span class="kw">else </span>{
<a href=#1784 id=1784 data-nosnippet>1784</a> <span class="prelude-val">Err</span>(())
<a href=#1785 id=1785 data-nosnippet>1785</a> }
<a href=#1786 id=1786 data-nosnippet>1786</a> }
<a href=#1787 id=1787 data-nosnippet>1787</a>
<a href=#1788 id=1788 data-nosnippet>1788</a> <span class="doccomment">/// Returns [`PathStats`] for a path, if available.
<a href=#1789 id=1789 data-nosnippet>1789</a> ///
<a href=#1790 id=1790 data-nosnippet>1790</a> /// This gets the stats from [`proto::Connection`]. If that returns `None`
<a href=#1791 id=1791 data-nosnippet>1791</a> /// it gets them from `Self::final_path_stats` instead.
<a href=#1792 id=1792 data-nosnippet>1792</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>path_stats(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path_id: PathId) -&gt; <span class="prelude-ty">Option</span>&lt;PathStats&gt; {
<a href=#1793 id=1793 data-nosnippet>1793</a> <span class="self">self</span>.inner
<a href=#1794 id=1794 data-nosnippet>1794</a> .path_stats(path_id)
<a href=#1795 id=1795 data-nosnippet>1795</a> .or_else(|| <span class="self">self</span>.final_path_stats.get(<span class="kw-2">&amp;</span>path_id).copied())
<a href=#1796 id=1796 data-nosnippet>1796</a> }
<a href=#1797 id=1797 data-nosnippet>1797</a>
<a href=#1798 id=1798 data-nosnippet>1798</a> <span class="doccomment">/// Acquire a new [`PathRef`] for a path id, bumping its reference counter by 1.
<a href=#1799 id=1799 data-nosnippet>1799</a> ///
<a href=#1800 id=1800 data-nosnippet>1800</a> /// The returned [`PathRef`] is intended to be stored on a [`Path`] or [`WeakPathHandle`].
<a href=#1801 id=1801 data-nosnippet>1801</a> /// Its reference count is automatically increased when cloned. When its owner is dropped,
<a href=#1802 id=1802 data-nosnippet>1802</a> /// [`PathRef::on_drop`] must be called to decrement the refcount.
<a href=#1803 id=1803 data-nosnippet>1803</a> ///
<a href=#1804 id=1804 data-nosnippet>1804</a> /// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#1805 id=1805 data-nosnippet>1805</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>acquire_path_ref(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path_id: PathId) -&gt; PathRef {
<a href=#1806 id=1806 data-nosnippet>1806</a> <span class="self">self</span>.path_refs.entry(path_id).or_default().acquire(path_id)
<a href=#1807 id=1807 data-nosnippet>1807</a> }
<a href=#1808 id=1808 data-nosnippet>1808</a>}
<a href=#1809 id=1809 data-nosnippet>1809</a>
<a href=#1810 id=1810 data-nosnippet>1810</a><span class="kw">impl </span>Drop <span class="kw">for </span>State {
<a href=#1811 id=1811 data-nosnippet>1811</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#1812 id=1812 data-nosnippet>1812</a> <span class="kw">if </span>!<span class="self">self</span>.inner.is_drained() {
<a href=#1813 id=1813 data-nosnippet>1813</a> <span class="comment">// Ensure the endpoint can tidy up
<a href=#1814 id=1814 data-nosnippet>1814</a> </span><span class="kw">let _ </span>= <span class="self">self
<a href=#1815 id=1815 data-nosnippet>1815</a> </span>.endpoint_events
<a href=#1816 id=1816 data-nosnippet>1816</a> .send((<span class="self">self</span>.handle, proto::EndpointEvent::drained()));
<a href=#1817 id=1817 data-nosnippet>1817</a> }
<a href=#1818 id=1818 data-nosnippet>1818</a>
<a href=#1819 id=1819 data-nosnippet>1819</a> <span class="kw">if </span>!<span class="self">self</span>.on_closed.is_empty()
<a href=#1820 id=1820 data-nosnippet>1820</a> &amp;&amp; <span class="kw">let </span><span class="prelude-val">Some</span>(reason) = <span class="self">self</span>.error.clone()
<a href=#1821 id=1821 data-nosnippet>1821</a> {
<a href=#1822 id=1822 data-nosnippet>1822</a> <span class="comment">// Ensure that all on_closed oneshot senders are triggered before dropping.
<a href=#1823 id=1823 data-nosnippet>1823</a> </span><span class="kw">let </span>closed = Closed::new(<span class="self">self</span>, reason);
<a href=#1824 id=1824 data-nosnippet>1824</a> <span class="kw">for </span>tx <span class="kw">in </span><span class="self">self</span>.on_closed.drain(..) {
<a href=#1825 id=1825 data-nosnippet>1825</a> tx.send(closed.clone()).ok();
<a href=#1826 id=1826 data-nosnippet>1826</a> }
<a href=#1827 id=1827 data-nosnippet>1827</a> }
<a href=#1828 id=1828 data-nosnippet>1828</a> }
<a href=#1829 id=1829 data-nosnippet>1829</a>}
<a href=#1830 id=1830 data-nosnippet>1830</a>
<a href=#1831 id=1831 data-nosnippet>1831</a><span class="kw">impl </span>fmt::Debug <span class="kw">for </span>State {
<a href=#1832 id=1832 data-nosnippet>1832</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#1833 id=1833 data-nosnippet>1833</a> f.debug_struct(<span class="string">"State"</span>).field(<span class="string">"inner"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner).finish()
<a href=#1834 id=1834 data-nosnippet>1834</a> }
<a href=#1835 id=1835 data-nosnippet>1835</a>}
<a href=#1836 id=1836 data-nosnippet>1836</a>
<a href=#1837 id=1837 data-nosnippet>1837</a><span class="kw">fn </span>wake_stream(stream_id: StreamId, wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Waker&gt;) {
<a href=#1838 id=1838 data-nosnippet>1838</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(waker) = wakers.remove(<span class="kw-2">&amp;</span>stream_id) {
<a href=#1839 id=1839 data-nosnippet>1839</a> waker.wake();
<a href=#1840 id=1840 data-nosnippet>1840</a> }
<a href=#1841 id=1841 data-nosnippet>1841</a>}
<a href=#1842 id=1842 data-nosnippet>1842</a>
<a href=#1843 id=1843 data-nosnippet>1843</a><span class="kw">fn </span>wake_all(wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Waker&gt;) {
<a href=#1844 id=1844 data-nosnippet>1844</a> wakers.drain().for_each(|(<span class="kw">_</span>, waker)| waker.wake())
<a href=#1845 id=1845 data-nosnippet>1845</a>}
<a href=#1846 id=1846 data-nosnippet>1846</a>
<a href=#1847 id=1847 data-nosnippet>1847</a><span class="kw">fn </span>wake_stream_notify(stream_id: StreamId, wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Arc&lt;Notify&gt;&gt;) {
<a href=#1848 id=1848 data-nosnippet>1848</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(notify) = wakers.remove(<span class="kw-2">&amp;</span>stream_id) {
<a href=#1849 id=1849 data-nosnippet>1849</a> notify.notify_waiters()
<a href=#1850 id=1850 data-nosnippet>1850</a> }
<a href=#1851 id=1851 data-nosnippet>1851</a>}
<a href=#1852 id=1852 data-nosnippet>1852</a>
<a href=#1853 id=1853 data-nosnippet>1853</a><span class="kw">fn </span>wake_all_notify(wakers: <span class="kw-2">&amp;mut </span>FxHashMap&lt;StreamId, Arc&lt;Notify&gt;&gt;) {
<a href=#1854 id=1854 data-nosnippet>1854</a> wakers
<a href=#1855 id=1855 data-nosnippet>1855</a> .drain()
<a href=#1856 id=1856 data-nosnippet>1856</a> .for_each(|(<span class="kw">_</span>, notify)| notify.notify_waiters())
<a href=#1857 id=1857 data-nosnippet>1857</a>}
<a href=#1858 id=1858 data-nosnippet>1858</a>
<a href=#1859 id=1859 data-nosnippet>1859</a><span class="doccomment">/// Errors that can arise when sending a datagram
<a href=#1860 id=1860 data-nosnippet>1860</a></span><span class="attr">#[derive(Debug, Error, Clone, Eq, PartialEq)]
<a href=#1861 id=1861 data-nosnippet>1861</a></span><span class="kw">pub enum </span>SendDatagramError {
<a href=#1862 id=1862 data-nosnippet>1862</a> <span class="doccomment">/// The peer does not support receiving datagram frames
<a href=#1863 id=1863 data-nosnippet>1863</a> </span><span class="attr">#[error(<span class="string">"datagrams not supported by peer"</span>)]
<a href=#1864 id=1864 data-nosnippet>1864</a> </span>UnsupportedByPeer,
<a href=#1865 id=1865 data-nosnippet>1865</a> <span class="doccomment">/// Datagram support is disabled locally
<a href=#1866 id=1866 data-nosnippet>1866</a> </span><span class="attr">#[error(<span class="string">"datagram support disabled"</span>)]
<a href=#1867 id=1867 data-nosnippet>1867</a> </span>Disabled,
<a href=#1868 id=1868 data-nosnippet>1868</a> <span class="doccomment">/// The datagram is larger than the connection can currently accommodate
<a href=#1869 id=1869 data-nosnippet>1869</a> ///
<a href=#1870 id=1870 data-nosnippet>1870</a> /// Indicates that the path MTU minus overhead or the limit advertised by the peer has been
<a href=#1871 id=1871 data-nosnippet>1871</a> /// exceeded.
<a href=#1872 id=1872 data-nosnippet>1872</a> </span><span class="attr">#[error(<span class="string">"datagram too large"</span>)]
<a href=#1873 id=1873 data-nosnippet>1873</a> </span>TooLarge,
<a href=#1874 id=1874 data-nosnippet>1874</a> <span class="doccomment">/// The connection was lost
<a href=#1875 id=1875 data-nosnippet>1875</a> </span><span class="attr">#[error(<span class="string">"connection lost"</span>)]
<a href=#1876 id=1876 data-nosnippet>1876</a> </span>ConnectionLost(<span class="attr">#[from] </span>ConnectionError),
<a href=#1877 id=1877 data-nosnippet>1877</a>}
<a href=#1878 id=1878 data-nosnippet>1878</a>
<a href=#1879 id=1879 data-nosnippet>1879</a><span class="doccomment">/// The maximum amount of datagrams which will be produced in a single `drive_transmit` call
<a href=#1880 id=1880 data-nosnippet>1880</a>///
<a href=#1881 id=1881 data-nosnippet>1881</a>/// This limits the amount of CPU resources consumed by datagram generation,
<a href=#1882 id=1882 data-nosnippet>1882</a>/// and allows other tasks (like receiving ACKs) to run in between.
<a href=#1883 id=1883 data-nosnippet>1883</a></span><span class="kw">const </span>MAX_TRANSMIT_DATAGRAMS: usize = <span class="number">20</span>;
<a href=#1884 id=1884 data-nosnippet>1884</a>
<a href=#1885 id=1885 data-nosnippet>1885</a><span class="doccomment">/// The maximum amount of datagrams that are sent in a single transmit
<a href=#1886 id=1886 data-nosnippet>1886</a>///
<a href=#1887 id=1887 data-nosnippet>1887</a>/// This can be lower than the maximum platform capabilities, to avoid excessive
<a href=#1888 id=1888 data-nosnippet>1888</a>/// memory allocations when calling `poll_transmit()`. Benchmarks have shown
<a href=#1889 id=1889 data-nosnippet>1889</a>/// that numbers around 10 are a good compromise.
<a href=#1890 id=1890 data-nosnippet>1890</a></span><span class="kw">const </span>MAX_TRANSMIT_SEGMENTS: NonZeroUsize = NonZeroUsize::new(<span class="number">10</span>).expect(<span class="string">"known"</span>);</code></pre></div></section></main></body></html>
+342 -329
View File
@@ -2,7 +2,7 @@
<a href=#2 id=2 data-nosnippet>2</a><span class="kw">use </span>std::net::{IpAddr, SocketAddr};
<a href=#3 id=3 data-nosnippet>3</a><span class="kw">use </span>std::pin::Pin;
<a href=#4 id=4 data-nosnippet>4</a><span class="kw">use </span>std::sync::Arc;
<a href=#5 id=5 data-nosnippet>5</a><span class="kw">use </span>std::sync::atomic::Ordering;
<a href=#5 id=5 data-nosnippet>5</a><span class="kw">use </span>std::sync::atomic::{AtomicUsize, Ordering};
<a href=#6 id=6 data-nosnippet>6</a><span class="kw">use </span>std::task::{Context, Poll, ready};
<a href=#7 id=7 data-nosnippet>7</a><span class="kw">use </span>std::time::Duration;
<a href=#8 id=8 data-nosnippet>8</a>
@@ -13,7 +13,7 @@
<a href=#13 id=13 data-nosnippet>13</a><span class="kw">use </span>tokio::sync::watch;
<a href=#14 id=14 data-nosnippet>14</a><span class="kw">use </span>tokio_stream::{Stream, wrappers::WatchStream};
<a href=#15 id=15 data-nosnippet>15</a>
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span><span class="kw">crate</span>::connection::{ConnectionRef, PathRef};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span><span class="kw">crate</span>::connection::ConnectionRef;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use crate</span>::{Runtime, WeakConnectionHandle};
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="doccomment">/// Future produced by [`crate::Connection::open_path`]
@@ -110,340 +110,353 @@
<a href=#110 id=110 data-nosnippet>110</a>/// [`PathStats`] for this path are not dropped even after the path is abandoned.
<a href=#111 id=111 data-nosnippet>111</a>///
<a href=#112 id=112 data-nosnippet>112</a>/// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#113 id=113 data-nosnippet>113</a></span><span class="attr">#[derive(Debug)]
<a href=#113 id=113 data-nosnippet>113</a></span><span class="attr">#[derive(Debug, Clone)]
<a href=#114 id=114 data-nosnippet>114</a></span><span class="kw">pub struct </span>Path {
<a href=#115 id=115 data-nosnippet>115</a> id: PathId,
<a href=#116 id=116 data-nosnippet>116</a> conn: ConnectionRef,
<a href=#117 id=117 data-nosnippet>117</a> path_ref: Arc&lt;PathRef&gt;,
<a href=#118 id=118 data-nosnippet>118</a>}
<a href=#119 id=119 data-nosnippet>119</a>
<a href=#120 id=120 data-nosnippet>120</a><span class="kw">impl </span>Clone <span class="kw">for </span>Path {
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">fn </span>clone(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<a href=#122 id=122 data-nosnippet>122</a> <span class="self">self</span>.path_ref.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#123 id=123 data-nosnippet>123</a> <span class="self">Self </span>{
<a href=#124 id=124 data-nosnippet>124</a> id: <span class="self">self</span>.id,
<a href=#125 id=125 data-nosnippet>125</a> conn: <span class="self">self</span>.conn.clone(),
<a href=#126 id=126 data-nosnippet>126</a> path_ref: <span class="self">self</span>.path_ref.clone(),
<a href=#127 id=127 data-nosnippet>127</a> }
<a href=#128 id=128 data-nosnippet>128</a> }
<a href=#129 id=129 data-nosnippet>129</a>}
<a href=#130 id=130 data-nosnippet>130</a>
<a href=#131 id=131 data-nosnippet>131</a><span class="kw">impl </span>Drop <span class="kw">for </span>Path {
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">if </span><span class="self">self</span>.path_ref.ref_count.fetch_sub(<span class="number">1</span>, Ordering::Relaxed) &gt; <span class="number">1 </span>{
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">return</span>;
<a href=#135 id=135 data-nosnippet>135</a> }
<a href=#136 id=136 data-nosnippet>136</a> clear_path_state(<span class="kw-2">&amp;</span><span class="self">self</span>.conn, <span class="self">self</span>.id, <span class="kw-2">&amp;</span><span class="self">self</span>.path_ref);
<a href=#137 id=137 data-nosnippet>137</a> }
<a href=#138 id=138 data-nosnippet>138</a>}
<a href=#139 id=139 data-nosnippet>139</a>
<a href=#140 id=140 data-nosnippet>140</a><span class="kw">impl </span>Path {
<a href=#141 id=141 data-nosnippet>141</a> <span class="doccomment">/// Returns a [`Path`] for a path id, after checking that the path is not closed.
<a href=#142 id=142 data-nosnippet>142</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(conn: <span class="kw-2">&amp;</span>ConnectionRef, id: PathId) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>&gt; {
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span>path_ref = {
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span><span class="kw-2">mut </span>state = conn.lock_without_waking(<span class="string">"Path::new"</span>);
<a href=#145 id=145 data-nosnippet>145</a> <span class="comment">// TODO(flub): Using this to know if the path still exists is... hacky.
<a href=#146 id=146 data-nosnippet>146</a> </span>state.inner.path_status(id).ok()<span class="question-mark">?</span>;
<a href=#147 id=147 data-nosnippet>147</a> state.acquire_path_ref(id)
<a href=#148 id=148 data-nosnippet>148</a> };
<a href=#149 id=149 data-nosnippet>149</a> <span class="prelude-val">Some</span>(<span class="self">Self </span>{
<a href=#150 id=150 data-nosnippet>150</a> id,
<a href=#151 id=151 data-nosnippet>151</a> conn: conn.clone(),
<a href=#152 id=152 data-nosnippet>152</a> path_ref,
<a href=#153 id=153 data-nosnippet>153</a> })
<a href=#154 id=154 data-nosnippet>154</a> }
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="doccomment">/// Returns a [`Path`] for a path id without checking if the path exists or is closed.
<a href=#157 id=157 data-nosnippet>157</a> </span><span class="kw">fn </span>new_unchecked(conn: ConnectionRef, id: PathId) -&gt; <span class="self">Self </span>{
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">let </span>path_ref = conn
<a href=#159 id=159 data-nosnippet>159</a> .lock_without_waking(<span class="string">"Path::new_unchecked"</span>)
<a href=#160 id=160 data-nosnippet>160</a> .acquire_path_ref(id);
<a href=#161 id=161 data-nosnippet>161</a> <span class="self">Self </span>{ id, conn, path_ref }
<a href=#162 id=162 data-nosnippet>162</a> }
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="doccomment">/// Returns a [`WeakPathHandle`] for this path.
<a href=#165 id=165 data-nosnippet>165</a> ///
<a href=#166 id=166 data-nosnippet>166</a> /// Holding a [`WeakPathHandle`] does not keep a connection alive, but ensures that the
<a href=#167 id=167 data-nosnippet>167</a> /// path's stats are not dropped until the underlying connection is dropped, even if the
<a href=#168 id=168 data-nosnippet>168</a> /// path is abandoned.
<a href=#169 id=169 data-nosnippet>169</a> </span><span class="kw">pub fn </span>weak_handle(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; WeakPathHandle {
<a href=#170 id=170 data-nosnippet>170</a> <span class="self">self</span>.path_ref.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#171 id=171 data-nosnippet>171</a> WeakPathHandle {
<a href=#172 id=172 data-nosnippet>172</a> id: <span class="self">self</span>.id,
<a href=#173 id=173 data-nosnippet>173</a> conn: <span class="self">self</span>.conn.weak_handle(),
<a href=#174 id=174 data-nosnippet>174</a> path_ref: <span class="self">self</span>.path_ref.clone(),
<a href=#175 id=175 data-nosnippet>175</a> }
<a href=#176 id=176 data-nosnippet>176</a> }
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> <span class="doccomment">/// The [`PathId`] of this path.
<a href=#179 id=179 data-nosnippet>179</a> </span><span class="kw">pub fn </span>id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathId {
<a href=#180 id=180 data-nosnippet>180</a> <span class="self">self</span>.id
<a href=#181 id=181 data-nosnippet>181</a> }
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> <span class="doccomment">/// The current local [`PathStatus`] of this path.
<a href=#184 id=184 data-nosnippet>184</a> </span><span class="kw">pub fn </span>status(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;PathStatus, ClosedPath&gt; {
<a href=#185 id=185 data-nosnippet>185</a> <span class="self">self</span>.conn
<a href=#186 id=186 data-nosnippet>186</a> .lock_without_waking(<span class="string">"path status"</span>)
<a href=#187 id=187 data-nosnippet>187</a> .inner
<a href=#188 id=188 data-nosnippet>188</a> .path_status(<span class="self">self</span>.id)
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a>
<a href=#191 id=191 data-nosnippet>191</a> <span class="doccomment">/// Sets the [`PathStatus`] of this path.
<a href=#192 id=192 data-nosnippet>192</a> ///
<a href=#193 id=193 data-nosnippet>193</a> /// Returns the previous status of the path.
<a href=#194 id=194 data-nosnippet>194</a> </span><span class="kw">pub fn </span>set_status(<span class="kw-2">&amp;</span><span class="self">self</span>, status: PathStatus) -&gt; <span class="prelude-ty">Result</span>&lt;PathStatus, SetPathStatusError&gt; {
<a href=#195 id=195 data-nosnippet>195</a> <span class="self">self</span>.conn
<a href=#196 id=196 data-nosnippet>196</a> .lock_and_wake(<span class="string">"set path status"</span>)
<a href=#197 id=197 data-nosnippet>197</a> .inner
<a href=#198 id=198 data-nosnippet>198</a> .set_path_status(<span class="self">self</span>.id, status)
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="doccomment">/// Returns the [`PathStats`] for this path.
<a href=#202 id=202 data-nosnippet>202</a> </span><span class="kw">pub fn </span>stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathStats {
<a href=#203 id=203 data-nosnippet>203</a> <span class="comment">// The `expect` is safe:
<a href=#204 id=204 data-nosnippet>204</a> // - `Path` can only be created for non-closed paths.
<a href=#205 id=205 data-nosnippet>205</a> // - `Path` and its clones or `WeakPathHandle`s all increment the connection state's `path_ref`
<a href=#206 id=206 data-nosnippet>206</a> // reference counter
<a href=#207 id=207 data-nosnippet>207</a> // - As long as a path is not abandoned, its stats are available from `proto::Connection`
<a href=#208 id=208 data-nosnippet>208</a> // - If a path is abandoned, the `crate::Connection` stores the final stats as long as
<a href=#209 id=209 data-nosnippet>209</a> // the path's refcount is not 0
<a href=#210 id=210 data-nosnippet>210</a> // - Therefore, we always get stats here.
<a href=#211 id=211 data-nosnippet>211</a> </span><span class="self">self</span>.conn
<a href=#212 id=212 data-nosnippet>212</a> .lock_without_waking(<span class="string">"Path::stats"</span>)
<a href=#213 id=213 data-nosnippet>213</a> .path_stats(<span class="self">self</span>.id)
<a href=#214 id=214 data-nosnippet>214</a> .expect(<span class="string">"either path stats or discarded path stats are always set as long as Path is not dropped"</span>)
<a href=#215 id=215 data-nosnippet>215</a> }
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a> <span class="doccomment">/// Closes this path.
<a href=#218 id=218 data-nosnippet>218</a> ///
<a href=#219 id=219 data-nosnippet>219</a> /// The path is immediately considered closed by the local endpoint. Once the state is removed,
<a href=#220 id=220 data-nosnippet>220</a> /// after a short period of time for any in-flight packets, a [`PathEvent::Abandoned`] is
<a href=#221 id=221 data-nosnippet>221</a> /// returned.
<a href=#222 id=222 data-nosnippet>222</a> </span><span class="kw">pub fn </span>close(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), ClosePathError&gt; {
<a href=#223 id=223 data-nosnippet>223</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"close_path"</span>);
<a href=#224 id=224 data-nosnippet>224</a> state.inner.close_path(
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">crate</span>::Instant::now(),
<a href=#226 id=226 data-nosnippet>226</a> <span class="self">self</span>.id,
<a href=#227 id=227 data-nosnippet>227</a> TransportErrorCode::APPLICATION_ABANDON_PATH.into(),
<a href=#228 id=228 data-nosnippet>228</a> )
<a href=#229 id=229 data-nosnippet>229</a> }
<a href=#230 id=230 data-nosnippet>230</a>
<a href=#231 id=231 data-nosnippet>231</a> <span class="doccomment">/// Sets the max idle timeout for a specific path
<a href=#232 id=232 data-nosnippet>232</a> ///
<a href=#233 id=233 data-nosnippet>233</a> /// See [`TransportConfig::default_path_max_idle_timeout`] for details.
<a href=#234 id=234 data-nosnippet>234</a> ///
<a href=#235 id=235 data-nosnippet>235</a> /// Returns the previous value of the setting.
<a href=#236 id=236 data-nosnippet>236</a> ///
<a href=#237 id=237 data-nosnippet>237</a> /// [`TransportConfig::default_path_max_idle_timeout`]: crate::TransportConfig::default_path_max_idle_timeout
<a href=#238 id=238 data-nosnippet>238</a> </span><span class="kw">pub fn </span>set_max_idle_timeout(
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#240 id=240 data-nosnippet>240</a> timeout: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#241 id=241 data-nosnippet>241</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Duration&gt;, ClosedPath&gt; {
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"path_set_max_idle_timeout"</span>);
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>now = state.runtime.now();
<a href=#244 id=244 data-nosnippet>244</a> state.inner.set_path_max_idle_timeout(now, <span class="self">self</span>.id, timeout)
<a href=#245 id=245 data-nosnippet>245</a> }
<a href=#246 id=246 data-nosnippet>246</a>
<a href=#247 id=247 data-nosnippet>247</a> <span class="doccomment">/// Sets the keep_alive_interval for a specific path
<a href=#248 id=248 data-nosnippet>248</a> ///
<a href=#249 id=249 data-nosnippet>249</a> /// See [`TransportConfig::default_path_keep_alive_interval`] for details.
<a href=#250 id=250 data-nosnippet>250</a> ///
<a href=#251 id=251 data-nosnippet>251</a> /// Returns the previous value of the setting.
<a href=#252 id=252 data-nosnippet>252</a> ///
<a href=#253 id=253 data-nosnippet>253</a> /// [`TransportConfig::default_path_keep_alive_interval`]: crate::TransportConfig::default_path_keep_alive_interval
<a href=#254 id=254 data-nosnippet>254</a> </span><span class="kw">pub fn </span>set_keep_alive_interval(
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#256 id=256 data-nosnippet>256</a> interval: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#257 id=257 data-nosnippet>257</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Duration&gt;, ClosedPath&gt; {
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"path_set_keep_alive_interval"</span>);
<a href=#259 id=259 data-nosnippet>259</a> state.inner.set_path_keep_alive_interval(<span class="self">self</span>.id, interval)
<a href=#260 id=260 data-nosnippet>260</a> }
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a> <span class="doccomment">/// Track changes on our external address as reported by the peer.
<a href=#263 id=263 data-nosnippet>263</a> ///
<a href=#264 id=264 data-nosnippet>264</a> /// If the address-discovery extension is not negotiated, the stream will never return.
<a href=#265 id=265 data-nosnippet>265</a> </span><span class="kw">pub fn </span>observed_external_addr(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;AddressDiscovery, ClosedPath&gt; {
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">let </span>state = <span class="self">self</span>.conn.lock_without_waking(<span class="string">"per_path_observed_address"</span>);
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">let </span>path_events = state.path_events.subscribe();
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">let </span>initial_value = state.inner.path_observed_address(<span class="self">self</span>.id)<span class="question-mark">?</span>;
<a href=#269 id=269 data-nosnippet>269</a> <span class="prelude-val">Ok</span>(AddressDiscovery::new(
<a href=#270 id=270 data-nosnippet>270</a> <span class="self">self</span>.id,
<a href=#271 id=271 data-nosnippet>271</a> path_events,
<a href=#272 id=272 data-nosnippet>272</a> initial_value,
<a href=#273 id=273 data-nosnippet>273</a> state.runtime.clone(),
<a href=#274 id=274 data-nosnippet>274</a> ))
<a href=#275 id=275 data-nosnippet>275</a> }
<a href=#276 id=276 data-nosnippet>276</a>
<a href=#277 id=277 data-nosnippet>277</a> <span class="doccomment">/// The peer's UDP address for this path.
<a href=#278 id=278 data-nosnippet>278</a> </span><span class="kw">pub fn </span>remote_address(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;SocketAddr, ClosedPath&gt; {
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">let </span>state = <span class="self">self</span>.conn.lock_without_waking(<span class="string">"per_path_remote_address"</span>);
<a href=#280 id=280 data-nosnippet>280</a> <span class="prelude-val">Ok</span>(state.inner.network_path(<span class="self">self</span>.id)<span class="question-mark">?</span>.remote())
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="doccomment">/// The local IP used for this path, if known.
<a href=#284 id=284 data-nosnippet>284</a> ///
<a href=#285 id=285 data-nosnippet>285</a> /// Returns `Ok(None)` for clients or when the platform does not expose this information; see
<a href=#286 id=286 data-nosnippet>286</a> /// [`noq_udp::RecvMeta::dst_ip`](udp::RecvMeta::dst_ip) for supported platforms.
<a href=#287 id=287 data-nosnippet>287</a> </span><span class="kw">pub fn </span>local_ip(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;IpAddr&gt;, ClosedPath&gt; {
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">let </span>state = <span class="self">self</span>.conn.lock_without_waking(<span class="string">"per_path_local_ip"</span>);
<a href=#289 id=289 data-nosnippet>289</a> <span class="prelude-val">Ok</span>(state.inner.network_path(<span class="self">self</span>.id)<span class="question-mark">?</span>.local_ip())
<a href=#290 id=290 data-nosnippet>290</a> }
<a href=#291 id=291 data-nosnippet>291</a>
<a href=#292 id=292 data-nosnippet>292</a> <span class="doccomment">/// Ping the remote endpoint over this path.
<a href=#293 id=293 data-nosnippet>293</a> </span><span class="kw">pub fn </span>ping(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), ClosedPath&gt; {
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"ping"</span>);
<a href=#295 id=295 data-nosnippet>295</a> state.inner.ping_path(<span class="self">self</span>.id)
<a href=#296 id=296 data-nosnippet>296</a> }
<a href=#297 id=297 data-nosnippet>297</a>}
<a href=#298 id=298 data-nosnippet>298</a>
<a href=#299 id=299 data-nosnippet>299</a><span class="kw">impl </span>PartialEq <span class="kw">for </span>Path {
<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">fn </span>eq(<span class="kw-2">&amp;</span><span class="self">self</span>, other: <span class="kw-2">&amp;</span><span class="self">Self</span>) -&gt; bool {
<a href=#301 id=301 data-nosnippet>301</a> <span class="self">self</span>.id == other.id &amp;&amp; <span class="self">self</span>.conn.stable_id() == other.conn.stable_id()
<a href=#302 id=302 data-nosnippet>302</a> }
<a href=#115 id=115 data-nosnippet>115</a> conn: ConnectionRef,
<a href=#116 id=116 data-nosnippet>116</a> path_ref: PathRef,
<a href=#117 id=117 data-nosnippet>117</a>}
<a href=#118 id=118 data-nosnippet>118</a>
<a href=#119 id=119 data-nosnippet>119</a><span class="kw">impl </span>Path {
<a href=#120 id=120 data-nosnippet>120</a> <span class="doccomment">/// Returns a [`Path`] for a path id, after checking that the path is not closed.
<a href=#121 id=121 data-nosnippet>121</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(conn: <span class="kw-2">&amp;</span>ConnectionRef, id: PathId) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>&gt; {
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span>path_ref = {
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span><span class="kw-2">mut </span>state = conn.lock_without_waking(<span class="string">"Path::new"</span>);
<a href=#124 id=124 data-nosnippet>124</a> <span class="comment">// TODO(flub): Using this to know if the path still exists is... hacky.
<a href=#125 id=125 data-nosnippet>125</a> </span>state.inner.path_status(id).ok()<span class="question-mark">?</span>;
<a href=#126 id=126 data-nosnippet>126</a> state.acquire_path_ref(id)
<a href=#127 id=127 data-nosnippet>127</a> };
<a href=#128 id=128 data-nosnippet>128</a> <span class="prelude-val">Some</span>(<span class="self">Self </span>{
<a href=#129 id=129 data-nosnippet>129</a> conn: conn.clone(),
<a href=#130 id=130 data-nosnippet>130</a> path_ref,
<a href=#131 id=131 data-nosnippet>131</a> })
<a href=#132 id=132 data-nosnippet>132</a> }
<a href=#133 id=133 data-nosnippet>133</a>
<a href=#134 id=134 data-nosnippet>134</a> <span class="doccomment">/// Returns a [`Path`] for a path id without checking if the path exists or is closed.
<a href=#135 id=135 data-nosnippet>135</a> </span><span class="kw">fn </span>new_unchecked(conn: ConnectionRef, id: PathId) -&gt; <span class="self">Self </span>{
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">let </span>path_ref = conn
<a href=#137 id=137 data-nosnippet>137</a> .lock_without_waking(<span class="string">"Path::new_unchecked"</span>)
<a href=#138 id=138 data-nosnippet>138</a> .acquire_path_ref(id);
<a href=#139 id=139 data-nosnippet>139</a> <span class="self">Self </span>{ conn, path_ref }
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a>
<a href=#142 id=142 data-nosnippet>142</a> <span class="doccomment">/// Returns a [`WeakPathHandle`] for this path.
<a href=#143 id=143 data-nosnippet>143</a> ///
<a href=#144 id=144 data-nosnippet>144</a> /// Holding a [`WeakPathHandle`] does not keep a connection alive, but ensures that the
<a href=#145 id=145 data-nosnippet>145</a> /// path's stats are not dropped until the underlying connection is dropped, even if the
<a href=#146 id=146 data-nosnippet>146</a> /// path is abandoned.
<a href=#147 id=147 data-nosnippet>147</a> </span><span class="kw">pub fn </span>weak_handle(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; WeakPathHandle {
<a href=#148 id=148 data-nosnippet>148</a> WeakPathHandle {
<a href=#149 id=149 data-nosnippet>149</a> path_ref: <span class="self">self</span>.path_ref.clone(),
<a href=#150 id=150 data-nosnippet>150</a> conn: <span class="self">self</span>.conn.weak_handle(),
<a href=#151 id=151 data-nosnippet>151</a> }
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="doccomment">/// The [`PathId`] of this path.
<a href=#155 id=155 data-nosnippet>155</a> </span><span class="kw">pub fn </span>id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathId {
<a href=#156 id=156 data-nosnippet>156</a> <span class="self">self</span>.path_ref.id
<a href=#157 id=157 data-nosnippet>157</a> }
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a> <span class="doccomment">/// The current local [`PathStatus`] of this path.
<a href=#160 id=160 data-nosnippet>160</a> </span><span class="kw">pub fn </span>status(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;PathStatus, ClosedPath&gt; {
<a href=#161 id=161 data-nosnippet>161</a> <span class="self">self</span>.conn
<a href=#162 id=162 data-nosnippet>162</a> .lock_without_waking(<span class="string">"path status"</span>)
<a href=#163 id=163 data-nosnippet>163</a> .inner
<a href=#164 id=164 data-nosnippet>164</a> .path_status(<span class="self">self</span>.id())
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a>
<a href=#167 id=167 data-nosnippet>167</a> <span class="doccomment">/// Sets the [`PathStatus`] of this path.
<a href=#168 id=168 data-nosnippet>168</a> ///
<a href=#169 id=169 data-nosnippet>169</a> /// Returns the previous status of the path.
<a href=#170 id=170 data-nosnippet>170</a> </span><span class="kw">pub fn </span>set_status(<span class="kw-2">&amp;</span><span class="self">self</span>, status: PathStatus) -&gt; <span class="prelude-ty">Result</span>&lt;PathStatus, SetPathStatusError&gt; {
<a href=#171 id=171 data-nosnippet>171</a> <span class="self">self</span>.conn
<a href=#172 id=172 data-nosnippet>172</a> .lock_and_wake(<span class="string">"set path status"</span>)
<a href=#173 id=173 data-nosnippet>173</a> .inner
<a href=#174 id=174 data-nosnippet>174</a> .set_path_status(<span class="self">self</span>.id(), status)
<a href=#175 id=175 data-nosnippet>175</a> }
<a href=#176 id=176 data-nosnippet>176</a>
<a href=#177 id=177 data-nosnippet>177</a> <span class="doccomment">/// Returns the [`PathStats`] for this path.
<a href=#178 id=178 data-nosnippet>178</a> </span><span class="kw">pub fn </span>stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathStats {
<a href=#179 id=179 data-nosnippet>179</a> <span class="comment">// The `expect` is safe:
<a href=#180 id=180 data-nosnippet>180</a> // - `Path` can only be created for non-closed paths.
<a href=#181 id=181 data-nosnippet>181</a> // - `Path` and its clones or `WeakPathHandle`s all increment the connection state's `path_ref`
<a href=#182 id=182 data-nosnippet>182</a> // reference counter
<a href=#183 id=183 data-nosnippet>183</a> // - As long as a path is not abandoned, its stats are available from `proto::Connection`
<a href=#184 id=184 data-nosnippet>184</a> // - If a path is abandoned, the `crate::Connection` stores the final stats as long as
<a href=#185 id=185 data-nosnippet>185</a> // the path's refcount is not 0
<a href=#186 id=186 data-nosnippet>186</a> // - Therefore, we always get stats here.
<a href=#187 id=187 data-nosnippet>187</a> </span><span class="self">self</span>.conn
<a href=#188 id=188 data-nosnippet>188</a> .lock_without_waking(<span class="string">"Path::stats"</span>)
<a href=#189 id=189 data-nosnippet>189</a> .path_stats(<span class="self">self</span>.id())
<a href=#190 id=190 data-nosnippet>190</a> .expect(<span class="string">"either path stats or discarded path stats are always set as long as Path is not dropped"</span>)
<a href=#191 id=191 data-nosnippet>191</a> }
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a> <span class="doccomment">/// Closes this path.
<a href=#194 id=194 data-nosnippet>194</a> ///
<a href=#195 id=195 data-nosnippet>195</a> /// The path is immediately considered closed by the local endpoint. Once the state is removed,
<a href=#196 id=196 data-nosnippet>196</a> /// after a short period of time for any in-flight packets, a [`PathEvent::Abandoned`] is
<a href=#197 id=197 data-nosnippet>197</a> /// returned.
<a href=#198 id=198 data-nosnippet>198</a> </span><span class="kw">pub fn </span>close(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), ClosePathError&gt; {
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"close_path"</span>);
<a href=#200 id=200 data-nosnippet>200</a> state.inner.close_path(
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">crate</span>::Instant::now(),
<a href=#202 id=202 data-nosnippet>202</a> <span class="self">self</span>.id(),
<a href=#203 id=203 data-nosnippet>203</a> TransportErrorCode::APPLICATION_ABANDON_PATH.into(),
<a href=#204 id=204 data-nosnippet>204</a> )
<a href=#205 id=205 data-nosnippet>205</a> }
<a href=#206 id=206 data-nosnippet>206</a>
<a href=#207 id=207 data-nosnippet>207</a> <span class="doccomment">/// Sets the max idle timeout for a specific path
<a href=#208 id=208 data-nosnippet>208</a> ///
<a href=#209 id=209 data-nosnippet>209</a> /// See [`TransportConfig::default_path_max_idle_timeout`] for details.
<a href=#210 id=210 data-nosnippet>210</a> ///
<a href=#211 id=211 data-nosnippet>211</a> /// Returns the previous value of the setting.
<a href=#212 id=212 data-nosnippet>212</a> ///
<a href=#213 id=213 data-nosnippet>213</a> /// [`TransportConfig::default_path_max_idle_timeout`]: crate::TransportConfig::default_path_max_idle_timeout
<a href=#214 id=214 data-nosnippet>214</a> </span><span class="kw">pub fn </span>set_max_idle_timeout(
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#216 id=216 data-nosnippet>216</a> timeout: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#217 id=217 data-nosnippet>217</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Duration&gt;, ClosedPath&gt; {
<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"path_set_max_idle_timeout"</span>);
<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">let </span>now = state.runtime.now();
<a href=#220 id=220 data-nosnippet>220</a> state
<a href=#221 id=221 data-nosnippet>221</a> .inner
<a href=#222 id=222 data-nosnippet>222</a> .set_path_max_idle_timeout(now, <span class="self">self</span>.id(), timeout)
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a>
<a href=#225 id=225 data-nosnippet>225</a> <span class="doccomment">/// Sets the keep_alive_interval for a specific path
<a href=#226 id=226 data-nosnippet>226</a> ///
<a href=#227 id=227 data-nosnippet>227</a> /// See [`TransportConfig::default_path_keep_alive_interval`] for details.
<a href=#228 id=228 data-nosnippet>228</a> ///
<a href=#229 id=229 data-nosnippet>229</a> /// Returns the previous value of the setting.
<a href=#230 id=230 data-nosnippet>230</a> ///
<a href=#231 id=231 data-nosnippet>231</a> /// [`TransportConfig::default_path_keep_alive_interval`]: crate::TransportConfig::default_path_keep_alive_interval
<a href=#232 id=232 data-nosnippet>232</a> </span><span class="kw">pub fn </span>set_keep_alive_interval(
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#234 id=234 data-nosnippet>234</a> interval: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#235 id=235 data-nosnippet>235</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Duration&gt;, ClosedPath&gt; {
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"path_set_keep_alive_interval"</span>);
<a href=#237 id=237 data-nosnippet>237</a> state
<a href=#238 id=238 data-nosnippet>238</a> .inner
<a href=#239 id=239 data-nosnippet>239</a> .set_path_keep_alive_interval(<span class="self">self</span>.id(), interval)
<a href=#240 id=240 data-nosnippet>240</a> }
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a> <span class="doccomment">/// Track changes on our external address as reported by the peer.
<a href=#243 id=243 data-nosnippet>243</a> ///
<a href=#244 id=244 data-nosnippet>244</a> /// If the address-discovery extension is not negotiated, the stream will never return.
<a href=#245 id=245 data-nosnippet>245</a> </span><span class="kw">pub fn </span>observed_external_addr(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;AddressDiscovery, ClosedPath&gt; {
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">let </span>state = <span class="self">self</span>.conn.lock_without_waking(<span class="string">"per_path_observed_address"</span>);
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">let </span>path_events = state.path_events.subscribe();
<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">let </span>initial_value = state.inner.path_observed_address(<span class="self">self</span>.id())<span class="question-mark">?</span>;
<a href=#249 id=249 data-nosnippet>249</a> <span class="prelude-val">Ok</span>(AddressDiscovery::new(
<a href=#250 id=250 data-nosnippet>250</a> <span class="self">self</span>.id(),
<a href=#251 id=251 data-nosnippet>251</a> path_events,
<a href=#252 id=252 data-nosnippet>252</a> initial_value,
<a href=#253 id=253 data-nosnippet>253</a> state.runtime.clone(),
<a href=#254 id=254 data-nosnippet>254</a> ))
<a href=#255 id=255 data-nosnippet>255</a> }
<a href=#256 id=256 data-nosnippet>256</a>
<a href=#257 id=257 data-nosnippet>257</a> <span class="doccomment">/// The peer's UDP address for this path.
<a href=#258 id=258 data-nosnippet>258</a> </span><span class="kw">pub fn </span>remote_address(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;SocketAddr, ClosedPath&gt; {
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">let </span>state = <span class="self">self</span>.conn.lock_without_waking(<span class="string">"per_path_remote_address"</span>);
<a href=#260 id=260 data-nosnippet>260</a> <span class="prelude-val">Ok</span>(state.inner.network_path(<span class="self">self</span>.id())<span class="question-mark">?</span>.remote())
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a>
<a href=#263 id=263 data-nosnippet>263</a> <span class="doccomment">/// The local IP used for this path, if known.
<a href=#264 id=264 data-nosnippet>264</a> ///
<a href=#265 id=265 data-nosnippet>265</a> /// Returns `Ok(None)` for clients or when the platform does not expose this information; see
<a href=#266 id=266 data-nosnippet>266</a> /// [`noq_udp::RecvMeta::dst_ip`](udp::RecvMeta::dst_ip) for supported platforms.
<a href=#267 id=267 data-nosnippet>267</a> </span><span class="kw">pub fn </span>local_ip(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;IpAddr&gt;, ClosedPath&gt; {
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">let </span>state = <span class="self">self</span>.conn.lock_without_waking(<span class="string">"per_path_local_ip"</span>);
<a href=#269 id=269 data-nosnippet>269</a> <span class="prelude-val">Ok</span>(state.inner.network_path(<span class="self">self</span>.id())<span class="question-mark">?</span>.local_ip())
<a href=#270 id=270 data-nosnippet>270</a> }
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="doccomment">/// Ping the remote endpoint over this path.
<a href=#273 id=273 data-nosnippet>273</a> </span><span class="kw">pub fn </span>ping(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), ClosedPath&gt; {
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.conn.lock_and_wake(<span class="string">"ping"</span>);
<a href=#275 id=275 data-nosnippet>275</a> state.inner.ping_path(<span class="self">self</span>.id())
<a href=#276 id=276 data-nosnippet>276</a> }
<a href=#277 id=277 data-nosnippet>277</a>}
<a href=#278 id=278 data-nosnippet>278</a>
<a href=#279 id=279 data-nosnippet>279</a><span class="kw">impl </span>Drop <span class="kw">for </span>Path {
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#281 id=281 data-nosnippet>281</a> <span class="self">self</span>.path_ref.on_drop(<span class="kw-2">&amp;</span><span class="self">self</span>.conn);
<a href=#282 id=282 data-nosnippet>282</a> }
<a href=#283 id=283 data-nosnippet>283</a>}
<a href=#284 id=284 data-nosnippet>284</a>
<a href=#285 id=285 data-nosnippet>285</a><span class="kw">impl </span>PartialEq <span class="kw">for </span>Path {
<a href=#286 id=286 data-nosnippet>286</a> <span class="kw">fn </span>eq(<span class="kw-2">&amp;</span><span class="self">self</span>, other: <span class="kw-2">&amp;</span><span class="self">Self</span>) -&gt; bool {
<a href=#287 id=287 data-nosnippet>287</a> <span class="self">self</span>.id() == other.id() &amp;&amp; <span class="self">self</span>.conn.stable_id() == other.conn.stable_id()
<a href=#288 id=288 data-nosnippet>288</a> }
<a href=#289 id=289 data-nosnippet>289</a>}
<a href=#290 id=290 data-nosnippet>290</a>
<a href=#291 id=291 data-nosnippet>291</a><span class="doccomment">/// Weak handle for a [`Path`] that does not keep the connection alive.
<a href=#292 id=292 data-nosnippet>292</a>///
<a href=#293 id=293 data-nosnippet>293</a>/// As long as a [`WeakPathHandle`] for a path exists, that path's final stats will not be dropped even if
<a href=#294 id=294 data-nosnippet>294</a>/// the path was abandoned.
<a href=#295 id=295 data-nosnippet>295</a>///
<a href=#296 id=296 data-nosnippet>296</a>/// The [`WeakPathHandle`] can be upgraded to a [`Path`] as long as its [`Connection`] has not been dropped.
<a href=#297 id=297 data-nosnippet>297</a>///
<a href=#298 id=298 data-nosnippet>298</a>/// [`Connection`]: crate::Connection
<a href=#299 id=299 data-nosnippet>299</a></span><span class="attr">#[derive(Debug, Clone)]
<a href=#300 id=300 data-nosnippet>300</a></span><span class="kw">pub struct </span>WeakPathHandle {
<a href=#301 id=301 data-nosnippet>301</a> conn: WeakConnectionHandle,
<a href=#302 id=302 data-nosnippet>302</a> path_ref: PathRef,
<a href=#303 id=303 data-nosnippet>303</a>}
<a href=#304 id=304 data-nosnippet>304</a>
<a href=#305 id=305 data-nosnippet>305</a><span class="doccomment">/// Weak handle for a [`Path`] that does not keep the connection alive.
<a href=#306 id=306 data-nosnippet>306</a>///
<a href=#307 id=307 data-nosnippet>307</a>/// As long as a [`WeakPathHandle`] for a path exists, that path's final stats will not be dropped even if
<a href=#308 id=308 data-nosnippet>308</a>/// the path was abandoned.
<a href=#309 id=309 data-nosnippet>309</a>///
<a href=#310 id=310 data-nosnippet>310</a>/// The [`WeakPathHandle`] can be upgraded to a [`Path`] as long as its [`Connection`] has not been dropped.
<a href=#311 id=311 data-nosnippet>311</a>///
<a href=#312 id=312 data-nosnippet>312</a>/// [`Connection`]: crate::Connection
<a href=#313 id=313 data-nosnippet>313</a></span><span class="attr">#[derive(Debug)]
<a href=#314 id=314 data-nosnippet>314</a></span><span class="kw">pub struct </span>WeakPathHandle {
<a href=#315 id=315 data-nosnippet>315</a> id: PathId,
<a href=#316 id=316 data-nosnippet>316</a> conn: WeakConnectionHandle,
<a href=#317 id=317 data-nosnippet>317</a> path_ref: Arc&lt;PathRef&gt;,
<a href=#318 id=318 data-nosnippet>318</a>}
<a href=#319 id=319 data-nosnippet>319</a>
<a href=#320 id=320 data-nosnippet>320</a><span class="kw">impl </span>Clone <span class="kw">for </span>WeakPathHandle {
<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">fn </span>clone(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<a href=#322 id=322 data-nosnippet>322</a> <span class="self">self</span>.path_ref.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#323 id=323 data-nosnippet>323</a> <span class="self">Self </span>{
<a href=#324 id=324 data-nosnippet>324</a> id: <span class="self">self</span>.id,
<a href=#325 id=325 data-nosnippet>325</a> conn: <span class="self">self</span>.conn.clone(),
<a href=#305 id=305 data-nosnippet>305</a><span class="kw">impl </span>PartialEq <span class="kw">for </span>WeakPathHandle {
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw">fn </span>eq(<span class="kw-2">&amp;</span><span class="self">self</span>, other: <span class="kw-2">&amp;</span><span class="self">Self</span>) -&gt; bool {
<a href=#307 id=307 data-nosnippet>307</a> <span class="self">self</span>.id() == other.id() &amp;&amp; <span class="self">self</span>.conn.is_same_connection(<span class="kw-2">&amp;</span>other.conn)
<a href=#308 id=308 data-nosnippet>308</a> }
<a href=#309 id=309 data-nosnippet>309</a>}
<a href=#310 id=310 data-nosnippet>310</a>
<a href=#311 id=311 data-nosnippet>311</a><span class="kw">impl </span>Eq <span class="kw">for </span>WeakPathHandle {}
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a><span class="kw">impl </span>WeakPathHandle {
<a href=#314 id=314 data-nosnippet>314</a> <span class="doccomment">/// Returns the [`PathId`] of this path.
<a href=#315 id=315 data-nosnippet>315</a> </span><span class="kw">pub fn </span>id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathId {
<a href=#316 id=316 data-nosnippet>316</a> <span class="self">self</span>.path_ref.id
<a href=#317 id=317 data-nosnippet>317</a> }
<a href=#318 id=318 data-nosnippet>318</a>
<a href=#319 id=319 data-nosnippet>319</a> <span class="doccomment">/// Upgrades to a [`Path`].
<a href=#320 id=320 data-nosnippet>320</a> ///
<a href=#321 id=321 data-nosnippet>321</a> /// Returns `None` if the connection was dropped.
<a href=#322 id=322 data-nosnippet>322</a> </span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Path&gt; {
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">let </span>conn = <span class="self">self</span>.conn.upgrade_to_ref()<span class="question-mark">?</span>;
<a href=#324 id=324 data-nosnippet>324</a> <span class="prelude-val">Some</span>(Path {
<a href=#325 id=325 data-nosnippet>325</a> conn,
<a href=#326 id=326 data-nosnippet>326</a> path_ref: <span class="self">self</span>.path_ref.clone(),
<a href=#327 id=327 data-nosnippet>327</a> }
<a href=#327 id=327 data-nosnippet>327</a> })
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a>}
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a><span class="kw">impl </span>PartialEq <span class="kw">for </span>WeakPathHandle {
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">fn </span>eq(<span class="kw-2">&amp;</span><span class="self">self</span>, other: <span class="kw-2">&amp;</span><span class="self">Self</span>) -&gt; bool {
<a href=#333 id=333 data-nosnippet>333</a> <span class="self">self</span>.id == other.id &amp;&amp; <span class="self">self</span>.conn.is_same_connection(<span class="kw-2">&amp;</span>other.conn)
<a href=#334 id=334 data-nosnippet>334</a> }
<a href=#335 id=335 data-nosnippet>335</a>}
<a href=#336 id=336 data-nosnippet>336</a>
<a href=#337 id=337 data-nosnippet>337</a><span class="kw">impl </span>Eq <span class="kw">for </span>WeakPathHandle {}
<a href=#331 id=331 data-nosnippet>331</a><span class="kw">impl </span>Drop <span class="kw">for </span>WeakPathHandle {
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(conn) = <span class="self">self</span>.conn.upgrade_to_ref() {
<a href=#334 id=334 data-nosnippet>334</a> <span class="self">self</span>.path_ref.on_drop(<span class="kw-2">&amp;</span>conn);
<a href=#335 id=335 data-nosnippet>335</a> }
<a href=#336 id=336 data-nosnippet>336</a> }
<a href=#337 id=337 data-nosnippet>337</a>}
<a href=#338 id=338 data-nosnippet>338</a>
<a href=#339 id=339 data-nosnippet>339</a><span class="kw">impl </span>Drop <span class="kw">for </span>WeakPathHandle {
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#341 id=341 data-nosnippet>341</a> <span class="kw">if </span><span class="self">self</span>.path_ref.ref_count.fetch_sub(<span class="number">1</span>, Ordering::Relaxed) &gt; <span class="number">1 </span>{
<a href=#342 id=342 data-nosnippet>342</a> <span class="kw">return</span>;
<a href=#343 id=343 data-nosnippet>343</a> }
<a href=#344 id=344 data-nosnippet>344</a> <span class="kw">let </span><span class="prelude-val">Some</span>(conn) = <span class="self">self</span>.conn.upgrade_to_ref() <span class="kw">else </span>{
<a href=#345 id=345 data-nosnippet>345</a> <span class="kw">return</span>;
<a href=#346 id=346 data-nosnippet>346</a> };
<a href=#347 id=347 data-nosnippet>347</a> clear_path_state(<span class="kw-2">&amp;</span>conn, <span class="self">self</span>.id, <span class="kw-2">&amp;</span><span class="self">self</span>.path_ref);
<a href=#348 id=348 data-nosnippet>348</a> }
<a href=#349 id=349 data-nosnippet>349</a>}
<a href=#350 id=350 data-nosnippet>350</a>
<a href=#351 id=351 data-nosnippet>351</a><span class="kw">impl </span>WeakPathHandle {
<a href=#352 id=352 data-nosnippet>352</a> <span class="doccomment">/// Returns the [`PathId`] of this path.
<a href=#353 id=353 data-nosnippet>353</a> </span><span class="kw">pub fn </span>id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathId {
<a href=#354 id=354 data-nosnippet>354</a> <span class="self">self</span>.id
<a href=#355 id=355 data-nosnippet>355</a> }
<a href=#356 id=356 data-nosnippet>356</a>
<a href=#357 id=357 data-nosnippet>357</a> <span class="doccomment">/// Upgrades to a [`Path`].
<a href=#358 id=358 data-nosnippet>358</a> ///
<a href=#359 id=359 data-nosnippet>359</a> /// Returns `None` if the connection was dropped.
<a href=#360 id=360 data-nosnippet>360</a> </span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Path&gt; {
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">let </span>conn = <span class="self">self</span>.conn.upgrade_to_ref()<span class="question-mark">?</span>;
<a href=#362 id=362 data-nosnippet>362</a> <span class="self">self</span>.path_ref.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#363 id=363 data-nosnippet>363</a> <span class="prelude-val">Some</span>(Path {
<a href=#364 id=364 data-nosnippet>364</a> id: <span class="self">self</span>.id,
<a href=#365 id=365 data-nosnippet>365</a> conn,
<a href=#366 id=366 data-nosnippet>366</a> path_ref: <span class="self">self</span>.path_ref.clone(),
<a href=#367 id=367 data-nosnippet>367</a> })
<a href=#368 id=368 data-nosnippet>368</a> }
<a href=#369 id=369 data-nosnippet>369</a>}
<a href=#370 id=370 data-nosnippet>370</a>
<a href=#371 id=371 data-nosnippet>371</a><span class="doccomment">/// Releases the connection state entries for a path once its reference count hits zero.
<a href=#372 id=372 data-nosnippet>372</a>///
<a href=#373 id=373 data-nosnippet>373</a>/// Acquires the connection state lock, re-checks the counter under the lock to guard against
<a href=#374 id=374 data-nosnippet>374</a>/// a concurrent constructor that bumped it back up between our `fetch_sub` and the lock, and
<a href=#375 id=375 data-nosnippet>375</a>/// then drops the [`PathRef`] entry along with any cached final stats.
<a href=#376 id=376 data-nosnippet>376</a></span><span class="kw">fn </span>clear_path_state(conn: <span class="kw-2">&amp;</span>ConnectionRef, id: PathId, path_ref: <span class="kw-2">&amp;</span>Arc&lt;PathRef&gt;) {
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">let </span><span class="kw-2">mut </span>state = conn.lock_without_waking(<span class="string">"clear_path_state"</span>);
<a href=#378 id=378 data-nosnippet>378</a> <span class="kw">if </span>path_ref.ref_count.load(Ordering::Relaxed) &gt; <span class="number">0 </span>{
<a href=#379 id=379 data-nosnippet>379</a> <span class="kw">return</span>;
<a href=#380 id=380 data-nosnippet>380</a> }
<a href=#381 id=381 data-nosnippet>381</a> state.path_refs.remove(<span class="kw-2">&amp;</span>id);
<a href=#382 id=382 data-nosnippet>382</a> state.final_path_stats.remove(<span class="kw-2">&amp;</span>id);
<a href=#383 id=383 data-nosnippet>383</a>}
<a href=#384 id=384 data-nosnippet>384</a>
<a href=#385 id=385 data-nosnippet>385</a><span class="doccomment">/// Stream produced by [`Path::observed_external_addr`]
<a href=#386 id=386 data-nosnippet>386</a>///
<a href=#387 id=387 data-nosnippet>387</a>/// This will always return the external address most recently reported by the remote over this
<a href=#388 id=388 data-nosnippet>388</a>/// path. If the extension is not negotiated, this stream will never return.
<a href=#389 id=389 data-nosnippet>389</a></span><span class="comment">// TODO(@divma): provide a way to check if the extension is negotiated.
<a href=#390 id=390 data-nosnippet>390</a></span><span class="kw">pub struct </span>AddressDiscovery {
<a href=#391 id=391 data-nosnippet>391</a> watcher: WatchStream&lt;SocketAddr&gt;,
<a href=#392 id=392 data-nosnippet>392</a>}
<a href=#393 id=393 data-nosnippet>393</a>
<a href=#394 id=394 data-nosnippet>394</a><span class="kw">impl </span>AddressDiscovery {
<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(
<a href=#396 id=396 data-nosnippet>396</a> path_id: PathId,
<a href=#397 id=397 data-nosnippet>397</a> <span class="kw-2">mut </span>path_events: tokio::sync::broadcast::Receiver&lt;PathEvent&gt;,
<a href=#398 id=398 data-nosnippet>398</a> initial_value: <span class="prelude-ty">Option</span>&lt;SocketAddr&gt;,
<a href=#399 id=399 data-nosnippet>399</a> runtime: Arc&lt;<span class="kw">dyn </span>Runtime&gt;,
<a href=#400 id=400 data-nosnippet>400</a> ) -&gt; <span class="self">Self </span>{
<a href=#401 id=401 data-nosnippet>401</a> <span class="kw">let </span>(tx, rx) = watch::channel(initial_value.unwrap_or_else(||
<a href=#402 id=402 data-nosnippet>402</a> <span class="comment">// if the dummy value is used, it will be ignored
<a href=#403 id=403 data-nosnippet>403</a> </span>SocketAddr::new([<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>].into(), <span class="number">0</span>)));
<a href=#404 id=404 data-nosnippet>404</a> <span class="kw">let </span>filter = <span class="kw">async move </span>{
<a href=#405 id=405 data-nosnippet>405</a> <span class="kw">loop </span>{
<a href=#406 id=406 data-nosnippet>406</a> <span class="kw">match </span>path_events.recv().<span class="kw">await </span>{
<a href=#407 id=407 data-nosnippet>407</a> <span class="prelude-val">Ok</span>(PathEvent::ObservedAddr { id, addr: observed }) <span class="kw">if </span>id == path_id =&gt; {
<a href=#408 id=408 data-nosnippet>408</a> tx.send_if_modified(|addr| {
<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">let </span>old = std::mem::replace(addr, observed);
<a href=#410 id=410 data-nosnippet>410</a> old != <span class="kw-2">*</span>addr
<a href=#411 id=411 data-nosnippet>411</a> });
<a href=#412 id=412 data-nosnippet>412</a> }
<a href=#413 id=413 data-nosnippet>413</a> <span class="prelude-val">Ok</span>(PathEvent::Discarded { id, .. }) <span class="kw">if </span>id == path_id =&gt; {
<a href=#414 id=414 data-nosnippet>414</a> <span class="comment">// If the path is closed, terminate the stream
<a href=#415 id=415 data-nosnippet>415</a> </span><span class="kw">break</span>;
<a href=#416 id=416 data-nosnippet>416</a> }
<a href=#417 id=417 data-nosnippet>417</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
<a href=#418 id=418 data-nosnippet>418</a> <span class="comment">// ignore any other event
<a href=#419 id=419 data-nosnippet>419</a> </span>}
<a href=#420 id=420 data-nosnippet>420</a> <span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; {
<a href=#421 id=421 data-nosnippet>421</a> <span class="comment">// A lagged error should never happen since this (detached) task is
<a href=#422 id=422 data-nosnippet>422</a> // constantly reading from the channel. Therefore, if an error does happen,
<a href=#423 id=423 data-nosnippet>423</a> // the stream can terminate
<a href=#424 id=424 data-nosnippet>424</a> </span><span class="kw">break</span>;
<a href=#339 id=339 data-nosnippet>339</a><span class="doccomment">/// Owner side of a path's reference counter, stored in [`State::path_refs`].
<a href=#340 id=340 data-nosnippet>340</a>///
<a href=#341 id=341 data-nosnippet>341</a>/// Holds the shared [`AtomicUsize`] but does not itself contribute to the count.
<a href=#342 id=342 data-nosnippet>342</a>/// Hands out [`PathRef`] handles via [`Self::acquire`].
<a href=#343 id=343 data-nosnippet>343</a></span><span class="attr">#[derive(Debug, Default)]
<a href=#344 id=344 data-nosnippet>344</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>PathRefOwner {
<a href=#345 id=345 data-nosnippet>345</a> ref_count: Arc&lt;AtomicUsize&gt;,
<a href=#346 id=346 data-nosnippet>346</a>}
<a href=#347 id=347 data-nosnippet>347</a>
<a href=#348 id=348 data-nosnippet>348</a><span class="kw">impl </span>PathRefOwner {
<a href=#349 id=349 data-nosnippet>349</a> <span class="doccomment">/// Acquire a new [`PathRef`] handle, bumping the reference counter by 1.
<a href=#350 id=350 data-nosnippet>350</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>acquire(<span class="kw-2">&amp;</span><span class="self">self</span>, path_id: PathId) -&gt; PathRef {
<a href=#351 id=351 data-nosnippet>351</a> <span class="self">self</span>.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#352 id=352 data-nosnippet>352</a> PathRef {
<a href=#353 id=353 data-nosnippet>353</a> id: path_id,
<a href=#354 id=354 data-nosnippet>354</a> ref_count: <span class="self">self</span>.ref_count.clone(),
<a href=#355 id=355 data-nosnippet>355</a> }
<a href=#356 id=356 data-nosnippet>356</a> }
<a href=#357 id=357 data-nosnippet>357</a>}
<a href=#358 id=358 data-nosnippet>358</a>
<a href=#359 id=359 data-nosnippet>359</a><span class="doccomment">/// Handle side of a path's reference counter, held by [`Path`] and [`WeakPathHandle`].
<a href=#360 id=360 data-nosnippet>360</a>///
<a href=#361 id=361 data-nosnippet>361</a>/// Cloning bumps the counter, dropping decrements it. The last-dropped handle takes
<a href=#362 id=362 data-nosnippet>362</a>/// the connection state lock to clear the corresponding entries from
<a href=#363 id=363 data-nosnippet>363</a>/// [`State::path_refs`] and [`State::final_path_stats`].
<a href=#364 id=364 data-nosnippet>364</a>///
<a href=#365 id=365 data-nosnippet>365</a>/// [`WeakPathHandle`]: crate::path::WeakPathHandle
<a href=#366 id=366 data-nosnippet>366</a></span><span class="attr">#[derive(Debug)]
<a href=#367 id=367 data-nosnippet>367</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>PathRef {
<a href=#368 id=368 data-nosnippet>368</a> id: PathId,
<a href=#369 id=369 data-nosnippet>369</a> ref_count: Arc&lt;AtomicUsize&gt;,
<a href=#370 id=370 data-nosnippet>370</a>}
<a href=#371 id=371 data-nosnippet>371</a>
<a href=#372 id=372 data-nosnippet>372</a><span class="kw">impl </span>Clone <span class="kw">for </span>PathRef {
<a href=#373 id=373 data-nosnippet>373</a> <span class="kw">fn </span>clone(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<a href=#374 id=374 data-nosnippet>374</a> <span class="self">self</span>.ref_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#375 id=375 data-nosnippet>375</a> <span class="self">Self </span>{
<a href=#376 id=376 data-nosnippet>376</a> id: <span class="self">self</span>.id,
<a href=#377 id=377 data-nosnippet>377</a> ref_count: <span class="self">self</span>.ref_count.clone(),
<a href=#378 id=378 data-nosnippet>378</a> }
<a href=#379 id=379 data-nosnippet>379</a> }
<a href=#380 id=380 data-nosnippet>380</a>}
<a href=#381 id=381 data-nosnippet>381</a>
<a href=#382 id=382 data-nosnippet>382</a><span class="kw">impl </span>PathRef {
<a href=#383 id=383 data-nosnippet>383</a> <span class="kw">fn </span>on_drop(<span class="kw-2">&amp;</span><span class="self">self</span>, conn: <span class="kw-2">&amp;</span>ConnectionRef) {
<a href=#384 id=384 data-nosnippet>384</a> <span class="kw">if </span><span class="self">self</span>.ref_count.fetch_sub(<span class="number">1</span>, Ordering::Relaxed) &gt; <span class="number">1 </span>{
<a href=#385 id=385 data-nosnippet>385</a> <span class="kw">return</span>;
<a href=#386 id=386 data-nosnippet>386</a> }
<a href=#387 id=387 data-nosnippet>387</a> <span class="kw">let </span><span class="kw-2">mut </span>state = conn.lock_without_waking(<span class="string">"PathRef::drop"</span>);
<a href=#388 id=388 data-nosnippet>388</a> <span class="comment">// Re-check under the lock: a concurrent `Path::new` may have bumped
<a href=#389 id=389 data-nosnippet>389</a> // the counter back up between our `fetch_sub` and the lock.
<a href=#390 id=390 data-nosnippet>390</a> </span><span class="kw">if </span><span class="self">self</span>.ref_count.load(Ordering::Relaxed) &gt; <span class="number">0 </span>{
<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">return</span>;
<a href=#392 id=392 data-nosnippet>392</a> }
<a href=#393 id=393 data-nosnippet>393</a> state.path_refs.remove(<span class="kw-2">&amp;</span><span class="self">self</span>.id);
<a href=#394 id=394 data-nosnippet>394</a> state.final_path_stats.remove(<span class="kw-2">&amp;</span><span class="self">self</span>.id);
<a href=#395 id=395 data-nosnippet>395</a> }
<a href=#396 id=396 data-nosnippet>396</a>}
<a href=#397 id=397 data-nosnippet>397</a>
<a href=#398 id=398 data-nosnippet>398</a><span class="doccomment">/// Stream produced by [`Path::observed_external_addr`]
<a href=#399 id=399 data-nosnippet>399</a>///
<a href=#400 id=400 data-nosnippet>400</a>/// This will always return the external address most recently reported by the remote over this
<a href=#401 id=401 data-nosnippet>401</a>/// path. If the extension is not negotiated, this stream will never return.
<a href=#402 id=402 data-nosnippet>402</a></span><span class="comment">// TODO(@divma): provide a way to check if the extension is negotiated.
<a href=#403 id=403 data-nosnippet>403</a></span><span class="kw">pub struct </span>AddressDiscovery {
<a href=#404 id=404 data-nosnippet>404</a> watcher: WatchStream&lt;SocketAddr&gt;,
<a href=#405 id=405 data-nosnippet>405</a>}
<a href=#406 id=406 data-nosnippet>406</a>
<a href=#407 id=407 data-nosnippet>407</a><span class="kw">impl </span>AddressDiscovery {
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(
<a href=#409 id=409 data-nosnippet>409</a> path_id: PathId,
<a href=#410 id=410 data-nosnippet>410</a> <span class="kw-2">mut </span>path_events: tokio::sync::broadcast::Receiver&lt;PathEvent&gt;,
<a href=#411 id=411 data-nosnippet>411</a> initial_value: <span class="prelude-ty">Option</span>&lt;SocketAddr&gt;,
<a href=#412 id=412 data-nosnippet>412</a> runtime: Arc&lt;<span class="kw">dyn </span>Runtime&gt;,
<a href=#413 id=413 data-nosnippet>413</a> ) -&gt; <span class="self">Self </span>{
<a href=#414 id=414 data-nosnippet>414</a> <span class="kw">let </span>(tx, rx) = watch::channel(initial_value.unwrap_or_else(||
<a href=#415 id=415 data-nosnippet>415</a> <span class="comment">// if the dummy value is used, it will be ignored
<a href=#416 id=416 data-nosnippet>416</a> </span>SocketAddr::new([<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>].into(), <span class="number">0</span>)));
<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">let </span>filter = <span class="kw">async move </span>{
<a href=#418 id=418 data-nosnippet>418</a> <span class="kw">loop </span>{
<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">match </span>path_events.recv().<span class="kw">await </span>{
<a href=#420 id=420 data-nosnippet>420</a> <span class="prelude-val">Ok</span>(PathEvent::ObservedAddr { id, addr: observed }) <span class="kw">if </span>id == path_id =&gt; {
<a href=#421 id=421 data-nosnippet>421</a> tx.send_if_modified(|addr| {
<a href=#422 id=422 data-nosnippet>422</a> <span class="kw">let </span>old = std::mem::replace(addr, observed);
<a href=#423 id=423 data-nosnippet>423</a> old != <span class="kw-2">*</span>addr
<a href=#424 id=424 data-nosnippet>424</a> });
<a href=#425 id=425 data-nosnippet>425</a> }
<a href=#426 id=426 data-nosnippet>426</a> }
<a href=#427 id=427 data-nosnippet>427</a> }
<a href=#428 id=428 data-nosnippet>428</a> };
<a href=#429 id=429 data-nosnippet>429</a>
<a href=#430 id=430 data-nosnippet>430</a> <span class="kw">let </span>watcher = <span class="kw">if </span>initial_value.is_some() {
<a href=#431 id=431 data-nosnippet>431</a> WatchStream::new(rx)
<a href=#432 id=432 data-nosnippet>432</a> } <span class="kw">else </span>{
<a href=#433 id=433 data-nosnippet>433</a> WatchStream::from_changes(rx)
<a href=#434 id=434 data-nosnippet>434</a> };
<a href=#435 id=435 data-nosnippet>435</a>
<a href=#436 id=436 data-nosnippet>436</a> runtime.spawn(Box::pin(filter));
<a href=#437 id=437 data-nosnippet>437</a> <span class="comment">// TODO(@divma): check if there's a way to ensure the future ends. AbortHandle is not an
<a href=#438 id=438 data-nosnippet>438</a> // option
<a href=#439 id=439 data-nosnippet>439</a> </span><span class="self">Self </span>{ watcher }
<a href=#440 id=440 data-nosnippet>440</a> }
<a href=#441 id=441 data-nosnippet>441</a>}
<a href=#426 id=426 data-nosnippet>426</a> <span class="prelude-val">Ok</span>(PathEvent::Discarded { id, .. }) <span class="kw">if </span>id == path_id =&gt; {
<a href=#427 id=427 data-nosnippet>427</a> <span class="comment">// If the path is closed, terminate the stream
<a href=#428 id=428 data-nosnippet>428</a> </span><span class="kw">break</span>;
<a href=#429 id=429 data-nosnippet>429</a> }
<a href=#430 id=430 data-nosnippet>430</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
<a href=#431 id=431 data-nosnippet>431</a> <span class="comment">// ignore any other event
<a href=#432 id=432 data-nosnippet>432</a> </span>}
<a href=#433 id=433 data-nosnippet>433</a> <span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; {
<a href=#434 id=434 data-nosnippet>434</a> <span class="comment">// A lagged error should never happen since this (detached) task is
<a href=#435 id=435 data-nosnippet>435</a> // constantly reading from the channel. Therefore, if an error does happen,
<a href=#436 id=436 data-nosnippet>436</a> // the stream can terminate
<a href=#437 id=437 data-nosnippet>437</a> </span><span class="kw">break</span>;
<a href=#438 id=438 data-nosnippet>438</a> }
<a href=#439 id=439 data-nosnippet>439</a> }
<a href=#440 id=440 data-nosnippet>440</a> }
<a href=#441 id=441 data-nosnippet>441</a> };
<a href=#442 id=442 data-nosnippet>442</a>
<a href=#443 id=443 data-nosnippet>443</a><span class="kw">impl </span>Stream <span class="kw">for </span>AddressDiscovery {
<a href=#444 id=444 data-nosnippet>444</a> <span class="kw">type </span>Item = SocketAddr;
<a href=#445 id=445 data-nosnippet>445</a>
<a href=#446 id=446 data-nosnippet>446</a> <span class="kw">fn </span>poll_next(<span class="kw-2">mut </span><span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<a href=#447 id=447 data-nosnippet>447</a> Pin::new(<span class="kw-2">&amp;mut </span><span class="self">self</span>.watcher).poll_next(cx)
<a href=#448 id=448 data-nosnippet>448</a> }
<a href=#449 id=449 data-nosnippet>449</a>}</code></pre></div></section></main></body></html>
<a href=#443 id=443 data-nosnippet>443</a> <span class="kw">let </span>watcher = <span class="kw">if </span>initial_value.is_some() {
<a href=#444 id=444 data-nosnippet>444</a> WatchStream::new(rx)
<a href=#445 id=445 data-nosnippet>445</a> } <span class="kw">else </span>{
<a href=#446 id=446 data-nosnippet>446</a> WatchStream::from_changes(rx)
<a href=#447 id=447 data-nosnippet>447</a> };
<a href=#448 id=448 data-nosnippet>448</a>
<a href=#449 id=449 data-nosnippet>449</a> runtime.spawn(Box::pin(filter));
<a href=#450 id=450 data-nosnippet>450</a> <span class="comment">// TODO(@divma): check if there's a way to ensure the future ends. AbortHandle is not an
<a href=#451 id=451 data-nosnippet>451</a> // option
<a href=#452 id=452 data-nosnippet>452</a> </span><span class="self">Self </span>{ watcher }
<a href=#453 id=453 data-nosnippet>453</a> }
<a href=#454 id=454 data-nosnippet>454</a>}
<a href=#455 id=455 data-nosnippet>455</a>
<a href=#456 id=456 data-nosnippet>456</a><span class="kw">impl </span>Stream <span class="kw">for </span>AddressDiscovery {
<a href=#457 id=457 data-nosnippet>457</a> <span class="kw">type </span>Item = SocketAddr;
<a href=#458 id=458 data-nosnippet>458</a>
<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">fn </span>poll_next(<span class="kw-2">mut </span><span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<a href=#460 id=460 data-nosnippet>460</a> Pin::new(<span class="kw-2">&amp;mut </span><span class="self">self</span>.watcher).poll_next(cx)
<a href=#461 id=461 data-nosnippet>461</a> }
<a href=#462 id=462 data-nosnippet>462</a>}</code></pre></div></section></main></body></html>