monoio/net/
mod.rs

1//! Network related
2//! Currently, TCP/UnixStream/UnixDatagram are implemented.
3
4mod listener_config;
5pub mod tcp;
6pub mod udp;
7#[cfg(unix)]
8pub mod unix;
9
10pub use listener_config::ListenerOpts;
11#[deprecated(since = "0.2.0", note = "use ListenerOpts")]
12pub use listener_config::ListenerOpts as ListenerConfig;
13pub use tcp::{TcpConnectOpts, TcpListener, TcpStream};
14#[cfg(unix)]
15pub use unix::{Pipe, UnixDatagram, UnixListener, UnixStream};
16#[cfg(windows)]
17use {
18    std::os::windows::prelude::RawSocket,
19    windows_sys::Win32::{
20        Foundation::NO_ERROR,
21        Networking::WinSock::{
22            closesocket, ioctlsocket, socket, WSACleanup, WSAStartup, ADDRESS_FAMILY, FIONBIO,
23            INVALID_SOCKET, WINSOCK_SOCKET_TYPE,
24        },
25    },
26};
27
28// Copied from mio.
29#[cfg(unix)]
30pub(crate) fn new_socket(
31    domain: libc::c_int,
32    socket_type: libc::c_int,
33) -> std::io::Result<libc::c_int> {
34    #[cfg(any(
35        target_os = "android",
36        target_os = "dragonfly",
37        target_os = "freebsd",
38        target_os = "illumos",
39        target_os = "netbsd",
40        target_os = "openbsd"
41    ))]
42    let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
43
44    #[cfg(target_os = "linux")]
45    let socket_type = {
46        if crate::driver::op::is_legacy() {
47            socket_type | libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK
48        } else {
49            socket_type | libc::SOCK_CLOEXEC
50        }
51    };
52
53    // Gives a warning for platforms without SOCK_NONBLOCK.
54    #[allow(clippy::let_and_return)]
55    #[cfg(unix)]
56    let socket = crate::syscall!(socket@RAW(domain, socket_type, 0));
57
58    // Mimic `libstd` and set `SO_NOSIGPIPE` on apple systems.
59    #[cfg(target_vendor = "apple")]
60    let socket = socket.and_then(|socket| {
61        crate::syscall!(setsockopt@RAW(
62            socket,
63            libc::SOL_SOCKET,
64            libc::SO_NOSIGPIPE,
65            &1 as *const libc::c_int as *const libc::c_void,
66            std::mem::size_of::<libc::c_int>() as libc::socklen_t
67        ))
68        .map(|_| socket)
69    });
70
71    // Darwin doesn't have SOCK_NONBLOCK or SOCK_CLOEXEC.
72    #[cfg(any(target_os = "ios", target_os = "macos"))]
73    let socket = socket.and_then(|socket| {
74        // For platforms that don't support flags in socket, we need to
75        // set the flags ourselves.
76        crate::syscall!(fcntl@RAW(socket, libc::F_SETFL, libc::O_NONBLOCK))
77            .and_then(|_| {
78                crate::syscall!(fcntl@RAW(socket, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| socket)
79            })
80            .inspect_err(|_| {
81                // If either of the `fcntl` calls failed, ensure the socket is
82                // closed and return the error.
83                let _ = crate::syscall!(close@RAW(socket));
84            })
85    });
86
87    socket
88}
89
90#[allow(non_snake_case, missing_docs)]
91#[cfg(windows)]
92#[inline]
93pub fn MAKEWORD(a: u8, b: u8) -> u16 {
94    (a as u16) | ((b as u16) << 8)
95}
96
97#[cfg(windows)]
98pub(crate) fn new_socket(
99    domain: ADDRESS_FAMILY,
100    socket_type: WINSOCK_SOCKET_TYPE,
101) -> std::io::Result<RawSocket> {
102    let _: i32 = crate::syscall!(
103        WSAStartup@RAW(MAKEWORD(2, 2), std::ptr::null_mut()),
104        PartialEq::eq,
105        NO_ERROR as _
106    )?;
107    let socket = crate::syscall!(
108        socket@RAW(domain as _, socket_type, 0),
109        PartialEq::eq,
110        INVALID_SOCKET
111    )?;
112    crate::syscall!(
113        ioctlsocket@RAW(socket, FIONBIO, &mut 1),
114        PartialEq::ne,
115        NO_ERROR as _
116    )
117    .map(|_: i32| socket as RawSocket)
118    .inspect_err(|_| {
119        // If either of the `ioctlsocket` calls failed, ensure the socket is
120        // closed and return the error.
121        unsafe {
122            closesocket(socket);
123            WSACleanup();
124        }
125    })
126}