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