diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index 8a4326e6004e9097aa11c984c453d656eeb6a87e..b0891fd25af35abc739e256734fa5f7dbec7d955 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -12,7 +12,6 @@ extern crate alloc; extern crate sc; #[cfg(all(not(feature = "no_std"), target_os = "redox"))] -#[macro_use] pub extern crate syscall; pub use allocator::*; diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index d08ff25833cbeed81370ce4df5eded6da6aa15ab..6121d939430758a5b7e7fb0cae79e9b5e05de145 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -19,6 +19,10 @@ pub fn e(sys: usize) -> usize { } } +pub unsafe fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int { + e(syscall!(ACCEPT, socket, address, address_len)) as c_int +} + pub unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int { e(syscall!(BIND, socket, address, address_len)) as c_int } @@ -119,6 +123,10 @@ pub fn getgid() -> gid_t { e(unsafe { syscall!(GETGID) }) } +pub unsafe fn getpeername(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int { + e(unsafe { syscall!(GETPEERNAME, socket, address, address_len) }) as c_int +} + pub fn getpgid(pid: pid_t) -> pid_t { e(unsafe { syscall!(GETPGID, pid) }) } @@ -131,6 +139,10 @@ pub fn getppid() -> pid_t { e(unsafe { syscall!(GETPPID) }) } +pub unsafe fn getsockname(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int { + e(unsafe { syscall!(GETSOCKNAME, socket, address, address_len) }) as c_int +} + pub fn getuid() -> uid_t { e(unsafe { syscall!(GETUID) }) } diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index dd48ef5d47055a58f3ebbcc90e23d68224b04974..0ba0697b29af10ff9bacba009fb4273ec0f60d69 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -1,8 +1,9 @@ -use alloc; +//! sys/socket implementation, following http://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/socket.h.html + use core::mem; use core::ptr; use core::slice; -use syscall; +use syscall::{self, Result}; use syscall::data::Stat as redox_stat; use syscall::data::TimeSpec as redox_timespec; use syscall::flag::*; @@ -17,7 +18,7 @@ struct SockData { _pad: [c_char; 8], } -pub fn e(sys: Result<usize, syscall::Error>) -> usize { +pub fn e(sys: Result<usize>) -> usize { match sys { Ok(ok) => ok, Err(err) => { @@ -64,6 +65,18 @@ macro_rules! bind_or_connect { }} } +pub 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() + && getpeername(stream, address, address_len) < 0 { + return -1; + } + stream +} + pub unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int { bind_or_connect!(bind socket, address, address_len) } @@ -268,6 +281,40 @@ pub fn getgid() -> gid_t { e(syscall::getgid()) as gid_t } +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"); + + let data = slice::from_raw_parts_mut( + &mut (*address).data as *mut _ as *mut u8, + (*address).data.len() + ); + + let len = data.len().min(part.len()); + data[..len].copy_from_slice(&part[..len]); + + *address_len = len as socklen_t; + Ok(0) +} + +pub 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 +} + pub fn getpgid(pid: pid_t) -> pid_t { e(syscall::getpgid(pid as usize)) as pid_t } @@ -280,6 +327,10 @@ pub fn getppid() -> pid_t { e(syscall::getppid()) as pid_t } +pub 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 +} + pub fn getuid() -> uid_t { e(syscall::getuid()) as pid_t } @@ -393,15 +444,10 @@ pub unsafe fn recvfrom( errno = syscall::EOPNOTSUPP; return -1; } - let data = slice::from_raw_parts_mut( - &mut (*address).data as *mut _ as *mut u8, - (*address).data.len(), - ); - let pathlen = e(syscall::fpath(socket as usize, data)); - if pathlen < 0 { + if address != ptr::null_mut() && address_len != ptr::null_mut() + && getpeername(socket, address, address_len) < 0 { return -1; } - *address_len = pathlen as socklen_t; read(socket, slice::from_raw_parts_mut(buf as *mut u8, len)) } @@ -427,10 +473,13 @@ pub unsafe fn sendto( buf: *const c_void, len: size_t, flags: c_int, - _dest_addr: *const sockaddr, - _dest_len: socklen_t, + dest_addr: *const sockaddr, + dest_len: socklen_t, ) -> ssize_t { - // TODO: Use dest_addr and dest_len + if dest_addr != ptr::null() || dest_len != 0 { + errno = syscall::EISCONN; + return -1; + } if flags != 0 { errno = syscall::EOPNOTSUPP; return -1; diff --git a/src/sys_socket/src/constants.rs b/src/sys_socket/src/constants.rs new file mode 100644 index 0000000000000000000000000000000000000000..6abb1b8e64daaeaf6b79a35fb8c405d2d23e23c7 --- /dev/null +++ b/src/sys_socket/src/constants.rs @@ -0,0 +1,60 @@ +use platform::types::*; + +// These constants also exist in platform. They need to match. +// Reason they are not just re-exported is cbindgen. +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_NONBLOCK: c_int = 0o4000; +pub const SOCK_CLOEXEC: c_int = 0o2000000; +pub const AF_INET: c_int = 2; + +// Other constants +pub const SOCK_SEQPACKET: c_int = 5; + +pub const SOL_SOCKET: c_int = 1; + +pub const SO_DEBUG: c_int = 1; +pub const SO_REUSEADDR: c_int = 2; +pub const SO_TYPE: c_int = 3; +pub const SO_ERROR: c_int = 4; +pub const SO_DONTROUTE: c_int = 5; +pub const SO_BROADCAST: c_int = 6; +pub const SO_SNDBUF: c_int = 7; +pub const SO_RCVBUF: c_int = 8; +pub const SO_KEEPALIVE: c_int = 9; +pub const SO_OOBINLINE: c_int = 10; +pub const SO_NO_CHECK: c_int = 11; +pub const SO_PRIORITY: c_int = 12; +pub const SO_LINGER: c_int = 13; +pub const SO_BSDCOMPAT: c_int = 14; +pub const SO_REUSEPORT: c_int = 15; +pub const SO_PASSCRED: c_int = 16; +pub const SO_PEERCRED: c_int = 17; +pub const SO_RCVLOWAT: c_int = 18; +pub const SO_SNDLOWAT: c_int = 19; +pub const SO_RCVTIMEO: c_int = 20; +pub const SO_SNDTIMEO: c_int = 21; +pub const SO_ACCEPTCONN: c_int = 30; +pub const SO_PEERSEC: c_int = 31; +pub const SO_SNDBUFFORCE: c_int = 32; +pub const SO_RCVBUFFORCE: c_int = 33; +pub const SO_PROTOCOL: c_int = 38; +pub const SO_DOMAIN: c_int = 39; + +pub const SOMAXCONN: c_int = 128; + +pub const MSG_CTRUNC: c_int = 1 << 3; +pub const MSG_DONTROUTE: c_int = 1 << 2; +pub const MSG_EOR: c_int = 1 << 7; +pub const MSG_OOB: c_int = 1; +pub const MSG_PEEK: c_int = 1 << 1; +pub const MSG_TRUNC: c_int = 1 << 5; +pub const MSG_WAITALL: c_int = 1 << 8; + +pub const AF_INET6: c_int = 10; +pub const AF_UNIX: c_int = 1; +pub const AF_UNSPEC: c_int = 0; + +pub const SHUT_RD: c_int = 0; +pub const SHUT_RDWR: c_int = 2; +pub const SHUT_WR: c_int = 1; diff --git a/src/sys_socket/src/lib.rs b/src/sys_socket/src/lib.rs index 01fd0c5bcd2108ad44413ec68b1124dd5f7d74f9..c360c9721c95d346ae525f0aa35af4aed8012807 100644 --- a/src/sys_socket/src/lib.rs +++ b/src/sys_socket/src/lib.rs @@ -8,6 +8,9 @@ extern crate platform; use core::ptr; use platform::types::*; +mod constants; +use constants::*; + pub type in_addr_t = [u8; 4]; pub type in_port_t = u16; pub type sa_family_t = u16; @@ -19,19 +22,13 @@ pub struct sockaddr { data: [c_char; 14], } -pub const AF_INET: c_int = 2; -pub const SOCK_STREAM: c_int = 1; -pub const SOCK_DGRAM: c_int = 2; -pub const SOCK_NONBLOCK: c_int = 0o4000; -pub const SOCK_CLOEXEC: c_int = 0o2000000; - #[no_mangle] pub unsafe extern "C" fn accept( socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { - unimplemented!(); + platform::accept(socket, address as *mut platform::sockaddr, address_len) } #[no_mangle] @@ -55,10 +52,10 @@ pub unsafe extern "C" fn connect( #[no_mangle] pub unsafe extern "C" fn getpeername( socket: c_int, - address: *const sockaddr, - address_len: socklen_t, + address: *mut sockaddr, + address_len: *mut socklen_t, ) -> c_int { - unimplemented!(); + platform::getpeername(socket, address as *mut platform::sockaddr, address_len) } #[no_mangle] @@ -67,7 +64,7 @@ pub unsafe extern "C" fn getsockname( address: *mut sockaddr, address_len: *mut socklen_t, ) -> c_int { - unimplemented!(); + platform::getsockname(socket, address as *mut platform::sockaddr, address_len) } #[no_mangle]