summaryrefslogtreecommitdiff
path: root/test/sys/test_socket.rs
diff options
context:
space:
mode:
authorGeoffrey Thomas <geofft@ldpreload.com>2015-08-23 22:15:07 -0400
committerGeoffrey Thomas <geofft@ldpreload.com>2015-10-06 19:30:26 -0400
commitb5c13463743d5c2e4dead1934b4abe74eceac104 (patch)
tree514f60bfdc6c113fd2e0e0fd243b70c251bfe4d5 /test/sys/test_socket.rs
parent0529fb8e324157bb02908eac5cfd9d0fa99c130f (diff)
downloadnix-b5c13463743d5c2e4dead1934b4abe74eceac104.zip
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 <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(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.
Diffstat (limited to 'test/sys/test_socket.rs')
-rw-r--r--test/sys/test_socket.rs55
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();
+}