use std::{
collections::HashSet,
io::{IoSlice, IoSliceMut, Write},
mem,
mem::MaybeUninit,
thread,
};
use testutils::*;
use uapi::*;
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
mod linux;
pub use linux::*;
}
}
mod cmsg;
mod sockopt;
fn addr(s: &str) -> c::sockaddr_un {
let mut addr: c::sockaddr_un = pod_zeroed();
addr.sun_family = c::AF_UNIX as _;
pod_write(s.as_bytes(), &mut addr.sun_path[..s.len()]).unwrap();
addr
}
#[test]
fn socket1() {
let tmp = Tempdir::new();
let server_path = &*format!("{}/server", tmp);
let client_path = &*format!("{}/client", tmp);
let server_addr = addr(server_path);
let client_addr = addr(client_path);
let server = {
let fd = socket(c::AF_UNIX, c::SOCK_STREAM, 0).unwrap();
bind(*fd, &server_addr).unwrap();
listen(*fd, 128).unwrap();
fd
};
let thread = thread::spawn(move || {
let mut client = socket(c::AF_UNIX, c::SOCK_STREAM, 0).unwrap();
bind(*client, &client_addr).unwrap();
connect(*client, &server_addr).unwrap();
let mut pa: c::sockaddr_un = pod_zeroed();
getpeername(*client, &mut pa).unwrap();
cmp_addr_un(&pa, &server_addr);
let mut sa: c::sockaddr_un = pod_zeroed();
getsockname(*client, &mut sa).unwrap();
cmp_addr_un(&sa, &client_addr);
send(*client, b"hello world", 0).unwrap();
shutdown(*client, c::SHUT_WR).unwrap();
assert_eq!(&client.read_to_new_ustring().unwrap(), "hol up");
});
let mut accepted_client_addr: c::sockaddr_un = pod_zeroed();
let (mut client, addr_size) =
accept(*server, Some(&mut accepted_client_addr)).unwrap();
assert!(addr_size <= mem::size_of::<c::sockaddr_un>());
cmp_addr_un(&accepted_client_addr, &client_addr);
let mut buf = [0u8; 128];
let buf = recv(*client, &mut buf[..], 0).unwrap();
assert_eq!(buf, b"hello world");
client.write_all(b"hol up").unwrap();
shutdown(*client, c::SHUT_WR).unwrap();
thread.join().unwrap();
}
fn cmp_addr_un(a: &c::sockaddr_un, b: &c::sockaddr_un) {
assert_eq!(a.sun_family, b.sun_family);
assert_eq!(&a.sun_path[..], &b.sun_path[..]);
}
#[test]
fn socket2() {
let tmp = Tempdir::new();
let server_path = &*format!("{}/server", tmp);
let client_path = &*format!("{}/client", tmp);
let server_addr = addr(server_path);
let client_addr = addr(client_path);
let server = {
let fd = socket(c::AF_UNIX, c::SOCK_DGRAM, 0).unwrap();
bind(*fd, &server_addr).unwrap();
fd
};
{
let client = socket(c::AF_UNIX, c::SOCK_DGRAM, 0).unwrap();
bind(*client, &client_addr).unwrap();
let msghdr = Msghdr {
iov: &[IoSlice::new(b"hello world")][..],
control: msghdr_control_none_ref(),
name: Some(&server_addr),
};
sendmsg(*client, &msghdr, 0).unwrap();
}
{
let mut buf = [0; 128];
let mut accepted_client_addr: c::sockaddr_un = pod_zeroed();
let mut msghdr = MsghdrMut {
iov: &mut [IoSliceMut::new(&mut buf)][..],
control: msghdr_control_none_mut(),
name: Some(&mut accepted_client_addr),
flags: 0,
};
let (buf, addr_size, _) = recvmsg(*server, &mut msghdr, 0).unwrap();
let mut buf = buf.iter();
assert_eq!(buf.next(), Some("hello world".as_bytes()));
assert_eq!(buf.next(), None);
assert!(addr_size <= mem::size_of::<c::sockaddr_un>());
cmp_addr_un(&accepted_client_addr, &client_addr);
}
unlink(client_path).unwrap();
{
let client = socket(c::AF_UNIX, c::SOCK_DGRAM, 0).unwrap();
bind(*client, &client_addr).unwrap();
sendto(*client, b"ayo", 0, &server_addr).unwrap();
}
{
let mut buf = [MaybeUninit::<u8>::uninit(); 128];
let mut accepted_client_addr: c::sockaddr_un = pod_zeroed();
let (buf, addr_size) =
recvfrom(*server, &mut buf[..], 0, &mut accepted_client_addr).unwrap();
assert_eq!(buf, b"ayo");
assert!(addr_size <= mem::size_of::<c::sockaddr_un>());
cmp_addr_un(&accepted_client_addr, &client_addr);
}
}
#[test]
fn cmsg1() {
let tmp = Tempdir::new();
let f1 = open(format!("{}/a", tmp), c::O_CREAT | c::O_RDONLY, 0).unwrap();
let f2 = open(format!("{}/b", tmp), c::O_CREAT | c::O_RDONLY, 0).unwrap();
#[cfg(not(any(target_os = "macos", target_os = "openbsd")))]
let f3 = open(format!("{}/c", tmp), c::O_CREAT | c::O_RDONLY, 0).unwrap();
let mut inos: HashSet<c::ino_t> = [
*f1,
*f2,
#[cfg(not(any(target_os = "macos", target_os = "openbsd")))]
*f3,
]
.iter()
.map(|f| fstat(*f).unwrap())
.map(|s| s.st_ino)
.collect();
let (a, b) = socketpair(c::AF_UNIX, c::SOCK_DGRAM, 0).unwrap();
#[cfg(any(target_os = "android", target_os = "linux"))]
setsockopt(*b, c::SOL_SOCKET, c::SO_PASSCRED, &1i32).unwrap();
{
let mut buf = [MaybeUninit::uninit(); 128];
let len = {
let mut buf = &mut buf[..];
let mut hdr: c::cmsghdr = pod_zeroed();
hdr.cmsg_level = c::SOL_SOCKET;
hdr.cmsg_type = c::SCM_RIGHTS;
let mut len = 0;
len += cmsg_write(&mut buf, hdr, &[*f1, *f2]).unwrap();
cfg_if::cfg_if! {
if #[cfg(not(any(target_os = "macos", target_os = "openbsd")))] {
len += cmsg_write(&mut buf, hdr, &[*f3]).unwrap();
}
}
len
};
let msghdr = Msghdr {
iov: &[IoSlice::new(b"hello world")][..],
control: Some(&buf[..len]),
name: sockaddr_none_ref(),
};
sendmsg(*a, &msghdr, 0).unwrap();
}
{
let mut data_buf = [0; 128];
let mut cmsg_buf = [0; 128];
let mut msghdr = MsghdrMut {
iov: &mut [IoSliceMut::new(&mut data_buf)][..],
control: Some(&mut cmsg_buf[..]),
name: sockaddr_none_mut(),
flags: 0,
};
let (data, _, mut cmsg) = recvmsg(*b, &mut msghdr, 0).unwrap();
let mut data = data.iter();
assert_eq!(data.next(), Some("hello world".as_bytes()));
assert_eq!(data.next(), None);
assert!(cmsg.len() > 0);
#[cfg(any(target_os = "android", target_os = "linux"))]
let mut saw_cred = false;
while cmsg.len() > 0 {
let (_, hdr, data) = cmsg_read(&mut cmsg).unwrap();
match (hdr.cmsg_level, hdr.cmsg_type) {
(c::SOL_SOCKET, c::SCM_RIGHTS) => {
let data: Vec<_> = pod_iter::<c::c_int, _>(data)
.unwrap()
.map(OwnedFd::new)
.collect();
for fd in data {
assert!(inos.remove(&fstat(*fd).unwrap().st_ino));
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
(c::SOL_SOCKET, c::SCM_CREDENTIALS) => {
let data: c::ucred = pod_read(data).unwrap();
assert_eq!(data.pid, getpid());
assert_eq!(data.uid, geteuid());
assert_eq!(data.gid, getegid());
saw_cred = true;
}
_ => panic!("unexpected cmsg_level"),
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
assert!(saw_cred);
assert!(inos.is_empty());
}
}