diff --git a/src/common.rs b/src/common.rs index 926d241..6b0a028 100644 --- a/src/common.rs +++ b/src/common.rs @@ -101,8 +101,33 @@ fn make_addr(_domain: Domain, sockaddr: &str) -> Result { UnixAddr::new(sockaddr).map_err(err_to_others_err!(e, "")) } -fn make_socket(addr: (&str, u32)) -> Result<(RawFd, Domain, Box)> { - let (sockaddr, _) = addr; +// addr: cid:port +// return (cid, port) +fn parse_vscok(addr: &str) -> Result<(u32, u32)> { + // vsock://cid:port + let sockaddr_port_v: Vec<&str> = addr.split(':').collect(); + if sockaddr_port_v.len() != 2 { + return Err(Error::Others(format!( + "sockaddr {addr} is not right for vsock" + ))); + } + + // for -1 need trace to libc::VMADDR_CID_ANY + let cid: u32 = if sockaddr_port_v[0].trim().eq("-1") { + libc::VMADDR_CID_ANY + } else { + sockaddr_port_v[0] + .parse() + .expect("the vsock cid is not an number") + }; + + let port: u32 = sockaddr_port_v[1] + .parse() + .expect("the vsock port is not an number"); + Ok((cid as u32, port)) +} + +fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box)> { let (domain, sockaddrv) = parse_sockaddr(sockaddr)?; let get_sock_addr = |domain, sockaddr| -> Result<(RawFd, Box)> { @@ -121,15 +146,7 @@ fn make_socket(addr: (&str, u32)) -> Result<(RawFd, Domain, Box get_sock_addr(domain, sockaddrv)?, #[cfg(any(target_os = "linux", target_os = "android"))] Domain::Vsock => { - let sockaddr_port_v: Vec<&str> = sockaddrv.split(':').collect(); - if sockaddr_port_v.len() != 2 { - return Err(Error::Others(format!( - "sockaddr {sockaddr} is not right for vsock" - ))); - } - let port: u32 = sockaddr_port_v[1] - .parse() - .expect("the vsock port is not an number"); + let (cid, port) = parse_vscok(sockaddrv)?; let fd = socket( AddressFamily::Vsock, SockType::Stream, @@ -137,7 +154,6 @@ fn make_socket(addr: (&str, u32)) -> Result<(RawFd, Domain, Box Result<(RawFd, Domain, Box Result<(RawFd, Domain)> { - let (fd, domain, sockaddr) = make_socket((sockaddr, VMADDR_CID_ANY))?; + let (fd, domain, sockaddr) = make_socket(sockaddr)?; setsockopt(fd, sockopt::ReusePort, &true)?; bind(fd, sockaddr.as_ref()).map_err(err_to_others_err!(e, ""))?; @@ -167,7 +173,7 @@ pub(crate) fn do_bind(sockaddr: &str) -> Result<(RawFd, Domain)> { /// Creates a unix socket for client. pub(crate) unsafe fn client_connect(sockaddr: &str) -> Result { - let (fd, _, sockaddr) = make_socket((sockaddr, VMADDR_CID_HOST))?; + let (fd, _, sockaddr) = make_socket(sockaddr)?; connect(fd, sockaddr.as_ref())?; @@ -236,4 +242,21 @@ mod tests { } } } + // Vsock is not supported on non Linux. + // #[cfg(any(target_os = "linux", target_os = "android"))] + #[test] + fn test_parse_vscok() { + for i in &[ + ("-1:1024", (libc::VMADDR_CID_ANY, 1024)), + ("0:1", (0, 1)), + ("1:2", (1, 2)), + ("4294967294:3", (4294967294, 3)), + // 4294967295 = 0xFFFFFFFF + ("4294967295:4", (libc::VMADDR_CID_ANY, 4)), + ] { + let (input, (cid, port)) = (i.0, i.1); + let r = parse_vscok(input); + assert_eq!(r.unwrap(), (cid, port), "parse {:?} failed", i); + } + } }