1#![allow(clippy::needless_lifetimes)]
10
11#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
56#![cfg_attr(docsrs, feature(doc_cfg))]
58#![cfg_attr(test, deny(warnings))]
60#![doc(test(attr(deny(warnings))))]
62
63use std::fmt;
64#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
65use std::io::IoSlice;
66#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
67use std::marker::PhantomData;
68#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
69use std::mem;
70use std::mem::MaybeUninit;
71use std::net::SocketAddr;
72use std::ops::{Deref, DerefMut};
73use std::time::Duration;
74
75macro_rules! impl_debug {
81 (
82 $type: path,
84 $(
85 $(#[$target: meta])*
86 $libc: ident :: $flag: ident
90 ),+ $(,)*
91 ) => {
92 impl std::fmt::Debug for $type {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 let string = match self.0 {
95 $(
96 $(#[$target])*
97 $libc :: $flag => stringify!($flag),
98 )+
99 n => return write!(f, "{n}"),
100 };
101 f.write_str(string)
102 }
103 }
104 };
105}
106
107macro_rules! from {
109 ($from: ty, $for: ty) => {
110 impl From<$from> for $for {
111 fn from(socket: $from) -> $for {
112 #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
113 unsafe {
114 <$for>::from_raw_fd(socket.into_raw_fd())
115 }
116 #[cfg(windows)]
117 unsafe {
118 <$for>::from_raw_socket(socket.into_raw_socket())
119 }
120 }
121 }
122 };
123}
124
125#[rustfmt::skip]
127macro_rules! man_links {
128 ($syscall: tt ( $section: tt ) ) => {
130 concat!(
131 man_links!(__ intro),
132 man_links!(__ unix $syscall($section)),
133 man_links!(__ windows $syscall($section)),
134 )
135 };
136 (unix: $syscall: tt ( $section: tt ) ) => {
138 concat!(
139 man_links!(__ intro),
140 man_links!(__ unix $syscall($section)),
141 )
142 };
143 (windows: $syscall: tt ( $section: tt ) ) => {
145 concat!(
146 man_links!(__ intro),
147 man_links!(__ windows $syscall($section)),
148 )
149 };
150 (__ intro) => {
152 "\n\nAdditional documentation can be found in manual of the OS:\n\n"
153 };
154 (__ unix $syscall: tt ( $section: tt ) ) => {
156 concat!(
157 " * DragonFly BSD: <https://man.dragonflybsd.org/?command=", stringify!($syscall), "§ion=", stringify!($section), ">\n",
158 " * FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=", stringify!($syscall), "&sektion=", stringify!($section), ">\n",
159 " * Linux: <https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html>\n",
160 " * macOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived, actually for iOS)\n",
161 " * NetBSD: <https://man.netbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
162 " * OpenBSD: <https://man.openbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
163 " * iOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived)\n",
164 " * illumos: <https://illumos.org/man/3SOCKET/", stringify!($syscall), ">\n",
165 )
166 };
167 (__ windows $syscall: tt ( $section: tt ) ) => {
169 concat!(
170 " * Windows: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-", stringify!($syscall), ">\n",
171 )
172 };
173}
174
175mod sockaddr;
176mod socket;
177mod sockref;
178
179#[cfg_attr(
180 any(unix, all(target_os = "wasi", not(target_env = "p1"))),
181 path = "sys/unix.rs"
182)]
183#[cfg_attr(windows, path = "sys/windows.rs")]
184mod sys;
185
186#[cfg(not(any(windows, unix, all(target_os = "wasi", not(target_env = "p1")))))]
187compile_error!("Socket2 doesn't support the compile target");
188
189use sys::c_int;
190
191pub use sockaddr::{sa_family_t, socklen_t, SockAddr, SockAddrStorage};
192#[cfg(not(any(
193 target_os = "haiku",
194 target_os = "illumos",
195 target_os = "netbsd",
196 target_os = "redox",
197 target_os = "solaris",
198 target_os = "wasi",
199)))]
200pub use socket::InterfaceIndexOrAddress;
201pub use socket::Socket;
202pub use sockref::SockRef;
203#[cfg(all(feature = "all", target_os = "linux"))]
204pub use sys::CcidEndpoints;
205#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
206pub use sys::SockFilter;
207
208#[derive(Copy, Clone, Eq, PartialEq)]
218pub struct Domain(c_int);
219
220impl Domain {
221 pub const IPV4: Domain = Domain(sys::AF_INET);
223
224 pub const IPV6: Domain = Domain(sys::AF_INET6);
226
227 #[cfg(not(target_os = "wasi"))]
229 pub const UNIX: Domain = Domain(sys::AF_UNIX);
230
231 pub const fn for_address(address: SocketAddr) -> Domain {
233 match address {
234 SocketAddr::V4(_) => Domain::IPV4,
235 SocketAddr::V6(_) => Domain::IPV6,
236 }
237 }
238}
239
240impl From<c_int> for Domain {
241 fn from(d: c_int) -> Domain {
242 Domain(d)
243 }
244}
245
246impl From<Domain> for c_int {
247 fn from(d: Domain) -> c_int {
248 d.0
249 }
250}
251
252#[derive(Copy, Clone, Eq, PartialEq)]
262pub struct Type(c_int);
263
264impl Type {
265 pub const STREAM: Type = Type(sys::SOCK_STREAM);
269
270 pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
274
275 #[cfg(all(feature = "all", target_os = "linux"))]
279 pub const DCCP: Type = Type(sys::SOCK_DCCP);
280
281 #[cfg(all(
283 feature = "all",
284 not(any(target_os = "espidf", target_os = "wasi", target_os = "horizon"))
285 ))]
286 pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
287
288 #[cfg(all(
290 feature = "all",
291 not(any(
292 target_os = "redox",
293 target_os = "espidf",
294 target_os = "wasi",
295 target_os = "horizon"
296 ))
297 ))]
298 pub const RAW: Type = Type(sys::SOCK_RAW);
299}
300
301impl From<c_int> for Type {
302 fn from(t: c_int) -> Type {
303 Type(t)
304 }
305}
306
307impl From<Type> for c_int {
308 fn from(t: Type) -> c_int {
309 t.0
310 }
311}
312
313#[derive(Copy, Clone, Eq, PartialEq)]
321pub struct Protocol(c_int);
322
323impl Protocol {
324 #[cfg(not(target_os = "wasi"))]
326 pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
327
328 #[cfg(not(target_os = "wasi"))]
330 pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
331
332 pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
334
335 pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
337
338 #[cfg(target_os = "linux")]
339 pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
341
342 #[cfg(all(feature = "all", target_os = "linux"))]
344 pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
345
346 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
348 pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
349
350 #[cfg(all(
352 feature = "all",
353 any(
354 target_os = "android",
355 target_os = "freebsd",
356 target_os = "fuchsia",
357 target_os = "linux",
358 )
359 ))]
360 pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
361
362 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
364 pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
365}
366
367impl From<c_int> for Protocol {
368 fn from(p: c_int) -> Protocol {
369 Protocol(p)
370 }
371}
372
373impl From<Protocol> for c_int {
374 fn from(p: Protocol) -> c_int {
375 p.0
376 }
377}
378
379#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
383#[derive(Copy, Clone, Eq, PartialEq)]
384pub struct RecvFlags(c_int);
385
386#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
387impl RecvFlags {
388 #[cfg(not(target_os = "espidf"))]
396 pub const fn is_truncated(self) -> bool {
397 self.0 & sys::MSG_TRUNC != 0
398 }
399}
400
401#[repr(transparent)]
405pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
406
407impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
408 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
409 fmt::Debug::fmt(self.0.as_slice(), fmt)
410 }
411}
412
413impl<'a> MaybeUninitSlice<'a> {
414 pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
420 MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
421 }
422}
423
424impl<'a> Deref for MaybeUninitSlice<'a> {
425 type Target = [MaybeUninit<u8>];
426
427 fn deref(&self) -> &[MaybeUninit<u8>] {
428 self.0.as_slice()
429 }
430}
431
432impl<'a> DerefMut for MaybeUninitSlice<'a> {
433 fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
434 self.0.as_mut_slice()
435 }
436}
437
438#[derive(Debug, Clone)]
442pub struct TcpKeepalive {
443 #[cfg_attr(
444 any(target_os = "openbsd", target_os = "haiku", target_os = "vita"),
445 allow(dead_code)
446 )]
447 time: Option<Duration>,
448 #[cfg(not(any(
449 target_os = "openbsd",
450 target_os = "redox",
451 target_os = "solaris",
452 target_os = "nto",
453 target_os = "espidf",
454 target_os = "vita",
455 target_os = "haiku",
456 target_os = "horizon"
457 )))]
458 interval: Option<Duration>,
459 #[cfg(not(any(
460 target_os = "openbsd",
461 target_os = "redox",
462 target_os = "solaris",
463 target_os = "nto",
464 target_os = "espidf",
465 target_os = "vita",
466 target_os = "haiku",
467 target_os = "horizon"
468 )))]
469 retries: Option<u32>,
470}
471
472impl TcpKeepalive {
473 #[allow(clippy::new_without_default)]
475 pub const fn new() -> TcpKeepalive {
476 TcpKeepalive {
477 time: None,
478 #[cfg(not(any(
479 target_os = "openbsd",
480 target_os = "redox",
481 target_os = "solaris",
482 target_os = "nto",
483 target_os = "espidf",
484 target_os = "vita",
485 target_os = "haiku",
486 target_os = "horizon"
487 )))]
488 interval: None,
489 #[cfg(not(any(
490 target_os = "openbsd",
491 target_os = "redox",
492 target_os = "solaris",
493 target_os = "nto",
494 target_os = "espidf",
495 target_os = "vita",
496 target_os = "haiku",
497 target_os = "horizon"
498 )))]
499 retries: None,
500 }
501 }
502
503 pub const fn with_time(self, time: Duration) -> Self {
515 Self {
516 time: Some(time),
517 ..self
518 }
519 }
520
521 #[cfg(any(
529 target_os = "android",
530 target_os = "dragonfly",
531 target_os = "emscripten",
532 target_os = "freebsd",
533 target_os = "fuchsia",
534 target_os = "illumos",
535 target_os = "ios",
536 target_os = "visionos",
537 target_os = "linux",
538 target_os = "macos",
539 target_os = "netbsd",
540 target_os = "tvos",
541 target_os = "watchos",
542 target_os = "windows",
543 target_os = "cygwin",
544 target_os = "nuttx",
545 all(target_os = "wasi", not(target_env = "p1")),
546 ))]
547 pub const fn with_interval(self, interval: Duration) -> Self {
548 Self {
549 interval: Some(interval),
550 ..self
551 }
552 }
553
554 #[cfg(all(
559 feature = "all",
560 any(
561 target_os = "android",
562 target_os = "dragonfly",
563 target_os = "emscripten",
564 target_os = "freebsd",
565 target_os = "fuchsia",
566 target_os = "illumos",
567 target_os = "ios",
568 target_os = "visionos",
569 target_os = "linux",
570 target_os = "macos",
571 target_os = "netbsd",
572 target_os = "tvos",
573 target_os = "watchos",
574 target_os = "cygwin",
575 target_os = "windows",
576 target_os = "nuttx",
577 all(target_os = "wasi", not(target_env = "p1")),
578 )
579 ))]
580 pub const fn with_retries(self, retries: u32) -> Self {
581 Self {
582 retries: Some(retries),
583 ..self
584 }
585 }
586}
587
588#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
593#[repr(transparent)]
594pub struct MsgHdr<'addr, 'bufs, 'control> {
595 inner: sys::msghdr,
596 #[allow(clippy::type_complexity)]
597 _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
598}
599
600#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
601impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
602 #[allow(clippy::new_without_default)]
604 pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
605 MsgHdr {
607 inner: unsafe { mem::zeroed() },
608 _lifetimes: PhantomData,
609 }
610 }
611
612 pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
617 sys::set_msghdr_name(&mut self.inner, addr);
618 self
619 }
620
621 pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
626 let ptr = bufs.as_ptr() as *mut _;
627 sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
628 self
629 }
630
631 pub fn with_control(mut self, buf: &'control [u8]) -> Self {
636 let ptr = buf.as_ptr() as *mut _;
637 sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
638 self
639 }
640
641 pub fn with_flags(mut self, flags: sys::c_int) -> Self {
645 sys::set_msghdr_flags(&mut self.inner, flags);
646 self
647 }
648}
649
650#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
651impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
652 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
653 "MsgHdr".fmt(fmt)
654 }
655}
656
657#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
658unsafe impl Send for MsgHdr<'_, '_, '_> {}
659
660#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
665#[repr(transparent)]
666pub struct MsgHdrMut<'addr, 'bufs, 'control> {
667 inner: sys::msghdr,
668 #[allow(clippy::type_complexity)]
669 _lifetimes: PhantomData<(
670 &'addr mut SockAddr,
671 &'bufs mut MaybeUninitSlice<'bufs>,
672 &'control mut [u8],
673 )>,
674}
675
676#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
677impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
678 #[allow(clippy::new_without_default)]
680 pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
681 MsgHdrMut {
683 inner: unsafe { mem::zeroed() },
684 _lifetimes: PhantomData,
685 }
686 }
687
688 #[allow(clippy::needless_pass_by_ref_mut)]
693 pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
694 sys::set_msghdr_name(&mut self.inner, addr);
695 self
696 }
697
698 pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
703 sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
704 self
705 }
706
707 pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
712 sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
713 self
714 }
715
716 pub fn flags(&self) -> RecvFlags {
718 sys::msghdr_flags(&self.inner)
719 }
720
721 pub fn control_len(&self) -> usize {
727 sys::msghdr_control_len(&self.inner)
728 }
729}
730
731#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
732impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
733 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
734 "MsgHdrMut".fmt(fmt)
735 }
736}
737
738#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
739unsafe impl Send for MsgHdrMut<'_, '_, '_> {}