1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
use std::io;
use std::net::{TcpListener, UdpSocket};
#[cfg(not(windows))]
use std::os::unix::net::{UnixDatagram, UnixListener};
#[cfg(not(windows))]
use crate::unix as imp;
#[cfg(windows)]
use crate::windows as imp;
/// A helper object that gives access to raw file descriptors.
pub struct ListenFd {
fds: Vec<Option<imp::FdType>>,
}
impl ListenFd {
/// Creates the listenfd manager object from the environment.
pub fn from_env() -> ListenFd {
match imp::get_fds() {
Some(fds) => ListenFd {
fds: fds.into_iter().map(Some).collect(),
},
None => ListenFd::empty(),
}
}
/// Creates an empty listenfd object.
///
/// This is helpful when the ability to work with external file
/// descriptors should be disabled in certain code paths. This
/// way the functions on the object will just never return
/// sockets.
pub fn empty() -> ListenFd {
ListenFd { fds: vec![] }
}
/// Returns the number of fds in the manager object.
///
/// Note that even if fds are taken out of the manager this count
/// does not change.
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.fds.len()
}
fn with_fd<R, F: FnOnce(imp::FdType) -> io::Result<R>>(
&mut self,
idx: usize,
f: F,
) -> io::Result<Option<R>> {
let bucket = match self.fds.get_mut(idx) {
Some(None) | None => return Ok(None),
Some(bucket) => bucket,
};
f(*bucket.as_ref().unwrap()).map(|rv| {
bucket.take();
Some(rv)
})
}
/// Takes the TCP listener at an index.
///
/// If the given index has been used before `Ok(None)` is returned,
/// otherwise the fd at that index is returned as `TcpListener`. If
/// the fd at that position is not a TCP socket then an error is
/// returned and the fd is left at its place.
pub fn take_tcp_listener(&mut self, idx: usize) -> io::Result<Option<TcpListener>> {
self.with_fd(idx, imp::make_tcp_listener)
}
/// Takes the UNIX stream listener at an index.
///
/// If the given index has been used before `Ok(None)` is returned,
/// otherwise the fd at that index is returned as `UnixListener`. If
/// the fd at that position is not a UNIX stream socket then an error is
/// returned and the fd is left at its place.
///
/// This function is only available on unix platforms.
#[cfg(not(windows))]
pub fn take_unix_listener(&mut self, idx: usize) -> io::Result<Option<UnixListener>> {
self.with_fd(idx, imp::make_unix_listener)
}
/// Takes the UDP socket at an index.
///
/// If the given index has been used before `Ok(None)` is returned,
/// otherwise the fd at that index is returned as `UdpSocket`. If
/// the fd at that position is not a UDP socket then an error is
/// returned and the fd is left at its place.
pub fn take_udp_socket(&mut self, idx: usize) -> io::Result<Option<UdpSocket>> {
let _idx = idx;
self.with_fd(idx, imp::make_udp_socket)
}
/// Takes the UNIX datagram socket at an index.
///
/// If the given index has been used before `Ok(None)` is returned,
/// otherwise the fd at that index is returned as `UnixDatagram`. If
/// the fd at that position is not a UNIX datagram socket then an error is
/// returned and the fd is left at its place.
///
/// This function is only available on unix platforms.
#[cfg(not(windows))]
pub fn take_unix_datagram(&mut self, idx: usize) -> io::Result<Option<UnixDatagram>> {
self.with_fd(idx, imp::make_unix_datagram)
}
/// Takes a custom socket on unix platforms.
///
/// You have to provide a socket family, socket type, and a hint
/// for the validation error, e.g.
/// `libc::AF_UNIX, libc::SOCK_SEQPACKET, "unix seqpacket socket"`.
///
/// The file descriptor will be validated to actually be a socket
/// with the appropriate options, set as CLOEXEC, and converted to
/// the given Rust type using `FromRawFd`.
///
/// This function is only available on unix platforms.
#[cfg(not(windows))]
pub fn take_custom<T: std::os::unix::prelude::FromRawFd>(
&mut self,
idx: usize,
sock_fam: libc::c_int,
sock_type: libc::c_int,
hint: &str,
) -> io::Result<Option<T>> {
self.with_fd(idx, |fd| imp::make_custom(fd, sock_fam, sock_type, hint))
}
/// Takes the `RawFd` on unix platforms.
#[cfg(not(windows))]
pub fn take_raw_fd(&mut self, idx: usize) -> io::Result<Option<imp::FdType>> {
let _idx = idx;
self.with_fd(idx, Ok)
}
/// Takes the `RawSocket` on windows platforms.
///
/// This will error if the fd at this position is not a socket (but a handle).
#[cfg(windows)]
pub fn take_raw_socket(&mut self, idx: usize) -> io::Result<Option<imp::RawSocket>> {
let _idx = idx;
Ok(None)
}
}