1use std::{
2 any::Any,
3 fmt::Debug,
4 future::Future,
5 io, mem,
6 net::SocketAddr,
7 ops::{Deref, DerefMut},
8 sync::{Arc, OnceLock},
9 task::{Context, Poll, ready},
10};
11
12use bytes::BytesMut;
13use dashmap::{DashMap, Entry};
14use futures::FutureExt;
15use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
16use qbase::{
17 net::route,
18 util::{UniqueId, UniqueIdGenerator},
19};
20use tokio::sync::SetOnce;
21use tracing::Instrument as _;
22
23use crate::{
24 BindInterface, Interface, RebindedError, WeakBindInterface,
25 bind_uri::BindUri,
26 component::{Component, Components},
27 io::{IO, IoExt, ProductIO},
28};
29
30#[derive(Default, Debug)]
40pub struct InterfaceManager {
41 interfaces: DashMap<BindUri, InterfaceEntry>,
42 bind_id_generator: UniqueIdGenerator,
43}
44
45#[derive(Debug)]
46struct InterfaceEntry {
47 weak_iface: WeakBindInterface,
48 dropped: Arc<SetOnce<()>>,
49}
50
51impl InterfaceEntry {
52 fn is_dropped(&self) -> bool {
53 self.dropped.get().is_some()
54 }
55
56 fn dropped(&self) -> impl Future<Output = ()> + use<> {
57 let dropped = self.dropped.clone();
58 async move {
59 dropped.wait().await;
60 }
61 }
62}
63
64impl InterfaceManager {
65 #[inline]
66 pub fn global() -> &'static Arc<Self> {
67 static GLOBAL: OnceLock<Arc<InterfaceManager>> = OnceLock::new();
68 GLOBAL.get_or_init(Arc::default)
69 }
70
71 #[inline]
72 pub fn new() -> Self {
73 Self::default()
74 }
75
76 fn new_binding(
77 self: &Arc<Self>,
78 entry: Entry<BindUri, InterfaceEntry>,
79 factory: Arc<dyn ProductIO>,
80 ) -> BindInterface {
81 let context = InterfaceContext {
82 factory: factory.clone(),
83 binding: RwLock::new(Binding::new(
84 factory.bind(entry.key().clone()),
85 self.bind_id_generator.generate(),
86 )),
87 dropped: Arc::new(SetOnce::new()),
88 ifaces: self.clone(),
89 components: RwLock::new(Components::default()),
90 };
91 let dropped = context.dropped.clone();
92 let iface = BindInterface::new(context);
93 let weak_iface = iface.downgrade();
94
95 entry.insert(InterfaceEntry {
96 weak_iface,
97 dropped,
98 });
99
100 iface
101 }
102
103 pub async fn bind(
104 self: &Arc<Self>,
105 bind_uri: BindUri,
106 factory: Arc<dyn ProductIO>,
107 ) -> BindInterface {
108 loop {
110 match self.interfaces.entry(bind_uri.clone()) {
111 Entry::Occupied(entry) if entry.get().is_dropped() => {
113 return self.new_binding(Entry::Occupied(entry), factory);
114 }
115 Entry::Vacant(entry) => {
117 return self.new_binding(Entry::Vacant(entry), factory);
118 }
119 Entry::Occupied(entry) => match entry.get().weak_iface.upgrade() {
121 Ok(iface) => {
123 if iface.borrow().bound_addr().is_ok() {
124 return iface.clone();
125 }
126
127 tracing::debug!(
128 target: "interface",
129 bind_uri = %bind_uri,
130 "replacing closed interface binding during bind"
131 );
132 drop(iface);
133 return self.new_binding(Entry::Occupied(entry), factory);
134 }
135 Err(..) => {
137 let dropped_future = entry.get().dropped();
138 drop(entry);
139 dropped_future.await;
140 }
141 },
142 }
143 }
144 }
145
146 #[inline]
147 pub fn borrow(&self, bind_uri: &BindUri) -> Option<Interface> {
148 self.interfaces
149 .get(bind_uri)
150 .and_then(|entry| Some(entry.weak_iface.upgrade().ok()?.borrow()))
151 }
152
153 #[inline]
154 pub fn get(&self, bind_uri: &BindUri) -> Option<BindInterface> {
155 self.interfaces
156 .get(bind_uri)
157 .and_then(|entry| entry.weak_iface.upgrade().ok())
158 }
159
160 #[inline]
161 pub fn unbind(self: &Arc<Self>, bind_uri: BindUri) -> impl Future<Output = ()> + Send + use<> {
162 let Entry::Occupied(entry) = self.interfaces.entry(bind_uri) else {
163 return std::future::ready(()).right_future();
164 };
165
166 match entry.get().weak_iface.upgrade() {
167 Ok(bind_iface) => {
168 let drop_future = bind_iface.context.as_ref().drop();
169 spawn_on_drop::SpawnOnDrop::new(Box::pin(drop_future)).left_future()
170 }
171 Err(..) => entry.get().dropped().right_future(),
173 }
174 .left_future()
175 }
176}
177
178mod spawn_on_drop {
179 use std::{
180 future::Future,
181 pin::Pin,
182 task::{Context, Poll, ready},
183 };
184
185 use tracing::Instrument;
186
187 pub(crate) struct SpawnOnDrop<F: Future<Output: Send + 'static> + Unpin + Send + 'static> {
188 pub(crate) future: Option<F>,
189 }
190
191 impl<F: Future<Output: Send + 'static> + Unpin + Send + 'static> SpawnOnDrop<F> {
192 pub(crate) fn new(future: F) -> Self {
193 Self {
194 future: Some(future),
195 }
196 }
197 }
198
199 impl<F: Future<Output: Send + 'static> + Unpin + Send + 'static> Future for SpawnOnDrop<F> {
200 type Output = F::Output;
201
202 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
203 match self.as_mut().get_mut().future.as_mut() {
204 Some(future) => {
205 let output = ready!(Pin::new(future).poll(cx));
206 self.future = None;
207 Poll::Ready(output)
208 }
209 None => panic!("future polled after completion"),
210 }
211 }
212 }
213
214 impl<F: Future<Output: Send + 'static> + Unpin + Send + 'static> Drop for SpawnOnDrop<F> {
215 fn drop(&mut self) {
216 if let Some(future) = self.future.take() {
217 tokio::spawn(future.in_current_span());
219 }
220 }
221 }
222}
223
224struct Binding {
225 io: Box<dyn IO>,
226 id: UniqueId,
227 span: tracing::Span,
228}
229
230impl Binding {
231 fn new(io: Box<dyn IO>, id: UniqueId) -> Self {
232 let bind_uri = io.bind_uri();
233 let span = tracing::debug_span!(
234 target: "interface",
235 parent: None,
236 "interface",
237 %bind_uri,
238 bind_id = usize::from(id),
239 );
240 Self { io, id, span }
241 }
242}
243
244pub struct InterfaceContext {
245 factory: Arc<dyn ProductIO>,
246 binding: RwLock<Binding>,
247 dropped: Arc<SetOnce<()>>,
249 ifaces: Arc<InterfaceManager>,
250 components: RwLock<Components>,
251}
252
253impl InterfaceContext {
254 fn binding(&self) -> RwLockReadGuard<'_, Binding> {
255 self.binding.read_recursive()
256 }
257
258 fn binding_mut(&self) -> RwLockWriteGuard<'_, Binding> {
259 self.binding.write()
260 }
261
262 pub fn bind_id(&self) -> UniqueId {
263 self.binding().id
264 }
265
266 fn with_io<T>(&self, f: impl FnOnce(&dyn IO) -> T) -> T {
267 let binding = self.binding();
268 let _guard = binding.span.enter();
269 f(binding.io.as_ref())
270 }
271
272 pub(crate) fn with_bind_io<T>(
273 &self,
274 bind_id: UniqueId,
275 f: impl FnOnce(&dyn IO) -> T,
276 ) -> Result<T, RebindedError> {
277 let binding = self.binding();
278 if binding.id != bind_id {
279 return Err(RebindedError);
280 }
281 let _guard = binding.span.enter();
282 Ok(f(binding.io.as_ref()))
283 }
284
285 fn components(&self) -> RwLockReadGuard<'_, Components> {
286 self.components.read_recursive()
287 }
288
289 fn components_mut(&self) -> RwLockWriteGuard<'_, Components> {
290 self.components.write()
291 }
292
293 pub fn poll_close(&self, cx: &mut Context) -> Poll<io::Result<()>> {
294 let (mut binding, components) = (self.binding_mut(), self.components());
295 for (.., component) in &components.map {
296 ready!(component.poll_shutdown(cx));
297 }
298 binding.io.poll_close(cx)
299 }
300}
301
302impl Debug for InterfaceContext {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 f.debug_struct("Interface")
305 .field("bind_uri", &self.binding().io.bind_uri())
306 .finish()
307 }
308}
309
310impl BindInterface {
311 pub fn poll_rebind(&self, cx: &mut Context<'_>) -> Poll<()> {
312 let context = self.context.as_ref();
313
314 let (new_bind_id, components, span) = {
324 let mut binding = context.binding_mut();
325 let components = context.components();
326
327 ready!(context.factory.poll_rebind(cx, &mut binding.io));
328 binding.id = context.ifaces.bind_id_generator.generate();
329 binding.span = tracing::debug_span!(
330 target: "interface",
331 parent: None,
332 "interface",
333 bind_uri = %binding.io.bind_uri(),
334 bind_id = usize::from(binding.id),
335 );
336 (binding.id, components, binding.span.clone())
337 };
338
339 let iface = Interface {
340 bind_id: new_bind_id,
341 bind_iface: self.clone(),
342 };
343 let _guard = span.enter();
344 for (.., component) in &components.map {
345 component.reinit(&iface);
346 }
347 Poll::Ready(())
348 }
349
350 pub fn insert_component_with<C: Component>(&self, init: impl FnOnce(&Interface) -> C) {
351 self.with_components_mut(|components, iface| {
352 components.init_with(|| init(iface));
353 });
354 }
355
356 pub fn with_components<T>(&self, f: impl FnOnce(&Components, &Interface) -> T) -> T {
357 let context = self.context.as_ref();
358 let (binding, components) = (context.binding(), context.components());
359 let _guard = binding.span.enter();
360
361 let iface = Interface {
362 bind_id: binding.id,
363 bind_iface: self.clone(),
364 };
365 f(components.deref(), &iface)
366 }
367
368 pub fn with_components_mut<T>(&self, f: impl FnOnce(&mut Components, &Interface) -> T) -> T {
369 let context = self.context.as_ref();
370 let (binding, mut components) = (context.binding(), context.components_mut());
371 let _guard = binding.span.enter();
372
373 let iface = Interface {
374 bind_id: binding.id,
375 bind_iface: self.clone(),
376 };
377 f(components.deref_mut(), &iface)
378 }
379}
380
381impl Interface {
382 pub fn with_component<C: Component, T>(
383 &self,
384 f: impl FnOnce(&C) -> T,
385 ) -> Result<Option<T>, RebindedError> {
386 let context = self.bind_iface.context.as_ref();
387 let (binding, components) = (context.binding(), context.components());
388
389 if self.bind_id != binding.id {
390 return Err(RebindedError);
391 }
392
393 let _guard = binding.span.enter();
394 Ok(components.with(f))
395 }
396
397 pub fn with_components<T>(&self, f: impl FnOnce(&Components) -> T) -> Result<T, RebindedError> {
398 let context = self.bind_iface.context.as_ref();
399 let (binding, components) = (context.binding(), context.components());
400
401 if self.bind_id != binding.id {
402 return Err(RebindedError);
403 }
404
405 let _guard = binding.span.enter();
406 Ok(f(components.deref()))
407 }
408
409 pub fn get_component<C: Component + Clone>(&self) -> Result<Option<C>, RebindedError> {
410 self.with_component(C::clone)
411 }
412}
413
414impl IO for InterfaceContext {
415 fn bind_uri(&self) -> BindUri {
416 self.binding().io.bind_uri()
417 }
418
419 fn bound_addr(&self) -> io::Result<SocketAddr> {
420 self.with_io(|io| io.bound_addr())
421 }
422
423 fn max_segment_size(&self) -> io::Result<usize> {
424 self.with_io(|io| io.max_segment_size())
425 }
426
427 fn max_segments(&self) -> io::Result<usize> {
428 self.with_io(|io| io.max_segments())
429 }
430
431 fn poll_send(
432 &self,
433 cx: &mut Context,
434 pkts: &[io::IoSlice],
435 route: route::Route,
436 ) -> Poll<io::Result<usize>> {
437 self.with_io(|io| io.poll_send(cx, pkts, route))
438 }
439
440 fn poll_recv(
441 &self,
442 cx: &mut Context,
443 pkts: &mut [BytesMut],
444 route: &mut [route::Route],
445 ) -> Poll<io::Result<usize>> {
446 self.with_io(|io| io.poll_recv(cx, pkts, route))
447 }
448
449 fn poll_close(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
450 InterfaceContext::poll_close(self, cx)
451 }
452}
453
454mod dropping_io {
455 use thiserror::Error;
456
457 use super::*;
458
459 #[derive(Debug, Clone, Error)]
460 #[error("QuicIO is dropping and cannot be used anymore, you should never see this error")]
461 pub(crate) struct DroppingIO {
462 pub(crate) bind_uri: BindUri,
463 }
464
465 impl DroppingIO {
466 pub(crate) fn to_io_error(&self) -> io::Error {
467 io::Error::new(io::ErrorKind::NotConnected, self.clone())
468 }
469 }
470
471 impl From<DroppingIO> for io::Error {
472 fn from(error: DroppingIO) -> Self {
473 error.to_io_error()
474 }
475 }
476
477 impl IO for DroppingIO {
478 fn bind_uri(&self) -> BindUri {
479 self.bind_uri.clone()
480 }
481
482 fn bound_addr(&self) -> io::Result<SocketAddr> {
483 Err(self.to_io_error())
484 }
485
486 fn max_segment_size(&self) -> io::Result<usize> {
487 Err(self.to_io_error())
488 }
489
490 fn max_segments(&self) -> io::Result<usize> {
491 Err(self.to_io_error())
492 }
493
494 fn poll_send(
495 &self,
496 _: &mut Context,
497 _: &[io::IoSlice],
498 _: route::Route,
499 ) -> Poll<io::Result<usize>> {
500 Poll::Ready(Err(self.to_io_error()))
501 }
502
503 fn poll_recv(
504 &self,
505 _: &mut Context,
506 _: &mut [BytesMut],
507 _: &mut [route::Route],
508 ) -> Poll<io::Result<usize>> {
509 Poll::Ready(Err(self.to_io_error()))
510 }
511
512 fn poll_close(&mut self, _: &mut Context) -> Poll<io::Result<()>> {
513 Poll::Ready(Ok(()))
514 }
515 }
516}
517
518impl Binding {
519 pub fn is_dropping(&self) -> bool {
520 (self.io.as_ref() as &dyn Any).is::<dropping_io::DroppingIO>()
521 }
522
523 pub fn take_io(&mut self) -> Option<Box<dyn IO>> {
524 if self.is_dropping() {
525 return None;
526 }
527 let bind_uri = self.io.bind_uri();
528 let dropping_io = Box::new(dropping_io::DroppingIO { bind_uri });
529 Some(mem::replace(&mut self.io, dropping_io))
530 }
531}
532
533impl InterfaceContext {
534 fn drop(&self) -> impl Future<Output = ()> + Send + use<> {
535 let dropped = self.dropped.clone();
536 let Some(mut io) = self.binding_mut().take_io() else {
537 return std::future::ready(()).right_future();
538 };
539
540 let ifaces = self.ifaces.clone();
541 let bind_uri = io.bind_uri();
542 let components = mem::take(self.components_mut().deref_mut());
543
544 async move {
545 for (_, component) in components.map {
546 _ = core::future::poll_fn(|cx| component.poll_shutdown(cx)).await;
547 }
548 _ = io.close().await;
549
550 dropped.set(()).expect("duplicated drop, this is a bug");
551 tokio::task::spawn_blocking(move || {
552 ifaces
553 .interfaces
554 .remove_if(&bind_uri, |_, entry| entry.is_dropped());
555 });
556 }
557 .left_future()
558 }
559}
560
561impl Drop for InterfaceContext {
562 fn drop(&mut self) {
563 if !{ self.binding().is_dropping() } {
564 tokio::spawn(InterfaceContext::drop(self).in_current_span());
566 }
567 }
568}
569
570#[cfg(test)]
571mod tests {
572 use std::{
573 sync::{
574 Arc,
575 atomic::{AtomicUsize, Ordering},
576 },
577 task::{Context, Poll},
578 };
579
580 use futures::task::noop_waker_ref;
581
582 use super::*;
583 use crate::{
584 component::Component,
585 io::{IO, ProductIO},
586 };
587
588 #[derive(Debug)]
589 struct TestComponent {
590 shutdown_calls: Arc<AtomicUsize>,
591 }
592
593 impl Component for TestComponent {
594 fn poll_shutdown(&self, _cx: &mut Context<'_>) -> Poll<()> {
595 self.shutdown_calls.fetch_add(1, Ordering::SeqCst);
596 Poll::Ready(())
597 }
598
599 fn reinit(&self, _iface: &crate::Interface) {}
600 }
601
602 #[derive(Debug)]
603 struct TestIo {
604 bind_uri: BindUri,
605 close_calls: Arc<AtomicUsize>,
606 }
607
608 impl IO for TestIo {
609 fn bind_uri(&self) -> BindUri {
610 self.bind_uri.clone()
611 }
612
613 fn bound_addr(&self) -> io::Result<SocketAddr> {
614 Err(io::Error::new(io::ErrorKind::Unsupported, "not needed"))
615 }
616
617 fn max_segment_size(&self) -> io::Result<usize> {
618 Ok(1200)
619 }
620
621 fn max_segments(&self) -> io::Result<usize> {
622 Ok(1)
623 }
624
625 fn poll_send(
626 &self,
627 _cx: &mut Context,
628 _pkts: &[io::IoSlice],
629 _route: route::Route,
630 ) -> Poll<io::Result<usize>> {
631 Poll::Ready(Ok(0))
632 }
633
634 fn poll_recv(
635 &self,
636 _cx: &mut Context,
637 _pkts: &mut [BytesMut],
638 _route: &mut [route::Route],
639 ) -> Poll<io::Result<usize>> {
640 Poll::Pending
641 }
642
643 fn poll_close(&mut self, _cx: &mut Context) -> Poll<io::Result<()>> {
644 self.close_calls.fetch_add(1, Ordering::SeqCst);
645 Poll::Ready(Ok(()))
646 }
647 }
648
649 #[derive(Debug)]
650 struct TestFactory {
651 close_calls: Arc<AtomicUsize>,
652 }
653
654 impl ProductIO for TestFactory {
655 fn bind(&self, bind_uri: BindUri) -> Box<dyn IO> {
656 Box::new(TestIo {
657 bind_uri,
658 close_calls: self.close_calls.clone(),
659 })
660 }
661 }
662
663 #[test]
664 fn binding_take_io_is_idempotent_and_switches_to_dropping_io() {
665 let close_calls = Arc::new(AtomicUsize::new(0));
666 let bind_uri: BindUri = "inet://127.0.0.1:0".into();
667
668 let mut binding = Binding::new(
669 Box::new(TestIo {
670 bind_uri: bind_uri.clone(),
671 close_calls: close_calls.clone(),
672 }),
673 UniqueIdGenerator::new().generate(),
674 );
675
676 let first = binding.take_io();
677 assert!(first.is_some());
678 assert!(binding.is_dropping());
679
680 let second = binding.take_io();
681 assert!(second.is_none());
682
683 assert_eq!(close_calls.load(Ordering::SeqCst), 0);
685 }
686
687 #[test]
688 fn poll_close_shuts_down_components_before_io_close() {
689 let shutdown_calls = Arc::new(AtomicUsize::new(0));
690 let close_calls = Arc::new(AtomicUsize::new(0));
691
692 let bind_uri: BindUri = "inet://127.0.0.1:0".into();
693 let mut components = Components::new();
694 components.init_with(|| TestComponent {
695 shutdown_calls: shutdown_calls.clone(),
696 });
697
698 let mut cx = Context::from_waker(noop_waker_ref());
699 let ctx = InterfaceContext {
700 factory: Arc::new(TestFactory {
701 close_calls: close_calls.clone(),
702 }),
703 binding: RwLock::new(Binding::new(
704 Box::new(TestIo {
705 bind_uri,
706 close_calls: close_calls.clone(),
707 }),
708 UniqueIdGenerator::new().generate(),
709 )),
710 dropped: Arc::new(SetOnce::new()),
711 ifaces: Arc::new(InterfaceManager::new()),
712 components: RwLock::new(components),
713 };
714
715 let r = ctx.poll_close(&mut cx);
716 assert!(matches!(r, Poll::Ready(Ok(()))));
717 assert_eq!(shutdown_calls.load(Ordering::SeqCst), 1);
718 assert_eq!(close_calls.load(Ordering::SeqCst), 1);
719
720 let _ = ctx.binding_mut().take_io();
722 }
723}