Skip to main content

simoom_sys/
net.rs

1//! Non-blocking TCP and UDP sockets on raw file descriptors (Unix) and `SOCKET`s (Windows).
2//!
3//! [`Socket`] owns the descriptor and closes it on drop (through std's `OwnedFd` /
4//! `OwnedSocket`). Every socket this module creates is non-blocking and close-on-exec
5//! (not inheritable on Windows), and on Windows it is created overlapped so IOCP can drive it.
6//! Operations that would block return an error of kind [`io::ErrorKind::WouldBlock`].
7
8use crate::os::sys;
9use core::ffi::c_void;
10use std::io;
11use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6};
12
13#[cfg(unix)]
14use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
15#[cfg(windows)]
16use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, OwnedSocket};
17
18/// The raw OS handle of a socket: a file descriptor on Unix, a `SOCKET` on Windows.
19#[cfg(unix)]
20pub type RawSock = i32;
21/// The raw OS handle of a socket: a file descriptor on Unix, a `SOCKET` on Windows.
22#[cfg(windows)]
23pub type RawSock = usize;
24
25/// An owned, non-blocking socket. Closed on drop.
26#[derive(Debug)]
27pub struct Socket {
28    #[cfg(unix)]
29    fd: OwnedFd,
30    #[cfg(windows)]
31    fd: OwnedSocket,
32}
33
34/// Options for [`Socket::tcp_listen`].
35#[derive(Clone, Debug)]
36pub struct ListenOptions {
37    /// Length of the kernel accept queue. The default is [`default_backlog`]: the system's
38    /// maximum (`net.core.somaxconn` on Linux, capped at 65535; `SOMAXCONN` on Windows), so a
39    /// burst of connections, or 100k idle ones arriving together, isn't dropped.
40    pub backlog: i32,
41    /// `SO_REUSEPORT` (Linux, BSD): several sockets may bind the same address and the kernel
42    /// spreads connections over them. Ignored on Windows.
43    pub reuse_port: bool,
44    /// Set `TCP_NODELAY` on the listener (Linux and Windows hand it down to accepted sockets).
45    pub nodelay: bool,
46    /// `IPV6_V6ONLY` for IPv6 addresses; `None` leaves the OS default.
47    pub v6_only: Option<bool>,
48    /// `SO_RCVBUF`, inherited by accepted sockets.
49    pub recv_buffer: Option<usize>,
50    /// `SO_SNDBUF`, inherited by accepted sockets.
51    pub send_buffer: Option<usize>,
52    /// `TCP_DEFER_ACCEPT` (Linux) in seconds: the kernel hands over a connection only once its
53    /// first data has arrived (or this long after the handshake), so accepting and reading the
54    /// first request take one turn. Only for protocols where the client speaks first (HTTP,
55    /// TLS). `None` (the default here) leaves it off; ignored on other systems.
56    pub defer_accept: Option<u32>,
57}
58
59impl Default for ListenOptions {
60    fn default() -> Self {
61        ListenOptions { backlog: default_backlog(), reuse_port: false, nodelay: true, v6_only: None, recv_buffer: None, send_buffer: None, defer_accept: None }
62    }
63}
64
65/// The default listen backlog: the system's maximum accept queue. On Linux that is
66/// `/proc/sys/net/core/somaxconn` (read once), capped at 65535, or 4096 if it can't be read; on
67/// Windows `SOMAXCONN` (the provider's maximum); elsewhere 65535, which the kernel clamps to its
68/// own `somaxconn`.
69pub fn default_backlog() -> i32 {
70    #[cfg(target_os = "linux")]
71    {
72        use std::sync::atomic::{AtomicI32, Ordering};
73        static CACHED: AtomicI32 = AtomicI32::new(0);
74        let c = CACHED.load(Ordering::Relaxed);
75        if c > 0 {
76            return c;
77        }
78        // A plain read and digit loop: `read_to_string` and `str::parse` cost about 2.5 KB.
79        let mut b = [0u8; 24];
80        let mut v: i64 = 0;
81        for &c in crate::cpu::read_small_bytes("/proc/sys/net/core/somaxconn", &mut b).iter().take_while(|c| c.is_ascii_digit()) {
82            v = (v * 10 + i64::from(c - b'0')).min(1 << 20);
83        }
84        let v = if v > 0 { v.min(65535) as i32 } else { 4096 };
85        CACHED.store(v, Ordering::Relaxed);
86        v
87    }
88    #[cfg(windows)]
89    {
90        sys::SOMAXCONN
91    }
92    #[cfg(not(any(target_os = "linux", windows)))]
93    {
94        65535
95    }
96}
97
98/// Options for [`Socket::udp_bind`].
99#[derive(Clone, Debug, Default)]
100pub struct UdpOptions {
101    /// `SO_REUSEPORT` (Linux, BSD): one socket per loop on the same address.
102    pub reuse_port: bool,
103    /// Generic receive offload: the kernel may hand over several datagrams from one peer as
104    /// one buffer with a segment size (Linux `UDP_GRO`, Windows URO). Off by default.
105    pub gro: bool,
106    /// Report the local destination address of each datagram (`IP_PKTINFO`/`IPV6_RECVPKTINFO`).
107    pub pktinfo: bool,
108    /// Report the ECN bits of each datagram (`IP_RECVTOS`/`IPV6_RECVTCLASS`, Windows `IP_ECN`).
109    pub ecn: bool,
110    /// Set the don't-fragment bit (path MTU probing, as QUIC requires).
111    pub dont_fragment: bool,
112    /// `IPV6_V6ONLY` for IPv6 addresses.
113    pub v6_only: Option<bool>,
114    /// `SO_RCVBUF`.
115    pub recv_buffer: Option<usize>,
116    /// `SO_SNDBUF`.
117    pub send_buffer: Option<usize>,
118}
119
120// ---------------------------------------------------------------------------------------------
121// Socket addresses
122// ---------------------------------------------------------------------------------------------
123
124/// Storage big enough for any socket address (`sockaddr_storage`).
125#[repr(C, align(8))]
126#[derive(Clone, Copy)]
127pub(crate) struct SockAddrBuf {
128    pub bytes: [u8; 128],
129}
130
131impl SockAddrBuf {
132    pub(crate) const fn new() -> SockAddrBuf {
133        SockAddrBuf { bytes: [0; 128] }
134    }
135    pub(crate) fn as_ptr(&self) -> *const c_void {
136        self.bytes.as_ptr().cast()
137    }
138    pub(crate) fn as_mut_ptr(&mut self) -> *mut c_void {
139        self.bytes.as_mut_ptr().cast()
140    }
141}
142
143/// Encodes `addr` into `out` and returns the address length.
144pub(crate) fn encode_addr(addr: &SocketAddr, out: &mut SockAddrBuf) -> u32 {
145    out.bytes = [0; 128];
146    match addr {
147        SocketAddr::V4(a) => {
148            let sa = sys::sockaddr_in {
149                #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
150                sin_len: core::mem::size_of::<sys::sockaddr_in>() as u8,
151                sin_family: sys::AF_INET as _,
152                sin_port: a.port().to_be(),
153                sin_addr: a.ip().octets(),
154                sin_zero: [0; 8],
155            };
156            let n = core::mem::size_of::<sys::sockaddr_in>();
157            // SAFETY: `out` holds 128 bytes and `sa` is a plain C struct of `n` <= 128 bytes; the
158            // regions don't overlap.
159            unsafe { core::ptr::copy_nonoverlapping((&sa as *const sys::sockaddr_in).cast::<u8>(), out.bytes.as_mut_ptr(), n) };
160            n as u32
161        }
162        SocketAddr::V6(a) => {
163            let sa = sys::sockaddr_in6 {
164                #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
165                sin6_len: core::mem::size_of::<sys::sockaddr_in6>() as u8,
166                sin6_family: sys::AF_INET6 as _,
167                sin6_port: a.port().to_be(),
168                sin6_flowinfo: a.flowinfo().to_be(),
169                sin6_addr: a.ip().octets(),
170                sin6_scope_id: a.scope_id(),
171            };
172            let n = core::mem::size_of::<sys::sockaddr_in6>();
173            // SAFETY: as above, `n` <= 128.
174            unsafe { core::ptr::copy_nonoverlapping((&sa as *const sys::sockaddr_in6).cast::<u8>(), out.bytes.as_mut_ptr(), n) };
175            n as u32
176        }
177    }
178}
179
180/// Decodes a socket address written by the OS. Returns `None` for other families.
181pub(crate) fn decode_addr(buf: &SockAddrBuf, len: usize) -> Option<SocketAddr> {
182    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
183    let family = buf.bytes[1] as i32;
184    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "freebsd")))]
185    let family = u16::from_ne_bytes([buf.bytes[0], buf.bytes[1]]) as i32;
186    if family == sys::AF_INET && len >= core::mem::size_of::<sys::sockaddr_in>() {
187        let port = u16::from_be_bytes([buf.bytes[2], buf.bytes[3]]);
188        let ip = Ipv4Addr::new(buf.bytes[4], buf.bytes[5], buf.bytes[6], buf.bytes[7]);
189        Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
190    } else if family == sys::AF_INET6 && len >= core::mem::size_of::<sys::sockaddr_in6>() {
191        let port = u16::from_be_bytes([buf.bytes[2], buf.bytes[3]]);
192        let flow = u32::from_be_bytes([buf.bytes[4], buf.bytes[5], buf.bytes[6], buf.bytes[7]]);
193        let mut ip = [0u8; 16];
194        ip.copy_from_slice(&buf.bytes[8..24]);
195        let scope = u32::from_ne_bytes([buf.bytes[24], buf.bytes[25], buf.bytes[26], buf.bytes[27]]);
196        Some(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from(ip), port, flow, scope)))
197    } else {
198        None
199    }
200}
201
202pub(crate) fn family_of(addr: &SocketAddr) -> i32 {
203    if addr.is_ipv4() {
204        sys::AF_INET
205    } else {
206        sys::AF_INET6
207    }
208}
209
210// ---------------------------------------------------------------------------------------------
211// Error helpers
212// ---------------------------------------------------------------------------------------------
213
214#[cfg(unix)]
215pub(crate) fn last_error() -> io::Error {
216    io::Error::last_os_error()
217}
218
219#[cfg(windows)]
220pub(crate) fn last_error() -> io::Error {
221    // SAFETY: reads the calling thread's last Winsock error; no arguments.
222    io::Error::from_raw_os_error(unsafe { sys::WSAGetLastError() })
223}
224
225#[cfg(unix)]
226fn cvt(r: i32) -> io::Result<i32> {
227    if r < 0 {
228        Err(last_error())
229    } else {
230        Ok(r)
231    }
232}
233
234#[cfg(unix)]
235fn cvt_size(r: isize) -> io::Result<usize> {
236    if r < 0 {
237        Err(last_error())
238    } else {
239        Ok(r as usize)
240    }
241}
242
243#[cfg(windows)]
244fn cvt(r: i32) -> io::Result<i32> {
245    if r == sys::SOCKET_ERROR {
246        Err(last_error())
247    } else {
248        Ok(r)
249    }
250}
251
252/// Makes sure Winsock is initialised (std does this lazily for its own sockets only).
253#[cfg(windows)]
254pub(crate) fn init() {
255    static ONCE: std::sync::Once = std::sync::Once::new();
256    ONCE.call_once(|| {
257        // SAFETY: WSADATA is a plain output struct; WSAStartup may be called any number of times.
258        unsafe {
259            let mut data: sys::WSADATA = core::mem::zeroed();
260            sys::WSAStartup(0x202, &mut data);
261        }
262    });
263}
264
265// ---------------------------------------------------------------------------------------------
266// Socket
267// ---------------------------------------------------------------------------------------------
268
269impl Socket {
270    /// Creates a raw non-blocking socket.
271    pub fn new(family: i32, ty: i32) -> io::Result<Socket> {
272        #[cfg(target_os = "linux")]
273        {
274            // SAFETY: plain syscall with integer arguments; the result is checked.
275            let fd = cvt(unsafe { sys::socket(family, ty | sys::SOCK_NONBLOCK | sys::SOCK_CLOEXEC, 0) })?;
276            // SAFETY: `fd` is a fresh descriptor that nothing else owns.
277            Ok(Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } })
278        }
279        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
280        {
281            // SAFETY: plain syscall with integer arguments; the result is checked.
282            let fd = cvt(unsafe { sys::socket(family, ty, 0) })?;
283            // SAFETY: `fd` is a fresh descriptor that nothing else owns.
284            let s = Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } };
285            // SAFETY: fcntl on a descriptor we own.
286            cvt(unsafe { sys::fcntl(fd, sys::F_SETFD, sys::FD_CLOEXEC) })?;
287            s.set_nonblocking(true)?;
288            #[cfg(any(target_os = "macos", target_os = "ios"))]
289            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_NOSIGPIPE, 1)?;
290            Ok(s)
291        }
292        #[cfg(windows)]
293        {
294            init();
295            // SAFETY: plain Winsock call; the result is checked against INVALID_SOCKET.
296            let raw = unsafe {
297                sys::WSASocketW(family, ty, 0, core::ptr::null_mut(), 0, sys::WSA_FLAG_OVERLAPPED | sys::WSA_FLAG_NO_HANDLE_INHERIT)
298            };
299            if raw == sys::INVALID_SOCKET {
300                return Err(last_error());
301            }
302            // SAFETY: `raw` is a fresh socket that nothing else owns.
303            let s = Socket { fd: unsafe { OwnedSocket::from_raw_socket(raw as u64) } };
304            s.set_nonblocking(true)?;
305            Ok(s)
306        }
307    }
308
309    /// A non-blocking TCP listener bound to `addr`.
310    pub fn tcp_listen(addr: SocketAddr, opts: &ListenOptions) -> io::Result<Socket> {
311        let s = Socket::new(family_of(&addr), sys::SOCK_STREAM)?;
312        #[cfg(unix)]
313        s.setsockopt_int(sys::SOL_SOCKET, sys::SO_REUSEADDR, 1)?;
314        #[cfg(unix)]
315        if opts.reuse_port {
316            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_REUSEPORT, 1)?;
317        }
318        #[cfg(windows)]
319        s.setsockopt_int(sys::SOL_SOCKET, sys::SO_EXCLUSIVEADDRUSE, 1)?;
320        if let (Some(v6), true) = (opts.v6_only, addr.is_ipv6()) {
321            s.setsockopt_int(sys::IPPROTO_IPV6, sys::IPV6_V6ONLY, v6 as i32)?;
322        }
323        if let Some(n) = opts.recv_buffer {
324            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_RCVBUF, n as i32)?;
325        }
326        if let Some(n) = opts.send_buffer {
327            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_SNDBUF, n as i32)?;
328        }
329        if opts.nodelay {
330            s.set_nodelay(true)?;
331        }
332        #[cfg(target_os = "linux")]
333        if let Some(secs) = opts.defer_accept {
334            s.setsockopt_int(sys::IPPROTO_TCP, sys::TCP_DEFER_ACCEPT, secs.min(i32::MAX as u32) as i32)?;
335        }
336        s.bind(&addr)?;
337        // SAFETY: listen on a bound socket we own.
338        cvt(unsafe { sys::listen(s.raw() as _, opts.backlog) })?;
339        Ok(s)
340    }
341
342    /// A non-blocking UDP socket bound to `addr`.
343    pub fn udp_bind(addr: SocketAddr, opts: &UdpOptions) -> io::Result<Socket> {
344        let s = Socket::new(family_of(&addr), sys::SOCK_DGRAM)?;
345        #[cfg(unix)]
346        if opts.reuse_port {
347            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_REUSEADDR, 1)?;
348            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_REUSEPORT, 1)?;
349        }
350        if let (Some(v6), true) = (opts.v6_only, addr.is_ipv6()) {
351            s.setsockopt_int(sys::IPPROTO_IPV6, sys::IPV6_V6ONLY, v6 as i32)?;
352        }
353        if let Some(n) = opts.recv_buffer {
354            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_RCVBUF, n as i32)?;
355        }
356        if let Some(n) = opts.send_buffer {
357            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_SNDBUF, n as i32)?;
358        }
359        crate::udp::configure(&s, addr.is_ipv6(), opts)?;
360        s.bind(&addr)?;
361        Ok(s)
362    }
363
364    /// Connects a TCP socket to `addr`, waiting for the handshake, and returns it non-blocking
365    /// with `TCP_NODELAY` set. Meant for clients and tests.
366    pub fn tcp_connect(addr: SocketAddr) -> io::Result<Socket> {
367        let std = std::net::TcpStream::connect(addr)?;
368        std.set_nodelay(true)?;
369        std.set_nonblocking(true)?;
370        Ok(Socket::from(std))
371    }
372
373    fn bind(&self, addr: &SocketAddr) -> io::Result<()> {
374        let mut buf = SockAddrBuf::new();
375        let len = encode_addr(addr, &mut buf);
376        // SAFETY: `buf` holds a valid socket address of `len` bytes.
377        cvt(unsafe { sys::bind(self.raw() as _, buf.as_ptr(), len as _) })?;
378        Ok(())
379    }
380
381    /// Accepts one pending connection without blocking. The new socket is non-blocking.
382    pub fn accept(&self) -> io::Result<(Socket, Option<SocketAddr>)> {
383        let mut buf = SockAddrBuf::new();
384        #[cfg(target_os = "linux")]
385        {
386            let mut len: sys::socklen_t = 128;
387            // SAFETY: `buf` has room for 128 bytes and `len` says so.
388            let fd = cvt(unsafe { sys::accept4(self.raw(), buf.as_mut_ptr(), &mut len, sys::SOCK_NONBLOCK | sys::SOCK_CLOEXEC) })?;
389            // SAFETY: `fd` is a fresh descriptor that nothing else owns.
390            let s = Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } };
391            Ok((s, decode_addr(&buf, len as usize)))
392        }
393        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
394        {
395            let mut len: sys::socklen_t = 128;
396            // SAFETY: `buf` has room for 128 bytes and `len` says so.
397            let fd = cvt(unsafe { sys::accept(self.raw(), buf.as_mut_ptr(), &mut len) })?;
398            // SAFETY: `fd` is a fresh descriptor that nothing else owns.
399            let s = Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } };
400            // SAFETY: fcntl on a descriptor we own.
401            cvt(unsafe { sys::fcntl(fd, sys::F_SETFD, sys::FD_CLOEXEC) })?;
402            s.set_nonblocking(true)?;
403            #[cfg(any(target_os = "macos", target_os = "ios"))]
404            s.setsockopt_int(sys::SOL_SOCKET, sys::SO_NOSIGPIPE, 1)?;
405            Ok((s, decode_addr(&buf, len as usize)))
406        }
407        #[cfg(windows)]
408        {
409            let mut len: i32 = 128;
410            // SAFETY: `buf` has room for 128 bytes and `len` says so.
411            let raw = unsafe { sys::accept(self.raw(), buf.as_mut_ptr(), &mut len) };
412            if raw == sys::INVALID_SOCKET {
413                return Err(last_error());
414            }
415            // SAFETY: `raw` is a fresh socket that nothing else owns.
416            let s = Socket { fd: unsafe { OwnedSocket::from_raw_socket(raw as u64) } };
417            s.set_nonblocking(true)?;
418            Ok((s, decode_addr(&buf, len as usize)))
419        }
420    }
421
422    /// Receives into `buf` without blocking. `Ok(0)` means the peer closed its side.
423    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
424        #[cfg(unix)]
425        {
426            // SAFETY: `buf` is a valid writable region of `buf.len()` bytes.
427            cvt_size(unsafe { sys::recv(self.raw(), buf.as_mut_ptr().cast(), buf.len(), 0) })
428        }
429        #[cfg(windows)]
430        {
431            let len = buf.len().min(i32::MAX as usize) as i32;
432            // SAFETY: `buf` is a valid writable region of at least `len` bytes.
433            let n = unsafe { sys::recv(self.raw(), buf.as_mut_ptr(), len, 0) };
434            if n < 0 {
435                Err(last_error())
436            } else {
437                Ok(n as usize)
438            }
439        }
440    }
441
442    /// Receives into the spare capacity of `buf` and extends its length by the bytes read.
443    pub fn recv_into(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
444        let spare = buf.capacity() - buf.len();
445        if spare == 0 {
446            return Ok(0);
447        }
448        let n;
449        #[cfg(unix)]
450        {
451            // SAFETY: the spare capacity is allocated memory owned by `buf`; recv writes at most
452            // `spare` bytes into it.
453            n = cvt_size(unsafe { sys::recv(self.raw(), buf.as_mut_ptr().add(buf.len()).cast(), spare, 0) })?;
454        }
455        #[cfg(windows)]
456        {
457            let len = spare.min(i32::MAX as usize) as i32;
458            // SAFETY: as above.
459            let r = unsafe { sys::recv(self.raw(), buf.as_mut_ptr().add(buf.len()), len, 0) };
460            if r < 0 {
461                return Err(last_error());
462            }
463            n = r as usize;
464        }
465        // SAFETY: the OS initialised `n` <= spare bytes after the old length.
466        unsafe { buf.set_len(buf.len() + n) };
467        Ok(n)
468    }
469
470    /// Sends from `buf` without blocking (never raises `SIGPIPE`).
471    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
472        #[cfg(unix)]
473        {
474            // SAFETY: `buf` is a valid readable region.
475            cvt_size(unsafe { sys::send(self.raw(), buf.as_ptr().cast(), buf.len(), sys::MSG_NOSIGNAL) })
476        }
477        #[cfg(windows)]
478        {
479            let len = buf.len().min(i32::MAX as usize) as i32;
480            // SAFETY: `buf` is a valid readable region of at least `len` bytes.
481            let n = unsafe { sys::send(self.raw(), buf.as_ptr(), len, 0) };
482            if n < 0 {
483                Err(last_error())
484            } else {
485                Ok(n as usize)
486            }
487        }
488    }
489
490    /// Sends several buffers with one call (`sendmsg` / `WSASend`) without blocking. At most
491    /// 64 buffers are sent per call.
492    pub fn send_vectored(&self, bufs: &[&[u8]]) -> io::Result<usize> {
493        const MAX: usize = 64;
494        let n = bufs.len().min(MAX);
495        #[cfg(unix)]
496        {
497            let mut iov = [sys::iovec { iov_base: core::ptr::null_mut(), iov_len: 0 }; MAX];
498            for (v, b) in iov.iter_mut().zip(bufs) {
499                *v = sys::iovec { iov_base: b.as_ptr() as *mut c_void, iov_len: b.len() };
500            }
501            // SAFETY: an all-zero msghdr is valid (no name, no control).
502            let mut msg: sys::msghdr = unsafe { core::mem::zeroed() };
503            msg.msg_iov = iov.as_mut_ptr();
504            msg.msg_iovlen = n as _;
505            // SAFETY: `msg` points at `n` iovecs that describe live, readable slices.
506            cvt_size(unsafe { sys::sendmsg(self.raw(), &msg, sys::MSG_NOSIGNAL) })
507        }
508        #[cfg(windows)]
509        {
510            let mut wb = [sys::WSABUF { len: 0, buf: core::ptr::null_mut() }; MAX];
511            for (v, b) in wb.iter_mut().zip(bufs) {
512                *v = sys::WSABUF { len: b.len().min(u32::MAX as usize) as u32, buf: b.as_ptr() as *mut u8 };
513            }
514            let mut sent = 0u32;
515            // SAFETY: `wb` describes `n` live slices; a null OVERLAPPED makes this a plain
516            // non-blocking call that completes before returning.
517            let r = unsafe { sys::WSASend(self.raw(), wb.as_ptr(), n as u32, &mut sent, 0, core::ptr::null_mut(), core::ptr::null_mut()) };
518            if r != 0 {
519                Err(last_error())
520            } else {
521                Ok(sent as usize)
522            }
523        }
524    }
525
526    /// Shuts down one or both directions.
527    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
528        #[cfg(unix)]
529        let h = match how {
530            Shutdown::Read => sys::SHUT_RD,
531            Shutdown::Write => sys::SHUT_WR,
532            Shutdown::Both => sys::SHUT_RDWR,
533        };
534        #[cfg(windows)]
535        let h = match how {
536            Shutdown::Read => sys::SD_RECEIVE,
537            Shutdown::Write => sys::SD_SEND,
538            Shutdown::Both => sys::SD_BOTH,
539        };
540        // SAFETY: shutdown on a socket we own.
541        cvt(unsafe { sys::shutdown(self.raw() as _, h) })?;
542        Ok(())
543    }
544
545    /// Sets or clears `TCP_NODELAY`.
546    pub fn set_nodelay(&self, on: bool) -> io::Result<()> {
547        self.setsockopt_int(sys::IPPROTO_TCP, sys::TCP_NODELAY, on as i32)
548    }
549
550    /// Whether `TCP_NODELAY` is set.
551    pub fn nodelay(&self) -> io::Result<bool> {
552        Ok(self.getsockopt_int(sys::IPPROTO_TCP, sys::TCP_NODELAY)? != 0)
553    }
554
555    /// Switches non-blocking mode.
556    pub fn set_nonblocking(&self, on: bool) -> io::Result<()> {
557        #[cfg(target_os = "linux")]
558        {
559            const FIONBIO: core::ffi::c_ulong = 0x5421;
560            extern "C" {
561                fn ioctl(fd: i32, req: core::ffi::c_ulong, ...) -> i32;
562            }
563            let mut v: i32 = on as i32;
564            // SAFETY: FIONBIO takes a pointer to an int.
565            cvt(unsafe { ioctl(self.raw(), FIONBIO, &mut v as *mut i32) })?;
566            Ok(())
567        }
568        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
569        {
570            // SAFETY: fcntl on a descriptor we own.
571            let fl = cvt(unsafe { sys::fcntl(self.raw(), sys::F_GETFL) })?;
572            let nfl = if on { fl | sys::O_NONBLOCK } else { fl & !sys::O_NONBLOCK };
573            // SAFETY: as above.
574            cvt(unsafe { sys::fcntl(self.raw(), sys::F_SETFL, nfl) })?;
575            Ok(())
576        }
577        #[cfg(windows)]
578        {
579            let mut v: u32 = on as u32;
580            // SAFETY: FIONBIO takes a pointer to a u_long.
581            cvt(unsafe { sys::ioctlsocket(self.raw(), sys::FIONBIO, &mut v) })?;
582            Ok(())
583        }
584    }
585
586    /// The local address.
587    pub fn local_addr(&self) -> io::Result<SocketAddr> {
588        let mut buf = SockAddrBuf::new();
589        let mut len = 128;
590        // SAFETY: `buf` has room for `len` bytes.
591        cvt(unsafe { sys::getsockname(self.raw() as _, buf.as_mut_ptr(), &mut len) })?;
592        decode_addr(&buf, len as usize).ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "unknown address family"))
593    }
594
595    /// The peer address.
596    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
597        let mut buf = SockAddrBuf::new();
598        let mut len = 128;
599        // SAFETY: `buf` has room for `len` bytes.
600        cvt(unsafe { sys::getpeername(self.raw() as _, buf.as_mut_ptr(), &mut len) })?;
601        decode_addr(&buf, len as usize).ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "unknown address family"))
602    }
603
604    /// Reads and clears the pending socket error (`SO_ERROR`).
605    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
606        let e = self.getsockopt_int(sys::SOL_SOCKET, sys::SO_ERROR)?;
607        Ok(if e == 0 { None } else { Some(io::Error::from_raw_os_error(e)) })
608    }
609
610    /// Sets an integer socket option.
611    pub fn setsockopt_int(&self, level: i32, name: i32, value: i32) -> io::Result<()> {
612        // SAFETY: passes a pointer to a live i32 and its size.
613        cvt(unsafe { sys::setsockopt(self.raw() as _, level, name, (&value as *const i32).cast(), 4) })?;
614        Ok(())
615    }
616
617    /// Reads an integer socket option.
618    pub fn getsockopt_int(&self, level: i32, name: i32) -> io::Result<i32> {
619        let mut v: i32 = 0;
620        let mut len = 4;
621        // SAFETY: passes a pointer to a live i32 and its size.
622        cvt(unsafe { sys::getsockopt(self.raw() as _, level, name, (&mut v as *mut i32).cast(), &mut len) })?;
623        Ok(v)
624    }
625
626    /// The raw handle (still owned by this `Socket`).
627    pub fn raw(&self) -> RawSock {
628        #[cfg(unix)]
629        {
630            self.fd.as_raw_fd()
631        }
632        #[cfg(windows)]
633        {
634            self.fd.as_raw_socket() as usize
635        }
636    }
637
638    /// Takes ownership of a raw handle.
639    ///
640    /// # Safety
641    /// `raw` must be an open socket that nothing else owns or will close.
642    pub unsafe fn from_raw(raw: RawSock) -> Socket {
643        #[cfg(unix)]
644        {
645            // SAFETY: guaranteed by the caller.
646            Socket { fd: unsafe { OwnedFd::from_raw_fd(raw) } }
647        }
648        #[cfg(windows)]
649        {
650            // SAFETY: guaranteed by the caller.
651            Socket { fd: unsafe { OwnedSocket::from_raw_socket(raw as u64) } }
652        }
653    }
654
655    /// Gives up ownership of the raw handle.
656    pub fn into_raw(self) -> RawSock {
657        #[cfg(unix)]
658        {
659            self.fd.into_raw_fd()
660        }
661        #[cfg(windows)]
662        {
663            self.fd.into_raw_socket() as usize
664        }
665    }
666
667    /// Converts into a std TCP stream (it stays non-blocking).
668    pub fn into_tcp_stream(self) -> std::net::TcpStream {
669        std::net::TcpStream::from(self.fd)
670    }
671
672    /// Converts into a std TCP listener (it stays non-blocking).
673    pub fn into_tcp_listener(self) -> std::net::TcpListener {
674        std::net::TcpListener::from(self.fd)
675    }
676
677    /// Converts into a std UDP socket (it stays non-blocking).
678    pub fn into_udp_socket(self) -> std::net::UdpSocket {
679        std::net::UdpSocket::from(self.fd)
680    }
681
682    /// An independent handle to the same socket (`dup` / `WSADuplicateSocket`).
683    pub fn try_clone(&self) -> io::Result<Socket> {
684        Ok(Socket { fd: self.fd.try_clone()? })
685    }
686}
687
688macro_rules! from_std {
689    ($t:ty) => {
690        impl From<$t> for Socket {
691            /// Takes over a std socket. Call `set_nonblocking(true)` on it first if it will be
692            /// driven by an event loop.
693            fn from(s: $t) -> Socket {
694                #[cfg(unix)]
695                {
696                    Socket { fd: OwnedFd::from(s) }
697                }
698                #[cfg(windows)]
699                {
700                    Socket { fd: OwnedSocket::from(s) }
701                }
702            }
703        }
704    };
705}
706from_std!(std::net::TcpStream);
707from_std!(std::net::TcpListener);
708from_std!(std::net::UdpSocket);
709
710/// The unspecified address of the same family as `addr` (port 0).
711/// Grows the process's file descriptor table to hold at least `n` descriptors (capped at the
712/// soft `RLIMIT_NOFILE`), by duplicating a descriptor to slot `n - 1` and closing it again.
713///
714/// Linux grows the table in steps (64, 128, 256...), and once the process has more than one
715/// thread each step waits for an RCU grace period (`synchronize_rcu` in `expand_fdtable`):
716/// 10-30 ms on a VM, on whichever thread opens the descriptor that crosses the step. Called
717/// before the loop threads exist, the growth is a plain reallocation. The table costs 8 bytes a
718/// slot of kernel memory (8 KiB for 1024). Returns the size reserved; elsewhere a no-op that
719/// returns 0.
720pub fn reserve_descriptors(n: usize) -> usize {
721    #[cfg(target_os = "linux")]
722    {
723        let mut lim = sys::rlimit::default();
724        // SAFETY: getrlimit writes one rlimit.
725        let soft = if unsafe { sys::getrlimit(sys::RLIMIT_NOFILE, &mut lim) } == 0 { lim.rlim_cur } else { 1024 };
726        let n = (n as u64).min(soft).min(i32::MAX as u64) as i32;
727        if n < 2 {
728            return 0;
729        }
730        // SAFETY: duplicates standard error (or, if it is closed, fails harmlessly) to the
731        // lowest free slot at or above n - 1; the result is a fresh descriptor we own.
732        let fd = unsafe { sys::fcntl(2, sys::F_DUPFD_CLOEXEC, n - 1) };
733        if fd < 0 {
734            return 0;
735        }
736        // SAFETY: `fd` is the fresh descriptor from above; nothing else owns it.
737        drop(unsafe { OwnedFd::from_raw_fd(fd) });
738        n as usize
739    }
740    #[cfg(not(target_os = "linux"))]
741    {
742        let _ = n;
743        0
744    }
745}
746
747/// The process's soft limit on open file descriptors (`RLIMIT_NOFILE` on Linux); `None`
748/// where there is no such limit to watch (Windows) or it can't be read.
749pub fn descriptor_limit() -> Option<usize> {
750    #[cfg(target_os = "linux")]
751    {
752        let mut lim = sys::rlimit::default();
753        // SAFETY: getrlimit writes one rlimit.
754        if unsafe { sys::getrlimit(sys::RLIMIT_NOFILE, &mut lim) } == 0 {
755            return Some(lim.rlim_cur.min(usize::MAX as u64) as usize);
756        }
757        None
758    }
759    #[cfg(not(target_os = "linux"))]
760    {
761        None
762    }
763}
764
765pub fn unspecified_like(addr: &SocketAddr) -> SocketAddr {
766    match addr {
767        SocketAddr::V4(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
768        SocketAddr::V6(_) => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
769    }
770}
771
772#[cfg(test)]
773mod tests {
774    use super::*;
775
776    // Bug 19: the descriptor table is grown before the loop threads exist (no RCU stall on a
777    // loop thread later); the next descriptors still come from the bottom of the table.
778    #[cfg(target_os = "linux")]
779    #[test]
780    fn reserve_descriptors_grows_the_table() {
781        let got = reserve_descriptors(512);
782        assert!(got == 0 || got >= 256, "{got}");
783        let s = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
784        assert!((s.as_raw_fd() as usize) < 256, "a fresh descriptor went to the top: {}", s.as_raw_fd());
785        assert_eq!(reserve_descriptors(0), 0);
786    }
787    use std::io::{Read, Write};
788
789    #[test]
790    fn address_round_trip() {
791        for a in ["127.0.0.1:8080", "[::1]:443", "[fe80::1%3]:9", "0.0.0.0:0"] {
792            let addr: SocketAddr = a.parse().unwrap();
793            let mut buf = SockAddrBuf::new();
794            let len = encode_addr(&addr, &mut buf);
795            assert_eq!(decode_addr(&buf, len as usize), Some(addr));
796        }
797    }
798
799    #[test]
800    fn listen_accept_send_recv_v4_and_v6() {
801        for host in ["127.0.0.1:0", "[::1]:0"] {
802            let l = match Socket::tcp_listen(host.parse().unwrap(), &ListenOptions::default()) {
803                Ok(l) => l,
804                Err(_) if host.starts_with('[') => continue, // no IPv6 loopback on this machine
805                Err(e) => panic!("{e}"),
806            };
807            assert!(matches!(l.accept(), Err(e) if e.kind() == io::ErrorKind::WouldBlock));
808            let addr = l.local_addr().unwrap();
809            let mut c = std::net::TcpStream::connect(addr).unwrap();
810            let (s, peer) = loop {
811                match l.accept() {
812                    Ok(x) => break x,
813                    Err(e) if e.kind() == io::ErrorKind::WouldBlock => std::thread::yield_now(),
814                    Err(e) => panic!("{e}"),
815                }
816            };
817            assert_eq!(peer, Some(c.local_addr().unwrap()));
818            assert_eq!(s.peer_addr().unwrap(), c.local_addr().unwrap());
819            assert!(s.nodelay().unwrap(), "TCP_NODELAY is handed down from the listener");
820            c.write_all(b"hello").unwrap();
821            let mut buf = Vec::with_capacity(64);
822            loop {
823                match s.recv_into(&mut buf) {
824                    Ok(_) if buf.len() >= 5 => break,
825                    Ok(_) => {}
826                    Err(e) if e.kind() == io::ErrorKind::WouldBlock => std::thread::yield_now(),
827                    Err(e) => panic!("{e}"),
828                }
829            }
830            assert_eq!(buf, b"hello");
831            assert_eq!(s.send_vectored(&[b"wor", b"ld", b"!"]).unwrap(), 6);
832            let mut got = [0u8; 6];
833            c.read_exact(&mut got).unwrap();
834            assert_eq!(&got, b"world!");
835            s.shutdown(Shutdown::Write).unwrap();
836            assert_eq!(c.read(&mut got).unwrap(), 0);
837            drop(c);
838        }
839    }
840
841    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
842    #[test]
843    fn reuse_port_lets_two_listeners_share_an_address() {
844        let o = ListenOptions { reuse_port: true, ..Default::default() };
845        let a = Socket::tcp_listen("127.0.0.1:0".parse().unwrap(), &o).unwrap();
846        let b = Socket::tcp_listen(a.local_addr().unwrap(), &o).unwrap();
847        assert_eq!(a.local_addr().unwrap(), b.local_addr().unwrap());
848    }
849
850    #[test]
851    fn std_conversions() {
852        let l = Socket::tcp_listen("127.0.0.1:0".parse().unwrap(), &ListenOptions::default()).unwrap();
853        let addr = l.local_addr().unwrap();
854        let std_l = l.into_tcp_listener();
855        assert_eq!(std_l.local_addr().unwrap(), addr);
856        let back = Socket::from(std_l);
857        assert_eq!(back.local_addr().unwrap(), addr);
858        let c = Socket::tcp_connect(addr).unwrap();
859        assert!(c.nodelay().unwrap());
860        assert!(c.take_error().unwrap().is_none());
861    }
862}