forked from libp2p/rust-libp2p
-
Notifications
You must be signed in to change notification settings - Fork 0
/
in_addr.rs
100 lines (93 loc) · 3.36 KB
/
in_addr.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use if_watch::{IfEvent, IfWatcher};
use futures::{
future::{BoxFuture, FutureExt},
stream::Stream,
};
use std::{
io::Result,
net::IpAddr,
ops::DerefMut,
pin::Pin,
task::{Context, Poll},
};
/// Watches for interface changes.
#[derive(Debug)]
pub enum InAddr {
/// The socket accepts connections on a single interface.
One { ip: Option<IpAddr> },
/// The socket accepts connections on all interfaces.
Any { if_watch: Box<IfWatch> },
}
impl InAddr {
/// If ip is specified then only one `IfEvent::Up` with IpNet(ip)/32 will be generated.
/// If ip is unspecified then `IfEvent::Up/Down` events will be generated for all interfaces.
pub fn new(ip: IpAddr) -> Self {
if ip.is_unspecified() {
let watcher = IfWatch::Pending(IfWatcher::new().boxed());
InAddr::Any {
if_watch: Box::new(watcher),
}
} else {
InAddr::One { ip: Some(ip) }
}
}
}
pub enum IfWatch {
Pending(BoxFuture<'static, std::io::Result<IfWatcher>>),
Ready(Box<IfWatcher>),
}
impl std::fmt::Debug for IfWatch {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
IfWatch::Pending(_) => write!(f, "Pending"),
IfWatch::Ready(_) => write!(f, "Ready"),
}
}
}
impl Stream for InAddr {
type Item = Result<IfEvent>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let me = Pin::into_inner(self);
loop {
match me {
// If the listener is bound to a single interface, make sure the
// address is reported once.
InAddr::One { ip } => {
if let Some(ip) = ip.take() {
return Poll::Ready(Some(Ok(IfEvent::Up(ip.into()))));
}
}
InAddr::Any { if_watch } => {
match if_watch.deref_mut() {
// If we listen on all interfaces, wait for `if-watch` to be ready.
IfWatch::Pending(f) => match futures::ready!(f.poll_unpin(cx)) {
Ok(watcher) => {
*if_watch = Box::new(IfWatch::Ready(Box::new(watcher)));
continue;
}
Err(err) => {
*if_watch = Box::new(IfWatch::Pending(IfWatcher::new().boxed()));
return Poll::Ready(Some(Err(err)));
}
},
// Consume all events for up/down interface changes.
IfWatch::Ready(watcher) => {
if let Poll::Ready(ev) = watcher.poll_unpin(cx) {
match ev {
Ok(event) => {
return Poll::Ready(Some(Ok(event)));
}
Err(err) => {
return Poll::Ready(Some(Err(err)));
}
}
}
}
}
}
}
break;
}
Poll::Pending
}
}