Skip to content

migrate to rust 1.64 network primitives #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "rust-sctp"
version = "0.0.5"
version = "0.0.6"
description = "High level SCTP networking library"
repository = "https://github.com/phsym/rust-sctp"
documentation = "http://phsym.github.io/rust-sctp"
Expand Down
80 changes: 45 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ use std::net::{ToSocketAddrs, SocketAddr, Shutdown};

#[cfg(target_os="linux")]
use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};

#[cfg(target_os="linux")]
pub mod mio_unix;

#[cfg(target_os="windows")]
use std::os::windows::io::{AsRawHandle, RawHandle, FromRawHandle};

Expand Down Expand Up @@ -60,9 +64,9 @@ impl SctpStream {

/// Create a new stream by connecting it to a remote endpoint
pub fn connect<A: ToSocketAddrs>(address: A) -> Result<SctpStream> {
let raw_addr = try!(SocketAddr::from_addr(&address));
let sock = try!(SctpSocket::new(raw_addr.family(), SOCK_STREAM));
try!(sock.connect(raw_addr));
let raw_addr = SocketAddr::from_addr(&address)?;
let sock = SctpSocket::new(raw_addr.family(), SOCK_STREAM)?;
sock.connect(raw_addr)?;
return Ok(SctpStream(sock));
}

Expand All @@ -72,26 +76,32 @@ impl SctpStream {
let mut vec = Vec::with_capacity(addresses.len());
let mut family = AF_INET;
for address in addresses {
let a = try!(SocketAddr::from_addr(address));
let a = SocketAddr::from_addr(address)?;
if a.family() == AF_INET6 { family = AF_INET6; }
vec.push(a);
}

let sock = try!(SctpSocket::new(family, SOCK_STREAM));
try!(sock.connectx(&vec));
let sock = SctpSocket::new(family, SOCK_STREAM)?;
sock.connectx(&vec)?;
return Ok(SctpStream(sock));
}

/// Send bytes on the specified SCTP stream. On success, returns the
/// quantity of bytes read
pub fn sendmsg(&self, msg: &[u8], stream: u16) -> Result<usize> {
return self.0.sendmsg::<SocketAddr>(msg, None, stream, 0);
return self.0.sendmsg::<SocketAddr>(msg, None, 0, stream, 0);
}

/// Send bytes on the specified SCTP stream. On success, returns the
/// quantity of bytes read
pub fn sendmsg_ppid(&self, msg: &[u8], ppid: u32, stream: u16) -> Result<usize> {
return self.0.sendmsg::<SocketAddr>(msg, None, ppid, stream, 0);
}

/// Read bytes. On success, return a tuple with the quantity of
/// bytes received and the stream they were recived on
pub fn recvmsg(&self, msg: &mut [u8]) -> Result<(usize, u16)> {
let (size, stream, _) = try!(self.0.recvmsg(msg));
let (size, stream, _) = self.0.recvmsg(msg)?;
return Ok((size, stream));
}

Expand All @@ -118,7 +128,7 @@ impl SctpStream {

/// Verify if SCTP_NODELAY option is activated for this socket
pub fn has_nodelay(&self) -> Result<bool> {
let val: libc::c_int = try!(self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0));
let val: libc::c_int = self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0)?;
return Ok(val == 1);
}

Expand All @@ -129,8 +139,8 @@ impl SctpStream {
}

