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}