diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca848701..cb5a15ac 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,9 +60,7 @@ jobs: strategy: fail-fast: false matrix: - # TODO: add the following targets, currently broken. - # "x86_64-unknown-redox" - target: ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-unknown-fuchsia", "x86_64-pc-windows-msvc", "x86_64-pc-solaris", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-netbsd"] + target: ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-unknown-fuchsia", "x86_64-pc-windows-msvc", "x86_64-pc-solaris", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-netbsd", "x86_64-unknown-redox"] steps: - uses: actions/checkout@master - name: Install Rust @@ -72,21 +70,18 @@ jobs: run: rustup target add ${{ matrix.target }} - name: Run check run: cargo hack check --feature-powerset --all-targets --examples --bins --tests --target ${{ matrix.target }} - - # Redox needs a nightly compiler for libc: - # https://github.com/rust-lang/libc/issues/2012 - Check_Redox: + CheckTier3: name: Check runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - target: ["x86_64-unknown-redox"] + target: ["armv7-sony-vita-newlibeabihf"] steps: - - uses: actions/checkout@master - - name: Install Rust nightly - run: rustup update nightly && rustup default nightly + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + with: + components: "rust-src" - uses: taiki-e/install-action@cargo-hack - - name: Install Target - run: rustup target add ${{ matrix.target }} - name: Run check - run: cargo hack check --feature-powerset --all-targets --examples --bins --tests --target ${{ matrix.target }} + run: cargo hack check -Z build-std=std,panic_abort --feature-powerset --all-targets --examples --bins --tests --target ${{ matrix.target }} diff --git a/Cargo.toml b/Cargo.toml index 78c8d5f1..97108f64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ rustdoc-args = ["--cfg", "docsrs"] features = ["all"] [target."cfg(unix)".dependencies] -libc = "0.2.139" +libc = "0.2.149" [target."cfg(windows)".dependencies] winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] } diff --git a/src/lib.rs b/src/lib.rs index 0abc1e9d..aa932a2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,7 +331,7 @@ impl<'a> DerefMut for MaybeUninitSlice<'a> { /// See [`Socket::set_tcp_keepalive`]. #[derive(Debug, Clone)] pub struct TcpKeepalive { - #[cfg_attr(target_os = "openbsd", allow(dead_code))] + #[cfg_attr(any(target_os = "openbsd", target_os = "vita"), allow(dead_code))] time: Option, #[cfg(not(any( target_os = "openbsd", @@ -339,6 +339,7 @@ pub struct TcpKeepalive { target_os = "solaris", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] interval: Option, #[cfg(not(any( @@ -348,6 +349,7 @@ pub struct TcpKeepalive { target_os = "windows", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] retries: Option, } @@ -363,6 +365,7 @@ impl TcpKeepalive { target_os = "solaris", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] interval: None, #[cfg(not(any( @@ -372,6 +375,7 @@ impl TcpKeepalive { target_os = "windows", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] retries: None, } diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 2ddb2626..e7210187 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -237,8 +237,11 @@ impl From for SockAddr { target_os = "openbsd", target_os = "nto", target_os = "espidf", + target_os = "vita", ))] sin_len: 0, + #[cfg(target_os = "vita")] + sin_vport: addr.port().to_be(), }; let mut storage = MaybeUninit::::zeroed(); // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage` @@ -278,8 +281,11 @@ impl From for SockAddr { target_os = "openbsd", target_os = "nto", target_os = "espidf", + target_os = "vita", ))] sin6_len: 0, + #[cfg(target_os = "vita")] + sin6_vport: addr.port().to_be(), #[cfg(any(target_os = "solaris", target_os = "illumos"))] __sin6_src_id: 0, }; diff --git a/src/socket.rs b/src/socket.rs index c4f262a4..90649d9d 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -730,6 +730,7 @@ fn set_common_flags(socket: Socket) -> io::Result { target_os = "netbsd", target_os = "openbsd", target_os = "espidf", + target_os = "vita", )) ))] socket._set_cloexec(true)?; @@ -1174,6 +1175,7 @@ impl Socket { target_os = "solaris", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub fn join_multicast_v4_n( &self, @@ -1205,6 +1207,7 @@ impl Socket { target_os = "solaris", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub fn leave_multicast_v4_n( &self, @@ -1238,6 +1241,7 @@ impl Socket { target_os = "fuchsia", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub fn join_ssm_v4( &self, @@ -1274,6 +1278,7 @@ impl Socket { target_os = "fuchsia", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub fn leave_ssm_v4( &self, @@ -1451,6 +1456,7 @@ impl Socket { target_os = "windows", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> { let recv_tos = if recv_tos { 1 } else { 0 }; @@ -1481,6 +1487,7 @@ impl Socket { target_os = "windows", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub fn recv_tos(&self) -> io::Result { unsafe { @@ -1697,14 +1704,24 @@ impl Socket { doc, all( feature = "all", - not(any(windows, target_os = "haiku", target_os = "openbsd")) + not(any( + windows, + target_os = "haiku", + target_os = "openbsd", + target_os = "vita" + )) ) ))] #[cfg_attr( docsrs, doc(cfg(all( feature = "all", - not(any(windows, target_os = "haiku", target_os = "openbsd")) + not(any( + windows, + target_os = "haiku", + target_os = "openbsd", + target_os = "vita" + )) ))) )] pub fn keepalive_time(&self) -> io::Result { diff --git a/src/sys/unix.rs b/src/sys/unix.rs index e9cfddf6..ec7c3e2e 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -92,6 +92,7 @@ pub(crate) use libc::IP_HDRINCL; target_os = "haiku", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub(crate) use libc::IP_RECVTOS; #[cfg(not(any( @@ -121,6 +122,7 @@ pub(crate) use libc::{ target_os = "fuchsia", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub(crate) use libc::{ ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, @@ -175,6 +177,7 @@ use libc::TCP_KEEPALIVE as KEEPALIVE_TIME; target_os = "haiku", target_os = "openbsd", target_os = "nto", + target_os = "vita", )))] use libc::TCP_KEEPIDLE as KEEPALIVE_TIME; @@ -237,6 +240,7 @@ type IovLen = usize; target_os = "nto", target_vendor = "apple", target_os = "espidf", + target_os = "vita", ))] type IovLen = c_int; @@ -713,6 +717,7 @@ pub(crate) fn try_clone(fd: Socket) -> io::Result { syscall!(fcntl(fd, libc::F_DUPFD_CLOEXEC, 0)) } +#[cfg(not(target_os = "vita"))] pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> { if nonblocking { fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK) @@ -721,6 +726,18 @@ pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> { } } +#[cfg(target_os = "vita")] +pub(crate) fn set_nonblocking(fd: Socket, nonblocking: bool) -> io::Result<()> { + unsafe { + setsockopt( + fd, + libc::SOL_SOCKET, + libc::SO_NONBLOCK, + nonblocking as libc::c_int, + ) + } +} + pub(crate) fn shutdown(fd: Socket, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Write => libc::SHUT_WR, @@ -923,7 +940,7 @@ fn into_timeval(duration: Option) -> libc::timeval { } #[cfg(feature = "all")] -#[cfg(not(any(target_os = "haiku", target_os = "openbsd")))] +#[cfg(not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita")))] pub(crate) fn keepalive_time(fd: Socket) -> io::Result { unsafe { getsockopt::(fd, IPPROTO_TCP, KEEPALIVE_TIME) @@ -933,7 +950,12 @@ pub(crate) fn keepalive_time(fd: Socket) -> io::Result { #[allow(unused_variables)] pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> { - #[cfg(not(any(target_os = "haiku", target_os = "openbsd", target_os = "nto")))] + #[cfg(not(any( + target_os = "haiku", + target_os = "openbsd", + target_os = "nto", + target_os = "vita" + )))] if let Some(time) = keepalive.time { let secs = into_secs(time); unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? } @@ -969,12 +991,18 @@ pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Res Ok(()) } -#[cfg(not(any(target_os = "haiku", target_os = "openbsd", target_os = "nto")))] +#[cfg(not(any( + target_os = "haiku", + target_os = "openbsd", + target_os = "nto", + target_os = "vita" +)))] fn into_secs(duration: Duration) -> c_int { min(duration.as_secs(), c_int::max_value() as u64) as c_int } /// Add `flag` to the current set flags of `F_GETFD`. +#[cfg(not(target_os = "vita"))] fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> { let previous = syscall!(fcntl(fd, get_cmd))?; let new = previous | flag; @@ -987,6 +1015,7 @@ fn fcntl_add(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Res } /// Remove `flag` to the current set flags of `F_GETFD`. +#[cfg(not(target_os = "vita"))] fn fcntl_remove(fd: Socket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> io::Result<()> { let previous = syscall!(fcntl(fd, get_cmd))?; let new = previous & !flag; @@ -1066,6 +1095,7 @@ pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr { target_os = "solaris", target_os = "nto", target_os = "espidf", + target_os = "vita", )))] pub(crate) fn to_mreqn( multiaddr: &Ipv4Addr, @@ -1152,12 +1182,13 @@ impl crate::Socket { /// # Notes /// /// On supported platforms you can use [`Type::cloexec`]. - #[cfg(feature = "all")] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))] + #[cfg(all(feature = "all", not(target_os = "vita")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "vita")))))] pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> { self._set_cloexec(close_on_exec) } + #[cfg(not(target_os = "vita"))] pub(crate) fn _set_cloexec(&self, close_on_exec: bool) -> io::Result<()> { if close_on_exec { fcntl_add( diff --git a/tests/socket.rs b/tests/socket.rs index 3b6e3f2d..3f409cdd 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -10,14 +10,16 @@ ))] use std::fs::File; use std::io; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] use std::io::IoSlice; #[cfg(all(unix, feature = "all"))] use std::io::Read; use std::io::Write; -use std::mem::{self, MaybeUninit}; +#[cfg(not(target_os = "vita"))] +use std::mem::MaybeUninit; +use std::mem::{self}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream}; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] use std::net::{Ipv6Addr, SocketAddrV6}; #[cfg(all( feature = "all", @@ -34,9 +36,10 @@ use std::os::unix::io::AsRawFd; #[cfg(windows)] use std::os::windows::io::AsRawSocket; use std::str; +#[cfg(not(target_os = "vita"))] use std::thread; use std::time::Duration; -#[cfg(all(unix, feature = "all"))] +#[cfg(all(unix, feature = "all", not(target_os = "vita")))] use std::{env, fs}; #[cfg(windows)] @@ -46,9 +49,11 @@ use winapi::um::handleapi::GetHandleInformation; #[cfg(windows)] use winapi::um::winbase::HANDLE_FLAG_INHERIT; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] use socket2::MaybeUninitSlice; -use socket2::{Domain, Protocol, SockAddr, Socket, TcpKeepalive, Type}; +#[cfg(not(target_os = "vita"))] +use socket2::TcpKeepalive; +use socket2::{Domain, Protocol, SockAddr, Socket, Type}; #[test] fn domain_for_address() { @@ -175,12 +180,19 @@ fn set_nonblocking() { } fn assert_common_flags(socket: &Socket, expected: bool) { - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "vita")))] assert_close_on_exec(socket, expected); #[cfg(target_vendor = "apple")] assert_flag_no_sigpipe(socket, expected); #[cfg(windows)] assert_flag_no_inherit(socket, expected); + + // Vita does not have process API, so neither SO_NOSIGPIPE nor FD_CLOEXEC are supported on this platform + #[cfg(target_os = "vita")] + { + let _ = socket; + let _ = expected; + } } #[test] @@ -239,8 +251,29 @@ pub fn assert_nonblocking(socket: &S, want: bool) where S: AsRawFd, { - let flags = unsafe { libc::fcntl(socket.as_raw_fd(), libc::F_GETFL) }; - assert_eq!(flags & libc::O_NONBLOCK != 0, want, "non-blocking option"); + #[cfg(not(target_os = "vita"))] + { + let flags = unsafe { libc::fcntl(socket.as_raw_fd(), libc::F_GETFL) }; + assert_eq!(flags & libc::O_NONBLOCK != 0, want, "non-blocking option"); + } + + #[cfg(target_os = "vita")] + { + let mut optval: libc::c_int = 0; + let mut optlen = std::mem::size_of::() as libc::socklen_t; + + let res = unsafe { + libc::getsockopt( + socket.as_raw_fd(), + libc::SOL_SOCKET, + libc::SO_NONBLOCK, + &mut optval as *mut libc::c_int as _, + &mut optlen, + ) + }; + assert_eq!(res, 0, "unable to get non-blocing option"); + assert_eq!(optval > 0, want, "non-blocking option"); + } } #[cfg(windows)] @@ -249,7 +282,7 @@ pub fn assert_nonblocking(_: &S, _: bool) { // No way to get this information... } -#[cfg(all(unix, feature = "all"))] +#[cfg(all(unix, feature = "all", not(target_os = "vita")))] #[test] fn set_cloexec() { let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); @@ -372,6 +405,7 @@ where assert_eq!(flags, want as _, "non-blocking option"); } +#[cfg_attr(target_os = "vita", allow(dead_code))] const DATA: &[u8] = b"hello world"; #[test] @@ -388,6 +422,7 @@ fn connect_timeout_unrouteable() { } #[test] +#[cfg(not(target_os = "vita"))] // Loopback has special behavior on vita fn connect_timeout_unbound() { // Bind and drop a socket to track down a "probably unassigned" port. let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); @@ -434,7 +469,7 @@ fn pair() { } #[test] -#[cfg(all(feature = "all", unix))] +#[cfg(all(feature = "all", unix, not(target_os = "vita")))] fn unix() { let mut path = env::temp_dir(); path.push("socket2"); @@ -483,6 +518,7 @@ fn vsock() { } #[test] +#[cfg(not(target_os = "vita"))] // Vita does not support OOB fn out_of_band() { let listener = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); listener.bind(&any_ipv4()).unwrap(); @@ -513,7 +549,7 @@ fn out_of_band() { } #[test] -#[cfg(not(target_os = "redox"))] // cfg of `udp_pair_unconnected()` +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn udp_peek_sender() { let (socket_a, socket_b) = udp_pair_unconnected(); @@ -528,7 +564,7 @@ fn udp_peek_sender() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn send_recv_vectored() { let (socket_a, socket_b) = udp_pair_connected(); @@ -575,7 +611,7 @@ fn send_recv_vectored() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn send_from_recv_to_vectored() { let (socket_a, socket_b) = udp_pair_unconnected(); let addr_a = socket_a.local_addr().unwrap(); @@ -624,7 +660,7 @@ fn send_from_recv_to_vectored() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn recv_vectored_truncated() { let (socket_a, socket_b) = udp_pair_connected(); @@ -644,7 +680,7 @@ fn recv_vectored_truncated() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn recv_from_vectored_truncated() { let (socket_a, socket_b) = udp_pair_unconnected(); let addr_a = socket_a.local_addr().unwrap(); @@ -670,7 +706,7 @@ fn recv_from_vectored_truncated() { } /// Create a pair of non-connected UDP sockets suitable for unit tests. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn udp_pair_unconnected() -> (Socket, Socket) { // Use ephemeral ports assigned by the OS. let unspecified_addr = SocketAddrV6::new(Ipv6Addr::LOCALHOST, 0, 0, 0); @@ -698,7 +734,7 @@ fn udp_pair_unconnected() -> (Socket, Socket) { } /// Create a pair of connected UDP sockets suitable for unit tests. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "vita")))] fn udp_pair_connected() -> (Socket, Socket) { let (socket_a, socket_b) = udp_pair_unconnected(); @@ -711,6 +747,7 @@ fn udp_pair_connected() -> (Socket, Socket) { } #[test] +#[cfg(not(target_os = "vita"))] fn tcp_keepalive() { let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); let params = TcpKeepalive::new().with_time(Duration::from_secs(200)); @@ -1022,11 +1059,18 @@ fn r#type() { let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); assert_eq!(socket.r#type().unwrap(), Type::STREAM); - let socket = Socket::new(Domain::IPV6, Type::DGRAM, None).unwrap(); - assert_eq!(socket.r#type().unwrap(), Type::DGRAM); + #[cfg(not(target_os = "vita"))] + { + let socket = Socket::new(Domain::IPV6, Type::DGRAM, None).unwrap(); + assert_eq!(socket.r#type().unwrap(), Type::DGRAM); + } // macos doesn't support seqpacket - #[cfg(all(unix, not(target_vendor = "apple"), feature = "all"))] + #[cfg(all( + unix, + not(any(target_vendor = "apple", target_os = "vita")), + feature = "all" + ))] { let socket = Socket::new(Domain::UNIX, Type::SEQPACKET, None).unwrap(); assert_eq!(socket.r#type().unwrap(), Type::SEQPACKET); @@ -1059,6 +1103,7 @@ fn any_ipv4() -> SockAddr { /// Assume the `buf`fer to be initialised. // TODO: replace with `MaybeUninit::slice_assume_init_ref` once stable. +#[cfg(not(target_os = "vita"))] // Loopback has special behavior on vita unsafe fn assume_init(buf: &[MaybeUninit]) -> &[u8] { &*(buf as *const [MaybeUninit] as *const [u8]) } @@ -1074,6 +1119,7 @@ macro_rules! test { $( #[$attr] )* fn $get_fn() { test!(__ Domain::IPV4, $get_fn, $set_fn($arg), $expected); + #[cfg(not(target_os = "vita"))] test!(__ Domain::IPV6, $get_fn, $set_fn($arg), $expected); } }; @@ -1197,18 +1243,22 @@ test!(IPv4 tos, set_tos(96)); target_os = "redox", target_os = "solaris", target_os = "windows", + target_os = "vita", )))] test!(IPv4 recv_tos, set_recv_tos(true)); #[cfg(not(windows))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows. test!(IPv4 broadcast, set_broadcast(true)); +#[cfg(not(target_os = "vita"))] test!(IPv6 unicast_hops_v6, set_unicast_hops_v6(20)); + #[cfg(not(any( windows, target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd" + target_os = "openbsd", + target_os = "vita" )))] test!(IPv6 only_v6, set_only_v6(true)); // IPv6 socket are already IPv6 only on FreeBSD and Windows. @@ -1232,6 +1282,7 @@ test!( target_os = "openbsd", target_os = "redox", target_os = "solaris", + target_os = "vita", )))] fn join_leave_multicast_v4_n() { let socket = Socket::new(Domain::IPV4, Type::DGRAM, None).unwrap(); @@ -1261,6 +1312,7 @@ fn join_leave_multicast_v4_n() { target_os = "openbsd", target_os = "redox", target_os = "fuchsia", + target_os = "vita", )))] fn join_leave_ssm_v4() { let socket = Socket::new(Domain::IPV4, Type::DGRAM, None).unwrap();