#[cfg(unix)]
pub mod unix {
use std::io;
use std::os::unix::fs::FileTypeExt;
use std::path::Path;
use tokio::net::{UnixListener, UnixStream};
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
let path_ref = path.as_ref();
match UnixListener::bind(path_ref) {
Ok(listener) => return Ok(listener),
Err(e) if e.kind() == io::ErrorKind::AddrInUse => {
}
Err(e) => return Err(e),
}
match tokio::fs::symlink_metadata(path_ref).await {
Ok(metadata) => {
let file_type = metadata.file_type();
if file_type.is_symlink() {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"IPC path exists and is a symlink (potential security risk)",
));
}
if !file_type.is_socket() {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"IPC path exists and is not a Unix socket",
));
}
tokio::fs::remove_file(path_ref).await?;
}
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::AddrInUse,
"Socket address in use but cannot verify file type",
));
}
}
UnixListener::bind(path_ref)
}
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
UnixStream::connect(path).await
}
}
#[cfg(windows)]
pub mod windows {
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::windows::named_pipe::{
ClientOptions, NamedPipeClient, NamedPipeServer, ServerOptions,
};
pub fn create_server<S: AsRef<str>>(name: S) -> std::io::Result<NamedPipeServer> {
ServerOptions::new()
.first_pipe_instance(true)
.create(name.as_ref())
}
pub async fn server_connect(server: &NamedPipeServer) -> std::io::Result<()> {
server.connect().await
}
pub async fn connect<S: AsRef<str>>(name: S) -> std::io::Result<NamedPipeClient> {
ClientOptions::new().open(name.as_ref())
}
pub async fn echo_once(mut server: NamedPipeServer) -> std::io::Result<()> {
let mut buf = [0u8; 1024];
let n = server.read(&mut buf).await?;
if n > 0 {
server.write_all(&buf[..n]).await?;
}
server.flush().await?;
Ok(())
}
}