1use super::{GetSockOpt, SetSockOpt};
3use crate::errno::Errno;
4use crate::sys::time::TimeVal;
5use crate::Result;
6use cfg_if::cfg_if;
7use libc::{self, c_int, c_void, socklen_t};
8use std::ffi::{CStr, CString, OsStr, OsString};
9use std::mem::{self, MaybeUninit};
10use std::os::unix::ffi::OsStrExt;
11use std::os::unix::io::{AsFd, AsRawFd};
12
13#[cfg(any(target_os = "freebsd", target_os = "linux"))]
16#[cfg(feature = "net")]
17const TCP_CA_NAME_MAX: usize = 16;
18
19macro_rules! setsockopt_impl {
42 ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
43 impl SetSockOpt for $name {
44 type Val = $ty;
45
46 fn set<F: AsFd>(&self, fd: &F, val: &$ty) -> Result<()> {
47 unsafe {
48 let setter: $setter = Set::new(val);
49
50 let res = libc::setsockopt(
51 fd.as_fd().as_raw_fd(),
52 $level,
53 $flag,
54 setter.ffi_ptr(),
55 setter.ffi_len(),
56 );
57 Errno::result(res).map(drop)
58 }
59 }
60 }
61 };
62}
63
64macro_rules! getsockopt_impl {
87 ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
88 impl GetSockOpt for $name {
89 type Val = $ty;
90
91 fn get<F: AsFd>(&self, fd: &F) -> Result<$ty> {
92 unsafe {
93 let mut getter: $getter = Get::uninit();
94
95 let res = libc::getsockopt(
96 fd.as_fd().as_raw_fd(),
97 $level,
98 $flag,
99 getter.ffi_ptr(),
100 getter.ffi_len(),
101 );
102 Errno::result(res)?;
103
104 match <$ty>::try_from(getter.assume_init()) {
105 Err(_) => Err(Errno::EINVAL),
106 Ok(r) => Ok(r),
107 }
108 }
109 }
110 }
111 };
112}
113
114#[allow(unused_macro_rules)]
141macro_rules! sockopt_impl {
142 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
143 sockopt_impl!($(#[$attr])*
144 $name, GetOnly, $level, $flag, bool, GetBool);
145 };
146
147 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
148 sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
149 };
150
151 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
152 {
153 sockopt_impl!($(#[$attr])*
154 $name, GetOnly, $level, $flag, usize, GetUsize);
155 };
156
157 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
158 sockopt_impl!($(#[$attr])*
159 $name, SetOnly, $level, $flag, bool, SetBool);
160 };
161
162 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
163 sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
164 };
165
166 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
167 {
168 sockopt_impl!($(#[$attr])*
169 $name, SetOnly, $level, $flag, usize, SetUsize);
170 };
171
172 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
173 sockopt_impl!($(#[$attr])*
174 $name, Both, $level, $flag, bool, GetBool, SetBool);
175 };
176
177 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
178 sockopt_impl!($(#[$attr])*
179 $name, Both, $level, $flag, u8, GetU8, SetU8);
180 };
181
182 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
183 sockopt_impl!($(#[$attr])*
184 $name, Both, $level, $flag, usize, GetUsize, SetUsize);
185 };
186
187 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
188 OsString<$array:ty>) =>
189 {
190 sockopt_impl!($(#[$attr])*
191 $name, Both, $level, $flag, OsString, GetOsString<$array>,
192 SetOsString);
193 };
194
195 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
200 {
201 sockopt_impl!($(#[$attr])*
202 $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
203 };
204
205 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
206 $getter:ty) =>
207 {
208 $(#[$attr])*
209 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
210 pub struct $name;
211
212 getsockopt_impl!($name, $level, $flag, $ty, $getter);
213 };
214
215 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
216 {
217 sockopt_impl!($(#[$attr])*
218 $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
219 };
220
221 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
222 $setter:ty) =>
223 {
224 $(#[$attr])*
225 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
226 pub struct $name;
227
228 setsockopt_impl!($name, $level, $flag, $ty, $setter);
229 };
230
231 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty,
232 $getter:ty, $setter:ty) =>
233 {
234 $(#[$attr])*
235 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
236 pub struct $name;
237
238 setsockopt_impl!($name, $level, $flag, $ty, $setter);
239 getsockopt_impl!($name, $level, $flag, $ty, $getter);
240 };
241
242 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
243 sockopt_impl!($(#[$attr])*
244 $name, Both, $level, $flag, $ty, GetStruct<$ty>,
245 SetStruct<$ty>);
246 };
247}
248
249sockopt_impl!(
256 ReuseAddr,
258 Both,
259 libc::SOL_SOCKET,
260 libc::SO_REUSEADDR,
261 bool
262);
263#[cfg(not(solarish))]
264sockopt_impl!(
265 ReusePort,
268 Both,
269 libc::SOL_SOCKET,
270 libc::SO_REUSEPORT,
271 bool
272);
273#[cfg(target_os = "freebsd")]
274sockopt_impl!(
275 ReusePortLb,
278 Both,
279 libc::SOL_SOCKET,
280 libc::SO_REUSEPORT_LB,
281 bool
282);
283#[cfg(feature = "net")]
284sockopt_impl!(
285 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
286 TcpNoDelay,
294 Both,
295 libc::IPPROTO_TCP,
296 libc::TCP_NODELAY,
297 bool
298);
299sockopt_impl!(
300 Linger,
304 Both,
305 libc::SOL_SOCKET,
306 libc::SO_LINGER,
307 libc::linger
308);
309#[cfg(feature = "net")]
310sockopt_impl!(
311 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
312 IpAddMembership,
314 SetOnly,
315 libc::IPPROTO_IP,
316 libc::IP_ADD_MEMBERSHIP,
317 super::IpMembershipRequest
318);
319#[cfg(feature = "net")]
320sockopt_impl!(
321 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
322 IpDropMembership,
324 SetOnly,
325 libc::IPPROTO_IP,
326 libc::IP_DROP_MEMBERSHIP,
327 super::IpMembershipRequest
328);
329cfg_if! {
330 if #[cfg(linux_android)] {
331 #[cfg(feature = "net")]
332 sockopt_impl!(
333 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
334 Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
336 #[cfg(feature = "net")]
337 sockopt_impl!(
338 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
339 Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
341 } else if #[cfg(any(bsd, solarish))] {
342 #[cfg(feature = "net")]
343 sockopt_impl!(
344 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
345 Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
347 libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
348 #[cfg(feature = "net")]
349 sockopt_impl!(
350 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
351 Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
353 libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
354 }
355}
356#[cfg(feature = "net")]
357sockopt_impl!(
358 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
359 IpMulticastTtl,
362 Both,
363 libc::IPPROTO_IP,
364 libc::IP_MULTICAST_TTL,
365 u8
366);
367#[cfg(feature = "net")]
368sockopt_impl!(
369 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
370 Ipv6MulticastHops,
373 Both,
374 libc::IPPROTO_IPV6,
375 libc::IPV6_MULTICAST_HOPS,
376 libc::c_int
377);
378#[cfg(feature = "net")]
379sockopt_impl!(
380 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
381 IpMulticastLoop,
384 Both,
385 libc::IPPROTO_IP,
386 libc::IP_MULTICAST_LOOP,
387 bool
388);
389#[cfg(target_os = "linux")]
390#[cfg(feature = "net")]
391sockopt_impl!(
392 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
393 Priority,
396 Both,
397 libc::SOL_SOCKET,
398 libc::SO_PRIORITY,
399 libc::c_int
400);
401#[cfg(target_os = "linux")]
402#[cfg(feature = "net")]
403sockopt_impl!(
404 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
405 IpTos,
408 Both,
409 libc::IPPROTO_IP,
410 libc::IP_TOS,
411 libc::c_int
412);
413#[cfg(target_os = "linux")]
414#[cfg(feature = "net")]
415sockopt_impl!(
416 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
417 Ipv6TClass,
419 Both,
420 libc::IPPROTO_IPV6,
421 libc::IPV6_TCLASS,
422 libc::c_int
423);
424#[cfg(any(linux_android, target_os = "fuchsia"))]
425#[cfg(feature = "net")]
426sockopt_impl!(
427 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
428 IpFreebind,
431 Both,
432 libc::IPPROTO_IP,
433 libc::IP_FREEBIND,
434 bool
435);
436#[cfg(linux_android)]
437#[cfg(feature = "net")]
438sockopt_impl!(
439 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
440 IpBindAddressNoPort,
445 Both,
446 libc::IPPROTO_IP,
447 libc::IP_BIND_ADDRESS_NO_PORT,
448 bool
449);
450sockopt_impl!(
451 ReceiveTimeout,
453 Both,
454 libc::SOL_SOCKET,
455 libc::SO_RCVTIMEO,
456 TimeVal
457);
458sockopt_impl!(
459 SendTimeout,
461 Both,
462 libc::SOL_SOCKET,
463 libc::SO_SNDTIMEO,
464 TimeVal
465);
466sockopt_impl!(
467 Broadcast,
469 Both,
470 libc::SOL_SOCKET,
471 libc::SO_BROADCAST,
472 bool
473);
474sockopt_impl!(
475 OobInline,
478 Both,
479 libc::SOL_SOCKET,
480 libc::SO_OOBINLINE,
481 bool
482);
483sockopt_impl!(
484 SocketError,
486 GetOnly,
487 libc::SOL_SOCKET,
488 libc::SO_ERROR,
489 i32
490);
491sockopt_impl!(
492 DontRoute,
494 Both,
495 libc::SOL_SOCKET,
496 libc::SO_DONTROUTE,
497 bool
498);
499sockopt_impl!(
500 KeepAlive,
502 Both,
503 libc::SOL_SOCKET,
504 libc::SO_KEEPALIVE,
505 bool
506);
507#[cfg(any(freebsdlike, apple_targets))]
508sockopt_impl!(
509 LocalPeerCred,
512 GetOnly,
513 0,
514 libc::LOCAL_PEERCRED,
515 super::XuCred
516);
517#[cfg(apple_targets)]
518sockopt_impl!(
519 LocalPeerPid,
521 GetOnly,
522 0,
523 libc::LOCAL_PEERPID,
524 libc::c_int
525);
526#[cfg(linux_android)]
527sockopt_impl!(
528 PeerCredentials,
530 GetOnly,
531 libc::SOL_SOCKET,
532 libc::SO_PEERCRED,
533 super::UnixCredentials
534);
535#[cfg(target_os = "freebsd")]
536#[cfg(feature = "net")]
537sockopt_impl!(
538 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
539 ListenQLimit,
541 GetOnly,
542 libc::SOL_SOCKET,
543 libc::SO_LISTENQLIMIT,
544 u32
545);
546#[cfg(apple_targets)]
547#[cfg(feature = "net")]
548sockopt_impl!(
549 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
550 TcpKeepAlive,
553 Both,
554 libc::IPPROTO_TCP,
555 libc::TCP_KEEPALIVE,
556 u32
557);
558#[cfg(any(freebsdlike, linux_android))]
559#[cfg(feature = "net")]
560sockopt_impl!(
561 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
562 TcpKeepIdle,
565 Both,
566 libc::IPPROTO_TCP,
567 libc::TCP_KEEPIDLE,
568 u32
569);
570cfg_if! {
571 if #[cfg(linux_android)] {
572 sockopt_impl!(
573 TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
575 } else if #[cfg(not(target_os = "redox"))] {
576 sockopt_impl!(
577 TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
579 }
580}
581#[cfg(not(any(
582 target_os = "openbsd",
583 target_os = "haiku",
584 target_os = "redox"
585)))]
586#[cfg(feature = "net")]
587sockopt_impl!(
588 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
589 TcpKeepCount,
592 Both,
593 libc::IPPROTO_TCP,
594 libc::TCP_KEEPCNT,
595 u32
596);
597#[cfg(any(linux_android, target_os = "fuchsia"))]
598sockopt_impl!(
599 #[allow(missing_docs)]
600 TcpRepair,
602 Both,
603 libc::IPPROTO_TCP,
604 libc::TCP_REPAIR,
605 u32
606);
607#[cfg(not(any(
608 target_os = "openbsd",
609 target_os = "haiku",
610 target_os = "redox"
611)))]
612#[cfg(feature = "net")]
613sockopt_impl!(
614 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
615 TcpKeepInterval,
617 Both,
618 libc::IPPROTO_TCP,
619 libc::TCP_KEEPINTVL,
620 u32
621);
622#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
623#[cfg(feature = "net")]
624sockopt_impl!(
625 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
626 TcpUserTimeout,
630 Both,
631 libc::IPPROTO_TCP,
632 libc::TCP_USER_TIMEOUT,
633 u32
634);
635#[cfg(linux_android)]
636#[cfg(feature = "net")]
637sockopt_impl!(
638 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
639 TcpFastOpenConnect,
650 Both,
651 libc::IPPROTO_TCP,
652 libc::TCP_FASTOPEN_CONNECT,
653 bool
654);
655sockopt_impl!(
656 RcvBuf,
658 Both,
659 libc::SOL_SOCKET,
660 libc::SO_RCVBUF,
661 usize
662);
663sockopt_impl!(
664 SndBuf,
666 Both,
667 libc::SOL_SOCKET,
668 libc::SO_SNDBUF,
669 usize
670);
671#[cfg(linux_android)]
672sockopt_impl!(
673 RcvBufForce,
677 SetOnly,
678 libc::SOL_SOCKET,
679 libc::SO_RCVBUFFORCE,
680 usize
681);
682#[cfg(linux_android)]
683sockopt_impl!(
684 SndBufForce,
688 SetOnly,
689 libc::SOL_SOCKET,
690 libc::SO_SNDBUFFORCE,
691 usize
692);
693sockopt_impl!(
694 SockType,
696 GetOnly,
697 libc::SOL_SOCKET,
698 libc::SO_TYPE,
699 super::SockType,
700 GetStruct<i32>
701);
702sockopt_impl!(
703 AcceptConn,
706 GetOnly,
707 libc::SOL_SOCKET,
708 libc::SO_ACCEPTCONN,
709 bool
710);
711#[cfg(linux_android)]
712sockopt_impl!(
713 BindToDevice,
715 Both,
716 libc::SOL_SOCKET,
717 libc::SO_BINDTODEVICE,
718 OsString<[u8; libc::IFNAMSIZ]>
719);
720#[cfg(linux_android)]
721#[cfg(feature = "net")]
722sockopt_impl!(
723 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
724 #[allow(missing_docs)]
725 OriginalDst,
727 GetOnly,
728 libc::SOL_IP,
729 libc::SO_ORIGINAL_DST,
730 libc::sockaddr_in
731);
732#[cfg(linux_android)]
733sockopt_impl!(
734 #[allow(missing_docs)]
735 Ip6tOriginalDst,
737 GetOnly,
738 libc::SOL_IPV6,
739 libc::IP6T_SO_ORIGINAL_DST,
740 libc::sockaddr_in6
741);
742#[cfg(linux_android)]
743sockopt_impl!(
744 Timestamping,
747 Both,
748 libc::SOL_SOCKET,
749 libc::SO_TIMESTAMPING,
750 super::TimestampingFlag
751);
752#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "hurd", target_os = "redox")))]
753sockopt_impl!(
754 ReceiveTimestamp,
756 Both,
757 libc::SOL_SOCKET,
758 libc::SO_TIMESTAMP,
759 bool
760);
761#[cfg(linux_android)]
762sockopt_impl!(
763 ReceiveTimestampns,
765 Both,
766 libc::SOL_SOCKET,
767 libc::SO_TIMESTAMPNS,
768 bool
769);
770#[cfg(target_os = "freebsd")]
771sockopt_impl!(
772 TsClock,
775 Both,
776 libc::SOL_SOCKET,
777 libc::SO_TS_CLOCK,
778 super::SocketTimestamp
779);
780#[cfg(linux_android)]
781#[cfg(feature = "net")]
782sockopt_impl!(
783 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
784 IpTransparent,
786 Both,
787 libc::SOL_IP,
788 libc::IP_TRANSPARENT,
789 bool
790);
791#[cfg(target_os = "openbsd")]
792#[cfg(feature = "net")]
793sockopt_impl!(
794 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
795 BindAny,
798 Both,
799 libc::SOL_SOCKET,
800 libc::SO_BINDANY,
801 bool
802);
803#[cfg(target_os = "freebsd")]
804#[cfg(feature = "net")]
805sockopt_impl!(
806 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
807 BindAny,
810 Both,
811 libc::IPPROTO_IP,
812 libc::IP_BINDANY,
813 bool
814);
815#[cfg(target_os = "freebsd")]
816sockopt_impl!(
817 Fib,
820 SetOnly,
821 libc::SOL_SOCKET,
822 libc::SO_SETFIB,
823 i32
824);
825#[cfg(target_os = "freebsd")]
826sockopt_impl!(
827 UserCookie,
830 SetOnly,
831 libc::SOL_SOCKET,
832 libc::SO_USER_COOKIE,
833 u32
834);
835#[cfg(target_os = "openbsd")]
836sockopt_impl!(
837 Rtable,
840 SetOnly,
841 libc::SOL_SOCKET,
842 libc::SO_RTABLE,
843 i32
844);
845#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
846sockopt_impl!(
847 AcceptFilter,
850 Both,
851 libc::SOL_SOCKET,
852 libc::SO_ACCEPTFILTER,
853 libc::accept_filter_arg
854);
855#[cfg(target_os = "linux")]
856sockopt_impl!(
857 Mark,
860 Both,
861 libc::SOL_SOCKET,
862 libc::SO_MARK,
863 u32
864);
865#[cfg(linux_android)]
866sockopt_impl!(
867 PassCred,
870 Both,
871 libc::SOL_SOCKET,
872 libc::SO_PASSCRED,
873 bool
874);
875#[cfg(any(target_os = "freebsd", target_os = "linux"))]
876#[cfg(feature = "net")]
877sockopt_impl!(
878 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
879 TcpCongestion,
882 Both,
883 libc::IPPROTO_TCP,
884 libc::TCP_CONGESTION,
885 OsString<[u8; TCP_CA_NAME_MAX]>
886);
887#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
888#[cfg(feature = "net")]
889sockopt_impl!(
890 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
891 Ipv4PacketInfo,
894 Both,
895 libc::IPPROTO_IP,
896 libc::IP_PKTINFO,
897 bool
898);
899#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))]
900#[cfg(feature = "net")]
901sockopt_impl!(
902 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
903 Ipv6RecvPacketInfo,
906 Both,
907 libc::IPPROTO_IPV6,
908 libc::IPV6_RECVPKTINFO,
909 bool
910);
911#[cfg(bsd)]
912#[cfg(feature = "net")]
913sockopt_impl!(
914 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
915 Ipv4RecvIf,
918 Both,
919 libc::IPPROTO_IP,
920 libc::IP_RECVIF,
921 bool
922);
923#[cfg(bsd)]
924#[cfg(feature = "net")]
925sockopt_impl!(
926 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
927 Ipv4RecvDstAddr,
930 Both,
931 libc::IPPROTO_IP,
932 libc::IP_RECVDSTADDR,
933 bool
934);
935#[cfg(any(linux_android, target_os = "freebsd"))]
936#[cfg(feature = "net")]
937sockopt_impl!(
938 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
939 Ipv4OrigDstAddr,
942 Both,
943 libc::IPPROTO_IP,
944 libc::IP_ORIGDSTADDR,
945 bool
946);
947#[cfg(target_os = "linux")]
948#[cfg(feature = "net")]
949sockopt_impl!(
950 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
951 #[allow(missing_docs)]
952 UdpGsoSegment,
954 Both,
955 libc::SOL_UDP,
956 libc::UDP_SEGMENT,
957 libc::c_int
958);
959#[cfg(target_os = "linux")]
960#[cfg(feature = "net")]
961sockopt_impl!(
962 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
963 #[allow(missing_docs)]
964 UdpGroSegment,
966 Both,
967 libc::IPPROTO_UDP,
968 libc::UDP_GRO,
969 bool
970);
971#[cfg(target_os = "linux")]
972sockopt_impl!(
973 TxTime,
976 Both,
977 libc::SOL_SOCKET,
978 libc::SO_TXTIME,
979 libc::sock_txtime
980);
981#[cfg(any(linux_android, target_os = "fuchsia"))]
982sockopt_impl!(
983 RxqOvfl,
987 Both,
988 libc::SOL_SOCKET,
989 libc::SO_RXQ_OVFL,
990 libc::c_int
991);
992#[cfg(feature = "net")]
993sockopt_impl!(
994 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
995 Ipv6V6Only,
997 Both,
998 libc::IPPROTO_IPV6,
999 libc::IPV6_V6ONLY,
1000 bool
1001);
1002#[cfg(linux_android)]
1003sockopt_impl!(
1004 Ipv4RecvErr,
1006 Both,
1007 libc::IPPROTO_IP,
1008 libc::IP_RECVERR,
1009 bool
1010);
1011#[cfg(linux_android)]
1012sockopt_impl!(
1013 Ipv6RecvErr,
1015 Both,
1016 libc::IPPROTO_IPV6,
1017 libc::IPV6_RECVERR,
1018 bool
1019);
1020#[cfg(linux_android)]
1021sockopt_impl!(
1022 IpMtu,
1024 GetOnly,
1025 libc::IPPROTO_IP,
1026 libc::IP_MTU,
1027 libc::c_int
1028);
1029#[cfg(any(linux_android, target_os = "freebsd"))]
1030sockopt_impl!(
1031 Ipv4Ttl,
1034 Both,
1035 libc::IPPROTO_IP,
1036 libc::IP_TTL,
1037 libc::c_int
1038);
1039#[cfg(any(apple_targets, linux_android, target_os = "freebsd"))]
1040sockopt_impl!(
1041 Ipv6Ttl,
1043 Both,
1044 libc::IPPROTO_IPV6,
1045 libc::IPV6_UNICAST_HOPS,
1046 libc::c_int
1047);
1048#[cfg(any(linux_android, target_os = "freebsd"))]
1049#[cfg(feature = "net")]
1050sockopt_impl!(
1051 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1052 Ipv6OrigDstAddr,
1055 Both,
1056 libc::IPPROTO_IPV6,
1057 libc::IPV6_ORIGDSTADDR,
1058 bool
1059);
1060#[cfg(apple_targets)]
1061sockopt_impl!(
1062 IpDontFrag,
1064 Both,
1065 libc::IPPROTO_IP,
1066 libc::IP_DONTFRAG,
1067 bool
1068);
1069#[cfg(any(linux_android, apple_targets))]
1070sockopt_impl!(
1071 Ipv6DontFrag,
1073 Both,
1074 libc::IPPROTO_IPV6,
1075 libc::IPV6_DONTFRAG,
1076 bool
1077);
1078#[cfg(apple_targets)]
1079#[cfg(feature = "net")]
1080sockopt_impl!(
1081 UtunIfname,
1083 GetOnly,
1084 libc::SYSPROTO_CONTROL,
1085 libc::UTUN_OPT_IFNAME,
1086 CString,
1087 GetCString<[u8; libc::IFNAMSIZ]>
1088);
1089
1090#[allow(missing_docs)]
1091#[cfg(linux_android)]
1093#[derive(Copy, Clone, Debug)]
1094pub struct AlgSetAeadAuthSize;
1095
1096#[cfg(linux_android)]
1099impl SetSockOpt for AlgSetAeadAuthSize {
1100 type Val = usize;
1101
1102 fn set<F: AsFd>(&self, fd: &F, val: &usize) -> Result<()> {
1103 unsafe {
1104 let res = libc::setsockopt(
1105 fd.as_fd().as_raw_fd(),
1106 libc::SOL_ALG,
1107 libc::ALG_SET_AEAD_AUTHSIZE,
1108 ::std::ptr::null(),
1109 *val as libc::socklen_t,
1110 );
1111 Errno::result(res).map(drop)
1112 }
1113 }
1114}
1115
1116#[allow(missing_docs)]
1117#[cfg(linux_android)]
1119#[derive(Clone, Debug)]
1120pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
1121
1122#[cfg(linux_android)]
1123impl<T> Default for AlgSetKey<T> {
1124 fn default() -> Self {
1125 AlgSetKey(Default::default())
1126 }
1127}
1128
1129#[cfg(linux_android)]
1130impl<T> SetSockOpt for AlgSetKey<T>
1131where
1132 T: AsRef<[u8]> + Clone,
1133{
1134 type Val = T;
1135
1136 fn set<F: AsFd>(&self, fd: &F, val: &T) -> Result<()> {
1137 unsafe {
1138 let res = libc::setsockopt(
1139 fd.as_fd().as_raw_fd(),
1140 libc::SOL_ALG,
1141 libc::ALG_SET_KEY,
1142 val.as_ref().as_ptr().cast(),
1143 val.as_ref().len() as libc::socklen_t,
1144 );
1145 Errno::result(res).map(drop)
1146 }
1147 }
1148}
1149
1150#[cfg(linux_android)]
1166#[derive(Clone, Debug)]
1167pub struct TcpUlp<T>(::std::marker::PhantomData<T>);
1168
1169#[cfg(linux_android)]
1170impl<T> Default for TcpUlp<T> {
1171 fn default() -> Self {
1172 TcpUlp(Default::default())
1173 }
1174}
1175
1176#[cfg(linux_android)]
1177impl<T> SetSockOpt for TcpUlp<T>
1178where
1179 T: AsRef<[u8]> + Clone,
1180{
1181 type Val = T;
1182
1183 fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1184 unsafe {
1185 let res = libc::setsockopt(
1186 fd.as_fd().as_raw_fd(),
1187 libc::SOL_TCP,
1188 libc::TCP_ULP,
1189 val.as_ref().as_ptr().cast(),
1190 val.as_ref().len() as libc::socklen_t,
1191 );
1192 Errno::result(res).map(drop)
1193 }
1194 }
1195}
1196
1197#[cfg(target_os = "linux")]
1199#[derive(Copy, Clone, Debug)]
1200pub enum TlsCryptoInfo {
1201 Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128),
1203
1204 Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256),
1206
1207 Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305),
1209}
1210
1211#[cfg(target_os = "linux")]
1225#[derive(Copy, Clone, Debug)]
1226pub struct TcpTlsTx;
1227
1228#[cfg(target_os = "linux")]
1229impl SetSockOpt for TcpTlsTx {
1230 type Val = TlsCryptoInfo;
1231
1232 fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1233 let (ffi_ptr, ffi_len) = match val {
1234 TlsCryptoInfo::Aes128Gcm(crypto_info) => {
1235 (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1236 }
1237 TlsCryptoInfo::Aes256Gcm(crypto_info) => {
1238 (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1239 }
1240 TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
1241 (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1242 }
1243 };
1244 unsafe {
1245 let res = libc::setsockopt(
1246 fd.as_fd().as_raw_fd(),
1247 libc::SOL_TLS,
1248 libc::TLS_TX,
1249 ffi_ptr,
1250 ffi_len as libc::socklen_t,
1251 );
1252 Errno::result(res).map(drop)
1253 }
1254 }
1255}
1256
1257#[cfg(target_os = "linux")]
1271#[derive(Copy, Clone, Debug)]
1272pub struct TcpTlsRx;
1273
1274#[cfg(target_os = "linux")]
1275impl SetSockOpt for TcpTlsRx {
1276 type Val = TlsCryptoInfo;
1277
1278 fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
1279 let (ffi_ptr, ffi_len) = match val {
1280 TlsCryptoInfo::Aes128Gcm(crypto_info) => {
1281 (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1282 }
1283 TlsCryptoInfo::Aes256Gcm(crypto_info) => {
1284 (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1285 }
1286 TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
1287 (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
1288 }
1289 };
1290 unsafe {
1291 let res = libc::setsockopt(
1292 fd.as_fd().as_raw_fd(),
1293 libc::SOL_TLS,
1294 libc::TLS_RX,
1295 ffi_ptr,
1296 ffi_len as libc::socklen_t,
1297 );
1298 Errno::result(res).map(drop)
1299 }
1300 }
1301}
1302
1303
1304trait Get<T> {
1312 fn uninit() -> Self;
1314 fn ffi_ptr(&mut self) -> *mut c_void;
1317 fn ffi_len(&mut self) -> *mut socklen_t;
1320 unsafe fn assume_init(self) -> T;
1322}
1323
1324trait Set<'a, T> {
1326 fn new(val: &'a T) -> Self;
1328 fn ffi_ptr(&self) -> *const c_void;
1331 fn ffi_len(&self) -> socklen_t;
1334}
1335
1336struct GetStruct<T> {
1338 len: socklen_t,
1339 val: MaybeUninit<T>,
1340}
1341
1342impl<T> Get<T> for GetStruct<T> {
1343 fn uninit() -> Self {
1344 GetStruct {
1345 len: mem::size_of::<T>() as socklen_t,
1346 val: MaybeUninit::uninit(),
1347 }
1348 }
1349
1350 fn ffi_ptr(&mut self) -> *mut c_void {
1351 self.val.as_mut_ptr().cast()
1352 }
1353
1354 fn ffi_len(&mut self) -> *mut socklen_t {
1355 &mut self.len
1356 }
1357
1358 unsafe fn assume_init(self) -> T {
1359 assert_eq!(
1360 self.len as usize,
1361 mem::size_of::<T>(),
1362 "invalid getsockopt implementation"
1363 );
1364 unsafe { self.val.assume_init() }
1365 }
1366}
1367
1368struct SetStruct<'a, T: 'static> {
1370 ptr: &'a T,
1371}
1372
1373impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
1374 fn new(ptr: &'a T) -> SetStruct<'a, T> {
1375 SetStruct { ptr }
1376 }
1377
1378 fn ffi_ptr(&self) -> *const c_void {
1379 self.ptr as *const T as *const c_void
1380 }
1381
1382 fn ffi_len(&self) -> socklen_t {
1383 mem::size_of::<T>() as socklen_t
1384 }
1385}
1386
1387struct GetBool {
1389 len: socklen_t,
1390 val: MaybeUninit<c_int>,
1391}
1392
1393impl Get<bool> for GetBool {
1394 fn uninit() -> Self {
1395 GetBool {
1396 len: mem::size_of::<c_int>() as socklen_t,
1397 val: MaybeUninit::uninit(),
1398 }
1399 }
1400
1401 fn ffi_ptr(&mut self) -> *mut c_void {
1402 self.val.as_mut_ptr().cast()
1403 }
1404
1405 fn ffi_len(&mut self) -> *mut socklen_t {
1406 &mut self.len
1407 }
1408
1409 unsafe fn assume_init(self) -> bool {
1410 assert_eq!(
1411 self.len as usize,
1412 mem::size_of::<c_int>(),
1413 "invalid getsockopt implementation"
1414 );
1415 unsafe { self.val.assume_init() != 0 }
1416 }
1417}
1418
1419struct SetBool {
1421 val: c_int,
1422}
1423
1424impl<'a> Set<'a, bool> for SetBool {
1425 fn new(val: &'a bool) -> SetBool {
1426 SetBool {
1427 val: i32::from(*val),
1428 }
1429 }
1430
1431 fn ffi_ptr(&self) -> *const c_void {
1432 &self.val as *const c_int as *const c_void
1433 }
1434
1435 fn ffi_len(&self) -> socklen_t {
1436 mem::size_of_val(&self.val) as socklen_t
1437 }
1438}
1439
1440struct GetU8 {
1442 len: socklen_t,
1443 val: MaybeUninit<u8>,
1444}
1445
1446impl Get<u8> for GetU8 {
1447 fn uninit() -> Self {
1448 GetU8 {
1449 len: mem::size_of::<u8>() as socklen_t,
1450 val: MaybeUninit::uninit(),
1451 }
1452 }
1453
1454 fn ffi_ptr(&mut self) -> *mut c_void {
1455 self.val.as_mut_ptr().cast()
1456 }
1457
1458 fn ffi_len(&mut self) -> *mut socklen_t {
1459 &mut self.len
1460 }
1461
1462 unsafe fn assume_init(self) -> u8 {
1463 assert_eq!(
1464 self.len as usize,
1465 mem::size_of::<u8>(),
1466 "invalid getsockopt implementation"
1467 );
1468 unsafe { self.val.assume_init() }
1469 }
1470}
1471
1472struct SetU8 {
1474 val: u8,
1475}
1476
1477impl<'a> Set<'a, u8> for SetU8 {
1478 fn new(val: &'a u8) -> SetU8 {
1479 SetU8 { val: *val }
1480 }
1481
1482 fn ffi_ptr(&self) -> *const c_void {
1483 &self.val as *const u8 as *const c_void
1484 }
1485
1486 fn ffi_len(&self) -> socklen_t {
1487 mem::size_of_val(&self.val) as socklen_t
1488 }
1489}
1490
1491struct GetUsize {
1493 len: socklen_t,
1494 val: MaybeUninit<c_int>,
1495}
1496
1497impl Get<usize> for GetUsize {
1498 fn uninit() -> Self {
1499 GetUsize {
1500 len: mem::size_of::<c_int>() as socklen_t,
1501 val: MaybeUninit::uninit(),
1502 }
1503 }
1504
1505 fn ffi_ptr(&mut self) -> *mut c_void {
1506 self.val.as_mut_ptr().cast()
1507 }
1508
1509 fn ffi_len(&mut self) -> *mut socklen_t {
1510 &mut self.len
1511 }
1512
1513 unsafe fn assume_init(self) -> usize {
1514 assert_eq!(
1515 self.len as usize,
1516 mem::size_of::<c_int>(),
1517 "invalid getsockopt implementation"
1518 );
1519 unsafe { self.val.assume_init() as usize }
1520 }
1521}
1522
1523struct SetUsize {
1525 val: c_int,
1526}
1527
1528impl<'a> Set<'a, usize> for SetUsize {
1529 fn new(val: &'a usize) -> SetUsize {
1530 SetUsize { val: *val as c_int }
1531 }
1532
1533 fn ffi_ptr(&self) -> *const c_void {
1534 &self.val as *const c_int as *const c_void
1535 }
1536
1537 fn ffi_len(&self) -> socklen_t {
1538 mem::size_of_val(&self.val) as socklen_t
1539 }
1540}
1541
1542struct GetOsString<T: AsMut<[u8]>> {
1544 len: socklen_t,
1545 val: MaybeUninit<T>,
1546}
1547
1548impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
1549 fn uninit() -> Self {
1550 GetOsString {
1551 len: mem::size_of::<T>() as socklen_t,
1552 val: MaybeUninit::uninit(),
1553 }
1554 }
1555
1556 fn ffi_ptr(&mut self) -> *mut c_void {
1557 self.val.as_mut_ptr().cast()
1558 }
1559
1560 fn ffi_len(&mut self) -> *mut socklen_t {
1561 &mut self.len
1562 }
1563
1564 unsafe fn assume_init(self) -> OsString {
1565 let len = self.len as usize;
1566 let mut v = unsafe { self.val.assume_init() };
1567 OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
1568 }
1569}
1570
1571struct SetOsString<'a> {
1573 val: &'a OsStr,
1574}
1575
1576impl<'a> Set<'a, OsString> for SetOsString<'a> {
1577 fn new(val: &'a OsString) -> SetOsString {
1578 SetOsString {
1579 val: val.as_os_str(),
1580 }
1581 }
1582
1583 fn ffi_ptr(&self) -> *const c_void {
1584 self.val.as_bytes().as_ptr().cast()
1585 }
1586
1587 fn ffi_len(&self) -> socklen_t {
1588 self.val.len() as socklen_t
1589 }
1590}
1591
1592struct GetCString<T: AsMut<[u8]>> {
1594 len: socklen_t,
1595 val: MaybeUninit<T>,
1596}
1597
1598impl<T: AsMut<[u8]>> Get<CString> for GetCString<T> {
1599 fn uninit() -> Self {
1600 GetCString {
1601 len: mem::size_of::<T>() as socklen_t,
1602 val: MaybeUninit::uninit(),
1603 }
1604 }
1605
1606 fn ffi_ptr(&mut self) -> *mut c_void {
1607 self.val.as_mut_ptr().cast()
1608 }
1609
1610 fn ffi_len(&mut self) -> *mut socklen_t {
1611 &mut self.len
1612 }
1613
1614 unsafe fn assume_init(self) -> CString {
1615 let mut v = unsafe { self.val.assume_init() };
1616 CStr::from_bytes_until_nul(v.as_mut())
1617 .expect("string should be null-terminated")
1618 .to_owned()
1619 }
1620}