1#![allow(clippy::needless_lifetimes)]
10
11#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
56#![cfg_attr(docsrs, feature(doc_auto_cfg))]
58#![cfg_attr(test, deny(warnings))]
60#![doc(test(attr(deny(warnings))))]
62
63use std::fmt;
64#[cfg(not(target_os = "redox"))]
65use std::io::IoSlice;
66#[cfg(not(target_os = "redox"))]
67use std::marker::PhantomData;
68#[cfg(not(target_os = "redox"))]
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(unix)]
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(unix, path = "sys/unix.rs")]
180#[cfg_attr(windows, path = "sys/windows.rs")]
181mod sys;
182
183#[cfg(not(any(windows, unix)))]
184compile_error!("Socket2 doesn't support the compile target");
185
186use sys::c_int;
187
188pub use sockaddr::{sa_family_t, socklen_t, SockAddr, SockAddrStorage};
189#[cfg(not(any(
190 target_os = "haiku",
191 target_os = "illumos",
192 target_os = "netbsd",
193 target_os = "redox",
194 target_os = "solaris",
195)))]
196pub use socket::InterfaceIndexOrAddress;
197pub use socket::Socket;
198pub use sockref::SockRef;
199#[cfg(all(feature = "all", target_os = "linux"))]
200pub use sys::CcidEndpoints;
201#[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
202pub use sys::SockFilter;
203
204#[derive(Copy, Clone, Eq, PartialEq)]
214pub struct Domain(c_int);
215
216impl Domain {
217 pub const IPV4: Domain = Domain(sys::AF_INET);
219
220 pub const IPV6: Domain = Domain(sys::AF_INET6);
222
223 pub const UNIX: Domain = Domain(sys::AF_UNIX);
225
226 pub const fn for_address(address: SocketAddr) -> Domain {
228 match address {
229 SocketAddr::V4(_) => Domain::IPV4,
230 SocketAddr::V6(_) => Domain::IPV6,
231 }
232 }
233}
234
235impl From<c_int> for Domain {
236 fn from(d: c_int) -> Domain {
237 Domain(d)
238 }
239}
240
241impl From<Domain> for c_int {
242 fn from(d: Domain) -> c_int {
243 d.0
244 }
245}
246
247#[derive(Copy, Clone, Eq, PartialEq)]
257pub struct Type(c_int);
258
259impl Type {
260 pub const STREAM: Type = Type(sys::SOCK_STREAM);
264
265 pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
269
270 #[cfg(all(feature = "all", target_os = "linux"))]
274 pub const DCCP: Type = Type(sys::SOCK_DCCP);
275
276 #[cfg(all(feature = "all", not(target_os = "espidf")))]
278 pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
279
280 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
282 pub const RAW: Type = Type(sys::SOCK_RAW);
283}
284
285impl From<c_int> for Type {
286 fn from(t: c_int) -> Type {
287 Type(t)
288 }
289}
290
291impl From<Type> for c_int {
292 fn from(t: Type) -> c_int {
293 t.0
294 }
295}
296
297#[derive(Copy, Clone, Eq, PartialEq)]
305pub struct Protocol(c_int);
306
307impl Protocol {
308 pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
310
311 pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
313
314 pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
316
317 pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
319
320 #[cfg(target_os = "linux")]
321 pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
323
324 #[cfg(all(feature = "all", target_os = "linux"))]
326 pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
327
328 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
330 pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
331
332 #[cfg(all(
334 feature = "all",
335 any(
336 target_os = "android",
337 target_os = "freebsd",
338 target_os = "fuchsia",
339 target_os = "linux",
340 )
341 ))]
342 pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
343
344 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
346 pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
347}
348
349impl From<c_int> for Protocol {
350 fn from(p: c_int) -> Protocol {
351 Protocol(p)
352 }
353}
354
355impl From<Protocol> for c_int {
356 fn from(p: Protocol) -> c_int {
357 p.0
358 }
359}
360
361#[cfg(not(target_os = "redox"))]
365#[derive(Copy, Clone, Eq, PartialEq)]
366pub struct RecvFlags(c_int);
367
368#[cfg(not(target_os = "redox"))]
369impl RecvFlags {
370 #[cfg(not(target_os = "espidf"))]
378 pub const fn is_truncated(self) -> bool {
379 self.0 & sys::MSG_TRUNC != 0
380 }
381}
382
383#[repr(transparent)]
387pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
388
389impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
390 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
391 fmt::Debug::fmt(self.0.as_slice(), fmt)
392 }
393}
394
395impl<'a> MaybeUninitSlice<'a> {
396 pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
402 MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
403 }
404}
405
406impl<'a> Deref for MaybeUninitSlice<'a> {
407 type Target = [MaybeUninit<u8>];
408
409 fn deref(&self) -> &[MaybeUninit<u8>] {
410 self.0.as_slice()
411 }
412}
413
414impl<'a> DerefMut for MaybeUninitSlice<'a> {
415 fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
416 self.0.as_mut_slice()
417 }
418}
419
420#[derive(Debug, Clone)]
424pub struct TcpKeepalive {
425 #[cfg_attr(
426 any(target_os = "openbsd", target_os = "haiku", target_os = "vita"),
427 allow(dead_code)
428 )]
429 time: Option<Duration>,
430 #[cfg(not(any(
431 target_os = "openbsd",
432 target_os = "redox",
433 target_os = "solaris",
434 target_os = "nto",
435 target_os = "espidf",
436 target_os = "vita",
437 target_os = "haiku",
438 )))]
439 interval: Option<Duration>,
440 #[cfg(not(any(
441 target_os = "openbsd",
442 target_os = "redox",
443 target_os = "solaris",
444 target_os = "nto",
445 target_os = "espidf",
446 target_os = "vita",
447 target_os = "haiku",
448 )))]
449 retries: Option<u32>,
450}
451
452impl TcpKeepalive {
453 #[allow(clippy::new_without_default)]
455 pub const fn new() -> TcpKeepalive {
456 TcpKeepalive {
457 time: None,
458 #[cfg(not(any(
459 target_os = "openbsd",
460 target_os = "redox",
461 target_os = "solaris",
462 target_os = "nto",
463 target_os = "espidf",
464 target_os = "vita",
465 target_os = "haiku",
466 )))]
467 interval: None,
468 #[cfg(not(any(
469 target_os = "openbsd",
470 target_os = "redox",
471 target_os = "solaris",
472 target_os = "nto",
473 target_os = "espidf",
474 target_os = "vita",
475 target_os = "haiku",
476 )))]
477 retries: None,
478 }
479 }
480
481 pub const fn with_time(self, time: Duration) -> Self {
493 Self {
494 time: Some(time),
495 ..self
496 }
497 }
498
499 #[cfg(any(
507 target_os = "android",
508 target_os = "dragonfly",
509 target_os = "freebsd",
510 target_os = "fuchsia",
511 target_os = "illumos",
512 target_os = "ios",
513 target_os = "visionos",
514 target_os = "linux",
515 target_os = "macos",
516 target_os = "netbsd",
517 target_os = "tvos",
518 target_os = "watchos",
519 target_os = "windows",
520 target_os = "cygwin",
521 ))]
522 pub const fn with_interval(self, interval: Duration) -> Self {
523 Self {
524 interval: Some(interval),
525 ..self
526 }
527 }
528
529 #[cfg(all(
534 feature = "all",
535 any(
536 target_os = "android",
537 target_os = "dragonfly",
538 target_os = "freebsd",
539 target_os = "fuchsia",
540 target_os = "illumos",
541 target_os = "ios",
542 target_os = "visionos",
543 target_os = "linux",
544 target_os = "macos",
545 target_os = "netbsd",
546 target_os = "tvos",
547 target_os = "watchos",
548 target_os = "cygwin",
549 target_os = "windows",
550 )
551 ))]
552 pub const fn with_retries(self, retries: u32) -> Self {
553 Self {
554 retries: Some(retries),
555 ..self
556 }
557 }
558}
559
560#[cfg(not(target_os = "redox"))]
565pub struct MsgHdr<'addr, 'bufs, 'control> {
566 inner: sys::msghdr,
567 #[allow(clippy::type_complexity)]
568 _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
569}
570
571#[cfg(not(target_os = "redox"))]
572impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
573 #[allow(clippy::new_without_default)]
575 pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
576 MsgHdr {
578 inner: unsafe { mem::zeroed() },
579 _lifetimes: PhantomData,
580 }
581 }
582
583 pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
588 sys::set_msghdr_name(&mut self.inner, addr);
589 self
590 }
591
592 pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
597 let ptr = bufs.as_ptr() as *mut _;
598 sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
599 self
600 }
601
602 pub fn with_control(mut self, buf: &'control [u8]) -> Self {
607 let ptr = buf.as_ptr() as *mut _;
608 sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
609 self
610 }
611
612 pub fn with_flags(mut self, flags: sys::c_int) -> Self {
616 sys::set_msghdr_flags(&mut self.inner, flags);
617 self
618 }
619}
620
621#[cfg(not(target_os = "redox"))]
622impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
623 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
624 "MsgHdr".fmt(fmt)
625 }
626}
627
628#[cfg(not(target_os = "redox"))]
633pub struct MsgHdrMut<'addr, 'bufs, 'control> {
634 inner: sys::msghdr,
635 #[allow(clippy::type_complexity)]
636 _lifetimes: PhantomData<(
637 &'addr mut SockAddr,
638 &'bufs mut MaybeUninitSlice<'bufs>,
639 &'control mut [u8],
640 )>,
641}
642
643#[cfg(not(target_os = "redox"))]
644impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
645 #[allow(clippy::new_without_default)]
647 pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
648 MsgHdrMut {
650 inner: unsafe { mem::zeroed() },
651 _lifetimes: PhantomData,
652 }
653 }
654
655 #[allow(clippy::needless_pass_by_ref_mut)]
660 pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
661 sys::set_msghdr_name(&mut self.inner, addr);
662 self
663 }
664
665 pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
670 sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
671 self
672 }
673
674 pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
679 sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
680 self
681 }
682
683 pub fn flags(&self) -> RecvFlags {
685 sys::msghdr_flags(&self.inner)
686 }
687
688 pub fn control_len(&self) -> usize {
694 sys::msghdr_control_len(&self.inner)
695 }
696}
697
698#[cfg(not(target_os = "redox"))]
699impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
700 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
701 "MsgHdrMut".fmt(fmt)
702 }
703}