capsicum_net/std.rs
1// vim: tw=80
2//! Extension traits for socket types from the standard library
3use ::std::{
4 io,
5 net::{TcpListener, TcpStream, ToSocketAddrs, UdpSocket},
6 os::{
7 fd::AsFd,
8 unix::net::{UnixDatagram, UnixListener},
9 },
10 path::Path,
11};
12use nix::sys::socket::{listen, AddressFamily, Backlog, SockFlag, SockType};
13
14use super::CapNetAgent;
15
16/// Adds extra features to `std::net::TcpListener` that require Casper.
17pub trait TcpListenerExt {
18 /// Create a new `TcpListener` bound to the specified address.
19 ///
20 /// # Examples
21 /// ```
22 /// use std::{io, str::FromStr, net::TcpListener };
23 ///
24 /// use capsicum::casper::Casper;
25 /// use capsicum_net::{CasperExt, std::TcpListenerExt};
26 ///
27 /// // Safe because we are single-threaded
28 /// let mut casper = unsafe { Casper::new().unwrap() };
29 /// let mut cap_net = casper.net().unwrap();
30 ///
31 /// let socket = TcpListener::cap_bind(&mut cap_net, "127.0.0.1:8084")
32 /// .unwrap();
33 /// ```
34 fn cap_bind<A>(
35 agent: &mut CapNetAgent,
36 addrs: A,
37 ) -> io::Result<TcpListener>
38 where
39 A: ToSocketAddrs;
40}
41
42impl TcpListenerExt for TcpListener {
43 fn cap_bind<A>(agent: &mut CapNetAgent, addrs: A) -> io::Result<TcpListener>
44 where
45 A: ToSocketAddrs,
46 {
47 let s: TcpListener = agent.bind_std_to_addrs(addrs)?;
48 listen(&s, Backlog::MAXALLOWABLE)?;
49 Ok(s)
50 }
51}
52
53/// Adds extra features to `std::net::TcpStream` that require Casper.
54pub trait TcpStreamExt {
55 /// Open a TCP connection to a remote host, connecting via a `cap_net`
56 /// service.
57 ///
58 /// # Examples
59 /// ```no_run
60 /// use std::{io, str::FromStr, net::TcpStream };
61 ///
62 /// use capsicum::casper::Casper;
63 /// use capsicum_net::{CasperExt, std::TcpStreamExt};
64 ///
65 /// // Safe because we are single-threaded
66 /// let mut casper = unsafe { Casper::new().unwrap() };
67 /// let mut cap_net = casper.net().unwrap();
68 ///
69 /// let sock = TcpStream::cap_connect(&mut cap_net, "8.8.8.8:53").unwrap();
70 /// ```
71 fn cap_connect<A: ToSocketAddrs>(
72 agent: &mut CapNetAgent,
73 addrs: A,
74 ) -> io::Result<TcpStream>;
75}
76
77impl TcpStreamExt for TcpStream {
78 fn cap_connect<A: ToSocketAddrs>(
79 agent: &mut CapNetAgent,
80 addrs: A,
81 ) -> io::Result<TcpStream> {
82 let mut last_err = None;
83 for addr in addrs.to_socket_addrs()? {
84 let family = if addr.is_ipv4() {
85 AddressFamily::Inet
86 } else {
87 AddressFamily::Inet6
88 };
89 let sock = nix::sys::socket::socket(
90 family,
91 SockType::Stream,
92 SockFlag::empty(),
93 None,
94 )
95 .map_err(io::Error::from)?;
96 match agent.connect_std_fd(sock.as_fd(), addr) {
97 Ok(()) => return Ok(TcpStream::from(sock)),
98 Err(e) => {
99 last_err = Some(e);
100 }
101 }
102 }
103 Err(last_err.unwrap_or_else(|| {
104 io::Error::new(
105 io::ErrorKind::InvalidInput,
106 "could not resolve to any addresses",
107 )
108 }))
109 }
110}
111
112/// Adds extra features to `std::net::UdpSocket` that require Casper.
113pub trait UdpSocketExt {
114 /// Bind a `std::net::UdpSocket` to a port.
115 ///
116 /// # Examples
117 /// ```
118 /// use std::{io, str::FromStr, net::UdpSocket };
119 ///
120 /// use capsicum::casper::Casper;
121 /// use capsicum_net::{CasperExt, std::UdpSocketExt};
122 ///
123 /// // Safe because we are single-threaded
124 /// let mut casper = unsafe { Casper::new().unwrap() };
125 /// let mut cap_net = casper.net().unwrap();
126 ///
127 /// let socket = UdpSocket::cap_bind(&mut cap_net, "127.0.0.1:8088")
128 /// .unwrap();
129 /// ```
130 fn cap_bind<A>(agent: &mut CapNetAgent, addr: A) -> io::Result<UdpSocket>
131 where
132 A: ToSocketAddrs;
133
134 /// Connects this UDP socket to a remote address, using a `cap_net` service.
135 ///
136 /// # Examples
137 /// ```no_run
138 /// use std::{io, str::FromStr, net::UdpSocket };
139 ///
140 /// use capsicum::casper::Casper;
141 /// use capsicum_net::{CasperExt, std::UdpSocketExt};
142 ///
143 /// // Safe because we are single-threaded
144 /// let mut casper = unsafe { Casper::new().unwrap() };
145 /// let mut cap_net = casper.net().unwrap();
146 ///
147 /// let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
148 /// socket.cap_connect(&mut cap_net, "8.8.8.8:53").unwrap();
149 /// ```
150 fn cap_connect<A>(
151 &self,
152 agent: &mut CapNetAgent,
153 addrs: A,
154 ) -> io::Result<()>
155 where
156 A: ToSocketAddrs;
157}
158
159impl UdpSocketExt for UdpSocket {
160 fn cap_bind<A>(agent: &mut CapNetAgent, addrs: A) -> io::Result<UdpSocket>
161 where
162 A: ToSocketAddrs,
163 {
164 agent.bind_std_to_addrs(addrs)
165 }
166
167 fn cap_connect<A>(
168 &self,
169 agent: &mut CapNetAgent,
170 addrs: A,
171 ) -> io::Result<()>
172 where
173 A: ToSocketAddrs,
174 {
175 agent.connect_std_to_addrs(self.as_fd(), addrs)
176 }
177}
178
179/// Adds extra features to `std::os::unix::net::UnixDatagram` that require
180/// Casper.
181pub trait UnixDatagramExt {
182 /// Bind a `std::net::UdpSocket` to a port.
183 ///
184 /// # Examples
185 /// ```no_run
186 /// use std::{io, str::FromStr, os::unix::net::UnixDatagram };
187 ///
188 /// use capsicum::casper::Casper;
189 /// use capsicum_net::{CasperExt, std::UnixDatagramExt};
190 ///
191 /// // Safe because we are single-threaded
192 /// let mut casper = unsafe { Casper::new().unwrap() };
193 /// let mut cap_net = casper.net().unwrap();
194 ///
195 /// let path = "/var/run/foo.sock";
196 /// let socket = UnixDatagram::cap_bind(&mut cap_net, &path).unwrap();
197 /// ```
198 fn cap_bind<P>(
199 agent: &mut CapNetAgent,
200 path: P,
201 ) -> io::Result<UnixDatagram>
202 where
203 P: AsRef<Path>;
204}
205
206impl UnixDatagramExt for UnixDatagram {
207 fn cap_bind<P>(agent: &mut CapNetAgent, path: P) -> io::Result<UnixDatagram>
208 where
209 P: AsRef<Path>,
210 {
211 let s = agent.bind_std_unix(SockType::Datagram, path)?;
212 Ok(UnixDatagram::from(s))
213 }
214}
215
216/// Adds extra features to `std::os::unix::net::UnixListener` that require
217/// Casper.
218pub trait UnixListenerExt {
219 /// Bind a `std::net::UdpSocket` to a port.
220 ///
221 /// # Examples
222 /// ```no_run
223 /// use std::{io, str::FromStr, os::unix::net::UnixListener };
224 ///
225 /// use capsicum::casper::Casper;
226 /// use capsicum_net::{CasperExt, std::UnixListenerExt};
227 ///
228 /// // Safe because we are single-threaded
229 /// let mut casper = unsafe { Casper::new().unwrap() };
230 /// let mut cap_net = casper.net().unwrap();
231 ///
232 /// let path = "/var/run/foo.sock";
233 /// let socket = UnixListener::cap_bind(&mut cap_net, &path).unwrap();
234 /// ```
235 fn cap_bind<P>(
236 agent: &mut CapNetAgent,
237 path: P,
238 ) -> io::Result<UnixListener>
239 where
240 P: AsRef<Path>;
241}
242
243impl UnixListenerExt for UnixListener {
244 fn cap_bind<P>(agent: &mut CapNetAgent, path: P) -> io::Result<UnixListener>
245 where
246 P: AsRef<Path>,
247 {
248 let s = agent.bind_std_unix(SockType::Stream, path)?;
249 listen(&s, Backlog::MAXALLOWABLE)?;
250 Ok(UnixListener::from(s))
251 }
252}