use core::{mem, ptr, slice}; use syscall::flag::*; use syscall::{self, Result}; use super::super::types::*; use super::super::{errno, Pal, PalSocket}; use super::{e, Sys}; use crate::header::netinet_in::{in_port_t, sockaddr_in}; use crate::header::sys_socket::constants::*; use crate::header::sys_socket::{sockaddr, socklen_t}; use crate::header::sys_time::timeval; macro_rules! bind_or_connect { (bind $path:expr) => { concat!("/", $path) }; (connect $path:expr) => { $path }; ($mode:ident into, $socket:expr, $address:expr, $address_len:expr) => {{ let fd = bind_or_connect!($mode copy, $socket, $address, $address_len); let result = syscall::dup2(fd, $socket as usize, &[]); let _ = syscall::close(fd); if (e(result) as c_int) < 0 { return -1; } 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::<sockaddr>() { 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 ); // Duplicate the socket, and then duplicate the copy back to the original fd let fd = e(syscall::dup($socket as usize, path.as_bytes())); if (fd as c_int) < 0 { return -1; } fd }}; } unsafe fn inner_get_name( local: bool, socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> Result<usize> { // 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 parts.next(); } let part = parts.next().expect("Invalid reply from netstack"); trace!("path: {}", ::core::str::from_utf8_unchecked(&part)); (*address).sa_family = AF_INET as c_ushort; let data = slice::from_raw_parts_mut( &mut (*address).sa_data as *mut _ as *mut u8, (*address).sa_data.len(), ); let len = data.len().min(part.len()); data[..len].copy_from_slice(&part[..len]); *address_len = len as socklen_t; Ok(0) } 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; if stream < 0 { return -1; } if address != ptr::null_mut() && address_len != ptr::null_mut() && Self::getpeername(stream, address, address_len) < 0 { return -1; } stream } unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int { bind_or_connect!(bind into, socket, address, address_len) } unsafe fn connect(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int { bind_or_connect!(connect into, socket, address, address_len) } unsafe fn getpeername( socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { e(inner_get_name(false, socket, address, address_len)) as c_int } unsafe fn getsockname( socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { e(inner_get_name(true, socket, address, address_len)) as c_int } fn getsockopt( socket: c_int, level: c_int, option_name: c_int, option_value: *mut c_void, option_len: *mut socklen_t, ) -> c_int { eprintln!( "getsockopt({}, {}, {}, {:p}, {:p})", socket, level, option_name, option_value, option_len ); e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int } fn listen(socket: c_int, backlog: c_int) -> c_int { // Redox has no need to listen 0 } unsafe fn recvfrom( socket: c_int, buf: *mut c_void, len: size_t, flags: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> ssize_t { if flags != 0 { errno = syscall::EOPNOTSUPP; return -1; } if address == ptr::null_mut() || address_len == ptr::null_mut() { Self::read(socket, slice::from_raw_parts_mut(buf as *mut u8, len)) } else { let fd = e(syscall::dup(socket as usize, b"listen")); if fd == !0 { return -1; } if Self::getpeername(fd as c_int, address, address_len) < 0 { let _ = syscall::close(fd); return -1; } let ret = Self::read(fd as c_int, slice::from_raw_parts_mut(buf as *mut u8, len)); let _ = syscall::close(fd); ret } } unsafe fn sendto( socket: c_int, buf: *const c_void, len: size_t, flags: c_int, dest_addr: *const sockaddr, dest_len: socklen_t, ) -> ssize_t { if flags != 0 { errno = syscall::EOPNOTSUPP; return -1; } if dest_addr == ptr::null() || dest_len == 0 { Self::write(socket, slice::from_raw_parts(buf as *const u8, len)) } else { let fd = bind_or_connect!(connect copy, socket, dest_addr, dest_len); let ret = Self::write(fd as c_int, slice::from_raw_parts(buf as *const u8, len)); let _ = syscall::close(fd); ret } } fn setsockopt( socket: c_int, level: c_int, option_name: c_int, option_value: *const c_void, option_len: socklen_t, ) -> c_int { let set_timeout = |timeout_name: &[u8]| -> c_int { if option_value.is_null() { return e(Err(syscall::Error::new(syscall::EFAULT))) as c_int; } if (option_len as usize) < mem::size_of::<timeval>() { return e(Err(syscall::Error::new(syscall::EINVAL))) as c_int; } let timeval = unsafe { &*(option_value as *const timeval) }; let fd = e(syscall::dup(socket as usize, timeout_name)); if fd == !0 { return -1; } let timespec = syscall::TimeSpec { tv_sec: timeval.tv_sec, tv_nsec: timeval.tv_usec * 1000, }; let ret = Self::write(fd as c_int, ×pec); let _ = syscall::close(fd); if ret >= 0 { 0 } else { -1 } }; match level { SOL_SOCKET => match option_name { SO_RCVTIMEO => return set_timeout(b"read_timeout"), SO_SNDTIMEO => return set_timeout(b"write_timeout"), _ => (), }, _ => () } eprintln!( "setsockopt({}, {}, {}, {:p}, {})", socket, level, option_name, option_value, option_len ); e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int } fn shutdown(socket: c_int, how: c_int) -> c_int { eprintln!( "shutdown({}, {})", socket, how ); 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 { if domain != AF_INET { errno = syscall::EAFNOSUPPORT; return -1; } // if protocol != 0 { // errno = syscall::EPROTONOSUPPORT; // 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; } // 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, _ => { 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; } }