1# crate and it aims
19to provide some features with safe APIs currently missing from `socket2`. As the result, this
20library can be used as a drop-in replacement of `socket2`.
21
22The following are the additional features or APIs:
23
24- [`socket::Socket::recv_from_initialized`]
25
26- [`socket::Socket::recvmsg_initialized`]
27
28- [`socket::Socket::set_pktinfo_v4`]
29
30- [`socket::Socket::set_recv_pktinfo_v6`]
31
32- [`MsgHdrInit`]: support `recvmsg` message header operations.
33
34- [`CMsgHdr`]: support Control Messages used in `recvmsg_initialized`.
35
36"#
37)]
38
39#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
86#![cfg_attr(docsrs, feature(doc_cfg))]
88#![cfg_attr(test, deny(warnings))]
90#![doc(test(attr(deny(warnings))))]
92
93use std::fmt;
94#[cfg(not(target_os = "redox"))]
95use std::io::IoSlice;
96#[cfg(not(any(
97 target_os = "freebsd",
98 target_os = "fuchsia",
99 target_os = "hurd",
100 target_os = "redox",
101 target_os = "vita",
102)))]
103use std::io::IoSliceMut;
104#[cfg(not(target_os = "redox"))]
105use std::marker::PhantomData;
106#[cfg(not(target_os = "redox"))]
107use std::mem;
108use std::mem::MaybeUninit;
109use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
110use std::ops::{Deref, DerefMut};
111#[cfg(not(any(
112 target_os = "freebsd",
113 target_os = "fuchsia",
114 target_os = "hurd",
115 target_os = "redox",
116 target_os = "vita",
117)))]
118use std::ptr;
119use std::time::Duration;
120
121macro_rules! impl_debug {
127 (
128 $type: path,
130 $(
131 $(#[$target: meta])*
132 $libc: ident :: $flag: ident
136 ),+ $(,)*
137 ) => {
138 impl std::fmt::Debug for $type {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 let string = match self.0 {
141 $(
142 $(#[$target])*
143 $libc :: $flag => stringify!($flag),
144 )+
145 n => return write!(f, "{n}"),
146 };
147 f.write_str(string)
148 }
149 }
150 };
151}
152
153macro_rules! from {
155 ($from: ty, $for: ty) => {
156 impl From<$from> for $for {
157 fn from(socket: $from) -> $for {
158 #[cfg(unix)]
159 unsafe {
160 <$for>::from_raw_fd(socket.into_raw_fd())
161 }
162 #[cfg(windows)]
163 unsafe {
164 <$for>::from_raw_socket(socket.into_raw_socket())
165 }
166 }
167 }
168 };
169}
170
171#[rustfmt::skip]
173macro_rules! man_links {
174 ($syscall: tt ( $section: tt ) ) => {
176 concat!(
177 man_links!(__ intro),
178 man_links!(__ unix $syscall($section)),
179 man_links!(__ windows $syscall($section)),
180 )
181 };
182 (unix: $syscall: tt ( $section: tt ) ) => {
184 concat!(
185 man_links!(__ intro),
186 man_links!(__ unix $syscall($section)),
187 )
188 };
189 (windows: $syscall: tt ( $section: tt ) ) => {
191 concat!(
192 man_links!(__ intro),
193 man_links!(__ windows $syscall($section)),
194 )
195 };
196 (__ intro) => {
198 "\n\nAdditional documentation can be found in manual of the OS:\n\n"
199 };
200 (__ unix $syscall: tt ( $section: tt ) ) => {
202 concat!(
203 " * DragonFly BSD: <https://man.dragonflybsd.org/?command=", stringify!($syscall), "§ion=", stringify!($section), ">\n",
204 " * FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=", stringify!($syscall), "&sektion=", stringify!($section), ">\n",
205 " * Linux: <https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html>\n",
206 " * macOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived, actually for iOS)\n",
207 " * NetBSD: <https://man.netbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
208 " * OpenBSD: <https://man.openbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
209 " * iOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived)\n",
210 " * illumos: <https://illumos.org/man/3SOCKET/", stringify!($syscall), ">\n",
211 )
212 };
213 (__ windows $syscall: tt ( $section: tt ) ) => {
215 concat!(
216 " * Windows: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-", stringify!($syscall), ">\n",
217 )
218 };
219}
220
221mod sockaddr;
222mod socket;
223mod sockref;
224
225#[cfg_attr(unix, path = "sys/unix.rs")]
226#[cfg_attr(windows, path = "sys/windows.rs")]
227mod sys;
228
229#[cfg(not(any(windows, unix)))]
230compile_error!("Socket2 doesn't support the compile target");
231
232use sys::c_int;
233
234pub use sockaddr::SockAddr;
235pub use socket::Socket;
236pub use sockref::SockRef;
237
238#[cfg(not(any(
239 target_os = "haiku",
240 target_os = "illumos",
241 target_os = "netbsd",
242 target_os = "redox",
243 target_os = "solaris",
244)))]
245pub use socket::InterfaceIndexOrAddress;
246
247#[derive(Copy, Clone, Eq, PartialEq)]
257pub struct Domain(c_int);
258
259impl Domain {
260 pub const IPV4: Domain = Domain(sys::AF_INET);
262
263 pub const IPV6: Domain = Domain(sys::AF_INET6);
265
266 pub const UNIX: Domain = Domain(sys::AF_UNIX);
268
269 pub const fn for_address(address: SocketAddr) -> Domain {
271 match address {
272 SocketAddr::V4(_) => Domain::IPV4,
273 SocketAddr::V6(_) => Domain::IPV6,
274 }
275 }
276}
277
278impl From<c_int> for Domain {
279 fn from(d: c_int) -> Domain {
280 Domain(d)
281 }
282}
283
284impl From<Domain> for c_int {
285 fn from(d: Domain) -> c_int {
286 d.0
287 }
288}
289
290#[derive(Copy, Clone, Eq, PartialEq)]
300pub struct Type(c_int);
301
302impl Type {
303 pub const STREAM: Type = Type(sys::SOCK_STREAM);
307
308 pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
312
313 #[cfg(all(feature = "all", target_os = "linux"))]
317 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
318 pub const DCCP: Type = Type(sys::SOCK_DCCP);
319
320 #[cfg(all(feature = "all", not(target_os = "espidf")))]
322 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "espidf")))))]
323 pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
324
325 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
327 #[cfg_attr(
328 docsrs,
329 doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
330 )]
331 pub const RAW: Type = Type(sys::SOCK_RAW);
332}
333
334impl From<c_int> for Type {
335 fn from(t: c_int) -> Type {
336 Type(t)
337 }
338}
339
340impl From<Type> for c_int {
341 fn from(t: Type) -> c_int {
342 t.0
343 }
344}
345
346#[derive(Copy, Clone, Eq, PartialEq)]
354pub struct Protocol(c_int);
355
356impl Protocol {
357 pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
359
360 pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
362
363 pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
365
366 pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
368
369 #[cfg(target_os = "linux")]
370 pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
372
373 #[cfg(all(feature = "all", target_os = "linux"))]
375 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
376 pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
377
378 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
380 pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
381
382 #[cfg(all(
384 feature = "all",
385 any(
386 target_os = "android",
387 target_os = "freebsd",
388 target_os = "fuchsia",
389 target_os = "linux",
390 )
391 ))]
392 pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
393
394 #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
396 pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
397}
398
399impl From<c_int> for Protocol {
400 fn from(p: c_int) -> Protocol {
401 Protocol(p)
402 }
403}
404
405impl From<Protocol> for c_int {
406 fn from(p: Protocol) -> c_int {
407 p.0
408 }
409}
410
411#[cfg(not(target_os = "redox"))]
415#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
416#[derive(Copy, Clone, Eq, PartialEq)]
417pub struct RecvFlags(c_int);
418
419#[cfg(not(target_os = "redox"))]
420impl RecvFlags {
421 #[cfg(not(target_os = "espidf"))]
429 pub const fn is_truncated(self) -> bool {
430 self.0 & sys::MSG_TRUNC != 0
431 }
432}
433
434#[repr(transparent)]
438pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
439
440impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
441 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
442 fmt::Debug::fmt(self.0.as_slice(), fmt)
443 }
444}
445
446impl<'a> MaybeUninitSlice<'a> {
447 pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
453 MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
454 }
455}
456
457impl<'a> Deref for MaybeUninitSlice<'a> {
458 type Target = [MaybeUninit<u8>];
459
460 fn deref(&self) -> &[MaybeUninit<u8>] {
461 self.0.as_slice()
462 }
463}
464
465impl<'a> DerefMut for MaybeUninitSlice<'a> {
466 fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
467 self.0.as_mut_slice()
468 }
469}
470
471#[derive(Debug, Clone)]
475pub struct TcpKeepalive {
476 #[cfg_attr(
477 any(target_os = "openbsd", target_os = "haiku", target_os = "vita"),
478 allow(dead_code)
479 )]
480 time: Option<Duration>,
481 #[cfg(not(any(
482 target_os = "openbsd",
483 target_os = "redox",
484 target_os = "solaris",
485 target_os = "nto",
486 target_os = "espidf",
487 target_os = "vita",
488 target_os = "haiku",
489 )))]
490 interval: Option<Duration>,
491 #[cfg(not(any(
492 target_os = "openbsd",
493 target_os = "redox",
494 target_os = "solaris",
495 target_os = "windows",
496 target_os = "nto",
497 target_os = "espidf",
498 target_os = "vita",
499 target_os = "haiku",
500 )))]
501 retries: Option<u32>,
502}
503
504impl TcpKeepalive {
505 pub const fn new() -> TcpKeepalive {
507 TcpKeepalive {
508 time: None,
509 #[cfg(not(any(
510 target_os = "openbsd",
511 target_os = "redox",
512 target_os = "solaris",
513 target_os = "nto",
514 target_os = "espidf",
515 target_os = "vita",
516 target_os = "haiku",
517 )))]
518 interval: None,
519 #[cfg(not(any(
520 target_os = "openbsd",
521 target_os = "redox",
522 target_os = "solaris",
523 target_os = "windows",
524 target_os = "nto",
525 target_os = "espidf",
526 target_os = "vita",
527 target_os = "haiku",
528 )))]
529 retries: None,
530 }
531 }
532
533 pub const fn with_time(self, time: Duration) -> Self {
545 Self {
546 time: Some(time),
547 ..self
548 }
549 }
550
551 #[cfg(any(
559 target_os = "android",
560 target_os = "dragonfly",
561 target_os = "freebsd",
562 target_os = "fuchsia",
563 target_os = "illumos",
564 target_os = "ios",
565 target_os = "linux",
566 target_os = "macos",
567 target_os = "netbsd",
568 target_os = "tvos",
569 target_os = "watchos",
570 target_os = "windows",
571 ))]
572 #[cfg_attr(
573 docsrs,
574 doc(cfg(any(
575 target_os = "android",
576 target_os = "dragonfly",
577 target_os = "freebsd",
578 target_os = "fuchsia",
579 target_os = "illumos",
580 target_os = "ios",
581 target_os = "linux",
582 target_os = "macos",
583 target_os = "netbsd",
584 target_os = "tvos",
585 target_os = "watchos",
586 target_os = "windows",
587 )))
588 )]
589 pub const fn with_interval(self, interval: Duration) -> Self {
590 Self {
591 interval: Some(interval),
592 ..self
593 }
594 }
595
596 #[cfg(all(
601 feature = "all",
602 any(
603 target_os = "android",
604 target_os = "dragonfly",
605 target_os = "freebsd",
606 target_os = "fuchsia",
607 target_os = "illumos",
608 target_os = "ios",
609 target_os = "linux",
610 target_os = "macos",
611 target_os = "netbsd",
612 target_os = "tvos",
613 target_os = "watchos",
614 )
615 ))]
616 #[cfg_attr(
617 docsrs,
618 doc(cfg(all(
619 feature = "all",
620 any(
621 target_os = "android",
622 target_os = "dragonfly",
623 target_os = "freebsd",
624 target_os = "fuchsia",
625 target_os = "illumos",
626 target_os = "ios",
627 target_os = "linux",
628 target_os = "macos",
629 target_os = "netbsd",
630 target_os = "tvos",
631 target_os = "watchos",
632 )
633 )))
634 )]
635 pub const fn with_retries(self, retries: u32) -> Self {
636 Self {
637 retries: Some(retries),
638 ..self
639 }
640 }
641}
642
643impl Default for TcpKeepalive {
644 fn default() -> Self {
645 Self::new()
646 }
647}
648
649#[cfg(not(target_os = "redox"))]
654pub struct MsgHdr<'addr, 'bufs, 'control> {
655 inner: sys::msghdr,
656 #[allow(clippy::type_complexity)]
657 _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
658}
659
660#[cfg(not(target_os = "redox"))]
661impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
662 #[allow(clippy::new_without_default)]
664 pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
665 MsgHdr {
667 inner: unsafe { mem::zeroed() },
668 _lifetimes: PhantomData,
669 }
670 }
671
672 pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
677 sys::set_msghdr_name(&mut self.inner, addr);
678 self
679 }
680
681 pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
686 let ptr = bufs.as_ptr() as *mut _;
687 sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
688 self
689 }
690
691 pub fn with_control(mut self, buf: &'control [u8]) -> Self {
696 let ptr = buf.as_ptr() as *mut _;
697 sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
698 self
699 }
700
701 pub fn with_flags(mut self, flags: sys::c_int) -> Self {
705 sys::set_msghdr_flags(&mut self.inner, flags);
706 self
707 }
708}
709
710#[cfg(not(target_os = "redox"))]
711impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
712 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
713 "MsgHdr".fmt(fmt)
714 }
715}
716
717#[cfg(not(target_os = "redox"))]
722pub struct MsgHdrMut<'addr, 'bufs, 'control> {
723 inner: sys::msghdr,
724 #[allow(clippy::type_complexity)]
725 _lifetimes: PhantomData<(
726 &'addr mut SockAddr,
727 &'bufs mut MaybeUninitSlice<'bufs>,
728 &'control mut [u8],
729 )>,
730}
731
732#[cfg(not(target_os = "redox"))]
733impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
734 #[allow(clippy::new_without_default)]
736 pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
737 MsgHdrMut {
739 inner: unsafe { mem::zeroed() },
740 _lifetimes: PhantomData,
741 }
742 }
743
744 #[allow(clippy::needless_pass_by_ref_mut)]
749 pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
750 sys::set_msghdr_name(&mut self.inner, addr);
751 self
752 }
753
754 pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
759 sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
760 self
761 }
762
763 pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
768 sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
769 self
770 }
771
772 pub fn flags(&self) -> RecvFlags {
774 sys::msghdr_flags(&self.inner)
775 }
776
777 pub fn control_len(&self) -> usize {
783 sys::msghdr_control_len(&self.inner)
784 }
785}
786
787#[cfg(not(target_os = "redox"))]
788impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
789 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
790 "MsgHdrMut".fmt(fmt)
791 }
792}
793
794#[cfg(not(any(
801 target_os = "freebsd",
802 target_os = "fuchsia",
803 target_os = "hurd",
804 target_os = "redox",
805 target_os = "vita",
806)))]
807pub struct MsgHdrInit<'addr, 'bufs, 'control> {
808 inner: sys::msghdr,
809
810 src: Option<&'addr mut SockAddr>,
817
818 _lifetimes: PhantomData<(&'bufs [IoSliceMut<'bufs>], &'control [u8])>,
819}
820
821#[cfg(not(any(
822 target_os = "freebsd",
823 target_os = "fuchsia",
824 target_os = "hurd",
825 target_os = "redox",
826 target_os = "vita",
827)))]
828impl<'addr, 'bufs, 'control> MsgHdrInit<'addr, 'bufs, 'control> {
829 #[allow(clippy::new_without_default)]
831 pub fn new() -> MsgHdrInit<'addr, 'bufs, 'control> {
832 MsgHdrInit {
834 inner: unsafe { mem::zeroed() },
835 src: None,
836 _lifetimes: PhantomData,
837 }
838 }
839
840 #[allow(clippy::needless_pass_by_ref_mut)]
845 pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
846 sys::set_msghdr_name(&mut self.inner, addr);
847 self.src = Some(addr);
848 self
849 }
850
851 pub fn with_buffers(mut self, buf_list: &'bufs mut [IoSliceMut<'_>]) -> Self {
856 sys::set_msghdr_iov(
857 &mut self.inner,
858 buf_list.as_mut_ptr().cast(),
859 buf_list.len(),
860 );
861 self
862 }
863
864 pub fn with_control(mut self, buf: &'control mut [u8]) -> Self {
869 sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
870 self
871 }
872
873 pub fn cmsg_hdr_vec(&self) -> Vec<CMsgHdr<'_>> {
877 let mut cmsg_vec = Vec::new();
878
879 let mut cmsg = self.inner.cmsg_first_hdr();
880 if !cmsg.is_null() {
881 let cmsg_hdr = unsafe { CMsgHdr { inner: &*cmsg } };
882 cmsg_vec.push(cmsg_hdr);
883
884 cmsg = self.inner.cmsg_next_hdr(unsafe { &*cmsg });
885 while !cmsg.is_null() {
886 let cmsg_hdr = unsafe { CMsgHdr { inner: &*cmsg } };
887 cmsg_vec.push(cmsg_hdr);
888 }
889 }
890
891 cmsg_vec
892 }
893
894 pub fn get_addr(&self) -> Option<&SockAddr> {
898 self.src.as_deref()
899 }
900}
901
902#[cfg(not(any(
903 target_os = "freebsd",
904 target_os = "fuchsia",
905 target_os = "hurd",
906 target_os = "redox",
907 target_os = "vita",
908)))]
909impl fmt::Debug for MsgHdrInit<'_, '_, '_> {
910 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
911 "MsgHdrInit".fmt(fmt)
912 }
913}
914
915#[cfg(not(any(
917 target_os = "freebsd",
918 target_os = "fuchsia",
919 target_os = "hurd",
920 target_os = "redox",
921 target_os = "vita",
922)))]
923pub(crate) trait MsgHdrOps {
924 fn cmsg_first_hdr(&self) -> *mut sys::cmsghdr;
925
926 fn cmsg_next_hdr(&self, cmsg: &sys::cmsghdr) -> *mut sys::cmsghdr;
927}
928
929#[cfg(not(any(
931 target_os = "freebsd",
932 target_os = "fuchsia",
933 target_os = "hurd",
934 target_os = "redox",
935 target_os = "vita",
936)))]
937pub struct CMsgHdr<'a> {
938 inner: &'a sys::cmsghdr,
939}
940
941#[cfg(not(any(
942 target_os = "freebsd",
943 target_os = "fuchsia",
944 target_os = "hurd",
945 target_os = "redox",
946 target_os = "vita",
947)))]
948impl CMsgHdr<'_> {
949 pub fn get_level(&self) -> CMsgLevel {
951 self.inner.cmsg_level
952 }
953
954 pub fn get_type(&self) -> CMsgType {
956 self.inner.cmsg_type
957 }
958
959 pub fn as_pktinfo_v4(&self) -> Option<PktInfoV4> {
961 if self.inner.cmsg_level != sys::IPPROTO_IP {
962 return None;
963 }
964
965 if self.inner.cmsg_type != sys::IP_PKTINFO {
966 return None;
967 }
968
969 let data_ptr = self.inner.cmsg_data();
970 let pktinfo = unsafe { ptr::read_unaligned(data_ptr as *const sys::InPktInfo) };
971
972 #[cfg(not(windows))]
973 let addr_dst = Ipv4Addr::from(u32::from_be(pktinfo.ipi_addr.s_addr));
974
975 #[cfg(windows)]
976 let addr_dst = Ipv4Addr::from(u32::from_be(unsafe { pktinfo.ipi_addr.S_un.S_addr }));
977
978 Some(PktInfoV4 {
979 if_index: pktinfo.ipi_ifindex as _,
980 addr_dst,
981 })
982 }
983
984 pub fn as_recvpktinfo_v6(&self) -> Option<PktInfoV6> {
986 if self.inner.cmsg_level != sys::IPPROTO_IPV6 {
987 return None;
988 }
989
990 if self.inner.cmsg_type != sys::IPV6_PKTINFO {
991 return None;
992 }
993
994 let data_ptr = self.inner.cmsg_data();
995 let pktinfo = unsafe { ptr::read_unaligned(data_ptr as *const sys::In6PktInfo) };
996
997 #[cfg(windows)]
998 let addr_dst = Ipv6Addr::from(unsafe { pktinfo.ipi6_addr.u.Byte });
999
1000 #[cfg(not(windows))]
1001 let addr_dst = Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr);
1002
1003 Some(PktInfoV6 {
1004 if_index: pktinfo.ipi6_ifindex as _,
1005 addr_dst,
1006 })
1007 }
1008}
1009
1010#[cfg(not(any(
1011 target_os = "freebsd",
1012 target_os = "fuchsia",
1013 target_os = "hurd",
1014 target_os = "redox",
1015 target_os = "vita",
1016)))]
1017pub(crate) trait CMsgHdrOps {
1018 fn cmsg_data(&self) -> *mut u8;
1020}
1021
1022#[cfg(not(any(
1025 target_os = "freebsd",
1026 target_os = "fuchsia",
1027 target_os = "hurd",
1028 target_os = "redox",
1029 target_os = "vita",
1030)))]
1031pub const fn cmsg_space(data_len: usize) -> usize {
1032 sys::_cmsg_space(data_len)
1033}
1034
1035#[cfg(not(any(
1036 target_os = "freebsd",
1037 target_os = "fuchsia",
1038 target_os = "hurd",
1039 target_os = "redox",
1040 target_os = "vita",
1041)))]
1042impl fmt::Debug for CMsgHdr<'_> {
1043 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1044 write!(
1045 f,
1046 "(len: {} level: {} type: {})",
1047 self.inner.cmsg_len, self.inner.cmsg_level, self.inner.cmsg_type
1048 )
1049 }
1050}
1051
1052#[cfg(not(any(
1053 target_os = "freebsd",
1054 target_os = "fuchsia",
1055 target_os = "hurd",
1056 target_os = "redox",
1057 target_os = "vita",
1058)))]
1059const IN_PKTINFO_SIZE: usize = mem::size_of::<sys::InPktInfo>();
1060#[cfg(not(any(
1061 target_os = "freebsd",
1062 target_os = "fuchsia",
1063 target_os = "hurd",
1064 target_os = "redox",
1065 target_os = "vita",
1066)))]
1067const IN6_PKTINFO_SIZE: usize = mem::size_of::<sys::In6PktInfo>();
1068
1069#[derive(Debug)]
1071pub struct PktInfoV4 {
1072 pub if_index: u64,
1074
1075 pub addr_dst: Ipv4Addr,
1077}
1078
1079impl PktInfoV4 {
1080 #[cfg(not(any(
1082 target_os = "freebsd",
1083 target_os = "fuchsia",
1084 target_os = "hurd",
1085 target_os = "redox",
1086 target_os = "vita",
1087 )))]
1088 pub const fn size() -> usize {
1089 IN_PKTINFO_SIZE
1090 }
1091}
1092
1093#[derive(Debug)]
1095pub struct PktInfoV6 {
1096 pub if_index: u64,
1098
1099 pub addr_dst: Ipv6Addr,
1101}
1102
1103impl PktInfoV6 {
1104 #[cfg(not(any(
1106 target_os = "freebsd",
1107 target_os = "fuchsia",
1108 target_os = "hurd",
1109 target_os = "redox",
1110 target_os = "vita",
1111 )))]
1112 pub const fn size() -> usize {
1113 IN6_PKTINFO_SIZE
1114 }
1115}
1116
1117pub type CMsgLevel = i32;
1119
1120#[cfg(not(any(
1122 target_os = "freebsd",
1123 target_os = "fuchsia",
1124 target_os = "hurd",
1125 target_os = "redox",
1126 target_os = "vita",
1127)))]
1128pub const CMSG_LEVEL_IPPROTO_IP: CMsgLevel = sys::IPPROTO_IP;
1129
1130#[cfg(not(any(
1132 target_os = "freebsd",
1133 target_os = "fuchsia",
1134 target_os = "hurd",
1135 target_os = "redox",
1136 target_os = "vita",
1137)))]
1138pub const CMSG_LEVEL_IPPROTO_IPV6: CMsgLevel = sys::IPPROTO_IPV6;
1139
1140pub type CMsgType = i32;
1142
1143#[cfg(not(any(
1145 target_os = "freebsd",
1146 target_os = "fuchsia",
1147 target_os = "hurd",
1148 target_os = "redox",
1149 target_os = "vita",
1150)))]
1151pub const CMSG_TYPE_IP_PKTINFO: CMsgType = sys::IP_PKTINFO;
1152
1153#[cfg(not(any(
1155 target_os = "freebsd",
1156 target_os = "fuchsia",
1157 target_os = "hurd",
1158 target_os = "redox",
1159 target_os = "vita",
1160)))]
1161pub const CMSG_TYPE_IPV6_PKTINFO: CMsgType = sys::IPV6_PKTINFO;