Skip to content

Commit

Permalink
Merge #1091
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
bors[bot] and stefano-garzarella committed Jul 12, 2019
2 parents 5e463aa + db72b7e commit 4978a38
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
91 changes: 88 additions & 3 deletions src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
}
}
}
Expand All @@ -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),
}
}
}
Expand Down Expand Up @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
}
}
Expand Down
52 changes: 52 additions & 0 deletions test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

0 comments on commit 4978a38

Please sign in to comment.