1
use std::net::{ IpAddr };
2
use std::os::unix::prelude::RawFd;
3

            
4
use nix::sys::socket::{self, SockaddrLike, SockaddrStorage};
5

            
6
use crate::{ Result, Error };
7

            
8
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
9
pub struct SocketAddr(std::net::SocketAddr);
10

            
11
impl std::fmt::Display for SocketAddr {
12
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13
        self.0.fmt(f)
14
    }
15
}
16

            
17
impl TryFrom<SockaddrStorage> for SocketAddr {
18
    type Error = Error;
19

            
20
    fn try_from(addr: SockaddrStorage) -> std::result::Result<Self, Self::Error> {
21
	if let Some(ip) = addr.as_sockaddr_in() {
22
	    use std::net::SocketAddrV4 as V4;
23

            
24
	    Ok(Self(V4::new(ip.ip().into(), ip.port()).into()))
25
	} else if let Some(ip) = addr.as_sockaddr_in6() {
26
	    use std::net::SocketAddrV6 as V6;
27

            
28
	    Ok(Self(V6::new(ip.ip(), ip.port(),
29
			    ip.flowinfo(), ip.scope_id()).into()))
30
	} else {
31
	    Err(crate::Error::Internal("unsupported address type"))
32
	}
33
    }
34
}
35

            
36
impl SocketAddr {
37
    pub fn new(ip: IpAddr, port: u16) -> Self {
38
	Self(std::net::SocketAddr::new(ip, port))
39
    }
40

            
41
    pub fn from_raw_fd(fd: RawFd) -> Result<Self>
42
    {
43
	socket::getsockname::<SockaddrStorage>(fd)
44
	    .map_err(|e| e.into())
45
	    .and_then(Self::try_from)
46
    }
47

            
48
    /// # Safety
49
    ///
50
    /// can leak a file descriptor
51
    pub unsafe fn socket(&self) -> Result<RawFd> {
52
	use socket::SockFlag as SF;
53

            
54
	socket::socket(self.get_af(), socket::SockType::Datagram,
55
		       SF::SOCK_CLOEXEC | SF::SOCK_NONBLOCK, None)
56
	    .map_err(|e| e.into())
57
    }
58

            
59
    pub fn get_af(&self) -> socket::AddressFamily {
60
	use std::net::SocketAddr as SA;
61
	use socket::AddressFamily as AF;
62

            
63
	match self.0 {
64
	    SA::V4(_)	=> AF::Inet,
65
	    SA::V6(_)	=> AF::Inet6,
66
	}
67
    }
68

            
69
    pub fn as_std(&self) -> &std::net::SocketAddr
70
    {
71
	&self.0
72
    }
73

            
74
    pub fn as_nix(&self) -> Box<dyn SockaddrLike + Send>
75
    {
76
	use std::net::SocketAddr as SA;
77

            
78
	match self.0 {
79
	    SA::V4(a)	=> Box::new(socket::SockaddrIn::from(a)),
80
	    SA::V6(a)	=> Box::new(socket::SockaddrIn6::from(a)),
81
	}
82
    }
83
}