Skip to content

Commit

Permalink
Migrate sys/socket to libc FFI types.
Browse files Browse the repository at this point in the history
  • Loading branch information
kinetiknz committed Dec 20, 2017
1 parent b68db41 commit 9994365
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 113 deletions.
81 changes: 0 additions & 81 deletions src/sys/socket/ffi.rs

This file was deleted.

83 changes: 51 additions & 32 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use sys::time::TimeVal;
use sys::uio::IoVec;

mod addr;
mod ffi;
pub mod sockopt;

/*
Expand All @@ -33,6 +32,8 @@ pub use self::addr::{
pub use ::sys::socket::addr::netlink::NetlinkAddr;

pub use libc::{
cmsghdr,
msghdr,
sa_family_t,
sockaddr,
sockaddr_in,
Expand Down Expand Up @@ -295,19 +296,30 @@ unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
mem::swap(dst, &mut remainder);
}

// Darwin and DragonFly BSD always aligns struct cmsghdr as if it were a 32-bit OS
#[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))]
type align_of_cmsg_data = u32;

use self::ffi::{cmsghdr, msghdr, type_of_cmsg_data, type_of_msg_iovlen, type_of_cmsg_len};
#[cfg(not(target_os = "macos"))]
type align_of_cmsg_data = size_t;

/// A structure used to make room in a cmsghdr passed to recvmsg. The
/// size and alignment match that of a cmsghdr followed by a T, but the
/// fields are not accessible, as the actual types will change on a call
/// to recvmsg.
///
/// To make room for multiple messages, nest the type parameter with
/// tuples, e.g.
/// `let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();`
/// tuples:
///
/// ```
/// use std::os::unix::io::RawFd;
/// use nix::sys::socket::CmsgSpace;
/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
/// ```
#[repr(C)]
pub struct CmsgSpace<T> {
_hdr: cmsghdr,
_pad: [align_of_cmsg_data; 0],
_data: T,
}

Expand Down Expand Up @@ -377,24 +389,25 @@ impl<'a> Iterator for CmsgIterator<'a> {
if aligned_cmsg_len > self.buf.len() {
return None;
}
let cmsg_data = &self.buf[cmsg_align(sizeof_cmsghdr)..cmsg_len];
self.buf = &self.buf[aligned_cmsg_len..];
self.next += 1;

match (cmsg.cmsg_level, cmsg.cmsg_type) {
(libc::SOL_SOCKET, libc::SCM_RIGHTS) => unsafe {
Some(ControlMessage::ScmRights(
slice::from_raw_parts(
&cmsg.cmsg_data as *const _ as *const _, 1)))
slice::from_raw_parts(cmsg_data.as_ptr() as *const _,
cmsg_data.len() / mem::size_of::<RawFd>())))
},
(libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => unsafe {
Some(ControlMessage::ScmTimestamp(
&*(&cmsg.cmsg_data as *const _ as *const _)))
&*(cmsg_data.as_ptr() as *const _)))
},
(_, _) => unsafe {
Some(ControlMessage::Unknown(UnknownCmsg(
&cmsg,
slice::from_raw_parts(
&cmsg.cmsg_data as *const _ as *const _,
cmsg_data.as_ptr() as *const _,
len))))
}
}
Expand Down Expand Up @@ -487,8 +500,13 @@ pub enum ControlMessage<'a> {
#[doc(hidden)]
pub struct UnknownCmsg<'a>(&'a cmsghdr, &'a [u8]);

// Round `len` up to meet the platform's required alignment for
// `cmsghdr`s and trailing `cmsghdr` data. This should match the
// behaviour of CMSG_ALIGN from the Linux headers and do the correct
// thing on other platforms that don't usually provide CMSG_ALIGN.
#[inline]
fn cmsg_align(len: usize) -> usize {
let align_bytes = mem::size_of::<type_of_cmsg_data>() - 1;
let align_bytes = mem::size_of::<align_of_cmsg_data>() - 1;
(len + align_bytes) & !align_bytes
}

Expand All @@ -513,17 +531,16 @@ impl<'a> ControlMessage<'a> {
}
}

// Unsafe: start and end of buffer must be size_t-aligned (that is,
// cmsg_align'd). Updates the provided slice; panics if the buffer
// is too small.
// Unsafe: start and end of buffer must be cmsg_align'd. Updates
// the provided slice; panics if the buffer is too small.
unsafe fn encode_into<'b>(&self, buf: &mut &'b mut [u8]) {
match *self {
ControlMessage::ScmRights(fds) => {
let cmsg = cmsghdr {
cmsg_len: self.len() as type_of_cmsg_len,
cmsg_level: libc::SOL_SOCKET,
cmsg_type: libc::SCM_RIGHTS,
cmsg_data: [],
cmsg_len: self.len() as _,
cmsg_level: libc::SOL_SOCKET,
cmsg_type: libc::SCM_RIGHTS,
..mem::uninitialized()
};
copy_bytes(&cmsg, buf);

Expand All @@ -539,10 +556,10 @@ impl<'a> ControlMessage<'a> {
},
ControlMessage::ScmTimestamp(t) => {
let cmsg = cmsghdr {
cmsg_len: self.len() as type_of_cmsg_len,
cmsg_len: self.len() as _,
cmsg_level: libc::SOL_SOCKET,
cmsg_type: libc::SCM_TIMESTAMP,
cmsg_data: [],
..mem::uninitialized()
};
copy_bytes(&cmsg, buf);

Expand Down Expand Up @@ -603,15 +620,16 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
};

let mhdr = msghdr {
msg_name: name as *const c_void,
msg_name: name as *mut _,
msg_namelen: namelen,
msg_iov: iov.as_ptr(),
msg_iovlen: iov.len() as type_of_msg_iovlen,
msg_control: cmsg_ptr,
msg_controllen: capacity as type_of_cmsg_len,
msg_iov: iov.as_ptr() as *mut _,
msg_iovlen: iov.len() as _,
msg_control: cmsg_ptr as *mut _,
msg_controllen: capacity as _,
msg_flags: 0,
..unsafe { mem::uninitialized() }
};
let ret = unsafe { ffi::sendmsg(fd, &mhdr, flags.bits()) };
let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };

Errno::result(ret).map(|r| r as usize)
}
Expand All @@ -626,15 +644,16 @@ pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&
None => (0 as *mut _, 0),
};
let mut mhdr = msghdr {
msg_name: &mut address as *const _ as *const c_void,
msg_name: &mut address as *mut _ as *mut _,
msg_namelen: mem::size_of::<sockaddr_storage>() as socklen_t,
msg_iov: iov.as_ptr() as *const IoVec<&[u8]>, // safe cast to add const-ness
msg_iovlen: iov.len() as type_of_msg_iovlen,
msg_control: msg_control as *const c_void,
msg_controllen: msg_controllen as type_of_cmsg_len,
msg_iov: iov.as_ptr() as *mut _,
msg_iovlen: iov.len() as _,
msg_control: msg_control as *mut _,
msg_controllen: msg_controllen as _,
msg_flags: 0,
..unsafe { mem::uninitialized() }
};
let ret = unsafe { ffi::recvmsg(fd, &mut mhdr, flags.bits()) };
let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };

Ok(unsafe { RecvMsg {
bytes: try!(Errno::result(ret)) as usize,
Expand Down Expand Up @@ -851,7 +870,7 @@ pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
unsafe {
let ret = ffi::recv(
let ret = libc::recv(
sockfd,
buf.as_ptr() as *mut c_void,
buf.len() as size_t,
Expand All @@ -870,7 +889,7 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
let addr: sockaddr_storage = mem::zeroed();
let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;

let ret = try!(Errno::result(ffi::recvfrom(
let ret = try!(Errno::result(libc::recvfrom(
sockfd,
buf.as_ptr() as *mut c_void,
buf.len() as size_t,
Expand Down

0 comments on commit 9994365

Please sign in to comment.