use std::{
fmt,
net::{SocketAddrV4, SocketAddrV6},
os::raw::c_char,
path::PathBuf,
};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum SocketAddr
{
InProc(String),
Ipc(PathBuf),
Inet(SocketAddrV4),
Inet6(SocketAddrV6),
#[doc(hidden)]
ZeroTier(SocketAddrZt),
#[doc(hidden)]
Unspecified,
}
impl fmt::Display for SocketAddr
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
match self {
SocketAddr::InProc(s) => write!(f, "inproc://{}", s),
SocketAddr::Ipc(s) => write!(f, "ipc://{}", s.to_string_lossy()),
SocketAddr::Inet(s) => write!(f, "tcp://{}", s),
SocketAddr::Inet6(s) => write!(f, "tcp://{}", s),
SocketAddr::ZeroTier(s) => write!(f, "zt://{}", s),
SocketAddr::Unspecified => write!(f, "unspecified"),
}
}
}
#[cfg_attr(not(feature = "ffi-module"), doc(hidden))]
impl From<nng_sys::nng_sockaddr> for SocketAddr
{
fn from(addr: nng_sys::nng_sockaddr) -> SocketAddr
{
unsafe {
match nng_sys::nng_sockaddr_family::try_convert_from(i32::from(addr.s_family)) {
Some(nng_sys::nng_sockaddr_family::NNG_AF_INPROC) => {
SocketAddr::InProc(buf_to_string(&addr.s_inproc.sa_name[..]))
},
Some(nng_sys::nng_sockaddr_family::NNG_AF_IPC) => {
SocketAddr::Ipc(buf_to_string(&addr.s_ipc.sa_path[..]).into())
},
Some(nng_sys::nng_sockaddr_family::NNG_AF_INET) => {
let v4_addr = u32::from_be(addr.s_in.sa_addr).into();
SocketAddr::Inet(SocketAddrV4::new(v4_addr, addr.s_in.sa_port))
},
Some(nng_sys::nng_sockaddr_family::NNG_AF_INET6) => {
let v6_addr = addr.s_in6.sa_addr.into();
let port = addr.s_in6.sa_port;
SocketAddr::Inet6(SocketAddrV6::new(v6_addr, port, 0, 0))
},
Some(nng_sys::nng_sockaddr_family::NNG_AF_ZT) => {
SocketAddr::ZeroTier(SocketAddrZt::new(&addr.s_zt))
},
Some(nng_sys::nng_sockaddr_family::NNG_AF_UNSPEC) | None => SocketAddr::Unspecified,
}
}
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SocketAddrZt
{
pub family: u16,
pub nwid: u64,
pub nodeid: u64,
pub port: u32,
}
impl SocketAddrZt
{
const fn new(addr: &nng_sys::nng_sockaddr_zt) -> SocketAddrZt
{
SocketAddrZt {
family: addr.sa_family,
nwid: addr.sa_nwid,
nodeid: addr.sa_nodeid,
port: addr.sa_port,
}
}
}
impl fmt::Display for SocketAddrZt
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
write!(f, "{}.{}:{}", self.nodeid, self.nwid, self.port)
}
}
unsafe fn buf_to_string(buf: &[c_char]) -> String
{
use std::slice;
let len = buf.len();
let buf = slice::from_raw_parts(&buf[0] as *const c_char as _, len);
let null_byte = buf.iter().position(|&b| b == 0).unwrap_or(len);
String::from_utf8_lossy(&buf[..null_byte]).into_owned()
}