Skip to content

Commit 8ff8fbc

Browse files
author
Olivier Médoc
committed
migrate to rust 1.64 network primitives rust-lang/rust#78802
Most code and macros to convert from and to rust layout such as Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6 has been copied from the mio crate. All system calls have been replaced by the syscall macro similarly to the mio crate. Fixes phsym#12
1 parent 3cd3358 commit 8ff8fbc

File tree

4 files changed

+337
-185
lines changed

4 files changed

+337
-185
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "rust-sctp"
4-
version = "0.0.5"
4+
version = "0.0.6"
55
description = "High level SCTP networking library"
66
repository = "https://github.com/phsym/rust-sctp"
77
documentation = "http://phsym.github.io/rust-sctp"

src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ use std::net::{ToSocketAddrs, SocketAddr, Shutdown};
1919

2020
#[cfg(target_os="linux")]
2121
use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
22+
23+
#[cfg(target_os="linux")]
24+
pub mod mio_unix;
25+
2226
#[cfg(target_os="windows")]
2327
use std::os::windows::io::{AsRawHandle, RawHandle, FromRawHandle};
2428

src/mio_unix.rs

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

0 commit comments

Comments
 (0)