/// Get the socket buffer size for the direction specified by `dir`
pub fn get_buffer_size(&self, dir: SoDirection) -> Result<(usize)> {
let val: u32 = try!(self.0.getsockopt(SOL_SOCKET, dir.buffer_opt()));
pub fn get_buffer_size(&self, dir: SoDirection) -> Result<usize> {
let val: u32 = self.0.getsockopt(SOL_SOCKET, dir.buffer_opt())?;
return Ok(val as usize);
}

Expand All @@ -144,7 +154,7 @@ impl SctpStream {
/// Try to clone the SctpStream. On success, returns a new stream
/// wrapping a new socket handler
pub fn try_clone(&self) -> Result<SctpStream> {
return Ok(SctpStream(try!(self.0.try_clone())));
return Ok(SctpStream(self.0.try_clone()?));
}
}

Expand Down Expand Up @@ -200,10 +210,10 @@ impl SctpEndpoint {

/// Create a one-to-many SCTP endpoint bound to a single address
pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpEndpoint> {
let raw_addr = try!(SocketAddr::from_addr(&address));
let sock = try!(SctpSocket::new(raw_addr.family(), SOCK_SEQPACKET));
try!(sock.bind(raw_addr));
try!(sock.listen(-1));
let raw_addr = SocketAddr::from_addr(&address)?;
let sock = SctpSocket::new(raw_addr.family(), SOCK_SEQPACKET)?;
sock.bind(raw_addr)?;
sock.listen(-1)?;
return Ok(SctpEndpoint(sock));
}

Expand All @@ -213,14 +223,14 @@ impl SctpEndpoint {
let mut vec = Vec::with_capacity(addresses.len());
let mut family = AF_INET;
for address in addresses {
let a = try!(SocketAddr::from_addr(address));
let a = SocketAddr::from_addr(address)?;
if a.family() == AF_INET6 { family = AF_INET6; }
vec.push(a);
}

let sock = try!(SctpSocket::new(family, SOCK_SEQPACKET));
try!(sock.bindx(&vec, BindOp::AddAddr));
try!(sock.listen(-1));
let sock = SctpSocket::new(family, SOCK_SEQPACKET)?;
sock.bindx(&vec, BindOp::AddAddr)?;
sock.listen(-1)?;
return Ok(SctpEndpoint(sock));
}

Expand All @@ -234,7 +244,7 @@ impl SctpEndpoint {
/// Send data in Sctp style, to the provided address on the stream `stream`.
/// On success, returns the quantity on bytes sent
pub fn send_to<A: ToSocketAddrs>(&self, msg: &mut [u8], address: A, stream: u16) -> Result<usize> {
return self.0.sendmsg(msg, Some(address), stream, 0);
return self.0.sendmsg(msg, Some(address), 0, stream, 0);
}

/// Get local socket addresses to which this socket is bound
Expand All @@ -255,7 +265,7 @@ impl SctpEndpoint {

/// Verify if SCTP_NODELAY option is activated for this socket
pub fn has_nodelay(&self) -> Result<bool> {
let val: libc::c_int = try!(self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0));
let val: libc::c_int = self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0)?;
return Ok(val == 1);
}

Expand All @@ -266,8 +276,8 @@ impl SctpEndpoint {
}

/// Get the socket buffer size for the direction specified by `dir`
pub fn get_buffer_size(&self, dir: SoDirection) -> Result<(usize)> {
let val: u32 = try!(self.0.getsockopt(SOL_SOCKET, dir.buffer_opt()));
pub fn get_buffer_size(&self, dir: SoDirection) -> Result<usize> {
let val: u32 = self.0.getsockopt(SOL_SOCKET, dir.buffer_opt())?;
return Ok(val as usize);
}

Expand All @@ -280,7 +290,7 @@ impl SctpEndpoint {

/// Try to clone this socket
pub fn try_clone(&self) -> Result<SctpEndpoint> {
return Ok(SctpEndpoint(try!(self.0.try_clone())));
return Ok(SctpEndpoint(self.0.try_clone()?));
}
}

Expand Down Expand Up @@ -336,10 +346,10 @@ impl SctpListener {

/// Create a listener bound to a single address
pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpListener> {
let raw_addr = try!(SocketAddr::from_addr(&address));
let sock = try!(SctpSocket::new(raw_addr.family(), SOCK_STREAM));
try!(sock.bind(raw_addr));
try!(sock.listen(-1));
let raw_addr = SocketAddr::from_addr(&address)?;
let sock = SctpSocket::new(raw_addr.family(), SOCK_STREAM)?;
sock.bind(raw_addr)?;
sock.listen(-1)?;
return Ok(SctpListener(sock));
}

Expand All @@ -349,20 +359,20 @@ impl SctpListener {
let mut vec = Vec::with_capacity(addresses.len());
let mut family = AF_INET;
for address in addresses {
let a = try!(SocketAddr::from_addr(address));
let a = SocketAddr::from_addr(address)?;
if a.family() == AF_INET6 { family = AF_INET6; }
vec.push(a);
}

let sock = try!(SctpSocket::new(family, SOCK_STREAM));
try!(sock.bindx(&vec, BindOp::AddAddr));
try!(sock.listen(-1));
let sock = SctpSocket::new(family, SOCK_STREAM)?;
sock.bindx(&vec, BindOp::AddAddr)?;
sock.listen(-1)?;
return Ok(SctpListener(sock));
}

/// Accept a new connection
pub fn accept(&self) -> Result<(SctpStream, SocketAddr)> {
let (sock, addr) = try!(self.0.accept());
let (sock, addr) = self.0.accept()?;
return Ok((SctpStream(sock), addr));
}

Expand All @@ -385,7 +395,7 @@ impl SctpListener {

/// Try to clone this listener
pub fn try_clone(&self) -> Result<SctpListener> {
return Ok(SctpListener(try!(self.0.try_clone())));
return Ok(SctpListener(self.0.try_clone()?));
}
}

Expand Down
135 changes: 135 additions & 0 deletions src/mio_unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#[macro_export]
// copy from mio::sys::unix::mod
// https://github.com/faern/mio/blob/master/src/sys/unix/mod.rs
/// Helper macro to execute a system call that returns an `io::Result`.
//
// Macro must be defined before any modules that uses them.
#[allow(unused_macros)]
macro_rules! syscall {
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
let res = unsafe { libc::$fn($($arg, )*) };
if res == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(res)
}
}};
}

#[macro_export]
#[allow(unused_macros)]
macro_rules! sctp_syscall {
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
let res = unsafe { sctp_sys::$fn($($arg, )*) };
if res == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(res)
}
}};
}

