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"))]
21#[cfg(feature = "net")]
22const TCP_CA_NAME_MAX: usize = 16;
23
24macro_rules! setsockopt_impl {
47 ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
48 impl SetSockOpt for $name {
49 type Val = $ty;
50
51 fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
52 unsafe {
53 let setter: $setter = Set::new(val);
54
55 let res = libc::setsockopt(fd, $level, $flag,
56 setter.ffi_ptr(),
57 setter.ffi_len());
58 Errno::result(res).map(drop)
59 }
60 }
61 }
62 }
63}
64
65macro_rules! getsockopt_impl {
88 ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
89 impl GetSockOpt for $name {
90 type Val = $ty;
91
92 fn get(&self, fd: RawFd) -> Result<$ty> {
93 unsafe {
94 let mut getter: $getter = Get::uninit();
95
96 let res = libc::getsockopt(fd, $level, $flag,
97 getter.ffi_ptr(),
98 getter.ffi_len());
99 Errno::result(res)?;
100
101 match <$ty>::try_from(getter.assume_init()) {
102 Err(_) => Err(Errno::EINVAL),
103 Ok(r) => Ok(r)
104 }
105 }
106 }
107 }
108 }
109}
110
111#[allow(unknown_lints)]
138#[allow(unused_macro_rules)]
139macro_rules! sockopt_impl {
140 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
141 sockopt_impl!($(#[$attr])*
142 $name, GetOnly, $level, $flag, bool, GetBool);
143 };
144
145 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => {
146 sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8);
147 };
148
149 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) =>
150 {
151 sockopt_impl!($(#[$attr])*
152 $name, GetOnly, $level, $flag, usize, GetUsize);
153 };
154
155 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => {
156 sockopt_impl!($(#[$attr])*
157 $name, SetOnly, $level, $flag, bool, SetBool);
158 };
159
160 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => {
161 sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8);
162 };
163
164 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) =>
165 {
166 sockopt_impl!($(#[$attr])*
167 $name, SetOnly, $level, $flag, usize, SetUsize);
168 };
169
170 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => {
171 sockopt_impl!($(#[$attr])*
172 $name, Both, $level, $flag, bool, GetBool, SetBool);
173 };
174
175 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => {
176 sockopt_impl!($(#[$attr])*
177 $name, Both, $level, $flag, u8, GetU8, SetU8);
178 };
179
180 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => {
181 sockopt_impl!($(#[$attr])*
182 $name, Both, $level, $flag, usize, GetUsize, SetUsize);
183 };
184
185 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path,
186 OsString<$array:ty>) =>
187 {
188 sockopt_impl!($(#[$attr])*
189 $name, Both, $level, $flag, OsString, GetOsString<$array>,
190 SetOsString);
191 };
192
193 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) =>
198 {
199 sockopt_impl!($(#[$attr])*
200 $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>);
201 };
202
203 ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty,
204 $getter:ty) =>
205 {
206 $(#[$attr])*
207 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
208 pub struct $name;
209
210 getsockopt_impl!($name, $level, $flag, $ty, $getter);
211 };
212
213 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) =>
214 {
215 sockopt_impl!($(#[$attr])*
216 $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>);
217 };
218
219 ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty,
220 $setter:ty) =>
221 {
222 $(#[$attr])*
223 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
224 pub struct $name;
225
226 setsockopt_impl!($name, $level, $flag, $ty, $setter);
227 };
228
229 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty,
230 $getter:ty, $setter:ty) =>
231 {
232 $(#[$attr])*
233 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
234 pub struct $name;
235
236 setsockopt_impl!($name, $level, $flag, $ty, $setter);
237 getsockopt_impl!($name, $level, $flag, $ty, $getter);
238 };
239
240 ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => {
241 sockopt_impl!($(#[$attr])*
242 $name, Both, $level, $flag, $ty, GetStruct<$ty>,
243 SetStruct<$ty>);
244 };
245}
246
247sockopt_impl!(
254 ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool
256);
257#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
258sockopt_impl!(
259 ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
262#[cfg(feature = "net")]
263sockopt_impl!(
264 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
265 TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
273sockopt_impl!(
274 Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
278#[cfg(feature = "net")]
279sockopt_impl!(
280 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
281 IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP,
283 super::IpMembershipRequest);
284#[cfg(feature = "net")]
285sockopt_impl!(
286 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
287 IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP,
289 super::IpMembershipRequest);
290cfg_if! {
291 if #[cfg(any(target_os = "android", target_os = "linux"))] {
292 #[cfg(feature = "net")]
293 sockopt_impl!(
294 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
295 Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
297 #[cfg(feature = "net")]
298 sockopt_impl!(
299 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
300 Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
302 } else if #[cfg(any(target_os = "dragonfly",
303 target_os = "freebsd",
304 target_os = "illumos",
305 target_os = "ios",
306 target_os = "macos",
307 target_os = "netbsd",
308 target_os = "openbsd",
309 target_os = "solaris"))] {
310 #[cfg(feature = "net")]
311 sockopt_impl!(
312 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
313 Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6,
315 libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
316 #[cfg(feature = "net")]
317 sockopt_impl!(
318 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
319 Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6,
321 libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
322 }
323}
324#[cfg(feature = "net")]
325sockopt_impl!(
326 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
327 IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
330#[cfg(feature = "net")]
331sockopt_impl!(
332 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
333 IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
336#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
337#[cfg(feature = "net")]
338sockopt_impl!(
339 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
340 IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool);
343sockopt_impl!(
344 ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
346sockopt_impl!(
347 SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
349sockopt_impl!(
350 Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
352sockopt_impl!(
353 OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
356sockopt_impl!(
357 SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32);
359sockopt_impl!(
360 KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
362#[cfg(any(
363 target_os = "dragonfly",
364 target_os = "freebsd",
365 target_os = "macos",
366 target_os = "ios"
367))]
368sockopt_impl!(
369 LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred);
372#[cfg(any(target_os = "android", target_os = "linux"))]
373sockopt_impl!(
374 PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
376#[cfg(any(target_os = "ios",
377 target_os = "macos"))]
378#[cfg(feature = "net")]
379sockopt_impl!(
380 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
381 TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
384#[cfg(any(target_os = "android",
385 target_os = "dragonfly",
386 target_os = "freebsd",
387 target_os = "linux",
388 target_os = "nacl"))]
389#[cfg(feature = "net")]
390sockopt_impl!(
391 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
392 TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
395cfg_if! {
396 if #[cfg(any(target_os = "android", target_os = "linux"))] {
397 sockopt_impl!(
398 TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
400 } else {
401 sockopt_impl!(
402 TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
404 }
405}
406#[cfg(not(target_os = "openbsd"))]
407#[cfg(feature = "net")]
408sockopt_impl!(
409 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
410 TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
413#[cfg(any(target_os = "android",
414 target_os = "fuchsia",
415 target_os = "linux"))]
416sockopt_impl!(
417 #[allow(missing_docs)]
418 TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32);
420#[cfg(not(target_os = "openbsd"))]
421#[cfg(feature = "net")]
422sockopt_impl!(
423 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
424 TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
426#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
427#[cfg(feature = "net")]
428sockopt_impl!(
429 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
430 TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32);
434sockopt_impl!(
435 RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
437sockopt_impl!(
438 SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
440#[cfg(any(target_os = "android", target_os = "linux"))]
441sockopt_impl!(
442 RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
446#[cfg(any(target_os = "android", target_os = "linux"))]
447sockopt_impl!(
448 SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
452sockopt_impl!(
453 SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType, GetStruct<i32>);
455sockopt_impl!(
456 AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
459#[cfg(any(target_os = "android", target_os = "linux"))]
460sockopt_impl!(
461 BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
463#[cfg(any(target_os = "android", target_os = "linux"))]
464#[cfg(feature = "net")]
465sockopt_impl!(
466 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
467 #[allow(missing_docs)]
468 OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
470#[cfg(any(target_os = "android", target_os = "linux"))]
471sockopt_impl!(
472 #[allow(missing_docs)]
473 Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6);
475#[cfg(any(target_os = "linux"))]
476sockopt_impl!(
477 Timestamping, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPING, super::TimestampingFlag);
480sockopt_impl!(
481 ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
483#[cfg(all(target_os = "linux"))]
484sockopt_impl!(
485 ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool);
487#[cfg(any(target_os = "android", target_os = "linux"))]
488#[cfg(feature = "net")]
489sockopt_impl!(
490 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
491 IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
493#[cfg(target_os = "openbsd")]
494#[cfg(feature = "net")]
495sockopt_impl!(
496 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
497 BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
500#[cfg(target_os = "freebsd")]
501#[cfg(feature = "net")]
502sockopt_impl!(
503 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
504 BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
507#[cfg(target_os = "linux")]
508sockopt_impl!(
509 Mark, Both, libc::SOL_SOCKET, libc::SO_MARK, u32);
512#[cfg(any(target_os = "android", target_os = "linux"))]
513sockopt_impl!(
514 PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
517#[cfg(any(target_os = "freebsd", target_os = "linux"))]
518#[cfg(feature = "net")]
519sockopt_impl!(
520 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
521 TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
524#[cfg(any(
525 target_os = "android",
526 target_os = "ios",
527 target_os = "linux",
528 target_os = "macos",
529 target_os = "netbsd",
530))]
531#[cfg(feature = "net")]
532sockopt_impl!(
533 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
534 Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
537#[cfg(any(
538 target_os = "android",
539 target_os = "freebsd",
540 target_os = "ios",
541 target_os = "linux",
542 target_os = "macos",
543 target_os = "netbsd",
544 target_os = "openbsd",
545))]
546#[cfg(feature = "net")]
547sockopt_impl!(
548 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
549 Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
552#[cfg(any(
553 target_os = "freebsd",
554 target_os = "ios",
555 target_os = "macos",
556 target_os = "netbsd",
557 target_os = "openbsd",
558))]
559#[cfg(feature = "net")]
560sockopt_impl!(
561 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
562 Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
565#[cfg(any(
566 target_os = "freebsd",
567 target_os = "ios",
568 target_os = "macos",
569 target_os = "netbsd",
570 target_os = "openbsd",
571))]
572#[cfg(feature = "net")]
573sockopt_impl!(
574 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
575 Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
578#[cfg(target_os = "linux")]
579#[cfg(feature = "net")]
580sockopt_impl!(
581 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
582 #[allow(missing_docs)]
583 UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
585#[cfg(target_os = "linux")]
586#[cfg(feature = "net")]
587sockopt_impl!(
588 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
589 #[allow(missing_docs)]
590 UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
592#[cfg(target_os = "linux")]
593sockopt_impl!(
594 TxTime, Both, libc::SOL_SOCKET, libc::SO_TXTIME, libc::sock_txtime);
597#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
598sockopt_impl!(
599 RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int);
603#[cfg(feature = "net")]
604sockopt_impl!(
605 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
606 Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool);
608#[cfg(any(target_os = "android", target_os = "linux"))]
609sockopt_impl!(
610 Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool);
612#[cfg(any(target_os = "android", target_os = "linux"))]
613sockopt_impl!(
614 Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool);
616#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
617sockopt_impl!(
618 Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int);
621#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
622sockopt_impl!(
623 Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int);
625#[cfg(any(target_os = "ios", target_os = "macos"))]
626sockopt_impl!(
627 IpDontFrag, Both, libc::IPPROTO_IP, libc::IP_DONTFRAG, bool);
629#[cfg(any(
630 target_os = "android",
631 target_os = "ios",
632 target_os = "linux",
633 target_os = "macos",
634))]
635sockopt_impl!(
636 Ipv6DontFrag, Both, libc::IPPROTO_IPV6, libc::IPV6_DONTFRAG, bool);
638
639#[allow(missing_docs)]
640#[cfg(any(target_os = "android", target_os = "linux"))]
642#[derive(Copy, Clone, Debug)]
643pub struct AlgSetAeadAuthSize;
644
645#[cfg(any(target_os = "android", target_os = "linux"))]
648impl SetSockOpt for AlgSetAeadAuthSize {
649 type Val = usize;
650
651 fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
652 unsafe {
653 let res = libc::setsockopt(fd,
654 libc::SOL_ALG,
655 libc::ALG_SET_AEAD_AUTHSIZE,
656 ::std::ptr::null(),
657 *val as libc::socklen_t);
658 Errno::result(res).map(drop)
659 }
660 }
661}
662
663#[allow(missing_docs)]
664#[cfg(any(target_os = "android", target_os = "linux"))]
666#[derive(Clone, Debug)]
667pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
668
669#[cfg(any(target_os = "android", target_os = "linux"))]
670impl<T> Default for AlgSetKey<T> {
671 fn default() -> Self {
672 AlgSetKey(Default::default())
673 }
674}
675
676#[cfg(any(target_os = "android", target_os = "linux"))]
677impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
678 type Val = T;
679
680 fn set(&self, fd: RawFd, val: &T) -> Result<()> {
681 unsafe {
682 let res = libc::setsockopt(fd,
683 libc::SOL_ALG,
684 libc::ALG_SET_KEY,
685 val.as_ref().as_ptr() as *const _,
686 val.as_ref().len() as libc::socklen_t);
687 Errno::result(res).map(drop)
688 }
689 }
690}
691
692trait Get<T> {
700 fn uninit() -> Self;
702 fn ffi_ptr(&mut self) -> *mut c_void;
705 fn ffi_len(&mut self) -> *mut socklen_t;
708 unsafe fn assume_init(self) -> T;
710}
711
712trait Set<'a, T> {
714 fn new(val: &'a T) -> Self;
716 fn ffi_ptr(&self) -> *const c_void;
719 fn ffi_len(&self) -> socklen_t;
722}
723
724struct GetStruct<T> {
726 len: socklen_t,
727 val: MaybeUninit<T>,
728}
729
730impl<T> Get<T> for GetStruct<T> {
731 fn uninit() -> Self {
732 GetStruct {
733 len: mem::size_of::<T>() as socklen_t,
734 val: MaybeUninit::uninit(),
735 }
736 }
737
738 fn ffi_ptr(&mut self) -> *mut c_void {
739 self.val.as_mut_ptr() as *mut c_void
740 }
741
742 fn ffi_len(&mut self) -> *mut socklen_t {
743 &mut self.len
744 }
745
746 unsafe fn assume_init(self) -> T {
747 assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
748 self.val.assume_init()
749 }
750}
751
752struct SetStruct<'a, T: 'static> {
754 ptr: &'a T,
755}
756
757impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
758 fn new(ptr: &'a T) -> SetStruct<'a, T> {
759 SetStruct { ptr }
760 }
761
762 fn ffi_ptr(&self) -> *const c_void {
763 self.ptr as *const T as *const c_void
764 }
765
766 fn ffi_len(&self) -> socklen_t {
767 mem::size_of::<T>() as socklen_t
768 }
769}
770
771struct GetBool {
773 len: socklen_t,
774 val: MaybeUninit<c_int>,
775}
776
777impl Get<bool> for GetBool {
778 fn uninit() -> Self {
779 GetBool {
780 len: mem::size_of::<c_int>() as socklen_t,
781 val: MaybeUninit::uninit(),
782 }
783 }
784
785 fn ffi_ptr(&mut self) -> *mut c_void {
786 self.val.as_mut_ptr() as *mut c_void
787 }
788
789 fn ffi_len(&mut self) -> *mut socklen_t {
790 &mut self.len
791 }
792
793 unsafe fn assume_init(self) -> bool {
794 assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
795 self.val.assume_init() != 0
796 }
797}
798
799struct SetBool {
801 val: c_int,
802}
803
804impl<'a> Set<'a, bool> for SetBool {
805 fn new(val: &'a bool) -> SetBool {
806 SetBool { val: i32::from(*val) }
807 }
808
809 fn ffi_ptr(&self) -> *const c_void {
810 &self.val as *const c_int as *const c_void
811 }
812
813 fn ffi_len(&self) -> socklen_t {
814 mem::size_of::<c_int>() as socklen_t
815 }
816}
817
818struct GetU8 {
820 len: socklen_t,
821 val: MaybeUninit<u8>,
822}
823
824impl Get<u8> for GetU8 {
825 fn uninit() -> Self {
826 GetU8 {
827 len: mem::size_of::<u8>() as socklen_t,
828 val: MaybeUninit::uninit(),
829 }
830 }
831
832 fn ffi_ptr(&mut self) -> *mut c_void {
833 self.val.as_mut_ptr() as *mut c_void
834 }
835
836 fn ffi_len(&mut self) -> *mut socklen_t {
837 &mut self.len
838 }
839
840 unsafe fn assume_init(self) -> u8 {
841 assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
842 self.val.assume_init()
843 }
844}
845
846struct SetU8 {
848 val: u8,
849}
850
851impl<'a> Set<'a, u8> for SetU8 {
852 fn new(val: &'a u8) -> SetU8 {
853 SetU8 { val: *val }
854 }
855
856 fn ffi_ptr(&self) -> *const c_void {
857 &self.val as *const u8 as *const c_void
858 }
859
860 fn ffi_len(&self) -> socklen_t {
861 mem::size_of::<c_int>() as socklen_t
862 }
863}
864
865struct GetUsize {
867 len: socklen_t,
868 val: MaybeUninit<c_int>,
869}
870
871impl Get<usize> for GetUsize {
872 fn uninit() -> Self {
873 GetUsize {
874 len: mem::size_of::<c_int>() as socklen_t,
875 val: MaybeUninit::uninit(),
876 }
877 }
878
879 fn ffi_ptr(&mut self) -> *mut c_void {
880 self.val.as_mut_ptr() as *mut c_void
881 }
882
883 fn ffi_len(&mut self) -> *mut socklen_t {
884 &mut self.len
885 }
886
887 unsafe fn assume_init(self) -> usize {
888 assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
889 self.val.assume_init() as usize
890 }
891}
892
893struct SetUsize {
895 val: c_int,
896}
897
898impl<'a> Set<'a, usize> for SetUsize {
899 fn new(val: &'a usize) -> SetUsize {
900 SetUsize { val: *val as c_int }
901 }
902
903 fn ffi_ptr(&self) -> *const c_void {
904 &self.val as *const c_int as *const c_void
905 }
906
907 fn ffi_len(&self) -> socklen_t {
908 mem::size_of::<c_int>() as socklen_t
909 }
910}
911
912struct GetOsString<T: AsMut<[u8]>> {
914 len: socklen_t,
915 val: MaybeUninit<T>,
916}
917
918impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
919 fn uninit() -> Self {
920 GetOsString {
921 len: mem::size_of::<T>() as socklen_t,
922 val: MaybeUninit::uninit(),
923 }
924 }
925
926 fn ffi_ptr(&mut self) -> *mut c_void {
927 self.val.as_mut_ptr() as *mut c_void
928 }
929
930 fn ffi_len(&mut self) -> *mut socklen_t {
931 &mut self.len
932 }
933
934 unsafe fn assume_init(self) -> OsString {
935 let len = self.len as usize;
936 let mut v = self.val.assume_init();
937 OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
938 }
939}
940
941struct SetOsString<'a> {
943 val: &'a OsStr,
944}
945
946impl<'a> Set<'a, OsString> for SetOsString<'a> {
947 fn new(val: &'a OsString) -> SetOsString {
948 SetOsString { val: val.as_os_str() }
949 }
950
951 fn ffi_ptr(&self) -> *const c_void {
952 self.val.as_bytes().as_ptr() as *const c_void
953 }
954
955 fn ffi_len(&self) -> socklen_t {
956 self.val.len() as socklen_t
957 }
958}
959
960
961#[cfg(test)]
962mod test {
963 #[cfg(any(target_os = "android", target_os = "linux"))]
964 #[test]
965 fn can_get_peercred_on_unix_socket() {
966 use super::super::*;
967
968 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
969 let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
970 let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
971 assert_eq!(a_cred, b_cred);
972 assert!(a_cred.pid() != 0);
973 }
974
975 #[test]
976 fn is_socket_type_unix() {
977 use super::super::*;
978 use crate::unistd::close;
979
980 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
981 let a_type = getsockopt(a, super::SockType).unwrap();
982 assert_eq!(a_type, SockType::Stream);
983 close(a).unwrap();
984 close(b).unwrap();
985 }
986
987 #[test]
988 fn is_socket_type_dgram() {
989 use super::super::*;
990 use crate::unistd::close;
991
992 let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
993 let s_type = getsockopt(s, super::SockType).unwrap();
994 assert_eq!(s_type, SockType::Datagram);
995 close(s).unwrap();
996 }
997
998 #[cfg(any(target_os = "freebsd",
999 target_os = "linux",
1000 target_os = "nacl"))]
1001 #[test]
1002 fn can_get_listen_on_tcp_socket() {
1003 use super::super::*;
1004 use crate::unistd::close;
1005
1006 let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
1007 let s_listening = getsockopt(s, super::AcceptConn).unwrap();
1008 assert!(!s_listening);
1009 listen(s, 10).unwrap();
1010 let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
1011 assert!(s_listening2);
1012 close(s).unwrap();
1013 }
1014
1015}