From b5c13463743d5c2e4dead1934b4abe74eceac104 Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Sun, 23 Aug 2015 22:15:07 -0400 Subject: Add support for sendmsg(2), recvmsg(2), and cmsg(3) 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 and Linux 4.0 , and tested on Debian 8.1 and FreeBSD 10.2 x86_64. The API differs a bit from the cmsg(3) API for type-safety reasons (and also because the cmsg(3) API is terrible). See test/sys/test_socket.rs for an example. Only supports SCM_RIGHTS at the moment. Fixes #88. --- test/sys/test_socket.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) (limited to 'test/sys') 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 = 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(); +} -- cgit v1.2.3