blob: 2671b42c5f73dc2a5b9a5cd98e5618990d0727c8 [file] [log] [blame]
#[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()),
}
}