sctp/
mio_unix.rs

1#[macro_export]
2// copy from mio::sys::unix::mod
3// https://github.com/faern/mio/blob/master/src/sys/unix/mod.rs
4/// Helper macro to execute a system call that returns an `io::Result`.
5//
6// Macro must be defined before any modules that uses them.
7#[allow(unused_macros)]
8macro_rules! syscall {
9	($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
10        #[allow(clippy::macro_metavars_in_unsafe)]
11		let res = unsafe { libc::$fn($($arg, )*) };
12		if res == -1 {
13			Err(std::io::Error::last_os_error())
14		} else {
15			Ok(res)
16		}
17	}};
18}
19
20#[macro_export]
21#[allow(unused_macros)]
22macro_rules! sctp_syscall {
23	($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
24        #[allow(clippy::macro_metavars_in_unsafe)]
25		let res = unsafe { sctp_sys::$fn($($arg, )*) };
26		if res == -1 {
27			Err(std::io::Error::last_os_error())
28		} else {
29			Ok(res)
30		}
31	}};
32}
33
34use std::mem;
35use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
36
37// copy from mio::sys::unix::net
38// https://github.com/faern/mio/blob/master/src/sys/unix/net.rs
39/// A type with the same memory layout as `libc::sockaddr`. Used in converting Rust level
40/// SocketAddr* types into their system representation. The benefit of this specific
41/// type over using `libc::sockaddr_storage` is that this type is exactly as large as it
42/// needs to be and not a lot larger. And it can be initialized cleaner from Rust.
43#[repr(C)]
44pub(crate) union SocketAddrCRepr {
45    v4: libc::sockaddr_in,
46    v6: libc::sockaddr_in6,
47}
48
49impl SocketAddrCRepr {
50    pub(crate) fn as_ptr(&self) -> *const libc::sockaddr {
51        self as *const _ as *const libc::sockaddr
52    }
53}
54
55/// Converts a Rust `SocketAddr` into the system representation.
56pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) {
57    match addr {
58        SocketAddr::V4(ref addr) => {
59            // `s_addr` is stored as BE on all machine and the array is in BE order.
60            // So the native endian conversion method is used so that it's never swapped.
61            let sin_addr = libc::in_addr {
62                s_addr: u32::from_ne_bytes(addr.ip().octets()),
63            };
64
65            let sockaddr_in = libc::sockaddr_in {
66                sin_family: libc::AF_INET as libc::sa_family_t,
67                sin_port: addr.port().to_be(),
68                sin_addr,
69                sin_zero: [0; 8],
70                #[cfg(any(
71                    target_os = "dragonfly",
72                    target_os = "freebsd",
73                    target_os = "ios",
74                    target_os = "macos",
75                    target_os = "netbsd",
76                    target_os = "openbsd"
77                ))]
78                sin_len: 0,
79            };
80
81            let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
82            (
83                sockaddr,
84                mem::size_of::<libc::sockaddr_in>() as libc::socklen_t,
85            )
86        }
87        SocketAddr::V6(ref addr) => {
88            let sockaddr_in6 = libc::sockaddr_in6 {
89                sin6_family: libc::AF_INET6 as libc::sa_family_t,
90                sin6_port: addr.port().to_be(),
91                sin6_addr: libc::in6_addr {
92                    s6_addr: addr.ip().octets(),
93                },
94                sin6_flowinfo: addr.flowinfo(),
95                sin6_scope_id: addr.scope_id(),
96                #[cfg(any(
97                    target_os = "dragonfly",
98                    target_os = "freebsd",
99                    target_os = "ios",
100                    target_os = "macos",
101                    target_os = "netbsd",
102                    target_os = "openbsd"
103                ))]
104                sin6_len: 0,
105                #[cfg(any(target_os = "solaris", target_os = "illumos"))]
106                __sin6_src_id: 0,
107            };
108
109            let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
110            (
111                sockaddr,
112                mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t,
113            )
114        }
115    }
116}
117
118/// Converts a `libc::sockaddr` compatible struct into a native Rust `SocketAddr`.
119///
120/// # Safety
121///
122/// `storage` must have the `ss_family` field correctly initialized.
123/// `storage` must be initialised to a `sockaddr_in` or `sockaddr_in6`.
124pub(crate) unsafe fn to_socket_addr(
125    storage: *const libc::sockaddr_storage,
126) -> std::io::Result<SocketAddr> {
127    match (*storage).ss_family as libc::c_int {
128        libc::AF_INET => {
129            // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
130            let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in);
131            let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
132            let port = u16::from_be(addr.sin_port);
133            Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
134        }
135        libc::AF_INET6 => {
136            // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
137            let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6);
138            let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
139            let port = u16::from_be(addr.sin6_port);
140            Ok(SocketAddr::V6(SocketAddrV6::new(
141                ip,
142                port,
143                addr.sin6_flowinfo,
144                addr.sin6_scope_id,
145            )))
146        }
147        _ => Err(std::io::ErrorKind::InvalidInput.into()),
148    }
149}
150//
151// CODE COPY ENDS HERE
152//