Skip to main content

dope_core/io/socket/
addr.rs

1use std::net::SocketAddr;
2use std::os::fd::RawFd;
3use std::path::Path;
4use std::{io, slice};
5
6use crate::backend::PlatformAbi;
7use crate::driver::Driver;
8use crate::io::socket::Pod;
9use std::io::{Error, ErrorKind};
10use std::net::Ipv4Addr;
11use std::net::Ipv6Addr;
12
13#[derive(Clone, Copy, Debug)]
14pub struct Addr {
15    storage: libc::sockaddr_storage,
16    len: libc::socklen_t,
17}
18
19#[derive(Clone, Copy)]
20#[repr(C)]
21union InetStorage {
22    v4: libc::sockaddr_in,
23    v6: libc::sockaddr_in6,
24}
25
26#[derive(Clone, Copy)]
27pub struct InetAddr {
28    storage: InetStorage,
29    len: libc::socklen_t,
30}
31
32impl InetAddr {
33    pub fn from_std(addr: SocketAddr) -> Self {
34        match addr {
35            SocketAddr::V4(v4) => Self {
36                storage: InetStorage {
37                    v4: Driver::encode_v4(v4),
38                },
39                len: size_of::<libc::sockaddr_in>() as libc::socklen_t,
40            },
41            SocketAddr::V6(v6) => Self {
42                storage: InetStorage {
43                    v6: Driver::encode_v6(v6),
44                },
45                len: size_of::<libc::sockaddr_in6>() as libc::socklen_t,
46            },
47        }
48    }
49
50    pub fn mut_ptr(&mut self) -> *mut libc::sockaddr {
51        &raw mut self.storage as *mut libc::sockaddr
52    }
53
54    pub fn socklen(&self) -> libc::socklen_t {
55        self.len
56    }
57}
58
59impl Addr {
60    pub fn empty() -> Self {
61        Self {
62            storage: Pod::zeroed(),
63            len: size_of::<libc::sockaddr_storage>() as libc::socklen_t,
64        }
65    }
66
67    fn from_payload<T: Copy>(payload: T, len: libc::socklen_t) -> Self {
68        const {
69            assert!(
70                size_of::<T>() <= size_of::<libc::sockaddr_storage>(),
71                "payload does not fit in sockaddr_storage",
72            );
73            assert!(
74                align_of::<T>() <= align_of::<libc::sockaddr_storage>(),
75                "payload over-aligned for sockaddr_storage",
76            );
77        }
78        let mut out = Self::empty();
79        let bytes =
80            unsafe { slice::from_raw_parts(&payload as *const T as *const u8, size_of::<T>()) };
81        out.storage_bytes()[..bytes.len()].copy_from_slice(bytes);
82        out.len = len;
83        out
84    }
85
86    fn storage_bytes(&mut self) -> &mut [u8] {
87        unsafe {
88            slice::from_raw_parts_mut(
89                &raw mut self.storage as *mut u8,
90                size_of::<libc::sockaddr_storage>(),
91            )
92        }
93    }
94
95    pub fn ptr(&self) -> *const libc::sockaddr {
96        &raw const self.storage as *const libc::sockaddr
97    }
98
99    pub fn mut_ptr(&mut self) -> *mut libc::sockaddr {
100        &raw mut self.storage as *mut libc::sockaddr
101    }
102
103    pub fn socklen(&self) -> libc::socklen_t {
104        self.len
105    }
106
107    pub fn len_ptr(&mut self) -> *mut libc::socklen_t {
108        &mut self.len as *mut libc::socklen_t
109    }
110
111    pub fn from_std(addr: SocketAddr) -> Self {
112        match addr {
113            SocketAddr::V4(v4) => Self::from_payload(
114                Driver::encode_v4(v4),
115                size_of::<libc::sockaddr_in>() as libc::socklen_t,
116            ),
117            SocketAddr::V6(v6) => Self::from_payload(
118                Driver::encode_v6(v6),
119                size_of::<libc::sockaddr_in6>() as libc::socklen_t,
120            ),
121        }
122    }
123
124    pub fn from_unix_path(path: &Path) -> io::Result<Self> {
125        let (sa, len) = Driver::encode_unix(path)?;
126        Ok(Self::from_payload(sa, len))
127    }
128
129    pub fn from_getsockname(fd: RawFd) -> io::Result<Self> {
130        let mut addr = Self::empty();
131        let rc = unsafe { libc::getsockname(fd, addr.mut_ptr(), addr.len_ptr()) };
132        if rc < 0 {
133            return Err(Error::last_os_error());
134        }
135        Ok(addr)
136    }
137
138    pub fn parse_msg_name(name: &[u8]) -> Option<SocketAddr> {
139        if name.len() > size_of::<libc::sockaddr_storage>() {
140            return None;
141        }
142        let mut addr = Self::empty();
143        addr.storage_bytes()[..name.len()].copy_from_slice(name);
144        addr.into_std_len(name.len() as libc::socklen_t).ok()
145    }
146
147    pub fn into_std(self) -> io::Result<SocketAddr> {
148        self.into_std_len(self.socklen())
149    }
150
151    fn into_std_len(self, len: libc::socklen_t) -> io::Result<SocketAddr> {
152        if (len as usize) < size_of::<libc::sa_family_t>() {
153            return Err(Error::new(ErrorKind::InvalidData, "short sockaddr"));
154        }
155
156        let family = self.storage.ss_family as i32;
157        match family {
158            libc::AF_INET => {
159                if (len as usize) < size_of::<libc::sockaddr_in>() {
160                    return Err(Error::new(ErrorKind::InvalidData, "short sockaddr_in"));
161                }
162                let sa = unsafe { &*self.ptr().cast::<libc::sockaddr_in>() };
163                let ip = Ipv4Addr::from(u32::from_be(sa.sin_addr.s_addr));
164                let port = u16::from_be(sa.sin_port);
165                Ok(SocketAddr::new(ip.into(), port))
166            }
167            libc::AF_INET6 => {
168                if (len as usize) < size_of::<libc::sockaddr_in6>() {
169                    return Err(Error::new(ErrorKind::InvalidData, "short sockaddr_in6"));
170                }
171                let sa = unsafe { &*self.ptr().cast::<libc::sockaddr_in6>() };
172                let ip = Ipv6Addr::from(sa.sin6_addr.s6_addr);
173                let port = u16::from_be(sa.sin6_port);
174                Ok(SocketAddr::new(ip.into(), port))
175            }
176            _ => Err(Error::new(
177                ErrorKind::InvalidData,
178                "unknown sockaddr family",
179            )),
180        }
181    }
182}