1use cfg_if::cfg_if;
3use super::{GetSockOpt, SetSockOpt};
4use crate::Result;
5use crate::errno::Errno;
6use crate::sys::time::TimeVal;
7use libc::{self, c_int, c_void, socklen_t};
8use std::convert::TryFrom;
9use std::mem::{
10 self,
11 MaybeUninit
12};
13use std::os::unix::io::RawFd;
14use std::ffi::{OsStr, OsString};
15#[cfg(target_family = "unix")]
16use std::os::unix::ffi::OsStrExt;
17
18#[cfg(any(target_os = "freebsd", target_os = "linux"))]
21const TCP_CA_NAME_MAX: usize = 16;
22
23macro_rules! setsockopt_impl {
46 ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
47 impl SetSockOpt for $name {
48 type Val = $ty;
49
50 fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
51 unsafe {
52 let setter: $setter = Set::new(val);
53
54 let res = libc::setsockopt(fd, $level, $flag,
55 setter.ffi_ptr(),
56 setter.ffi_len());
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(&self, fd: RawFd) -> Result<$ty> {
92 unsafe {
93 let mut getter: $getter = Get::uninit();
94
95 let res = libc::getsockopt(fd, $level, $flag,
96 getter.ffi_ptr(),
97 getter.ffi_len());
98 Errno::result(res)?;
99
100 match <$ty>::try_from(getter.assume_init()) {
101 Err(_) => Err(Errno::EINVAL),
102 Ok(r) => Ok(r)
103 }
104 }
105 }
106 }
107 }
108}
109
110#[allow(unknown_lints)]
137#[allow(unused_macro_rules)]
138macro_rules! sockopt_impl {
139 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
140 sockopt_impl!($(#[$attr])*
141 $name, GetOnly, $level, $flag, bool, GetBool);
142 };
143
144 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
145 sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
146 };
147
148 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
149 {
150 sockopt_impl!($(#[$attr])*
151 $name, GetOnly, $level, $flag, usize, GetUsize);
152 };
153
154 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
155 sockopt_impl!($(#[$attr])*
156 $name, SetOnly, $level, $flag, bool, SetBool);
157 };
158
159 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
160 sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
161 };
162
163 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
164 {
165 sockopt_impl!($(#[$attr])*
166 $name, SetOnly, $level, $flag, usize, SetUsize);
167 };
168
169 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
170 sockopt_impl!($(#[$attr])*
171 $name, Both, $level, $flag, bool, GetBool, SetBool);
172 };
173
174 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
175 sockopt_impl!($(#[$attr])*
176 $name, Both, $level, $flag, u8, GetU8, SetU8);
177 };
178
179 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
180 sockopt_impl!($(#[$attr])*
181 $name, Both, $level, $flag, usize, GetUsize, SetUsize);
182 };
183
184 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
185 OsString<$array:ty>) =>
186 {
187 sockopt_impl!($(#[$attr])*
188 $name, Both, $level, $flag, OsString, GetOsString<$array>,
189 SetOsString);
190 };
191
192 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
197 {
198 sockopt_impl!($(#[$attr])*
199 $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
200 };
201
202 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
203 $getter:ty) =>
204 {
205 $(#[$attr])*
206 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
207 pub struct $name;
208
209 getsockopt_impl!($name, $level, $flag, $ty, $getter);
210 };
211
212 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
213 {
214 sockopt_impl!($(#[$attr])*
215 $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
216 };
217
218 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
219 $setter:ty) =>
220 {
221 $(#[$attr])*
222 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
223 pub struct $name;
224
225 setsockopt_impl!($name, $level, $flag, $ty, $setter);
226 };
227
228 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty,
229 $getter:ty, $setter:ty) =>
230 {
231 $(#[$attr])*
232 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
233 pub struct $name;
234
235 setsockopt_impl!($name, $level, $flag, $ty, $setter);
236 getsockopt_impl!($name, $level, $flag, $ty, $getter);
237 };
238
239 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
240 sockopt_impl!($(#[$attr])*
241 $name, Both, $level, $flag, $ty, GetStruct<$ty>,
242 SetStruct<$ty>);
243 };
244}
245
246sockopt_impl!(
253 ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool
255);
256#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
257sockopt_impl!(
258 ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
261sockopt_impl!(
262 TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
270sockopt_impl!(
271 Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
275sockopt_impl!(
276 IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP,
278 super::IpMembershipRequest);
279sockopt_impl!(
280 IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP,
282 super::IpMembershipRequest);
283cfg_if! {
284 if #[cfg(any(target_os = "android", target_os = "linux"))] {
285 sockopt_impl!(
286 Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
288 sockopt_impl!(
289 Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
291 } else if #[cfg(any(target_os = "dragonfly",
292 target_os = "freebsd",
293 target_os = "illumos",
294 target_os = "ios",
295 target_os = "macos",
296 target_os = "netbsd",
297 target_os = "openbsd",
298 target_os = "solaris"))] {
299 sockopt_impl!(
300 Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
302 libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
303 sockopt_impl!(
304 Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
306 libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
307 }
308}
309sockopt_impl!(
310 IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
313sockopt_impl!(
314 IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
317#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
318sockopt_impl!(
319 IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool);
322sockopt_impl!(
323 ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
325sockopt_impl!(
326 SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
328sockopt_impl!(
329 Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
331sockopt_impl!(
332 OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
335sockopt_impl!(
336 SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32);
338sockopt_impl!(
339 KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
341#[cfg(any(
342 target_os = "dragonfly",
343 target_os = "freebsd",
344 target_os = "macos",
345 target_os = "ios"
346))]
347sockopt_impl!(
348 LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred);
351#[cfg(any(target_os = "android", target_os = "linux"))]
352sockopt_impl!(
353 PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
355#[cfg(any(target_os = "ios",
356 target_os = "macos"))]
357sockopt_impl!(
358 TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
361#[cfg(any(target_os = "android",
362 target_os = "dragonfly",
363 target_os = "freebsd",
364 target_os = "linux",
365 target_os = "nacl"))]
366sockopt_impl!(
367 TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
370cfg_if! {
371 if #[cfg(any(target_os = "android", target_os = "linux"))] {
372 sockopt_impl!(
373 TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
375 } else {
376 sockopt_impl!(
377 TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
379 }
380}
381#[cfg(not(target_os = "openbsd"))]
382sockopt_impl!(
383 TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
386#[cfg(any(target_os = "android",
387 target_os = "fuchsia",
388 target_os = "linux"))]
389sockopt_impl!(
390 #[allow(missing_docs)]
391 TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32);
393#[cfg(not(target_os = "openbsd"))]
394sockopt_impl!(
395 TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
397#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
398sockopt_impl!(
399 TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32);
403sockopt_impl!(
404 RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
406sockopt_impl!(
407 SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
409#[cfg(any(target_os = "android", target_os = "linux"))]
410sockopt_impl!(
411 RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
415#[cfg(any(target_os = "android", target_os = "linux"))]
416sockopt_impl!(
417 SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
421sockopt_impl!(
422 SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType, GetStruct<i32>);
424sockopt_impl!(
425 AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
428#[cfg(any(target_os = "android", target_os = "linux"))]
429sockopt_impl!(
430 BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
432#[cfg(any(target_os = "android", target_os = "linux"))]
433sockopt_impl!(
434 #[allow(missing_docs)]
435 OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
437#[cfg(any(target_os = "android", target_os = "linux"))]
438sockopt_impl!(
439 #[allow(missing_docs)]
440 Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6);
442sockopt_impl!(
443 ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
445#[cfg(all(target_os = "linux"))]
446sockopt_impl!(
447 ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool);
449#[cfg(any(target_os = "android", target_os = "linux"))]
450sockopt_impl!(
451 IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
453#[cfg(target_os = "openbsd")]
454sockopt_impl!(
455 BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
458#[cfg(target_os = "freebsd")]
459sockopt_impl!(
460 BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
463#[cfg(target_os = "linux")]
464sockopt_impl!(
465 Mark, Both, libc::SOL_SOCKET, libc::SO_MARK, u32);
468#[cfg(any(target_os = "android", target_os = "linux"))]
469sockopt_impl!(
470 PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
473#[cfg(any(target_os = "freebsd", target_os = "linux"))]
474sockopt_impl!(
475 TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
478#[cfg(any(
479 target_os = "android",
480 target_os = "ios",
481 target_os = "linux",
482 target_os = "macos",
483 target_os = "netbsd",
484))]
485sockopt_impl!(
486 Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
489#[cfg(any(
490 target_os = "android",
491 target_os = "freebsd",
492 target_os = "ios",
493 target_os = "linux",
494 target_os = "macos",
495 target_os = "netbsd",
496 target_os = "openbsd",
497))]
498sockopt_impl!(
499 Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
502#[cfg(any(
503 target_os = "freebsd",
504 target_os = "ios",
505 target_os = "macos",
506 target_os = "netbsd",
507 target_os = "openbsd",
508))]
509sockopt_impl!(
510 Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
513#[cfg(any(
514 target_os = "freebsd",
515 target_os = "ios",
516 target_os = "macos",
517 target_os = "netbsd",
518 target_os = "openbsd",
519))]
520sockopt_impl!(
521 Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
524#[cfg(target_os = "linux")]
525sockopt_impl!(
526 #[allow(missing_docs)]
527 UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
529#[cfg(target_os = "linux")]
530sockopt_impl!(
531 #[allow(missing_docs)]
532 UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
534#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
535sockopt_impl!(
536 RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int);
540sockopt_impl!(
541 Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool);
543#[cfg(any(target_os = "android", target_os = "linux"))]
544sockopt_impl!(
545 Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool);
547#[cfg(any(target_os = "android", target_os = "linux"))]
548sockopt_impl!(
549 Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool);
551#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
552sockopt_impl!(
553 Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int);
556#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
557sockopt_impl!(
558 Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int);
560
561#[allow(missing_docs)]
562#[cfg(any(target_os = "android", target_os = "linux"))]
564#[derive(Copy, Clone, Debug)]
565pub struct AlgSetAeadAuthSize;
566
567#[cfg(any(target_os = "android", target_os = "linux"))]
570impl SetSockOpt for AlgSetAeadAuthSize {
571 type Val = usize;
572
573 fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
574 unsafe {
575 let res = libc::setsockopt(fd,
576 libc::SOL_ALG,
577 libc::ALG_SET_AEAD_AUTHSIZE,
578 ::std::ptr::null(),
579 *val as libc::socklen_t);
580 Errno::result(res).map(drop)
581 }
582 }
583}
584
585#[allow(missing_docs)]
586#[cfg(any(target_os = "android", target_os = "linux"))]
588#[derive(Clone, Debug)]
589pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
590
591#[cfg(any(target_os = "android", target_os = "linux"))]
592impl<T> Default for AlgSetKey<T> {
593 fn default() -> Self {
594 AlgSetKey(Default::default())
595 }
596}
597
598#[cfg(any(target_os = "android", target_os = "linux"))]
599impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
600 type Val = T;
601
602 fn set(&self, fd: RawFd, val: &T) -> Result<()> {
603 unsafe {
604 let res = libc::setsockopt(fd,
605 libc::SOL_ALG,
606 libc::ALG_SET_KEY,
607 val.as_ref().as_ptr() as *const _,
608 val.as_ref().len() as libc::socklen_t);
609 Errno::result(res).map(drop)
610 }
611 }
612}
613
614trait Get<T> {
622 fn uninit() -> Self;
624 fn ffi_ptr(&mut self) -> *mut c_void;
627 fn ffi_len(&mut self) -> *mut socklen_t;
630 unsafe fn assume_init(self) -> T;
632}
633
634trait Set<'a, T> {
636 fn new(val: &'a T) -> Self;
638 fn ffi_ptr(&self) -> *const c_void;
641 fn ffi_len(&self) -> socklen_t;
644}
645
646struct GetStruct<T> {
648 len: socklen_t,
649 val: MaybeUninit<T>,
650}
651
652impl<T> Get<T> for GetStruct<T> {
653 fn uninit() -> Self {
654 GetStruct {
655 len: mem::size_of::<T>() as socklen_t,
656 val: MaybeUninit::uninit(),
657 }
658 }
659
660 fn ffi_ptr(&mut self) -> *mut c_void {
661 self.val.as_mut_ptr() as *mut c_void
662 }
663
664 fn ffi_len(&mut self) -> *mut socklen_t {
665 &mut self.len
666 }
667
668 unsafe fn assume_init(self) -> T {
669 assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
670 self.val.assume_init()
671 }
672}
673
674struct SetStruct<'a, T: 'static> {
676 ptr: &'a T,
677}
678
679impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
680 fn new(ptr: &'a T) -> SetStruct<'a, T> {
681 SetStruct { ptr }
682 }
683
684 fn ffi_ptr(&self) -> *const c_void {
685 self.ptr as *const T as *const c_void
686 }
687
688 fn ffi_len(&self) -> socklen_t {
689 mem::size_of::<T>() as socklen_t
690 }
691}
692
693struct GetBool {
695 len: socklen_t,
696 val: MaybeUninit<c_int>,
697}
698
699impl Get<bool> for GetBool {
700 fn uninit() -> Self {
701 GetBool {
702 len: mem::size_of::<c_int>() as socklen_t,
703 val: MaybeUninit::uninit(),
704 }
705 }
706
707 fn ffi_ptr(&mut self) -> *mut c_void {
708 self.val.as_mut_ptr() as *mut c_void
709 }
710
711 fn ffi_len(&mut self) -> *mut socklen_t {
712 &mut self.len
713 }
714
715 unsafe fn assume_init(self) -> bool {
716 assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
717 self.val.assume_init() != 0
718 }
719}
720
721struct SetBool {
723 val: c_int,
724}
725
726impl<'a> Set<'a, bool> for SetBool {
727 fn new(val: &'a bool) -> SetBool {
728 SetBool { val: i32::from(*val) }
729 }
730
731 fn ffi_ptr(&self) -> *const c_void {
732 &self.val as *const c_int as *const c_void
733 }
734
735 fn ffi_len(&self) -> socklen_t {
736 mem::size_of::<c_int>() as socklen_t
737 }
738}
739
740struct GetU8 {
742 len: socklen_t,
743 val: MaybeUninit<u8>,
744}
745
746impl Get<u8> for GetU8 {
747 fn uninit() -> Self {
748 GetU8 {
749 len: mem::size_of::<u8>() as socklen_t,
750 val: MaybeUninit::uninit(),
751 }
752 }
753
754 fn ffi_ptr(&mut self) -> *mut c_void {
755 self.val.as_mut_ptr() as *mut c_void
756 }
757
758 fn ffi_len(&mut self) -> *mut socklen_t {
759 &mut self.len
760 }
761
762 unsafe fn assume_init(self) -> u8 {
763 assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
764 self.val.assume_init()
765 }
766}
767
768struct SetU8 {
770 val: u8,
771}
772
773impl<'a> Set<'a, u8> for SetU8 {
774 fn new(val: &'a u8) -> SetU8 {
775 SetU8 { val: *val }
776 }
777
778 fn ffi_ptr(&self) -> *const c_void {
779 &self.val as *const u8 as *const c_void
780 }
781
782 fn ffi_len(&self) -> socklen_t {
783 mem::size_of::<c_int>() as socklen_t
784 }
785}
786
787struct GetUsize {
789 len: socklen_t,
790 val: MaybeUninit<c_int>,
791}
792
793impl Get<usize> for GetUsize {
794 fn uninit() -> Self {
795 GetUsize {
796 len: mem::size_of::<c_int>() as socklen_t,
797 val: MaybeUninit::uninit(),
798 }
799 }
800
801 fn ffi_ptr(&mut self) -> *mut c_void {
802 self.val.as_mut_ptr() as *mut c_void
803 }
804
805 fn ffi_len(&mut self) -> *mut socklen_t {
806 &mut self.len
807 }
808
809 unsafe fn assume_init(self) -> usize {
810 assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
811 self.val.assume_init() as usize
812 }
813}
814
815struct SetUsize {
817 val: c_int,
818}
819
820impl<'a> Set<'a, usize> for SetUsize {
821 fn new(val: &'a usize) -> SetUsize {
822 SetUsize { val: *val as c_int }
823 }
824
825 fn ffi_ptr(&self) -> *const c_void {
826 &self.val as *const c_int as *const c_void
827 }
828
829 fn ffi_len(&self) -> socklen_t {
830 mem::size_of::<c_int>() as socklen_t
831 }
832}
833
834struct GetOsString<T: AsMut<[u8]>> {
836 len: socklen_t,
837 val: MaybeUninit<T>,
838}
839
840impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
841 fn uninit() -> Self {
842 GetOsString {
843 len: mem::size_of::<T>() as socklen_t,
844 val: MaybeUninit::uninit(),
845 }
846 }
847
848 fn ffi_ptr(&mut self) -> *mut c_void {
849 self.val.as_mut_ptr() as *mut c_void
850 }
851
852 fn ffi_len(&mut self) -> *mut socklen_t {
853 &mut self.len
854 }
855
856 unsafe fn assume_init(self) -> OsString {
857 let len = self.len as usize;
858 let mut v = self.val.assume_init();
859 OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
860 }
861}
862
863struct SetOsString<'a> {
865 val: &'a OsStr,
866}
867
868impl<'a> Set<'a, OsString> for SetOsString<'a> {
869 fn new(val: &'a OsString) -> SetOsString {
870 SetOsString { val: val.as_os_str() }
871 }
872
873 fn ffi_ptr(&self) -> *const c_void {
874 self.val.as_bytes().as_ptr() as *const c_void
875 }
876
877 fn ffi_len(&self) -> socklen_t {
878 self.val.len() as socklen_t
879 }
880}
881
882
883#[cfg(test)]
884mod test {
885 #[cfg(any(target_os = "android", target_os = "linux"))]
886 #[test]
887 fn can_get_peercred_on_unix_socket() {
888 use super::super::*;
889
890 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
891 let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
892 let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
893 assert_eq!(a_cred, b_cred);
894 assert!(a_cred.pid() != 0);
895 }
896
897 #[test]
898 fn is_socket_type_unix() {
899 use super::super::*;
900 use crate::unistd::close;
901
902 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
903 let a_type = getsockopt(a, super::SockType).unwrap();
904 assert_eq!(a_type, SockType::Stream);
905 close(a).unwrap();
906 close(b).unwrap();
907 }
908
909 #[test]
910 fn is_socket_type_dgram() {
911 use super::super::*;
912 use crate::unistd::close;
913
914 let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
915 let s_type = getsockopt(s, super::SockType).unwrap();
916 assert_eq!(s_type, SockType::Datagram);
917 close(s).unwrap();
918 }
919
920 #[cfg(any(target_os = "freebsd",
921 target_os = "linux",
922 target_os = "nacl"))]
923 #[test]
924 fn can_get_listen_on_tcp_socket() {
925 use super::super::*;
926 use crate::unistd::close;
927
928 let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
929 let s_listening = getsockopt(s, super::AcceptConn).unwrap();
930 assert!(!s_listening);
931 listen(s, 10).unwrap();
932 let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
933 assert!(s_listening2);
934 close(s).unwrap();
935 }
936
937}