From f8b49936bc97b5e7303f60c2e45f504249da31a2 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 27 Jun 2020 16:15:27 +0200 Subject: [PATCH] Various unix socket fixes (+socketpair!) --- src/header/sys_un/mod.rs | 9 ++++ src/platform/redox/epoll.rs | 10 ++-- src/platform/redox/socket.rs | 89 ++++++++++++++++++++++++++---------- 3 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/header/sys_un/mod.rs b/src/header/sys_un/mod.rs index 6399f74bd2..b573889959 100644 --- a/src/header/sys_un/mod.rs +++ b/src/header/sys_un/mod.rs @@ -5,3 +5,12 @@ pub struct sockaddr_un { pub sun_family: sa_family_t, pub sun_path: [c_char; 108], } + +impl sockaddr_un { + pub fn path_len(&self) -> usize { + let base = self as *const _ as usize; + let path = &self.sun_path as *const _ as usize; + trace!("base: {:#X}, path: {:#X}", base, path); + path - base + } +} diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs index 610a81063c..74b55d6655 100644 --- a/src/platform/redox/epoll.rs +++ b/src/platform/redox/epoll.rs @@ -29,9 +29,9 @@ impl PalEpoll for Sys { id: fd as usize, flags: syscall::EventFlags::from_bits(unsafe { (*event).events as usize }) .expect("epoll: invalid bit pattern"), - // NOTE: Danger when using non 64-bit systems. If this is - // needed, use a box or something - data: unsafe { mem::transmute((*event).data) }, + // NOTE: Danger when using something smaller than 64-bit + // systems. If this is needed, use a box or something + data: unsafe { (*event).data.u64 as usize }, }, ) as c_int } @@ -102,7 +102,7 @@ impl PalEpoll for Sys { if bytes_read == -1 { return -1; } - let read = bytes_read as usize / mem::size_of::(); + let read = bytes_read as usize / mem::size_of::(); let mut count = 0; for i in 0..read { @@ -117,7 +117,7 @@ impl PalEpoll for Sys { } *event_ptr = epoll_event { events: event.flags.bits() as _, - data: mem::transmute(event.data), + data: epoll_data { u64: event.data as u64, }, ..Default::default() }; count += 1; diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index ab26d3694d..60ecdcd629 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -32,13 +32,17 @@ macro_rules! bind_or_connect { 0 }}; ($mode:ident copy, $socket:expr, $address:expr, $address_len:expr) => {{ - if ($address_len as usize) < mem::size_of::() { + if ($address_len as usize) < mem::size_of::() { errno = syscall::EINVAL; return -1; } let path = match (*$address).sa_family as c_int { AF_INET => { + 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, @@ -58,9 +62,10 @@ macro_rules! bind_or_connect { }, AF_UNIX => { let data = &*($address as *const sockaddr_un); + trace!("address: {:p}, data: {:p}, data2: {:#X}", $address, data, data as *const _ as usize); let addr = slice::from_raw_parts( &data.sun_path as *const _ as *const u8, - mem::size_of_val(&data.sun_path), + $address_len as usize - data.path_len(), ); let path = format!( "{}", @@ -91,7 +96,7 @@ unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut so let path = slice::from_raw_parts_mut( &mut data.sun_path as *mut _ as *mut u8, - mem::size_of_val(&data.sun_path), + data.path_len(), ); let len = cmp::min(path.len(), buf.len()); @@ -165,6 +170,19 @@ unsafe fn inner_get_name( Ok(0) } +fn socket_kind(mut kind: c_int) -> (c_int, usize) { + let mut flags = O_RDWR; + if kind & SOCK_NONBLOCK == SOCK_NONBLOCK { + kind &= !SOCK_NONBLOCK; + flags |= O_NONBLOCK; + } + if kind & SOCK_CLOEXEC == SOCK_CLOEXEC { + kind &= !SOCK_CLOEXEC; + flags |= O_CLOEXEC; + } + (kind, flags) +} + impl PalSocket for Sys { unsafe fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int { let stream = e(syscall::dup(socket as usize, b"listen")) as c_int; @@ -357,7 +375,7 @@ impl PalSocket for Sys { e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int } - unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int { + unsafe fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int { if domain != AF_INET && domain != AF_UNIX { errno = syscall::EAFNOSUPPORT; return -1; @@ -367,15 +385,7 @@ impl PalSocket for Sys { // return -1; // } - let mut flags = O_RDWR; - if kind & SOCK_NONBLOCK == SOCK_NONBLOCK { - kind &= !SOCK_NONBLOCK; - flags |= O_NONBLOCK; - } - if kind & SOCK_CLOEXEC == SOCK_CLOEXEC { - kind &= !SOCK_CLOEXEC; - flags |= O_CLOEXEC; - } + let (kind, flags) = socket_kind(kind); // The tcp: and udp: schemes allow using no path, // and later specifying one using `dup`. @@ -386,19 +396,52 @@ impl PalSocket for Sys { _ => { errno = syscall::EPROTONOSUPPORT; -1 - } + }, } } fn socketpair(domain: c_int, kind: c_int, protocol: c_int, sv: &mut [c_int; 2]) -> c_int { - eprintln!( - "socketpair({}, {}, {}, {:p})", - domain, - kind, - protocol, - sv.as_mut_ptr() - ); - unsafe { errno = syscall::ENOSYS }; - return -1; + let (kind, flags) = socket_kind(kind); + + match (domain, kind) { + (AF_UNIX, SOCK_STREAM) => { + let listener = e(syscall::open("chan:", flags | O_CREAT)); + if listener == !0 { + return -1; + } + + // For now, chan: lets connects be instant, and instead blocks + // on any I/O performed. So we don't need to mark this as + // nonblocking. + + let fd0 = e(syscall::dup(listener, b"connect")); + if fd0 == !0 { + let _ = syscall::close(listener); + return -1; + } + + let fd1 = e(syscall::dup(listener, b"listen")); + if fd1 == !0 { + let _ = syscall::close(fd0); + let _ = syscall::close(listener); + return -1; + } + + sv[0] = fd0 as c_int; + sv[1] = fd1 as c_int; + 0 + }, + _ => unsafe { + eprintln!( + "socketpair({}, {}, {}, {:p})", + domain, + kind, + protocol, + sv.as_mut_ptr() + ); + errno = syscall::EPROTONOSUPPORT; + -1 + }, + } } }