cap_std/net/
pool.rs

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