1use 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#[cfg(unix)]
20pub type RawSock = i32;
21#[cfg(windows)]
23pub type RawSock = usize;
24
25#[derive(Debug)]
27pub struct Socket {
28 #[cfg(unix)]
29 fd: OwnedFd,
30 #[cfg(windows)]
31 fd: OwnedSocket,
32}
33
34#[derive(Clone, Debug)]
36pub struct ListenOptions {
37 pub backlog: i32,
41 pub reuse_port: bool,
44 pub nodelay: bool,
46 pub v6_only: Option<bool>,
48 pub recv_buffer: Option<usize>,
50 pub send_buffer: Option<usize>,
52 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
65pub 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 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#[derive(Clone, Debug, Default)]
100pub struct UdpOptions {
101 pub reuse_port: bool,
103 pub gro: bool,
106 pub pktinfo: bool,
108 pub ecn: bool,
110 pub dont_fragment: bool,
112 pub v6_only: Option<bool>,
114 pub recv_buffer: Option<usize>,
116 pub send_buffer: Option<usize>,
118}
119
120#[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
143pub(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 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 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
180pub(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#[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 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#[cfg(windows)]
254pub(crate) fn init() {
255 static ONCE: std::sync::Once = std::sync::Once::new();
256 ONCE.call_once(|| {
257 unsafe {
259 let mut data: sys::WSADATA = core::mem::zeroed();
260 sys::WSAStartup(0x202, &mut data);
261 }
262 });
263}
264
265impl Socket {
270 pub fn new(family: i32, ty: i32) -> io::Result<Socket> {
272 #[cfg(target_os = "linux")]
273 {
274 let fd = cvt(unsafe { sys::socket(family, ty | sys::SOCK_NONBLOCK | sys::SOCK_CLOEXEC, 0) })?;
276 Ok(Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } })
278 }
279 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
280 {
281 let fd = cvt(unsafe { sys::socket(family, ty, 0) })?;
283 let s = Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } };
285 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 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 let s = Socket { fd: unsafe { OwnedSocket::from_raw_socket(raw as u64) } };
304 s.set_nonblocking(true)?;
305 Ok(s)
306 }
307 }
308
309 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 cvt(unsafe { sys::listen(s.raw() as _, opts.backlog) })?;
339 Ok(s)
340 }
341
342 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 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 cvt(unsafe { sys::bind(self.raw() as _, buf.as_ptr(), len as _) })?;
378 Ok(())
379 }
380
381 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 let fd = cvt(unsafe { sys::accept4(self.raw(), buf.as_mut_ptr(), &mut len, sys::SOCK_NONBLOCK | sys::SOCK_CLOEXEC) })?;
389 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 let fd = cvt(unsafe { sys::accept(self.raw(), buf.as_mut_ptr(), &mut len) })?;
398 let s = Socket { fd: unsafe { OwnedFd::from_raw_fd(fd) } };
400 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 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 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 pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
424 #[cfg(unix)]
425 {
426 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 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 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 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 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 unsafe { buf.set_len(buf.len() + n) };
467 Ok(n)
468 }
469
470 pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
472 #[cfg(unix)]
473 {
474 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 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 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 let mut msg: sys::msghdr = unsafe { core::mem::zeroed() };
503 msg.msg_iov = iov.as_mut_ptr();
504 msg.msg_iovlen = n as _;
505 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 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 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 cvt(unsafe { sys::shutdown(self.raw() as _, h) })?;
542 Ok(())
543 }
544
545 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 pub fn nodelay(&self) -> io::Result<bool> {
552 Ok(self.getsockopt_int(sys::IPPROTO_TCP, sys::TCP_NODELAY)? != 0)
553 }
554
555 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 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 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 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 cvt(unsafe { sys::ioctlsocket(self.raw(), sys::FIONBIO, &mut v) })?;
582 Ok(())
583 }
584 }
585
586 pub fn local_addr(&self) -> io::Result<SocketAddr> {
588 let mut buf = SockAddrBuf::new();
589 let mut len = 128;
590 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 pub fn peer_addr(&self) -> io::Result<SocketAddr> {
597 let mut buf = SockAddrBuf::new();
598 let mut len = 128;
599 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 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 pub fn setsockopt_int(&self, level: i32, name: i32, value: i32) -> io::Result<()> {
612 cvt(unsafe { sys::setsockopt(self.raw() as _, level, name, (&value as *const i32).cast(), 4) })?;
614 Ok(())
615 }
616
617 pub fn getsockopt_int(&self, level: i32, name: i32) -> io::Result<i32> {
619 let mut v: i32 = 0;
620 let mut len = 4;
621 cvt(unsafe { sys::getsockopt(self.raw() as _, level, name, (&mut v as *mut i32).cast(), &mut len) })?;
623 Ok(v)
624 }
625
626 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 pub unsafe fn from_raw(raw: RawSock) -> Socket {
643 #[cfg(unix)]
644 {
645 Socket { fd: unsafe { OwnedFd::from_raw_fd(raw) } }
647 }
648 #[cfg(windows)]
649 {
650 Socket { fd: unsafe { OwnedSocket::from_raw_socket(raw as u64) } }
652 }
653 }
654
655 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 pub fn into_tcp_stream(self) -> std::net::TcpStream {
669 std::net::TcpStream::from(self.fd)
670 }
671
672 pub fn into_tcp_listener(self) -> std::net::TcpListener {
674 std::net::TcpListener::from(self.fd)
675 }
676
677 pub fn into_udp_socket(self) -> std::net::UdpSocket {
679 std::net::UdpSocket::from(self.fd)
680 }
681
682 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 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
710pub fn reserve_descriptors(n: usize) -> usize {
721 #[cfg(target_os = "linux")]
722 {
723 let mut lim = sys::rlimit::default();
724 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 let fd = unsafe { sys::fcntl(2, sys::F_DUPFD_CLOEXEC, n - 1) };
733 if fd < 0 {
734 return 0;
735 }
736 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
747pub fn descriptor_limit() -> Option<usize> {
750 #[cfg(target_os = "linux")]
751 {
752 let mut lim = sys::rlimit::default();
753 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 #[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, 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}