diff options
author | Geoffrey Thomas <geofft@ldpreload.com> | 2015-08-23 22:15:07 -0400 |
---|---|---|
committer | Geoffrey Thomas <geofft@ldpreload.com> | 2015-09-24 23:18:44 -0400 |
commit | 046af7d1ba82506f9bc48e62ac0584361025fc02 (patch) | |
tree | ab984c4fb6589d800ef50b6f68488cb7acbbccf8 /test/sys/test_socket.rs | |
parent | 0fd0337e0f55b0f5b976c22bbe97fe49a2875bf0 (diff) | |
download | nix-046af7d1ba82506f9bc48e62ac0584361025fc02.zip |
Add support for sendmsg(2), recvmsg(2), and cmsg(4)
The best specification for control message layout appears to be
[RFC 2292, section 4](https://tools.ietf.org/html/rfc2292#section-4),
despite this not being a wire protocol. These definitions have also been
checked against glibc 2.19 <bits/socket.h> and Linux 4.0
<linux/socket.h>, and tested on Debian 8.1 and FreeBSD 10.2 x86_64.
The API differs a bit from the cmsg(4) API for type-safety reasons (and
also because the cmsg(4) API is terrible). See test/sys/test_socket.rs
for an example.
Only supports SCM_RIGHTS at the moment.
Fixes #88.
Diffstat (limited to 'test/sys/test_socket.rs')
-rw-r--r-- | test/sys/test_socket.rs | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index e8cb4bed..7b95767e 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -2,7 +2,7 @@ use nix::sys::socket::{InetAddr, UnixAddr, getsockname}; use std::{mem, net}; use std::path::Path; use std::str::FromStr; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, RawFd}; use ports::localhost; #[test] @@ -63,3 +63,56 @@ pub fn test_socketpair() { assert_eq!(&buf[..], b"hello"); } + +#[test] +pub fn test_scm_rights() { + use nix::sys::uio::IoVec; + use nix::unistd::{pipe, read, write, close}; + use nix::sys::socket::{socketpair, sendmsg, recvmsg, + AddressFamily, SockType, SockFlag, + ControlMessage, CmsgSpace, + MSG_TRUNC, MSG_CTRUNC}; + + let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, 0, + SockFlag::empty()) + .unwrap(); + let (r, w) = pipe().unwrap(); + let mut received_r: Option<RawFd> = None; + + { + let iov = [IoVec::from_slice(b"hello")]; + let fds = [r]; + let cmsg = ControlMessage::ScmRights(&fds); + assert_eq!(sendmsg(fd1, &iov, &[cmsg], 0, None).unwrap(), 5); + close(r).unwrap(); + close(fd1).unwrap(); + } + + { + let mut buf = [0u8; 5]; + let iov = [IoVec::from_mut_slice(&mut buf[..])]; + let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new(); + let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), 0).unwrap(); + + for cmsg in msg.cmsgs() { + if let ControlMessage::ScmRights(fd) = cmsg { + assert_eq!(received_r, None); + assert_eq!(fd.len(), 1); + received_r = Some(fd[0]); + } else { + panic!("unexpected cmsg"); + } + } + assert_eq!(msg.flags & (MSG_TRUNC | MSG_CTRUNC), 0); + close(fd2).unwrap(); + } + + let received_r = received_r.expect("Did not receive passed fd"); + // Ensure that the received file descriptor works + write(w, b"world").unwrap(); + let mut buf = [0u8; 5]; + read(received_r, &mut buf).unwrap(); + assert_eq!(&buf[..], b"world"); + close(received_r).unwrap(); + close(w).unwrap(); +} |