use std::io;
#[cfg(any(feature = "udp", feature = "secure-udp"))]
use std::net::{SocketAddr, UdpSocket};
use std::os::unix::net::UnixDatagram;
use std::path::{Path, PathBuf};
pub trait BeatTransport: Send + 'static {
fn send(&mut self, buf: &[u8; 32]) -> io::Result<usize>;
fn reconnect(&mut self) -> io::Result<()>;
}
pub struct UdsTransport {
sock: UnixDatagram,
path: PathBuf,
}
impl UdsTransport {
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let path = path.as_ref().to_path_buf();
let sock = UnixDatagram::unbound()?;
sock.connect(&path)?;
sock.set_nonblocking(true)?;
Ok(UdsTransport { sock, path })
}
}
impl BeatTransport for UdsTransport {
fn send(&mut self, buf: &[u8; 32]) -> io::Result<usize> {
self.sock.send(buf)
}
fn reconnect(&mut self) -> io::Result<()> {
let sock = UnixDatagram::unbound()?;
sock.connect(&self.path)?;
sock.set_nonblocking(true)?;
self.sock = sock;
Ok(())
}
}
#[cfg(any(feature = "udp", feature = "secure-udp"))]
pub(crate) fn bind_ephemeral(addr: &SocketAddr) -> io::Result<UdpSocket> {
let bind_addr = if addr.is_ipv4() {
"0.0.0.0:0"
} else {
"[::]:0"
};
UdpSocket::bind(bind_addr)
}
#[cfg(feature = "udp")]
mod udp_impl {
use std::io;
use std::net::{SocketAddr, UdpSocket};
use super::bind_ephemeral;
use super::BeatTransport;
pub struct UdpTransport {
sock: UdpSocket,
addr: SocketAddr,
}
impl UdpTransport {
pub fn connect(addr: SocketAddr) -> io::Result<Self> {
let sock = bind_ephemeral(&addr)?;
sock.connect(addr)?;
sock.set_nonblocking(true)?;
Ok(UdpTransport { sock, addr })
}
}
impl BeatTransport for UdpTransport {
fn send(&mut self, buf: &[u8; 32]) -> io::Result<usize> {
self.sock.send(buf)
}
fn reconnect(&mut self) -> io::Result<()> {
let sock = bind_ephemeral(&self.addr)?;
sock.connect(self.addr)?;
sock.set_nonblocking(true)?;
self.sock = sock;
Ok(())
}
}
}
#[cfg(feature = "udp")]
pub use udp_impl::UdpTransport;