From 2bc667f71c11b75c4f6bab82e9a5fdb529ba708c Mon Sep 17 00:00:00 2001 From: Tiago Lam Date: Wed, 5 Feb 2020 22:32:12 +0000 Subject: [PATCH 1/4] header/sys_un: Set sockaddr_un members to public. Future commits will make use of this, in order to support AF_UNIX sockets. --- src/header/sys_un/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/header/sys_un/mod.rs b/src/header/sys_un/mod.rs index 69f0e6f662..6399f74bd2 100644 --- a/src/header/sys_un/mod.rs +++ b/src/header/sys_un/mod.rs @@ -2,6 +2,6 @@ use crate::{header::sys_socket::sa_family_t, platform::types::*}; #[repr(C)] pub struct sockaddr_un { - sun_family: sa_family_t, - sun_path: [c_char; 108], + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108], } From 12f6ffd15214634f97f2bb9c5e35bb1f74cf546b Mon Sep 17 00:00:00 2001 From: Tiago Lam Date: Wed, 5 Feb 2020 22:35:50 +0000 Subject: [PATCH 2/4] platform/redox: Support AF_UNIX in socket. To add support for UNIX sockets (AF_UNIX), of SOCK_STREAM type, the "chan:" scheme is used, which will be supportedby the ipcd running in userspace. Later commits add similar AF_UNIX support for the rest of the methods in impl PalSocket. --- src/platform/redox/socket.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index 56aa5532cb..bf9785455e 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -292,7 +292,7 @@ impl PalSocket for Sys { } unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int { - if domain != AF_INET { + if domain != AF_INET && domain != AF_UNIX { errno = syscall::EAFNOSUPPORT; return -1; } @@ -313,9 +313,10 @@ impl PalSocket for Sys { // The tcp: and udp: schemes allow using no path, // and later specifying one using `dup`. - match kind { - SOCK_STREAM => e(syscall::open("tcp:", flags)) as c_int, - SOCK_DGRAM => e(syscall::open("udp:", flags)) as c_int, + match (domain, kind) { + (AF_INET, SOCK_STREAM) => e(syscall::open("tcp:", flags)) as c_int, + (AF_INET, SOCK_DGRAM) => e(syscall::open("udp:", flags)) as c_int, + (AF_UNIX, SOCK_STREAM) => e(syscall::open("chan:", flags | O_CREAT)) as c_int, _ => { errno = syscall::EPROTONOSUPPORT; -1 From d36cd72788e3381485f44a853529112593e78da3 Mon Sep 17 00:00:00 2001 From: Tiago Lam Date: Wed, 5 Feb 2020 22:45:09 +0000 Subject: [PATCH 3/4] platform/redox: Support AF_UNIX in bind / connect. Previously, domain AF_INET was assumed while processing bind() / connect(), which end up calling bind_or_connect!. Instead, match on the domain type and process the path for AF_UNIX domains. --- src/platform/redox/socket.rs | 59 ++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index bf9785455e..ba64170978 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -1,4 +1,4 @@ -use core::{mem, ptr, slice}; +use core::{mem, ptr, slice, str}; use syscall::{self, flag::*, Result}; use super::{ @@ -9,6 +9,7 @@ use crate::header::{ netinet_in::{in_port_t, sockaddr_in}, sys_socket::{constants::*, sockaddr, socklen_t}, sys_time::timeval, + sys_un::sockaddr_un, }; macro_rules! bind_or_connect { @@ -29,28 +30,48 @@ macro_rules! bind_or_connect { 0 }}; ($mode:ident copy, $socket:expr, $address:expr, $address_len:expr) => {{ - if (*$address).sa_family as c_int != AF_INET { - errno = syscall::EAFNOSUPPORT; - return -1; - } if ($address_len as usize) < mem::size_of::() { errno = syscall::EINVAL; return -1; } - let data = &*($address as *const sockaddr_in); - let addr = slice::from_raw_parts( - &data.sin_addr.s_addr as *const _ as *const u8, - mem::size_of_val(&data.sin_addr.s_addr), - ); - let port = in_port_t::from_be(data.sin_port); - let path = format!( - bind_or_connect!($mode "{}.{}.{}.{}:{}"), - addr[0], - addr[1], - addr[2], - addr[3], - port - ); + + let path = match (*$address).sa_family as c_int { + AF_INET => { + let data = &*($address as *const sockaddr_in); + let addr = slice::from_raw_parts( + &data.sin_addr.s_addr as *const _ as *const u8, + mem::size_of_val(&data.sin_addr.s_addr), + ); + let port = in_port_t::from_be(data.sin_port); + let path = format!( + bind_or_connect!($mode "{}.{}.{}.{}:{}"), + addr[0], + addr[1], + addr[2], + addr[3], + port + ); + + path + }, + AF_UNIX => { + let data = &*($address as *const sockaddr_un); + let addr = slice::from_raw_parts( + &data.sun_path as *const _ as *const u8, + mem::size_of_val(&data.sun_path), + ); + let path = format!( + "{}", + str::from_utf8(addr).unwrap() + ); + + path + }, + _ => { + errno = syscall::EAFNOSUPPORT; + return -1; + }, + }; // Duplicate the socket, and then duplicate the copy back to the original fd let fd = e(syscall::dup($socket as usize, path.as_bytes())); From 76f07b163b92e781e6cb4aa92480d96819ce1f09 Mon Sep 17 00:00:00 2001 From: Tiago Lam Date: Wed, 5 Feb 2020 22:49:11 +0000 Subject: [PATCH 4/4] platform/redox: Support AF_UNIX in accept. As with the previous commit, accept() was calling inner_get_name() and assuming only "tcp:" or "udp:" addresses would be received. Thus, in order to support AF_UNIX sockets, inner_get_name() was split into two, inner_af_inet() and inner_af_unix() - where the former keeps the previous logic, dealing with "tcp:" and "udp:" addresses, and the latter deals now with "chan:" addresses and filling in the sockaddr_un appropriately. --- src/platform/redox/socket.rs | 57 ++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index ba64170978..80eb515e8b 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -82,21 +82,28 @@ macro_rules! bind_or_connect { }}; } -unsafe fn inner_get_name( +unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t) { + let data = &mut *(address as *mut sockaddr_un); + + data.sun_family = AF_UNIX as c_ushort; + + let path = slice::from_raw_parts_mut( + &mut data.sun_path as *mut _ as *mut u8, + mem::size_of_val(&data.sun_path), + ); + + let len = path.len().min(buf.len()); + path[..len].copy_from_slice(&buf[..len]); + + *address_len = len as socklen_t; +} + +unsafe fn inner_af_inet( local: bool, - socket: c_int, + buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t, -) -> Result { - // 32 should probably be large enough. - // Format: tcp:remote/local - // and since we only yet support IPv4 (I think)... - let mut buf = [0; 32]; - let len = syscall::fpath(socket as usize, &mut buf)?; - let buf = &buf[..len]; - assert!(&buf[..4] == b"tcp:" || &buf[..4] == b"udp:"); - let buf = &buf[4..]; - +) { let mut parts = buf.split(|c| *c == b'/'); if local { // Skip the remote part @@ -117,6 +124,32 @@ unsafe fn inner_get_name( data[..len].copy_from_slice(&part[..len]); *address_len = len as socklen_t; +} + +unsafe fn inner_get_name( + local: bool, + socket: c_int, + address: *mut sockaddr, + address_len: *mut socklen_t, +) -> Result { + // 32 should probably be large enough. + // Format: [udp|tcp:]remote/local, chan:path + let mut buf = [0; 32]; + let len = syscall::fpath(socket as usize, &mut buf)?; + let buf = &buf[..len]; + assert!(&buf[..4] == b"tcp:" || &buf[..4] == b"udp:" || &buf[..5] == b"chan:"); + + match &buf[..5] { + b"tcp:" | b"udp:" => { + inner_af_inet(local, &buf[4..], address, address_len); + } + b"chan:" => { + inner_af_unix(&buf[5..], address, address_len); + } + // Socket doesn't belong to any scheme + _ => panic!("socket doesn't match either tcp, udp or chan schemes"), + }; + Ok(0) }