aboutsummaryrefslogtreecommitdiff
path: root/src/sys/unix/net.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/unix/net.rs')
-rw-r--r--src/sys/unix/net.rs103
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()),
+ }
+}