summaryrefslogtreecommitdiff
path: root/src/sys/socket/addr.rs
blob: 7a814d153958f6d4dfbe9d1ac61ca5190d9d592d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use {NixResult, NixError};
use super::{sa_family_t, in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, AF_UNIX, AF_INET};
use errno::Errno;
use std::{mem, net, path, ptr};
use std::ffi::{AsOsStr, CStr, OsStr};
use std::os::unix::OsStrExt;

/// Represents a socket address
#[derive(Copy)]
pub enum SockAddr {
    // TODO: Rename these variants IpV4, IpV6, Unix
    IpV4(sockaddr_in),
    IpV6(sockaddr_in6),
    Unix(sockaddr_un)
}

/// A trait for values which can be converted or resolved to a SockAddr.
pub trait ToSockAddr {
    /// Converts the value to a SockAddr
    fn to_sock_addr(&self) -> NixResult<SockAddr>;

    /// Converts and yields the value as a SockAddr
    fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
        Ok(action(&try!(self.to_sock_addr())))
    }
}

impl ToSockAddr for SockAddr {
    fn to_sock_addr(&self) -> NixResult<SockAddr> {
        Ok(*self)
    }

    fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
        Ok(action(self))
    }
}

/// Convert a path into a unix domain socket address
impl ToSockAddr for path::Path {
    fn to_sock_addr(&self) -> NixResult<SockAddr> {
        let bytes = self.as_os_str().as_bytes();

        Ok(SockAddr::Unix(unsafe {
            let mut ret = sockaddr_un {
                sun_family: AF_UNIX as sa_family_t,
                .. mem::zeroed()
            };

            // Make sure the destination has enough capacity
            if bytes.len() >= ret.sun_path.len() {
                return Err(NixError::Sys(Errno::ENAMETOOLONG));
            }

            // Copy the path
            ptr::copy_memory(
                ret.sun_path.as_mut_ptr(),
                bytes.as_ptr() as *const i8,
                bytes.len());

            ret
        }))
    }
}

/// Convert an inet address into a socket address
impl ToSockAddr for net::SocketAddr {
    fn to_sock_addr(&self) -> NixResult<SockAddr> {
        use std::net::IpAddr;
        use std::num::Int;

        match self.ip() {
            IpAddr::V4(ip) => {
                let addr = ip.octets();
                Ok(SockAddr::IpV4(sockaddr_in {
                    sin_family: AF_INET as sa_family_t,
                    sin_port: self.port(),
                    sin_addr: in_addr {
                        s_addr: Int::from_be(
                            ((addr[0] as u32) << 24) |
                            ((addr[1] as u32) << 16) |
                            ((addr[2] as u32) <<  8) |
                            ((addr[3] as u32) <<  0))
                    },
                    .. unsafe { mem::zeroed() }
                }))
            }
            _ => unimplemented!()
        }
    }
}

/// Convert from a socket address
pub trait FromSockAddr {
    fn from_sock_addr(addr: &SockAddr) -> Option<Self>;
}

impl FromSockAddr for net::SocketAddr {
    fn from_sock_addr(addr: &SockAddr) -> Option<net::SocketAddr> {
        use std::net::{IpAddr, Ipv4Addr};
        use std::num::Int;

        match *addr {
            SockAddr::IpV4(ref addr) => {
                let ip = Int::from_be(addr.sin_addr.s_addr);
                let ip = Ipv4Addr::new(
                    ((ip >> 24) as u8) & 0xff,
                    ((ip >> 16) as u8) & 0xff,
                    ((ip >>  8) as u8) & 0xff,
                    ((ip >>  0) as u8) & 0xff);

                Some(net::SocketAddr::new(IpAddr::V4(ip), addr.sin_port))
            }
            SockAddr::IpV6(_) => unimplemented!(),
            _ =>  None,
        }
    }
}

impl FromSockAddr for path::PathBuf {
    fn from_sock_addr(addr: &SockAddr) -> Option<path::PathBuf> {
        if let SockAddr::Unix(ref addr) = *addr {
            unsafe {
                let bytes = CStr::from_ptr(addr.sun_path.as_ptr()).to_bytes();
                let osstr = <OsStr as OsStrExt>::from_bytes(bytes);
                return Some(path::PathBuf::new(osstr));
            }
        }

        None
    }
}