#![cfg(any(target_os="android", target_os="l4re", target_os="linux"))]
#![doc(cfg(any(target_os="android", target_os="l4re", target_os="linux")))]
use {
std::{
io::{ErrorKind, Write},
os::{
fd::FromRawFd,
unix::net::{SocketAddr, UnixListener, UnixStream},
},
},
crate::{
Result,
UdsxUnixStream,
linux::Cmd,
},
super::{Namaste, RwNamaste},
};
#[cfg(not(target_os="android"))]
use std::os::linux::net::SocketAddrExt;
#[cfg(target_os="android")]
use std::os::android::net::SocketAddrExt;
#[cfg(test)]
mod tests;
const CLONABLE: Option<bool> = Some(true);
const UNCLONABLE: Option<bool> = Some(false);
macro_rules! read { ($self: ident) => {{
loop {
match Namaste::make(&$self.read_id, CLONABLE) {
Ok(read) => return match Namaste::make(&$self.write_id, UNCLONABLE) {
Ok(_) => Ok(read),
Err(_) => Err(err!("Another write is working")),
},
Err(err) => match err.kind() {
ErrorKind::AddrInUse => match connect_to(&$self.read_id) {
Ok(mut stream) => {
Cmd::DuplicateServerFd.encode(&mut stream)?;
stream.flush()?;
let read = Namaste::make_from_unix_listener(
unsafe {
UnixListener::from_raw_fd(stream.recv_streams::<_, _, 1>(crate::linux::STREAM_ID)?[usize::MIN])
},
CLONABLE,
)?;
return Ok(read);
},
Err(_) => continue,
},
_ => return Err(err),
},
};
}
}}}
macro_rules! write { ($self: ident) => {{
let err = || Err(err!("Another read is working"));
let write = Namaste::make(&$self.write_id, UNCLONABLE)?;
match connect_to(&$self.read_id) {
Ok(_) => err(),
Err(_) => match Namaste::make(&$self.read_id, UNCLONABLE) {
Ok(_) => Ok(write),
Err(_) => err(),
},
}
}}}
impl<R, W> RwNamaste<R, W> where R: AsRef<[u8]>, W: AsRef<[u8]> {
#[cfg(not(feature="tokio"))]
#[doc(cfg(not(feature="tokio")))]
pub (crate) fn read(&self) -> Result<Namaste> {
read!(self)
}
#[cfg(feature="tokio")]
#[doc(cfg(feature="tokio"))]
pub (crate) async fn read(&self) -> Result<Namaste> {
read!(self)
}
#[cfg(not(feature="tokio"))]
#[doc(cfg(not(feature="tokio")))]
pub (crate) fn write(&self) -> Result<Namaste> {
write!(self)
}
#[cfg(feature="tokio")]
#[doc(cfg(feature="tokio"))]
pub (crate) async fn write(&self) -> Result<Namaste> {
write!(self)
}
}
fn connect_to<B>(address: B) -> Result<UnixStream> where B: AsRef<[u8]> {
UnixStream::connect_addr(&SocketAddr::from_abstract_name(address)?)
}