cap_async_std/net/
pool.rs

1use crate::net::{TcpListener, TcpStream, ToSocketAddrs, UdpSocket};
2use async_std::{io, net};
3use cap_primitives::net::no_socket_addrs;
4use cap_primitives::{ipnet, AmbientAuthority};
5
6/// A pool of network addresses.
7///
8/// This does not directly correspond to anything in `async_std`, however its
9/// methods correspond to the several functions in [`async_std::net`].
10///
11/// `Pool` implements `Clone`, which creates new independent entities that
12/// carry the full authority of the originals. This means that in a borrow
13/// of a `Pool`, the scope of the authority is not necessarily limited to
14/// the scope of the borrow.
15///
16/// Similarly, the [`cap_net_ext::PoolExt`] class allows creating "binder"
17/// and "connecter" objects which represent capabilities to bind and
18/// connect to addresses.
19///
20/// [`cap_net_ext::PoolExt`]: https://docs.rs/cap-net-ext/latest/cap_net_ext/trait.PoolExt.html
21#[derive(Clone, Default)]
22pub struct Pool {
23    cap: cap_primitives::net::Pool,
24}
25
26impl Pool {
27    /// Construct a new empty pool.
28    pub fn new() -> Self {
29        Self {
30            cap: cap_primitives::net::Pool::new(),
31        }
32    }
33
34    /// Add addresses to the pool.
35    ///
36    /// # Ambient Authority
37    ///
38    /// This function allows ambient access to any IP address.
39    pub async fn insert<A: ToSocketAddrs>(
40        &mut self,
41        addrs: A,
42        ambient_authority: AmbientAuthority,
43    ) -> io::Result<()> {
44        for addr in addrs.to_socket_addrs().await? {
45            self.cap.insert(addr, ambient_authority)?;
46        }
47        Ok(())
48    }
49
50    /// Add a specific [`net::SocketAddr`] to the pool.
51    ///
52    /// # Ambient Authority
53    ///
54    /// This function allows ambient access to any IP address.
55    pub fn insert_socket_addr(
56        &mut self,
57        addr: net::SocketAddr,
58        ambient_authority: AmbientAuthority,
59    ) {
60        self.cap.insert_socket_addr(addr, ambient_authority)
61    }
62
63    /// Add a range of network addresses, accepting any port, to the pool.
64    ///
65    /// Unlike `insert_ip_net`, this function grants access to any requested
66    /// port.
67    ///
68    /// # Ambient Authority
69    ///
70    /// This function allows ambient access to any IP address.
71    pub fn insert_ip_net_port_any(
72        &mut self,
73        ip_net: ipnet::IpNet,
74        ambient_authority: AmbientAuthority,
75    ) {
76        self.cap.insert_ip_net_port_any(ip_net, ambient_authority)
77    }
78
79    /// Add a range of network addresses, accepting a range of ports, to the
80    /// pool.
81    ///
82    /// This grants access to the port range starting at `ports_start` and,
83    /// if `ports_end` is provided, ending before `ports_end`.
84    ///
85    /// # Ambient Authority
86    ///
87    /// This function allows ambient access to any IP address.
88    pub fn insert_ip_net_port_range(
89        &mut self,
90        ip_net: ipnet::IpNet,
91        ports_start: u16,
92        ports_end: Option<u16>,
93        ambient_authority: AmbientAuthority,
94    ) {
95        self.cap
96            .insert_ip_net_port_range(ip_net, ports_start, ports_end, ambient_authority)
97    }
98
99    /// Add a range of network addresses with a specific port to the pool.
100    ///
101    /// # Ambient Authority
102    ///
103    /// This function allows ambient access to any IP address.
104    pub fn insert_ip_net(
105        &mut self,
106        ip_net: ipnet::IpNet,
107        port: u16,
108        ambient_authority: AmbientAuthority,
109    ) {
110        self.cap.insert_ip_net(ip_net, port, ambient_authority)
111    }
112
113    /// Creates a new `TcpListener` which will be bound to the specified
114    /// address.
115    ///
116    /// This corresponds to [`async_std::net::TcpListener::bind`].
117    #[doc(alias = "bind")]
118    #[inline]
119    pub async fn bind_tcp_listener<A: ToSocketAddrs>(&self, addr: A) -> io::Result<TcpListener> {
120        let addrs = addr.to_socket_addrs().await?;
121
122        let mut last_err = None;
123        for addr in addrs {
124            self.cap.check_addr(&addr)?;
125            // TODO: when compiling for WASI, use WASI-specific methods instead
126            match net::TcpListener::bind(addr).await {
127                Ok(tcp_listener) => return Ok(TcpListener::from_std(tcp_listener)),
128                Err(e) => last_err = Some(e),
129            }
130        }
131        match last_err {
132            Some(e) => Err(e),
133            None => Err(no_socket_addrs()),
134        }
135    }
136
137    /// Creates a new TCP stream connected to the specified address.
138    ///
139    /// This corresponds to [`async_std::net::TcpStream::connect`].
140    #[doc(alias = "connect")]
141    #[inline]
142    pub async fn connect_tcp_stream<A: ToSocketAddrs>(&self, addr: A) -> io::Result<TcpStream> {
143        let addrs = addr.to_socket_addrs().await?;
144
145        let mut last_err = None;
146        for addr in addrs {
147            self.cap.check_addr(&addr)?;
148            // TODO: when compiling for WASI, use WASI-specific methods instead
149            match net::TcpStream::connect(addr).await {
150                Ok(tcp_stream) => return Ok(TcpStream::from_std(tcp_stream)),
151                Err(e) => last_err = Some(e),
152            }
153        }
154        match last_err {
155            Some(e) => Err(e),
156            None => Err(no_socket_addrs()),
157        }
158    }
159
160    // async_std doesn't have `connect_timeout`.
161
162    /// Creates a UDP socket from the given address.
163    ///
164    /// This corresponds to [`async_std::net::UdpSocket::bind`].
165    #[doc(alias = "bind")]
166    #[inline]
167    pub async fn bind_udp_socket<A: ToSocketAddrs>(&self, addr: A) -> io::Result<UdpSocket> {
168        let addrs = addr.to_socket_addrs().await?;
169
170        let mut last_err = None;
171        for addr in addrs {
172            self.cap.check_addr(&addr)?;
173            match net::UdpSocket::bind(addr).await {
174                Ok(udp_socket) => return Ok(UdpSocket::from_std(udp_socket)),
175                Err(e) => last_err = Some(e),
176            }
177        }
178        match last_err {
179            Some(e) => Err(e),
180            None => Err(no_socket_addrs()),
181        }
182    }
183
184    /// Sends data on the socket to the given address.
185    ///
186    /// This corresponds to [`async_std::net::UdpSocket::send_to`].
187    #[doc(alias = "send_to")]
188    #[inline]
189    pub async fn send_to_udp_socket_addr<A: ToSocketAddrs>(
190        &self,
191        udp_socket: &UdpSocket,
192        buf: &[u8],
193        addr: A,
194    ) -> io::Result<usize> {
195        let mut addrs = addr.to_socket_addrs().await?;
196
197        // `UdpSocket::send_to` only sends to the first address.
198        let addr = match addrs.next() {
199            None => return Err(no_socket_addrs()),
200            Some(addr) => addr,
201        };
202        self.cap.check_addr(&addr)?;
203        udp_socket.std.send_to(buf, addr).await
204    }
205
206    /// Connects the UDP socket to a remote address.
207    ///
208    /// This corresponds to [`async_std::net::UdpSocket::connect`].
209    #[doc(alias = "connect")]
210    #[inline]
211    pub async fn connect_udp_socket<A: ToSocketAddrs>(
212        &self,
213        udp_socket: &UdpSocket,
214        addr: A,
215    ) -> io::Result<()> {
216        let addrs = addr.to_socket_addrs().await?;
217
218        let mut last_err = None;
219        for addr in addrs {
220            self.cap.check_addr(&addr)?;
221            match udp_socket.std.connect(addr).await {
222                Ok(()) => return Ok(()),
223                Err(e) => last_err = Some(e),
224            }
225        }
226        match last_err {
227            Some(e) => Err(e),
228            None => Err(no_socket_addrs()),
229        }
230    }
231}