Skip to content

Commit

Permalink
Support Freebsd
Browse files Browse the repository at this point in the history
Add support for FreeBSD and rename linux module to unix
  • Loading branch information
dlrobertson committed Sep 18, 2016
1 parent ca63fdb commit 65c0e76
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 52 deletions.
5 changes: 3 additions & 2 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
// except according to those terms.

mod os {
#[cfg(all(not(feature = "force-inprocess"), target_os = "linux"))]
include!("linux/mod.rs");
#[cfg(all(not(feature = "force-inprocess"),
any(target_os = "linux", target_os = "freebsd")))]
include!("unix/mod.rs");

#[cfg(all(not(feature = "force-inprocess"), target_os = "macos"))]
include!("macos/mod.rs");
Expand Down
4 changes: 2 additions & 2 deletions src/platform/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ fn big_data_with_sender_transfer() {
thread.join().unwrap();
}

#[cfg(all(not(feature = "force-inprocess"), target_os = "linux"))]
#[cfg(all(not(feature="force-inprocess"), any(target_os="linux", target_os="freebsd")))]
fn with_n_fds(n: usize, size: usize) {
let (sender_fds, receivers): (Vec<_>, Vec<_>) = (0..n).map(|_| platform::channel().unwrap())
.map(|(tx, rx)| (OsIpcChannel::Sender(tx), rx))
Expand Down Expand Up @@ -207,7 +207,7 @@ fn with_n_fds(n: usize, size: usize) {
}

// These tests only apply to platforms that need fragmentation.
#[cfg(all(not(feature = "force-inprocess"), target_os = "linux"))]
#[cfg(all(not(feature = "force-inprocess"), any(target_os="linux", target_os="freebsd")))]
mod fragment_tests {
use platform;
use super::with_n_fds;
Expand Down
130 changes: 82 additions & 48 deletions src/platform/linux/mod.rs → src/platform/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use bincode::serde::DeserializeError;
use libc::{self, MAP_FAILED, MAP_SHARED, POLLIN, PROT_READ, PROT_WRITE, SOCK_SEQPACKET, SOL_SOCKET};
use libc::{SO_LINGER, S_IFMT, S_IFSOCK, c_char, c_int, c_short, c_ushort, c_void, getsockopt};
use libc::{SO_LINGER, S_IFMT, S_IFSOCK, c_char, c_int, c_void, getsockopt};
use libc::{iovec, mkstemp, mode_t, msghdr, nfds_t, off_t, poll, pollfd, recvmsg, sendmsg};
use libc::{setsockopt, size_t, sockaddr, sockaddr_un, socketpair, socklen_t};
use std::cmp;
Expand All @@ -26,18 +26,64 @@ use std::thread;

const MAX_FDS_IN_CMSG: u32 = 64;

const SCM_RIGHTS: c_int = 0x01;

// The value Linux returns for SO_SNDBUF
// is not the size we are actually allowed to use...
// Empirically, we have to deduct 32 bytes from that.
const RESERVED_SIZE: usize = 32;

#[cfg(target_os="android")]
const TEMP_FILE_TEMPLATE: &'static str = "/sdcard/servo/ipc-channel-shared-memory.XXXXXX";

#[cfg(not(target_os="android"))]
const TEMP_FILE_TEMPLATE: &'static str = "/tmp/ipc-channel-shared-memory.XXXXXX";


#[cfg(target_os="linux")]
type IovLen = usize;
#[cfg(target_os="linux")]
type SockLen = usize;
#[cfg(target_os="linux")]
#[inline]
unsafe fn new_sockaddr_un(path: *const c_char) -> (sockaddr_un, usize) {
let mut sockaddr = sockaddr_un {
sun_family: libc::AF_UNIX as u16,
sun_path: [ 0; 108 ],
};
libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
path,
sockaddr.sun_path.len() - 1);
let len = mem::size_of::<sockaddr_un>() - 104 + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
(sockaddr, len)
}

#[cfg(target_os="freebsd")]
type IovLen = i32;
#[cfg(target_os="freebsd")]
type SockLen = socklen_t;
#[cfg(target_os="freebsd")]
#[inline]
unsafe fn new_sockaddr_un(path: *const c_char) -> (sockaddr_un, usize) {
let mut sockaddr = sockaddr_un {
sun_len: 0,
sun_family: libc::AF_UNIX as u8,
sun_path: [ 0; 104 ],
};
libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
path,
sockaddr.sun_path.len() - 1);
let len = mem::size_of::<sockaddr_un>() - 104 + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
(sockaddr, len)
}

