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}