diff options
Diffstat (limited to 'src/sys/unix/net.rs')
-rw-r--r-- | src/sys/unix/net.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs new file mode 100644 index 0000000..2671b42 --- /dev/null +++ b/src/sys/unix/net.rs @@ -0,0 +1,103 @@ +#[cfg(all(feature = "os-poll", any(feature = "tcp", feature = "udp")))] +use std::net::SocketAddr; + +#[cfg(all(feature = "os-poll", any(feature = "udp")))] +pub(crate) fn new_ip_socket( + addr: SocketAddr, + socket_type: libc::c_int, +) -> std::io::Result<libc::c_int> { + let domain = match addr { + SocketAddr::V4(..) => libc::AF_INET, + SocketAddr::V6(..) => libc::AF_INET6, + }; + + new_socket(domain, socket_type) +} + +/// Create a new non-blocking socket. +#[cfg(all( + feature = "os-poll", + any(feature = "tcp", feature = "udp", feature = "uds") +))] +pub(crate) fn new_socket( + domain: libc::c_int, + socket_type: libc::c_int, +) -> std::io::Result<libc::c_int> { + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" + ))] + let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC; + + // Gives a warning for platforms without SOCK_NONBLOCK. + #[allow(clippy::let_and_return)] + let socket = syscall!(socket(domain, socket_type, 0)); + + // Mimick `libstd` and set `SO_NOSIGPIPE` on apple systems. + #[cfg(target_vendor = "apple")] + let socket = socket.and_then(|socket| { + syscall!(setsockopt( + socket, + libc::SOL_SOCKET, + libc::SO_NOSIGPIPE, + &1 as *const libc::c_int as *const libc::c_void, + std::mem::size_of::<libc::c_int>() as libc::socklen_t + )) + .map(|_| socket) + }); + + // Darwin doesn't have SOCK_NONBLOCK or SOCK_CLOEXEC. Not sure about + // Solaris, couldn't find anything online. + #[cfg(any(target_os = "ios", target_os = "macos", target_os = "solaris"))] + let socket = socket.and_then(|socket| { + // For platforms that don't support flags in socket, we need to + // set the flags ourselves. + syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK)) + .and_then(|_| syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| socket)) + .map_err(|e| { + // If either of the `fcntl` calls failed, ensure the socket is + // closed and return the error. + let _ = syscall!(close(socket)); + e + }) + }); + + socket +} + +#[cfg(all(feature = "os-poll", any(feature = "tcp", feature = "udp")))] +pub(crate) fn socket_addr(addr: &SocketAddr) -> (*const libc::sockaddr, libc::socklen_t) { + use std::mem::size_of_val; + + match addr { + SocketAddr::V4(ref addr) => ( + addr as *const _ as *const libc::sockaddr, + size_of_val(addr) as libc::socklen_t, + ), + SocketAddr::V6(ref addr) => ( + addr as *const _ as *const libc::sockaddr, + size_of_val(addr) as libc::socklen_t, + ), + } +} + +/// `storage` must be initialised to `sockaddr_in` or `sockaddr_in6`. +#[cfg(all(feature = "os-poll", feature = "tcp"))] +pub(crate) unsafe fn to_socket_addr( + storage: *const libc::sockaddr_storage, +) -> std::io::Result<SocketAddr> { + match (*storage).ss_family as libc::c_int { + libc::AF_INET => Ok(SocketAddr::V4( + *(storage as *const libc::sockaddr_in as *const _), + )), + libc::AF_INET6 => Ok(SocketAddr::V6( + *(storage as *const libc::sockaddr_in6 as *const _), + )), + _ => Err(std::io::ErrorKind::InvalidInput.into()), + } +} |