lazy_static! {
static ref SYSTEM_SENDBUF_SIZE: usize = {
let (tx, _) = channel().expect("Failed to obtain a socket for checking maximum send size");
tx.get_system_sendbuf_size().expect("Failed to obtain maximum send size for socket")
};
}

// The value Linux returns for SO_SNDBUF
// is not the size we are actually allowed to use...
// Empirically, we have to deduct 32 bytes from that.
const RESERVED_SIZE: usize = 32;

pub fn channel() -> Result<(OsIpcSender, OsIpcReceiver),UnixError> {
let mut results = [0, 0];
unsafe {
Expand Down Expand Up @@ -192,13 +238,13 @@ impl OsIpcSender {
let result = unsafe {
let cmsg_length = mem::size_of_val(fds);
let (cmsg_buffer, cmsg_space) = if cmsg_length > 0 {
let cmsg_buffer = libc::malloc(CMSG_SPACE(cmsg_length)) as *mut cmsghdr;
(*cmsg_buffer).cmsg_len = CMSG_LEN(cmsg_length);
let cmsg_buffer = libc::malloc(CMSG_SPACE(cmsg_length) as usize) as *mut cmsghdr;
(*cmsg_buffer).cmsg_len = CMSG_LEN(cmsg_length as SockLen);
(*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
(*cmsg_buffer).cmsg_type = SCM_RIGHTS;

ptr::copy_nonoverlapping(fds.as_ptr(),
cmsg_buffer.offset(1) as *mut c_int,
CMSG_DATA(cmsg_buffer) as *mut c_int,
fds.len());
(cmsg_buffer, CMSG_SPACE(cmsg_length))
} else {
Expand All @@ -225,9 +271,9 @@ impl OsIpcSender {
msg_name: ptr::null_mut(),
msg_namelen: 0,
msg_iov: iovec.as_mut_ptr(),
msg_iovlen: iovec.len(),
msg_iovlen: iovec.len() as IovLen,
msg_control: cmsg_buffer as *mut c_void,
msg_controllen: cmsg_space,
msg_controllen: cmsg_space as SockLen,
msg_flags: 0,
};

Expand Down Expand Up @@ -352,15 +398,7 @@ impl OsIpcSender {
let name = CString::new(name).unwrap();
unsafe {
let fd = libc::socket(libc::AF_UNIX, SOCK_SEQPACKET, 0);
let mut sockaddr = sockaddr_un {
sun_family: libc::AF_UNIX as u16,
sun_path: [ 0; 108 ],
};
libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
name.as_ptr(),
sockaddr.sun_path.len() - 1);

let len = mem::size_of::<c_short>() + libc::strlen(sockaddr.sun_path.as_ptr());
let (sockaddr, len) = new_sockaddr_un(name.as_ptr() as *const c_char);
if libc::connect(fd, &sockaddr as *const _ as *const sockaddr, len as socklen_t) < 0 {
return Err(UnixError::last())
}
Expand Down Expand Up @@ -532,16 +570,7 @@ impl OsIpcOneShotServer {
return Err(UnixError::last())
}

let mut sockaddr = sockaddr_un {
sun_family: libc::AF_UNIX as c_ushort,
sun_path: [ 0; 108 ],
};
libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
path.as_ptr() as *const c_char,
sockaddr.sun_path.len() - 1);

let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as
usize);
let (sockaddr, len) = new_sockaddr_un(path.as_mut_ptr() as *const c_char);
if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as socklen_t) == 0 {
break
}
Expand Down Expand Up @@ -765,7 +794,7 @@ fn recv(fd: c_int, blocking_mode: BlockingMode)
let channel_length = if cmsg_length == 0 {
0
} else {
(cmsg.cmsg_len() - mem::size_of::<cmsghdr>()) / mem::size_of::<c_int>()
(cmsg.cmsg_len() - mem::size_of::<cmsghdr>() as SockLen) / mem::size_of::<c_int>() as SockLen
};
for index in 0..channel_length {
let fd = *cmsg_fds.offset(index as isize);
Expand Down Expand Up @@ -825,12 +854,6 @@ fn recv(fd: c_int, blocking_mode: BlockingMode)
Ok((main_data_buffer, channels, shared_memory_regions))
}

#[cfg(target_os="android")]
const TEMP_FILE_TEMPLATE: &'static str = "/sdcard/servo/ipc-channel-shared-memory.XXXXXX";

#[cfg(not(target_os="android"))]
const TEMP_FILE_TEMPLATE: &'static str = "/tmp/ipc-channel-shared-memory.XXXXXX";

#[cfg(target_os="android")]
fn maybe_unlink(_: *const c_char) -> c_int {
// Calling `unlink` on a file stored on an sdcard immediately deletes it.
Expand Down Expand Up @@ -903,9 +926,9 @@ impl UnixCmsg {
msg_name: ptr::null_mut(),
msg_namelen: 0,
msg_iov: iovec.as_mut_ptr(),
msg_iovlen: iovec.len(),
msg_iovlen: iovec.len() as IovLen,
msg_control: cmsg_buffer as *mut c_void,
msg_controllen: cmsg_length,
msg_controllen: cmsg_length as SockLen,
msg_flags: 0,
},
}
Expand Down Expand Up @@ -936,7 +959,7 @@ impl UnixCmsg {
result
}

unsafe fn cmsg_len(&self) -> size_t {
unsafe fn cmsg_len(&self) -> SockLen {
(*(self.msghdr.msg_control as *const cmsghdr)).cmsg_len
}
}
Expand All @@ -953,21 +976,32 @@ fn is_socket(fd: c_int) -> bool {

// FFI stuff follows:

const SCM_RIGHTS: c_int = 0x01;
#[allow(non_snake_case)]
fn CMSG_LEN(length: SockLen) -> SockLen {
(CMSG_ALIGN(mem::size_of::<cmsghdr>()) + length) as SockLen
}

#[allow(non_snake_case)]
fn CMSG_ALIGN(length: size_t) -> SockLen {
((length + mem::size_of::<size_t>() - 1) & !(mem::size_of::<size_t>() - 1)) as SockLen
}

#[allow(non_snake_case)]
fn CMSG_LEN(length: size_t) -> size_t {
CMSG_ALIGN(mem::size_of::<cmsghdr>()) + length
#[cfg(target_os = "linux")]
unsafe fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void {
cmsg.offset(1) as *mut c_void
}

#[allow(non_snake_case)]
fn CMSG_ALIGN(length: size_t) -> size_t {
(length + mem::size_of::<size_t>() - 1) & !(mem::size_of::<size_t>() - 1)
#[cfg(target_os = "freebsd")]
unsafe fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void {
(cmsg as *mut libc::c_uchar).offset(CMSG_ALIGN(
mem::size_of::<cmsghdr>()) as isize) as *mut c_void
}

#[allow(non_snake_case)]
fn CMSG_SPACE(length: size_t) -> size_t {
CMSG_ALIGN(length) + CMSG_ALIGN(mem::size_of::<cmsghdr>())
fn CMSG_SPACE(length: size_t) -> SockLen {
(CMSG_ALIGN(length) + CMSG_ALIGN(mem::size_of::<cmsghdr>())) as SockLen
}

#[allow(non_snake_case)]
Expand All @@ -982,7 +1016,7 @@ extern {

#[repr(C)]
struct cmsghdr {
cmsg_len: size_t,
cmsg_len: SockLen,
cmsg_level: c_int,
cmsg_type: c_int,
}
Expand Down

0 comments on commit 65c0e76

Please sign in to comment.