use super::listener;
use listener::Listen;
use listener::ReadWrite;
use log::error;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::os::unix::io::FromRawFd;
use std::os::unix::net::UnixListener;
use std::path::Path;
use std::time::Duration;
static SOCKET_PATH: &str = "/tmp/security-daemon-socket";
#[derive(Debug)]
pub struct DomainSocketListener {
listener: UnixListener,
timeout: Duration,
}
impl DomainSocketListener {
pub fn new(timeout: Duration) -> Result<Self> {
let listener = match sd_notify::listen_fds()? {
0 => {
let socket = Path::new(SOCKET_PATH);
if socket.exists() {
fs::remove_file(&socket)?;
}
let listener = UnixListener::bind(SOCKET_PATH)?;
listener.set_nonblocking(true)?;
listener
}
1 => {
let nfd = sd_notify::SD_LISTEN_FDS_START;
unsafe { UnixListener::from_raw_fd(nfd) }
}
n => {
error!(
"Received too many file descriptors ({} received, 0 or 1 expected).",
n
);
return Err(Error::new(
ErrorKind::InvalidData,
"too many file descriptors received",
));
}
};
Ok(Self { listener, timeout })
}
}
impl Listen for DomainSocketListener {
fn set_timeout(&mut self, duration: Duration) {
self.timeout = duration;
}
fn accept(&self) -> Option<Box<dyn ReadWrite + Send>> {
let stream_result = self.listener.accept();
match stream_result {
Ok((stream, _)) => {
if let Err(err) = stream.set_read_timeout(Some(self.timeout)) {
error!("Failed to set read timeout ({})", err);
None
} else if let Err(err) = stream.set_write_timeout(Some(self.timeout)) {
error!("Failed to set write timeout ({})", err);
None
} else if let Err(err) = stream.set_nonblocking(false) {
error!("Failed to set stream as blocking ({})", err);
None
} else {
Some(Box::from(stream))
}
}
Err(err) => {
if err.kind() != ErrorKind::WouldBlock {
error!("Failed to connect with a UnixStream ({})", err);
}
None
}
}
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct DomainSocketListenerBuilder {
timeout: Option<Duration>,
}
impl DomainSocketListenerBuilder {
pub fn new() -> Self {
DomainSocketListenerBuilder { timeout: None }
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn build(self) -> Result<DomainSocketListener> {
DomainSocketListener::new(self.timeout.ok_or_else(|| {
error!("The listener timeout was not set.");
Error::new(ErrorKind::InvalidInput, "listener timeout missing")
})?)
}
}