use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};

// copy from mio::sys::unix::net
// https://github.com/faern/mio/blob/master/src/sys/unix/net.rs
/// A type with the same memory layout as `libc::sockaddr`. Used in converting Rust level
/// SocketAddr* types into their system representation. The benefit of this specific
/// type over using `libc::sockaddr_storage` is that this type is exactly as large as it
/// needs to be and not a lot larger. And it can be initialized cleaner from Rust.
#[repr(C)]
pub(crate) union SocketAddrCRepr {
v4: libc::sockaddr_in,
v6: libc::sockaddr_in6,
}

impl SocketAddrCRepr {
pub(crate) fn as_ptr(&self) -> *const libc::sockaddr {
self as *const _ as *const libc::sockaddr
}
}

/// Converts a Rust `SocketAddr` into the system representation.
pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_t) {
match addr {
SocketAddr::V4(ref addr) => {
// `s_addr` is stored as BE on all machine and the array is in BE order.
// So the native endian conversion method is used so that it's never swapped.
let sin_addr = libc::in_addr { s_addr: u32::from_ne_bytes(addr.ip().octets()) };

let sockaddr_in = libc::sockaddr_in {
sin_family: libc::AF_INET as libc::sa_family_t,
sin_port: addr.port().to_be(),
sin_addr,
sin_zero: [0; 8],
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
sin_len: 0,
};

let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
(sockaddr, mem::size_of::<libc::sockaddr_in>() as libc::socklen_t)
}
SocketAddr::V6(ref addr) => {
let sockaddr_in6 = libc::sockaddr_in6 {
sin6_family: libc::AF_INET6 as libc::sa_family_t,
sin6_port: addr.port().to_be(),
sin6_addr: libc::in6_addr { s6_addr: addr.ip().octets() },
sin6_flowinfo: addr.flowinfo(),
sin6_scope_id: addr.scope_id(),
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
sin6_len: 0,
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
__sin6_src_id: 0,
};

let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
(sockaddr, mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t)
}
}
}

/// Converts a `libc::sockaddr` compatible struct into a native Rust `SocketAddr`.
///
/// # Safety
///
/// `storage` must have the `ss_family` field correctly initialized.
/// `storage` must be initialised to a `sockaddr_in` or `sockaddr_in6`.
pub(crate) unsafe fn to_socket_addr(
storage: *const libc::sockaddr_storage,
) -> std::io::Result<SocketAddr> {
match (*storage).ss_family as libc::c_int {
libc::AF_INET => {
// Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
let addr: &libc::sockaddr_in = &*(storage as *const libc::sockaddr_in);
let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
let port = u16::from_be(addr.sin_port);
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
},
libc::AF_INET6 => {
// Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
let addr: &libc::sockaddr_in6 = &*(storage as *const libc::sockaddr_in6);
let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr);
let port = u16::from_be(addr.sin6_port);
Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, addr.sin6_flowinfo, addr.sin6_scope_id)))
},
_ => Err(std::io::ErrorKind::InvalidInput.into()),
}
}
//
// CODE COPY ENDS HERE
//
Loading