diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-07-12 20:27:49 +0000 |
---|---|---|
committer | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-07-12 20:27:49 +0000 |
commit | 4978a382ee343108bf89173704c030f7cdf12a38 (patch) | |
tree | f812d83361991dfd1714189951db770f5c8c6d67 | |
parent | 5e463aa51f0e644d54c21f0db2effa4b757f982a (diff) | |
parent | db72b7ea35c8200d79f4af324349fc3b49074079 (diff) | |
download | nix-4978a382ee343108bf89173704c030f7cdf12a38.zip |
Merge #1091
1091: socket: add support for AF_VSOCK r=asomers a=stefano-garzarella
This patch adds the support of AF_VSOCK in the socket module.
VSOCK is present since Linux 3.9.
Co-authored-by: Stefano Garzarella <sgarzare@redhat.com>
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/sys/socket/addr.rs | 91 | ||||
-rw-r--r-- | src/sys/socket/mod.rs | 7 | ||||
-rw-r--r-- | test/sys/test_socket.rs | 52 |
4 files changed, 149 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 777b4d98..cf30fd98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#1084](https://github.com/nix-rust/nix/pull/1084)) - Add `posix_fadvise`. ([#1089](https://github.com/nix-rust/nix/pull/1089)) +- Added `AF_VSOCK` to `AddressFamily`. + ([#1091](https://github.com/nix-rust/nix/pull/1091)) ### Changed - Support for `ifaddrs` now present when building for Android. diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index e6c5f8ae..ed414411 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -24,6 +24,8 @@ use ::sys::socket::addr::sys_control::SysControlAddr; target_os = "netbsd", target_os = "openbsd"))] pub use self::datalink::LinkAddr; +#[cfg(target_os = "linux")] +pub use self::vsock::VsockAddr; /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) @@ -241,6 +243,8 @@ impl AddressFamily { target_os = "netbsd", target_os = "openbsd"))] libc::AF_LINK => Some(AddressFamily::Link), + #[cfg(target_os = "linux")] + libc::AF_VSOCK => Some(AddressFamily::Vsock), _ => None } } @@ -638,7 +642,9 @@ pub enum SockAddr { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] - Link(LinkAddr) + Link(LinkAddr), + #[cfg(target_os = "linux")] + Vsock(VsockAddr), } impl SockAddr { @@ -665,6 +671,11 @@ impl SockAddr { SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a)) } + #[cfg(target_os = "linux")] + pub fn new_vsock(cid: u32, port: u32) -> SockAddr { + SockAddr::Vsock(VsockAddr::new(cid, port)) + } + pub fn family(&self) -> AddressFamily { match *self { SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, @@ -684,7 +695,9 @@ impl SockAddr { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] - SockAddr::Link(..) => AddressFamily::Link + SockAddr::Link(..) => AddressFamily::Link, + #[cfg(target_os = "linux")] + SockAddr::Vsock(..) => AddressFamily::Vsock, } } @@ -729,6 +742,9 @@ impl SockAddr { Some(SockAddr::Link(ether_addr)) } }, + #[cfg(target_os = "linux")] + Some(AddressFamily::Vsock) => Some(SockAddr::Vsock( + VsockAddr(*(addr as *const libc::sockaddr_vm)))), // Other address families are currently not supported and simply yield a None // entry instead of a proper conversion to a `SockAddr`. Some(_) | None => None, @@ -763,6 +779,8 @@ impl SockAddr { target_os = "netbsd", target_os = "openbsd"))] SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t), + #[cfg(target_os = "linux")] + SockAddr::Vsock(VsockAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t), } } } @@ -786,7 +804,9 @@ impl fmt::Display for SockAddr { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] - SockAddr::Link(ref ether_addr) => ether_addr.fmt(f) + SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), + #[cfg(target_os = "linux")] + SockAddr::Vsock(ref svm) => svm.fmt(f), } } } @@ -1124,6 +1144,71 @@ mod datalink { } } +#[cfg(target_os = "linux")] +pub mod vsock { + use ::sys::socket::addr::AddressFamily; + use libc::{sa_family_t, sockaddr_vm}; + use std::{fmt, mem}; + use std::hash::{Hash, Hasher}; + + #[derive(Copy, Clone)] + pub struct VsockAddr(pub sockaddr_vm); + + impl PartialEq for VsockAddr { + fn eq(&self, other: &Self) -> bool { + let (inner, other) = (self.0, other.0); + (inner.svm_family, inner.svm_cid, inner.svm_port) == + (other.svm_family, other.svm_cid, other.svm_port) + } + } + + impl Eq for VsockAddr {} + + impl Hash for VsockAddr { + fn hash<H: Hasher>(&self, s: &mut H) { + let inner = self.0; + (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); + } + } + + /// VSOCK Address + /// + /// The address for AF_VSOCK socket is defined as a combination of a + /// 32-bit Context Identifier (CID) and a 32-bit port number. + impl VsockAddr { + pub fn new(cid: u32, port: u32) -> VsockAddr { + let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; + addr.svm_family = AddressFamily::Vsock as sa_family_t; + addr.svm_cid = cid; + addr.svm_port = port; + + VsockAddr(addr) + } + + /// Context Identifier (CID) + pub fn cid(&self) -> u32 { + self.0.svm_cid + } + + /// Port number + pub fn port(&self) -> u32 { + self.0.svm_port + } + } + + impl fmt::Display for VsockAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "cid: {} port: {}", self.cid(), self.port()) + } + } + + impl fmt::Debug for VsockAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } +} + #[cfg(test)] mod tests { #[cfg(any(target_os = "android", diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 0e27216f..d3cbdaac 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -33,6 +33,8 @@ pub use self::addr::{ pub use ::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use sys::socket::addr::alg::AlgAddr; +#[cfg(target_os = "linux")] +pub use sys::socket::addr::vsock::VsockAddr; pub use libc::{ cmsghdr, @@ -1254,6 +1256,11 @@ pub unsafe fn sockaddr_storage_to_addr( use libc::sockaddr_alg; Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg)))) } + #[cfg(target_os = "linux")] + libc::AF_VSOCK => { + use libc::sockaddr_vm; + Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm)))) + } af => panic!("unexpected address family {}", af), } } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 12afc84c..bbe067f8 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1013,3 +1013,55 @@ pub fn test_recv_ipv6pktinfo() { ); } } + +#[cfg(target_os = "linux")] +#[test] +pub fn test_vsock() { + use libc; + use nix::Error; + use nix::errno::Errno; + use nix::sys::socket::{AddressFamily, socket, bind, connect, listen, + SockAddr, SockType, SockFlag}; + use nix::unistd::{close}; + use std::thread; + + let port: u32 = 3000; + + let s1 = socket(AddressFamily::Vsock, SockType::Stream, + SockFlag::empty(), None) + .expect("socket failed"); + + // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect + // an EADDRNOTAVAIL error. + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port); + assert_eq!(bind(s1, &sockaddr).err(), + Some(Error::Sys(Errno::EADDRNOTAVAIL))); + + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port); + assert_eq!(bind(s1, &sockaddr).err(), + Some(Error::Sys(Errno::EADDRNOTAVAIL))); + + + let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port); + assert_eq!(bind(s1, &sockaddr), Ok(())); + listen(s1, 10).expect("listen failed"); + + let thr = thread::spawn(move || { + let cid: u32 = libc::VMADDR_CID_HOST; + + let s2 = socket(AddressFamily::Vsock, SockType::Stream, + SockFlag::empty(), None) + .expect("socket failed"); + + let sockaddr = SockAddr::new_vsock(cid, port); + + // The current implementation does not support loopback devices, so, + // for now, we expect a failure on the connect. + assert_ne!(connect(s2, &sockaddr), Ok(())); + + close(s2).unwrap(); + }); + + close(s1).unwrap(); + thr.join().unwrap(); +} |