1use std::future::Future;
2use std::net::SocketAddr;
3use std::pin::Pin;
4use std::sync::Arc;
5use std::task::{Context, Poll, ready};
6use std::time::Duration;
7
8use proto::{
9 ClosePathError, ClosedPath, PathError, PathEvent, PathId, PathStats, PathStatus,
10 SetPathStatusError, TransportErrorCode,
11};
12use tokio::sync::watch;
13use tokio_stream::{Stream, wrappers::WatchStream};
14
15use crate::connection::ConnectionRef;
16use crate::{Runtime, WeakConnectionHandle};
17
18pub struct OpenPath(OpenPathInner);
20
21enum OpenPathInner {
22 Ongoing {
26 opened: WatchStream<Result<(), PathError>>,
27 path_id: PathId,
28 conn: ConnectionRef,
29 },
30 Rejected {
32 err: PathError,
34 },
35 Ready {
37 path_id: PathId,
38 conn: ConnectionRef,
39 },
40}
41
42impl OpenPath {
43 pub(crate) fn new(
44 path_id: PathId,
45 opened: watch::Receiver<Result<(), PathError>>,
46 conn: ConnectionRef,
47 ) -> Self {
48 Self(OpenPathInner::Ongoing {
49 opened: WatchStream::from_changes(opened),
50 path_id,
51 conn,
52 })
53 }
54
55 pub(crate) fn ready(path_id: PathId, conn: ConnectionRef) -> Self {
56 Self(OpenPathInner::Ready { path_id, conn })
57 }
58
59 pub(crate) fn rejected(err: PathError) -> Self {
60 Self(OpenPathInner::Rejected { err })
61 }
62
63 pub fn path_id(&self) -> Option<PathId> {
70 match self.0 {
71 OpenPathInner::Ongoing { path_id, .. } => Some(path_id),
72 OpenPathInner::Rejected { .. } => None,
73 OpenPathInner::Ready { path_id, .. } => Some(path_id),
74 }
75 }
76}
77
78impl Future for OpenPath {
79 type Output = Result<Path, PathError>;
80 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
81 match self.get_mut().0 {
82 OpenPathInner::Ongoing {
83 ref mut opened,
84 path_id,
85 ref mut conn,
86 } => match ready!(Pin::new(opened).poll_next(ctx)) {
87 Some(value) => {
88 Poll::Ready(value.map(|_| Path::new_unchecked(conn.clone(), path_id)))
89 }
90 None => {
91 Poll::Ready(Err(PathError::ValidationFailed))
95 }
96 },
97 OpenPathInner::Ready {
98 path_id,
99 ref mut conn,
100 } => Poll::Ready(Ok(Path::new_unchecked(conn.clone(), path_id))),
101 OpenPathInner::Rejected { err } => Poll::Ready(Err(err)),
102 }
103 }
104}
105
106#[derive(Debug)]
111pub struct Path {
112 id: PathId,
113 conn: ConnectionRef,
114}
115
116impl Clone for Path {
117 fn clone(&self) -> Self {
118 self.conn
119 .state
120 .lock("Path::clone")
121 .increment_path_refs(self.id);
122 Self {
123 id: self.id,
124 conn: self.conn.clone(),
125 }
126 }
127}
128
129impl Drop for Path {
130 fn drop(&mut self) {
131 let mut state = self.conn.state.lock("Path::drop");
132 state.decrement_path_refs(self.id);
133 }
134}
135
136impl Path {
137 pub(crate) fn new(conn: &ConnectionRef, id: PathId) -> Option<Self> {
139 {
140 let mut state = conn.state.lock("Path::new");
141 state.inner.path_status(id).ok()?;
143 state.increment_path_refs(id);
144 }
145 Some(Self {
146 id,
147 conn: conn.clone(),
148 })
149 }
150
151 fn new_unchecked(conn: ConnectionRef, id: PathId) -> Self {
153 conn.state
154 .lock("Path::new_unchecked")
155 .increment_path_refs(id);
156 Self { id, conn }
157 }
158
159 pub fn weak_handle(&self) -> WeakPathHandle {
165 self.conn
166 .state
167 .lock("Path::weak_handle")
168 .increment_path_refs(self.id);
169 WeakPathHandle {
170 id: self.id,
171 conn: self.conn.weak_handle(),
172 }
173 }
174
175 pub fn id(&self) -> PathId {
177 self.id
178 }
179
180 pub fn status(&self) -> Result<PathStatus, ClosedPath> {
182 self.conn
183 .state
184 .lock("path status")
185 .inner
186 .path_status(self.id)
187 }
188
189 pub fn set_status(&self, status: PathStatus) -> Result<(), SetPathStatusError> {
191 self.conn
192 .state
193 .lock("set path status")
194 .inner
195 .set_path_status(self.id, status)?;
196 Ok(())
197 }
198
199 pub fn stats(&self) -> PathStats {
201 self.conn
210 .state
211 .lock("Path::stats")
212 .path_stats(self.id)
213 .expect("either path stats or discarded path stats are always set as long as Path is not dropped")
214 }
215
216 pub fn close(&self) -> Result<(), ClosePathError> {
222 let mut state = self.conn.state.lock("close_path");
223 state.inner.close_path(
224 crate::Instant::now(),
225 self.id,
226 TransportErrorCode::APPLICATION_ABANDON_PATH.into(),
227 )
228 }
229
230 pub fn set_max_idle_timeout(
238 &self,
239 timeout: Option<Duration>,
240 ) -> Result<Option<Duration>, ClosedPath> {
241 let mut state = self.conn.state.lock("path_set_max_idle_timeout");
242 state.inner.set_path_max_idle_timeout(self.id, timeout)
243 }
244
245 pub fn set_keep_alive_interval(
253 &self,
254 interval: Option<Duration>,
255 ) -> Result<Option<Duration>, ClosedPath> {
256 let mut state = self.conn.state.lock("path_set_keep_alive_interval");
257 state.inner.set_path_keep_alive_interval(self.id, interval)
258 }
259
260 pub fn observed_external_addr(&self) -> Result<AddressDiscovery, ClosedPath> {
264 let state = self.conn.state.lock("per_path_observed_address");
265 let path_events = state.path_events.subscribe();
266 let initial_value = state.inner.path_observed_address(self.id)?;
267 Ok(AddressDiscovery::new(
268 self.id,
269 path_events,
270 initial_value,
271 state.runtime.clone(),
272 ))
273 }
274
275 pub fn remote_address(&self) -> Result<SocketAddr, ClosedPath> {
277 let state = self.conn.state.lock("per_path_remote_address");
278 Ok(state.inner.network_path(self.id)?.remote)
279 }
280
281 pub fn ping(&self) -> Result<(), ClosedPath> {
283 let mut state = self.conn.state.lock("ping");
284 state.inner.ping_path(self.id)
285 }
286}
287
288impl PartialEq for Path {
289 fn eq(&self, other: &Self) -> bool {
290 self.id == other.id && self.conn.stable_id() == other.conn.stable_id()
291 }
292}
293
294#[derive(Debug)]
303pub struct WeakPathHandle {
304 id: PathId,
305 conn: WeakConnectionHandle,
306}
307
308impl Clone for WeakPathHandle {
309 fn clone(&self) -> Self {
310 if let Some(conn) = self.conn.upgrade_to_ref() {
311 conn.state
312 .lock("WeakPathHandle::clone")
313 .increment_path_refs(self.id);
314 }
315 Self {
316 id: self.id,
317 conn: self.conn.clone(),
318 }
319 }
320}
321
322impl PartialEq for WeakPathHandle {
323 fn eq(&self, other: &Self) -> bool {
324 self.id == other.id && self.conn.is_same_connection(&other.conn)
325 }
326}
327
328impl Eq for WeakPathHandle {}
329
330impl Drop for WeakPathHandle {
331 fn drop(&mut self) {
332 if let Some(conn) = self.conn.upgrade_to_ref() {
333 conn.state
334 .lock("WeakPathHandle::drop")
335 .decrement_path_refs(self.id);
336 }
337 }
338}
339
340impl WeakPathHandle {
341 pub fn id(&self) -> PathId {
343 self.id
344 }
345
346 pub fn upgrade(&self) -> Option<Path> {
350 let conn = self.conn.upgrade_to_ref()?;
351 Some(Path::new_unchecked(conn, self.id))
352 }
353}
354
355pub struct AddressDiscovery {
361 watcher: WatchStream<SocketAddr>,
362}
363
364impl AddressDiscovery {
365 pub(super) fn new(
366 path_id: PathId,
367 mut path_events: tokio::sync::broadcast::Receiver<PathEvent>,
368 initial_value: Option<SocketAddr>,
369 runtime: Arc<dyn Runtime>,
370 ) -> Self {
371 let (tx, rx) = watch::channel(initial_value.unwrap_or_else(||
372 SocketAddr::new([0, 0, 0, 0].into(), 0)));
374 let filter = async move {
375 loop {
376 match path_events.recv().await {
377 Ok(PathEvent::ObservedAddr { id, addr: observed }) if id == path_id => {
378 tx.send_if_modified(|addr| {
379 let old = std::mem::replace(addr, observed);
380 old != *addr
381 });
382 }
383 Ok(PathEvent::Discarded { id, .. }) if id == path_id => {
384 break;
386 }
387 Ok(_) => {
388 }
390 Err(_) => {
391 break;
395 }
396 }
397 }
398 };
399
400 let watcher = if initial_value.is_some() {
401 WatchStream::new(rx)
402 } else {
403 WatchStream::from_changes(rx)
404 };
405
406 runtime.spawn(Box::pin(filter));
407 Self { watcher }
410 }
411}
412
413impl Stream for AddressDiscovery {
414 type Item = SocketAddr;
415
416 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
417 Pin::new(&mut self.watcher).poll_next(cx)
418 }
419}