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(Copy, Clone, Debug)]
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(Copy, Clone, Debug)]
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(Copy, Clone, Debug)]
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 ))]
280 sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
281 #[cfg(any(
282     target_os = "android",
283     target_os = "freebsd",
284     target_os = "ios",
285     target_os = "linux",
286     target_os = "macos"
287 ))]
288 sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
289 
290 
291 /*
292  *
293  * ===== Accessor helpers =====
294  *
295  */
296 
297 /// Helper trait that describes what is expected from a `GetSockOpt` getter.
298 unsafe trait Get<T> {
299     /// Returns an empty value.
blank() -> Self300     unsafe fn blank() -> Self;
301     /// Returns a pointer to the stored value. This pointer will be passed to the system's
302     /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
ffi_ptr(&mut self) -> *mut c_void303     fn ffi_ptr(&mut self) -> *mut c_void;
304     /// Returns length of the stored value. This pointer will be passed to the system's
305     /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
ffi_len(&mut self) -> *mut socklen_t306     fn ffi_len(&mut self) -> *mut socklen_t;
307     /// Returns the stored value.
unwrap(self) -> T308     unsafe fn unwrap(self) -> T;
309 }
310 
311 /// Helper trait that describes what is expected from a `SetSockOpt` setter.
312 unsafe trait Set<'a, T> {
313     /// Initialize the setter with a given value.
new(val: &'a T) -> Self314     fn new(val: &'a T) -> Self;
315     /// Returns a pointer to the stored value. This pointer will be passed to the system's
316     /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
ffi_ptr(&self) -> *const c_void317     fn ffi_ptr(&self) -> *const c_void;
318     /// Returns length of the stored value. This pointer will be passed to the system's
319     /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
ffi_len(&self) -> socklen_t320     fn ffi_len(&self) -> socklen_t;
321 }
322 
323 /// Getter for an arbitrary `struct`.
324 struct GetStruct<T> {
325     len: socklen_t,
326     val: T,
327 }
328 
329 unsafe impl<T> Get<T> for GetStruct<T> {
blank() -> Self330     unsafe fn blank() -> Self {
331         GetStruct {
332             len: mem::size_of::<T>() as socklen_t,
333             val: mem::zeroed(),
334         }
335     }
336 
ffi_ptr(&mut self) -> *mut c_void337     fn ffi_ptr(&mut self) -> *mut c_void {
338         &mut self.val as *mut T as *mut c_void
339     }
340 
ffi_len(&mut self) -> *mut socklen_t341     fn ffi_len(&mut self) -> *mut socklen_t {
342         &mut self.len
343     }
344 
unwrap(self) -> T345     unsafe fn unwrap(self) -> T {
346         assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
347         self.val
348     }
349 }
350 
351 /// Setter for an arbitrary `struct`.
352 struct SetStruct<'a, T: 'static> {
353     ptr: &'a T,
354 }
355 
356 unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
new(ptr: &'a T) -> SetStruct<'a, T>357     fn new(ptr: &'a T) -> SetStruct<'a, T> {
358         SetStruct { ptr: ptr }
359     }
360 
ffi_ptr(&self) -> *const c_void361     fn ffi_ptr(&self) -> *const c_void {
362         self.ptr as *const T as *const c_void
363     }
364 
ffi_len(&self) -> socklen_t365     fn ffi_len(&self) -> socklen_t {
366         mem::size_of::<T>() as socklen_t
367     }
368 }
369 
370 /// Getter for a boolean value.
371 struct GetBool {
372     len: socklen_t,
373     val: c_int,
374 }
375 
376 unsafe impl Get<bool> for GetBool {
blank() -> Self377     unsafe fn blank() -> Self {
378         GetBool {
379             len: mem::size_of::<c_int>() as socklen_t,
380             val: mem::zeroed(),
381         }
382     }
383 
ffi_ptr(&mut self) -> *mut c_void384     fn ffi_ptr(&mut self) -> *mut c_void {
385         &mut self.val as *mut c_int as *mut c_void
386     }
387 
ffi_len(&mut self) -> *mut socklen_t388     fn ffi_len(&mut self) -> *mut socklen_t {
389         &mut self.len
390     }
391 
unwrap(self) -> bool392     unsafe fn unwrap(self) -> bool {
393         assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
394         self.val != 0
395     }
396 }
397 
398 /// Setter for a boolean value.
399 struct SetBool {
400     val: c_int,
401 }
402 
403 unsafe impl<'a> Set<'a, bool> for SetBool {
new(val: &'a bool) -> SetBool404     fn new(val: &'a bool) -> SetBool {
405         SetBool { val: if *val { 1 } else { 0 } }
406     }
407 
ffi_ptr(&self) -> *const c_void408     fn ffi_ptr(&self) -> *const c_void {
409         &self.val as *const c_int as *const c_void
410     }
411 
ffi_len(&self) -> socklen_t412     fn ffi_len(&self) -> socklen_t {
413         mem::size_of::<c_int>() as socklen_t
414     }
415 }
416 
417 /// Getter for an `u8` value.
418 struct GetU8 {
419     len: socklen_t,
420     val: u8,
421 }
422 
423 unsafe impl Get<u8> for GetU8 {
blank() -> Self424     unsafe fn blank() -> Self {
425         GetU8 {
426             len: mem::size_of::<u8>() as socklen_t,
427             val: mem::zeroed(),
428         }
429     }
430 
ffi_ptr(&mut self) -> *mut c_void431     fn ffi_ptr(&mut self) -> *mut c_void {
432         &mut self.val as *mut u8 as *mut c_void
433     }
434 
ffi_len(&mut self) -> *mut socklen_t435     fn ffi_len(&mut self) -> *mut socklen_t {
436         &mut self.len
437     }
438 
unwrap(self) -> u8439     unsafe fn unwrap(self) -> u8 {
440         assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
441         self.val as u8
442     }
443 }
444 
445 /// Setter for an `u8` value.
446 struct SetU8 {
447     val: u8,
448 }
449 
450 unsafe impl<'a> Set<'a, u8> for SetU8 {
new(val: &'a u8) -> SetU8451     fn new(val: &'a u8) -> SetU8 {
452         SetU8 { val: *val as u8 }
453     }
454 
ffi_ptr(&self) -> *const c_void455     fn ffi_ptr(&self) -> *const c_void {
456         &self.val as *const u8 as *const c_void
457     }
458 
ffi_len(&self) -> socklen_t459     fn ffi_len(&self) -> socklen_t {
460         mem::size_of::<c_int>() as socklen_t
461     }
462 }
463 
464 /// Getter for an `usize` value.
465 struct GetUsize {
466     len: socklen_t,
467     val: c_int,
468 }
469 
470 unsafe impl Get<usize> for GetUsize {
blank() -> Self471     unsafe fn blank() -> Self {
472         GetUsize {
473             len: mem::size_of::<c_int>() as socklen_t,
474             val: mem::zeroed(),
475         }
476     }
477 
ffi_ptr(&mut self) -> *mut c_void478     fn ffi_ptr(&mut self) -> *mut c_void {
479         &mut self.val as *mut c_int as *mut c_void
480     }
481 
ffi_len(&mut self) -> *mut socklen_t482     fn ffi_len(&mut self) -> *mut socklen_t {
483         &mut self.len
484     }
485 
unwrap(self) -> usize486     unsafe fn unwrap(self) -> usize {
487         assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
488         self.val as usize
489     }
490 }
491 
492 /// Setter for an `usize` value.
493 struct SetUsize {
494     val: c_int,
495 }
496 
497 unsafe impl<'a> Set<'a, usize> for SetUsize {
new(val: &'a usize) -> SetUsize498     fn new(val: &'a usize) -> SetUsize {
499         SetUsize { val: *val as c_int }
500     }
501 
ffi_ptr(&self) -> *const c_void502     fn ffi_ptr(&self) -> *const c_void {
503         &self.val as *const c_int as *const c_void
504     }
505 
ffi_len(&self) -> socklen_t506     fn ffi_len(&self) -> socklen_t {
507         mem::size_of::<c_int>() as socklen_t
508     }
509 }
510 
511 /// Getter for a `OsString` value.
512 struct GetOsString<T: AsMut<[u8]>> {
513     len: socklen_t,
514     val: T,
515 }
516 
517 unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
blank() -> Self518     unsafe fn blank() -> Self {
519         GetOsString {
520             len: mem::size_of::<T>() as socklen_t,
521             val: mem::zeroed(),
522         }
523     }
524 
ffi_ptr(&mut self) -> *mut c_void525     fn ffi_ptr(&mut self) -> *mut c_void {
526         &mut self.val as *mut T as *mut c_void
527     }
528 
ffi_len(&mut self) -> *mut socklen_t529     fn ffi_len(&mut self) -> *mut socklen_t {
530         &mut self.len
531     }
532 
unwrap(mut self) -> OsString533     unsafe fn unwrap(mut self) -> OsString {
534         OsStr::from_bytes(self.val.as_mut()).to_owned()
535     }
536 }
537 
538 /// Setter for a `OsString` value.
539 struct SetOsString<'a> {
540     val: &'a OsStr,
541 }
542 
543 unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
new(val: &'a OsString) -> SetOsString544     fn new(val: &'a OsString) -> SetOsString {
545         SetOsString { val: val.as_os_str() }
546     }
547 
ffi_ptr(&self) -> *const c_void548     fn ffi_ptr(&self) -> *const c_void {
549         self.val.as_bytes().as_ptr() as *const c_void
550     }
551 
ffi_len(&self) -> socklen_t552     fn ffi_len(&self) -> socklen_t {
553         self.val.len() as socklen_t
554     }
555 }
556 
557 
558 #[cfg(test)]
559 mod test {
560     #[cfg(any(target_os = "android", target_os = "linux"))]
561     #[test]
can_get_peercred_on_unix_socket()562     fn can_get_peercred_on_unix_socket() {
563         use super::super::*;
564 
565         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
566         let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
567         let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
568         assert_eq!(a_cred, b_cred);
569         assert!(a_cred.pid() != 0);
570     }
571 
572     #[test]
is_socket_type_unix()573     fn is_socket_type_unix() {
574         use super::super::*;
575         use ::unistd::close;
576 
577         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
578         let a_type = getsockopt(a, super::SockType).unwrap();
579         assert!(a_type == SockType::Stream);
580         close(a).unwrap();
581         close(b).unwrap();
582     }
583 
584     #[test]
is_socket_type_dgram()585     fn is_socket_type_dgram() {
586         use super::super::*;
587         use ::unistd::close;
588 
589         let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
590         let s_type = getsockopt(s, super::SockType).unwrap();
591         assert!(s_type == SockType::Datagram);
592         close(s).unwrap();
593     }
594 
595     #[cfg(any(target_os = "freebsd",
596               target_os = "linux",
597               target_os = "nacl"))]
598     #[test]
can_get_listen_on_tcp_socket()599     fn can_get_listen_on_tcp_socket() {
600         use super::super::*;
601         use ::unistd::close;
602 
603         let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
604         let s_listening = getsockopt(s, super::AcceptConn).unwrap();
605         assert!(!s_listening);
606         listen(s, 10).unwrap();
607         let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
608         assert!(s_listening2);
609         close(s).unwrap();
610     }
611 
612     #[cfg(target_os = "linux")]
613     #[test]
is_so_mark_functional()614     fn is_so_mark_functional() {
615         use super::super::*;
616         use ::unistd::Uid;
617         use ::std::io::{self, Write};
618 
619         if !Uid::current().is_root() {
620             let stderr = io::stderr();
621             let mut handle = stderr.lock();
622             writeln!(handle, "SO_MARK requires root privileges. Skipping test.").unwrap();
623             return;
624         }
625 
626         let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
627         setsockopt(s, super::Mark, &1337).unwrap();
628         let mark = getsockopt(s, super::Mark).unwrap();
629         assert_eq!(mark, 1337);
630     }
631 }
632