1 use cfg_if::cfg_if;
2 use super::{GetSockOpt, SetSockOpt};
3 use crate::Result;
4 use crate::errno::Errno;
5 use crate::sys::time::TimeVal;
6 use libc::{self, c_int, c_void, socklen_t};
7 use std::mem::{
8     self,
9     MaybeUninit
10 };
11 use std::os::unix::io::RawFd;
12 use std::ffi::{OsStr, OsString};
13 #[cfg(target_family = "unix")]
14 use std::os::unix::ffi::OsStrExt;
15 
16 // Constants
17 // TCP_CA_NAME_MAX isn't defined in user space include files
18 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
19 const TCP_CA_NAME_MAX: usize = 16;
20 
21 /// Helper for implementing `SetSockOpt` for a given socket option. See
22 /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
23 ///
24 /// This macro aims to help implementing `SetSockOpt` for different socket options that accept
25 /// different kinds of data to be used with `setsockopt`.
26 ///
27 /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
28 /// you are implementing represents a simple type.
29 ///
30 /// # Arguments
31 ///
32 /// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
33 /// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
34 ///    (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
35 ///    and more. Please refer to your system manual for more options. Will be passed as the second
36 ///    argument (`level`) to the `setsockopt` call.
37 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
38 ///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
39 ///    to the `setsockopt` call.
40 /// * Type of the value that you are going to set.
41 /// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
42 ///    `bool`, `SetUsize` for `usize`, etc.).
43 macro_rules! setsockopt_impl {
44     ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
45         impl SetSockOpt for $name {
46             type Val = $ty;
47 
48             fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
49                 unsafe {
50                     let setter: $setter = Set::new(val);
51 
52                     let res = libc::setsockopt(fd, $level, $flag,
53                                                setter.ffi_ptr(),
54                                                setter.ffi_len());
55                     Errno::result(res).map(drop)
56                 }
57             }
58         }
59     }
60 }
61 
62 /// Helper for implementing `GetSockOpt` for a given socket option. See
63 /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
64 ///
65 /// This macro aims to help implementing `GetSockOpt` for different socket options that accept
66 /// different kinds of data to be use with `getsockopt`.
67 ///
68 /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
69 /// you are implementing represents a simple type.
70 ///
71 /// # Arguments
72 ///
73 /// * Name of the type you want to implement `GetSockOpt` for.
74 /// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`),  *ip
75 ///    protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),  and more. Please refer
76 ///    to your system manual for more options. Will be passed as the second argument (`level`) to
77 ///    the `getsockopt` call.
78 /// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
79 ///    `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
80 ///    the `getsockopt` call.
81 /// * Type of the value that you are going to get.
82 /// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
83 ///    `bool`, `GetUsize` for `usize`, etc.).
84 macro_rules! getsockopt_impl {
85     ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
86         impl GetSockOpt for $name {
87             type Val = $ty;
88 
89             fn get(&self, fd: RawFd) -> Result<$ty> {
90                 unsafe {
91                     let mut getter: $getter = Get::uninit();
92 
93                     let res = libc::getsockopt(fd, $level, $flag,
94                                                getter.ffi_ptr(),
95                                                getter.ffi_len());
96                     Errno::result(res)?;
97 
98                     Ok(getter.assume_init())
99                 }
100             }
101         }
102     }
103 }
104 
105 /// Helper to generate the sockopt accessors. See
106 /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
107 /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
108 ///
109 /// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
110 /// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
111 ///
112 /// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
113 /// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
114 ///
115 /// # Arguments
116 ///
117 /// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
118 ///    both of them.
119 /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
120 /// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
121 ///    (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
122 ///    and more. Please refer to your system manual for more options. Will be passed as the second
123 ///    argument (`level`) to the `getsockopt`/`setsockopt` call.
124 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
125 ///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
126 ///    to the `setsockopt`/`getsockopt` call.
127 /// * `$ty:ty`: type of the value that will be get/set.
128 /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
129 /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
130 macro_rules! sockopt_impl {
131     (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
132         sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
133     };
134 
135     (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
136         sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
137     };
138 
139     (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
140         sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
141     };
142 
143     (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
144         sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
145     };
146 
147     (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
148         sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
149     };
150 
151     (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
152         sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
153     };
154 
155     (Both, $name:ident, $level:path, $flag:path, bool) => {
156         sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
157     };
158 
159     (Both, $name:ident, $level:path, $flag:path, u8) => {
160         sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
161     };
162 
163     (Both, $name:ident, $level:path, $flag:path, usize) => {
164         sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
165     };
166 
167     (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
168         sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
169     };
170 
171     /*
172      * Matchers with generic getter types must be placed at the end, so
173      * they'll only match _after_ specialized matchers fail
174      */
175     (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
176         sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
177     };
178 
179     (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
180         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
181         pub struct $name;
182 
183         getsockopt_impl!($name, $level, $flag, $ty, $getter);
184     };
185 
186     (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
187         sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
188     };
189 
190     (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
191         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
192         pub struct $name;
193 
194         setsockopt_impl!($name, $level, $flag, $ty, $setter);
195     };
196 
197     (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
198         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
199         pub struct $name;
200 
201         setsockopt_impl!($name, $level, $flag, $ty, $setter);
202         getsockopt_impl!($name, $level, $flag, $ty, $getter);
203     };
204 
205     (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
206         sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
207     };
208 }
209 
210 /*
211  *
212  * ===== Define sockopts =====
213  *
214  */
215 
216 sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool);
217 sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
218 sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
219 sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
220 sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest);
221 sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest);
222 cfg_if! {
223     if #[cfg(any(target_os = "android", target_os = "linux"))] {
224         sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
225         sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
226     } else if #[cfg(any(target_os = "dragonfly",
227                         target_os = "freebsd",
228                         target_os = "ios",
229                         target_os = "macos",
230                         target_os = "netbsd",
231                         target_os = "openbsd"))] {
232         sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
233         sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
234     }
235 }
236 sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
237 sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
238 sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
239 sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
240 sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
241 sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
242 sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32);
243 sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
244 #[cfg(any(target_os = "android", target_os = "linux"))]
245 sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
246 #[cfg(any(target_os = "ios",
247           target_os = "macos"))]
248 sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
249 #[cfg(any(target_os = "android",
250           target_os = "dragonfly",
251           target_os = "freebsd",
252           target_os = "linux",
253           target_os = "nacl"))]
254 sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
255 #[cfg(not(target_os = "openbsd"))]
256 sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
257 #[cfg(not(target_os = "openbsd"))]
258 sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
259 sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
260 sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
261 #[cfg(any(target_os = "android", target_os = "linux"))]
262 sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
263 #[cfg(any(target_os = "android", target_os = "linux"))]
264 sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
265 sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
266 sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
267 #[cfg(any(target_os = "android", target_os = "linux"))]
268 sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
269 #[cfg(any(target_os = "android", target_os = "linux"))]
270 sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
271 sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
272 #[cfg(any(target_os = "android", target_os = "linux"))]
273 sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
274 #[cfg(target_os = "openbsd")]
275 sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
276 #[cfg(target_os = "freebsd")]
277 sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
278 #[cfg(target_os = "linux")]
279 sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
280 #[cfg(any(target_os = "android", target_os = "linux"))]
281 sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
282 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
283 sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
284 #[cfg(any(
285     target_os = "android",
286     target_os = "ios",
287     target_os = "linux",
288     target_os = "macos",
289     target_os = "netbsd",
290 ))]
291 sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
292 #[cfg(any(
293     target_os = "android",
294     target_os = "freebsd",
295     target_os = "ios",
296     target_os = "linux",
297     target_os = "macos",
298     target_os = "netbsd",
299     target_os = "openbsd",
300 ))]
301 sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
302 #[cfg(any(
303     target_os = "freebsd",
304     target_os = "ios",
305     target_os = "macos",
306     target_os = "netbsd",
307     target_os = "openbsd",
308 ))]
309 sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
310 #[cfg(any(
311     target_os = "freebsd",
312     target_os = "ios",
313     target_os = "macos",
314     target_os = "netbsd",
315     target_os = "openbsd",
316 ))]
317 sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
318 #[cfg(target_os = "linux")]
319 sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
320 #[cfg(target_os = "linux")]
321 sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
322 
323 #[cfg(any(target_os = "android", target_os = "linux"))]
324 #[derive(Copy, Clone, Debug)]
325 pub struct AlgSetAeadAuthSize;
326 
327 // ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
328 // See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
329 #[cfg(any(target_os = "android", target_os = "linux"))]
330 impl SetSockOpt for AlgSetAeadAuthSize {
331     type Val = usize;
332 
set(&self, fd: RawFd, val: &usize) -> Result<()>333     fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
334         unsafe {
335             let res = libc::setsockopt(fd,
336                                        libc::SOL_ALG,
337                                        libc::ALG_SET_AEAD_AUTHSIZE,
338                                        ::std::ptr::null(),
339                                        *val as libc::socklen_t);
340             Errno::result(res).map(drop)
341         }
342     }
343 }
344 
345 #[cfg(any(target_os = "android", target_os = "linux"))]
346 #[derive(Clone, Debug)]
347 pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
348 
349 #[cfg(any(target_os = "android", target_os = "linux"))]
350 impl<T> Default for AlgSetKey<T> {
default() -> Self351     fn default() -> Self {
352         AlgSetKey(Default::default())
353     }
354 }
355 
356 #[cfg(any(target_os = "android", target_os = "linux"))]
357 impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
358     type Val = T;
359 
set(&self, fd: RawFd, val: &T) -> Result<()>360     fn set(&self, fd: RawFd, val: &T) -> Result<()> {
361         unsafe {
362             let res = libc::setsockopt(fd,
363                                        libc::SOL_ALG,
364                                        libc::ALG_SET_KEY,
365                                        val.as_ref().as_ptr() as *const _,
366                                        val.as_ref().len() as libc::socklen_t);
367             Errno::result(res).map(drop)
368         }
369     }
370 }
371 
372 /*
373  *
374  * ===== Accessor helpers =====
375  *
376  */
377 
378 /// Helper trait that describes what is expected from a `GetSockOpt` getter.
379 unsafe trait Get<T> {
380     /// Returns an uninitialized value.
uninit() -> Self381     unsafe fn uninit() -> Self;
382     /// Returns a pointer to the stored value. This pointer will be passed to the system's
383     /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
ffi_ptr(&mut self) -> *mut c_void384     fn ffi_ptr(&mut self) -> *mut c_void;
385     /// Returns length of the stored value. This pointer will be passed to the system's
386     /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
ffi_len(&mut self) -> *mut socklen_t387     fn ffi_len(&mut self) -> *mut socklen_t;
388     /// Returns the hopefully initialized inner value.
assume_init(self) -> T389     unsafe fn assume_init(self) -> T;
390 }
391 
392 /// Helper trait that describes what is expected from a `SetSockOpt` setter.
393 unsafe trait Set<'a, T> {
394     /// Initialize the setter with a given value.
new(val: &'a T) -> Self395     fn new(val: &'a T) -> Self;
396     /// Returns a pointer to the stored value. This pointer will be passed to the system's
397     /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
ffi_ptr(&self) -> *const c_void398     fn ffi_ptr(&self) -> *const c_void;
399     /// Returns length of the stored value. This pointer will be passed to the system's
400     /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
ffi_len(&self) -> socklen_t401     fn ffi_len(&self) -> socklen_t;
402 }
403 
404 /// Getter for an arbitrary `struct`.
405 struct GetStruct<T> {
406     len: socklen_t,
407     val: MaybeUninit<T>,
408 }
409 
410 unsafe impl<T> Get<T> for GetStruct<T> {
uninit() -> Self411     unsafe fn uninit() -> Self {
412         GetStruct {
413             len: mem::size_of::<T>() as socklen_t,
414             val: MaybeUninit::uninit(),
415         }
416     }
417 
ffi_ptr(&mut self) -> *mut c_void418     fn ffi_ptr(&mut self) -> *mut c_void {
419         self.val.as_mut_ptr() as *mut c_void
420     }
421 
ffi_len(&mut self) -> *mut socklen_t422     fn ffi_len(&mut self) -> *mut socklen_t {
423         &mut self.len
424     }
425 
assume_init(self) -> T426     unsafe fn assume_init(self) -> T {
427         assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
428         self.val.assume_init()
429     }
430 }
431 
432 /// Setter for an arbitrary `struct`.
433 struct SetStruct<'a, T: 'static> {
434     ptr: &'a T,
435 }
436 
437 unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
new(ptr: &'a T) -> SetStruct<'a, T>438     fn new(ptr: &'a T) -> SetStruct<'a, T> {
439         SetStruct { ptr }
440     }
441 
ffi_ptr(&self) -> *const c_void442     fn ffi_ptr(&self) -> *const c_void {
443         self.ptr as *const T as *const c_void
444     }
445 
ffi_len(&self) -> socklen_t446     fn ffi_len(&self) -> socklen_t {
447         mem::size_of::<T>() as socklen_t
448     }
449 }
450 
451 /// Getter for a boolean value.
452 struct GetBool {
453     len: socklen_t,
454     val: MaybeUninit<c_int>,
455 }
456 
457 unsafe impl Get<bool> for GetBool {
uninit() -> Self458     unsafe fn uninit() -> Self {
459         GetBool {
460             len: mem::size_of::<c_int>() as socklen_t,
461             val: MaybeUninit::uninit(),
462         }
463     }
464 
ffi_ptr(&mut self) -> *mut c_void465     fn ffi_ptr(&mut self) -> *mut c_void {
466         self.val.as_mut_ptr() as *mut c_void
467     }
468 
ffi_len(&mut self) -> *mut socklen_t469     fn ffi_len(&mut self) -> *mut socklen_t {
470         &mut self.len
471     }
472 
assume_init(self) -> bool473     unsafe fn assume_init(self) -> bool {
474         assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
475         self.val.assume_init() != 0
476     }
477 }
478 
479 /// Setter for a boolean value.
480 struct SetBool {
481     val: c_int,
482 }
483 
484 unsafe impl<'a> Set<'a, bool> for SetBool {
new(val: &'a bool) -> SetBool485     fn new(val: &'a bool) -> SetBool {
486         SetBool { val: if *val { 1 } else { 0 } }
487     }
488 
ffi_ptr(&self) -> *const c_void489     fn ffi_ptr(&self) -> *const c_void {
490         &self.val as *const c_int as *const c_void
491     }
492 
ffi_len(&self) -> socklen_t493     fn ffi_len(&self) -> socklen_t {
494         mem::size_of::<c_int>() as socklen_t
495     }
496 }
497 
498 /// Getter for an `u8` value.
499 struct GetU8 {
500     len: socklen_t,
501     val: MaybeUninit<u8>,
502 }
503 
504 unsafe impl Get<u8> for GetU8 {
uninit() -> Self505     unsafe fn uninit() -> Self {
506         GetU8 {
507             len: mem::size_of::<u8>() as socklen_t,
508             val: MaybeUninit::uninit(),
509         }
510     }
511 
ffi_ptr(&mut self) -> *mut c_void512     fn ffi_ptr(&mut self) -> *mut c_void {
513         self.val.as_mut_ptr() as *mut c_void
514     }
515 
ffi_len(&mut self) -> *mut socklen_t516     fn ffi_len(&mut self) -> *mut socklen_t {
517         &mut self.len
518     }
519 
assume_init(self) -> u8520     unsafe fn assume_init(self) -> u8 {
521         assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
522         self.val.assume_init()
523     }
524 }
525 
526 /// Setter for an `u8` value.
527 struct SetU8 {
528     val: u8,
529 }
530 
531 unsafe impl<'a> Set<'a, u8> for SetU8 {
new(val: &'a u8) -> SetU8532     fn new(val: &'a u8) -> SetU8 {
533         SetU8 { val: *val as u8 }
534     }
535 
ffi_ptr(&self) -> *const c_void536     fn ffi_ptr(&self) -> *const c_void {
537         &self.val as *const u8 as *const c_void
538     }
539 
ffi_len(&self) -> socklen_t540     fn ffi_len(&self) -> socklen_t {
541         mem::size_of::<c_int>() as socklen_t
542     }
543 }
544 
545 /// Getter for an `usize` value.
546 struct GetUsize {
547     len: socklen_t,
548     val: MaybeUninit<c_int>,
549 }
550 
551 unsafe impl Get<usize> for GetUsize {
uninit() -> Self552     unsafe fn uninit() -> Self {
553         GetUsize {
554             len: mem::size_of::<c_int>() as socklen_t,
555             val: MaybeUninit::uninit(),
556         }
557     }
558 
ffi_ptr(&mut self) -> *mut c_void559     fn ffi_ptr(&mut self) -> *mut c_void {
560         self.val.as_mut_ptr() as *mut c_void
561     }
562 
ffi_len(&mut self) -> *mut socklen_t563     fn ffi_len(&mut self) -> *mut socklen_t {
564         &mut self.len
565     }
566 
assume_init(self) -> usize567     unsafe fn assume_init(self) -> usize {
568         assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
569         self.val.assume_init() as usize
570     }
571 }
572 
573 /// Setter for an `usize` value.
574 struct SetUsize {
575     val: c_int,
576 }
577 
578 unsafe impl<'a> Set<'a, usize> for SetUsize {
new(val: &'a usize) -> SetUsize579     fn new(val: &'a usize) -> SetUsize {
580         SetUsize { val: *val as c_int }
581     }
582 
ffi_ptr(&self) -> *const c_void583     fn ffi_ptr(&self) -> *const c_void {
584         &self.val as *const c_int as *const c_void
585     }
586 
ffi_len(&self) -> socklen_t587     fn ffi_len(&self) -> socklen_t {
588         mem::size_of::<c_int>() as socklen_t
589     }
590 }
591 
592 /// Getter for a `OsString` value.
593 struct GetOsString<T: AsMut<[u8]>> {
594     len: socklen_t,
595     val: MaybeUninit<T>,
596 }
597 
598 unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
uninit() -> Self599     unsafe fn uninit() -> Self {
600         GetOsString {
601             len: mem::size_of::<T>() as socklen_t,
602             val: MaybeUninit::uninit(),
603         }
604     }
605 
ffi_ptr(&mut self) -> *mut c_void606     fn ffi_ptr(&mut self) -> *mut c_void {
607         self.val.as_mut_ptr() as *mut c_void
608     }
609 
ffi_len(&mut self) -> *mut socklen_t610     fn ffi_len(&mut self) -> *mut socklen_t {
611         &mut self.len
612     }
613 
assume_init(self) -> OsString614     unsafe fn assume_init(self) -> OsString {
615         let len = self.len as usize;
616         let mut v = self.val.assume_init();
617         OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
618     }
619 }
620 
621 /// Setter for a `OsString` value.
622 struct SetOsString<'a> {
623     val: &'a OsStr,
624 }
625 
626 unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
new(val: &'a OsString) -> SetOsString627     fn new(val: &'a OsString) -> SetOsString {
628         SetOsString { val: val.as_os_str() }
629     }
630 
ffi_ptr(&self) -> *const c_void631     fn ffi_ptr(&self) -> *const c_void {
632         self.val.as_bytes().as_ptr() as *const c_void
633     }
634 
ffi_len(&self) -> socklen_t635     fn ffi_len(&self) -> socklen_t {
636         self.val.len() as socklen_t
637     }
638 }
639 
640 
641 #[cfg(test)]
642 mod test {
643     #[cfg(any(target_os = "android", target_os = "linux"))]
644     #[test]
can_get_peercred_on_unix_socket()645     fn can_get_peercred_on_unix_socket() {
646         use super::super::*;
647 
648         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
649         let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
650         let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
651         assert_eq!(a_cred, b_cred);
652         assert!(a_cred.pid() != 0);
653     }
654 
655     #[test]
is_socket_type_unix()656     fn is_socket_type_unix() {
657         use super::super::*;
658         use crate::unistd::close;
659 
660         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
661         let a_type = getsockopt(a, super::SockType).unwrap();
662         assert_eq!(a_type, SockType::Stream);
663         close(a).unwrap();
664         close(b).unwrap();
665     }
666 
667     #[test]
is_socket_type_dgram()668     fn is_socket_type_dgram() {
669         use super::super::*;
670         use crate::unistd::close;
671 
672         let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
673         let s_type = getsockopt(s, super::SockType).unwrap();
674         assert_eq!(s_type, SockType::Datagram);
675         close(s).unwrap();
676     }
677 
678     #[cfg(any(target_os = "freebsd",
679               target_os = "linux",
680               target_os = "nacl"))]
681     #[test]
can_get_listen_on_tcp_socket()682     fn can_get_listen_on_tcp_socket() {
683         use super::super::*;
684         use crate::unistd::close;
685 
686         let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
687         let s_listening = getsockopt(s, super::AcceptConn).unwrap();
688         assert!(!s_listening);
689         listen(s, 10).unwrap();
690         let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
691         assert!(s_listening2);
692         close(s).unwrap();
693     }
694 
695 }
696