1 | //! Socket options as used by `setsockopt` and `getsockopt`. |
2 | use super::{GetSockOpt, SetSockOpt}; |
3 | use crate::errno::Errno; |
4 | use crate::sys::time::TimeVal; |
5 | use crate::Result; |
6 | use cfg_if::cfg_if; |
7 | use libc::{self, c_int, c_void, socklen_t}; |
8 | use std::ffi::{OsStr, OsString}; |
9 | use std::{ |
10 | convert::TryFrom, |
11 | mem::{self, MaybeUninit} |
12 | }; |
13 | #[cfg (target_family = "unix" )] |
14 | use std::os::unix::ffi::OsStrExt; |
15 | use std::os::unix::io::RawFd; |
16 | |
17 | // Constants |
18 | // TCP_CA_NAME_MAX isn't defined in user space include files |
19 | #[cfg (any(target_os = "freebsd" , target_os = "linux" ))] |
20 | #[cfg (feature = "net" )] |
21 | const TCP_CA_NAME_MAX: usize = 16; |
22 | |
23 | /// Helper for implementing `SetSockOpt` for a given socket option. See |
24 | /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). |
25 | /// |
26 | /// This macro aims to help implementing `SetSockOpt` for different socket options that accept |
27 | /// different kinds of data to be used with `setsockopt`. |
28 | /// |
29 | /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option |
30 | /// you are implementing represents a simple type. |
31 | /// |
32 | /// # Arguments |
33 | /// |
34 | /// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. |
35 | /// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* |
36 | /// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), |
37 | /// and more. Please refer to your system manual for more options. Will be passed as the second |
38 | /// argument (`level`) to the `setsockopt` call. |
39 | /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, |
40 | /// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) |
41 | /// to the `setsockopt` call. |
42 | /// * Type of the value that you are going to set. |
43 | /// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for |
44 | /// `bool`, `SetUsize` for `usize`, etc.). |
45 | macro_rules! setsockopt_impl { |
46 | ($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => { |
47 | impl SetSockOpt for $name { |
48 | type Val = $ty; |
49 | |
50 | fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { |
51 | unsafe { |
52 | let setter: $setter = Set::new(val); |
53 | |
54 | let res = libc::setsockopt( |
55 | fd, |
56 | $level, |
57 | $flag, |
58 | setter.ffi_ptr(), |
59 | setter.ffi_len(), |
60 | ); |
61 | Errno::result(res).map(drop) |
62 | } |
63 | } |
64 | } |
65 | }; |
66 | } |
67 | |
68 | /// Helper for implementing `GetSockOpt` for a given socket option. See |
69 | /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html). |
70 | /// |
71 | /// This macro aims to help implementing `GetSockOpt` for different socket options that accept |
72 | /// different kinds of data to be use with `getsockopt`. |
73 | /// |
74 | /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option |
75 | /// you are implementing represents a simple type. |
76 | /// |
77 | /// # Arguments |
78 | /// |
79 | /// * Name of the type you want to implement `GetSockOpt` for. |
80 | /// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip |
81 | /// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer |
82 | /// to your system manual for more options. Will be passed as the second argument (`level`) to |
83 | /// the `getsockopt` call. |
84 | /// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, |
85 | /// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to |
86 | /// the `getsockopt` call. |
87 | /// * Type of the value that you are going to get. |
88 | /// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for |
89 | /// `bool`, `GetUsize` for `usize`, etc.). |
90 | macro_rules! getsockopt_impl { |
91 | ($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => { |
92 | impl GetSockOpt for $name { |
93 | type Val = $ty; |
94 | |
95 | fn get(&self, fd: RawFd) -> Result<$ty> { |
96 | unsafe { |
97 | let mut getter: $getter = Get::uninit(); |
98 | |
99 | let res = libc::getsockopt( |
100 | fd, |
101 | $level, |
102 | $flag, |
103 | getter.ffi_ptr(), |
104 | getter.ffi_len(), |
105 | ); |
106 | Errno::result(res)?; |
107 | |
108 | match <$ty>::try_from(getter.assume_init()) { |
109 | Err(_) => Err(Errno::EINVAL), |
110 | Ok(r) => Ok(r) |
111 | } |
112 | } |
113 | } |
114 | } |
115 | }; |
116 | } |
117 | |
118 | /// Helper to generate the sockopt accessors. See |
119 | /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and |
120 | /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). |
121 | /// |
122 | /// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options |
123 | /// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively. |
124 | /// |
125 | /// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and |
126 | /// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros. |
127 | /// |
128 | /// # Arguments |
129 | /// |
130 | /// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or |
131 | /// both of them. |
132 | /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. |
133 | /// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets* |
134 | /// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), |
135 | /// and more. Please refer to your system manual for more options. Will be passed as the second |
136 | /// argument (`level`) to the `getsockopt`/`setsockopt` call. |
137 | /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, |
138 | /// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) |
139 | /// to the `setsockopt`/`getsockopt` call. |
140 | /// * `$ty:ty`: type of the value that will be get/set. |
141 | /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. |
142 | /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. |
143 | // Some targets don't use all rules. |
144 | #[allow (unknown_lints)] |
145 | #[allow (unused_macro_rules)] |
146 | macro_rules! sockopt_impl { |
147 | ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { |
148 | sockopt_impl!($(#[$attr])* |
149 | $name, GetOnly, $level, $flag, bool, GetBool); |
150 | }; |
151 | |
152 | ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, u8) => { |
153 | sockopt_impl!($(#[$attr])* $name, GetOnly, $level, $flag, u8, GetU8); |
154 | }; |
155 | |
156 | ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, usize) => |
157 | { |
158 | sockopt_impl!($(#[$attr])* |
159 | $name, GetOnly, $level, $flag, usize, GetUsize); |
160 | }; |
161 | |
162 | ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, bool) => { |
163 | sockopt_impl!($(#[$attr])* |
164 | $name, SetOnly, $level, $flag, bool, SetBool); |
165 | }; |
166 | |
167 | ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, u8) => { |
168 | sockopt_impl!($(#[$attr])* $name, SetOnly, $level, $flag, u8, SetU8); |
169 | }; |
170 | |
171 | ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, usize) => |
172 | { |
173 | sockopt_impl!($(#[$attr])* |
174 | $name, SetOnly, $level, $flag, usize, SetUsize); |
175 | }; |
176 | |
177 | ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, bool) => { |
178 | sockopt_impl!($(#[$attr])* |
179 | $name, Both, $level, $flag, bool, GetBool, SetBool); |
180 | }; |
181 | |
182 | ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, u8) => { |
183 | sockopt_impl!($(#[$attr])* |
184 | $name, Both, $level, $flag, u8, GetU8, SetU8); |
185 | }; |
186 | |
187 | ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, usize) => { |
188 | sockopt_impl!($(#[$attr])* |
189 | $name, Both, $level, $flag, usize, GetUsize, SetUsize); |
190 | }; |
191 | |
192 | ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, |
193 | OsString<$array:ty>) => |
194 | { |
195 | sockopt_impl!($(#[$attr])* |
196 | $name, Both, $level, $flag, OsString, GetOsString<$array>, |
197 | SetOsString); |
198 | }; |
199 | |
200 | /* |
201 | * Matchers with generic getter types must be placed at the end, so |
202 | * they'll only match _after_ specialized matchers fail |
203 | */ |
204 | ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty) => |
205 | { |
206 | sockopt_impl!($(#[$attr])* |
207 | $name, GetOnly, $level, $flag, $ty, GetStruct<$ty>); |
208 | }; |
209 | |
210 | ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, $ty:ty, |
211 | $getter:ty) => |
212 | { |
213 | $(#[$attr])* |
214 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
215 | pub struct $name; |
216 | |
217 | getsockopt_impl!($name, $level, $flag, $ty, $getter); |
218 | }; |
219 | |
220 | ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty) => |
221 | { |
222 | sockopt_impl!($(#[$attr])* |
223 | $name, SetOnly, $level, $flag, $ty, SetStruct<$ty>); |
224 | }; |
225 | |
226 | ($(#[$attr:meta])* $name:ident, SetOnly, $level:expr, $flag:path, $ty:ty, |
227 | $setter:ty) => |
228 | { |
229 | $(#[$attr])* |
230 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
231 | pub struct $name; |
232 | |
233 | setsockopt_impl!($name, $level, $flag, $ty, $setter); |
234 | }; |
235 | |
236 | ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty, |
237 | $getter:ty, $setter:ty) => |
238 | { |
239 | $(#[$attr])* |
240 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
241 | pub struct $name; |
242 | |
243 | setsockopt_impl!($name, $level, $flag, $ty, $setter); |
244 | getsockopt_impl!($name, $level, $flag, $ty, $getter); |
245 | }; |
246 | |
247 | ($(#[$attr:meta])* $name:ident, Both, $level:expr, $flag:path, $ty:ty) => { |
248 | sockopt_impl!($(#[$attr])* |
249 | $name, Both, $level, $flag, $ty, GetStruct<$ty>, |
250 | SetStruct<$ty>); |
251 | }; |
252 | } |
253 | |
254 | /* |
255 | * |
256 | * ===== Define sockopts ===== |
257 | * |
258 | */ |
259 | |
260 | sockopt_impl!( |
261 | /// Enables local address reuse |
262 | ReuseAddr, |
263 | Both, |
264 | libc::SOL_SOCKET, |
265 | libc::SO_REUSEADDR, |
266 | bool |
267 | ); |
268 | #[cfg (not(any(target_os = "illumos" , target_os = "solaris" )))] |
269 | sockopt_impl!( |
270 | /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an |
271 | /// identical socket address. |
272 | ReusePort, |
273 | Both, |
274 | libc::SOL_SOCKET, |
275 | libc::SO_REUSEPORT, |
276 | bool |
277 | ); |
278 | #[cfg (feature = "net" )] |
279 | sockopt_impl!( |
280 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
281 | /// Under most circumstances, TCP sends data when it is presented; when |
282 | /// outstanding data has not yet been acknowledged, it gathers small amounts |
283 | /// of output to be sent in a single packet once an acknowledgement is |
284 | /// received. For a small number of clients, such as window systems that |
285 | /// send a stream of mouse events which receive no replies, this |
286 | /// packetization may cause significant delays. The boolean option |
287 | /// TCP_NODELAY defeats this algorithm. |
288 | TcpNoDelay, |
289 | Both, |
290 | libc::IPPROTO_TCP, |
291 | libc::TCP_NODELAY, |
292 | bool |
293 | ); |
294 | sockopt_impl!( |
295 | /// When enabled, a close(2) or shutdown(2) will not return until all |
296 | /// queued messages for the socket have been successfully sent or the |
297 | /// linger timeout has been reached. |
298 | Linger, |
299 | Both, |
300 | libc::SOL_SOCKET, |
301 | libc::SO_LINGER, |
302 | libc::linger |
303 | ); |
304 | #[cfg (feature = "net" )] |
305 | sockopt_impl!( |
306 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
307 | /// Join a multicast group |
308 | IpAddMembership, |
309 | SetOnly, |
310 | libc::IPPROTO_IP, |
311 | libc::IP_ADD_MEMBERSHIP, |
312 | super::IpMembershipRequest |
313 | ); |
314 | #[cfg (feature = "net" )] |
315 | sockopt_impl!( |
316 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
317 | /// Leave a multicast group. |
318 | IpDropMembership, |
319 | SetOnly, |
320 | libc::IPPROTO_IP, |
321 | libc::IP_DROP_MEMBERSHIP, |
322 | super::IpMembershipRequest |
323 | ); |
324 | cfg_if! { |
325 | if #[cfg(any(target_os = "android" , target_os = "linux" ))] { |
326 | #[cfg (feature = "net" )] |
327 | sockopt_impl!( |
328 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
329 | /// Join an IPv6 multicast group. |
330 | Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); |
331 | #[cfg (feature = "net" )] |
332 | sockopt_impl!( |
333 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
334 | /// Leave an IPv6 multicast group. |
335 | Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); |
336 | } else if #[cfg(any(target_os = "dragonfly" , |
337 | target_os = "freebsd" , |
338 | target_os = "illumos" , |
339 | target_os = "ios" , |
340 | target_os = "macos" , |
341 | target_os = "netbsd" , |
342 | target_os = "openbsd" , |
343 | target_os = "solaris" ))] { |
344 | #[cfg (feature = "net" )] |
345 | sockopt_impl!( |
346 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
347 | /// Join an IPv6 multicast group. |
348 | Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, |
349 | libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); |
350 | #[cfg (feature = "net" )] |
351 | sockopt_impl!( |
352 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
353 | /// Leave an IPv6 multicast group. |
354 | Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, |
355 | libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); |
356 | } |
357 | } |
358 | #[cfg (feature = "net" )] |
359 | sockopt_impl!( |
360 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
361 | /// Set or read the time-to-live value of outgoing multicast packets for |
362 | /// this socket. |
363 | IpMulticastTtl, |
364 | Both, |
365 | libc::IPPROTO_IP, |
366 | libc::IP_MULTICAST_TTL, |
367 | u8 |
368 | ); |
369 | #[cfg (feature = "net" )] |
370 | sockopt_impl!( |
371 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
372 | /// Set or read a boolean integer argument that determines whether sent |
373 | /// multicast packets should be looped back to the local sockets. |
374 | IpMulticastLoop, |
375 | Both, |
376 | libc::IPPROTO_IP, |
377 | libc::IP_MULTICAST_LOOP, |
378 | bool |
379 | ); |
380 | #[cfg (target_os = "linux" )] |
381 | #[cfg (feature = "net" )] |
382 | sockopt_impl!( |
383 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
384 | /// Set the protocol-defined priority for all packets to be |
385 | /// sent on this socket |
386 | Priority, |
387 | Both, |
388 | libc::SOL_SOCKET, |
389 | libc::SO_PRIORITY, |
390 | libc::c_int |
391 | ); |
392 | #[cfg (target_os = "linux" )] |
393 | #[cfg (feature = "net" )] |
394 | sockopt_impl!( |
395 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
396 | /// Set or receive the Type-Of-Service (TOS) field that is |
397 | /// sent with every IP packet originating from this socket |
398 | IpTos, |
399 | Both, |
400 | libc::IPPROTO_IP, |
401 | libc::IP_TOS, |
402 | libc::c_int |
403 | ); |
404 | #[cfg (target_os = "linux" )] |
405 | #[cfg (feature = "net" )] |
406 | sockopt_impl!( |
407 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
408 | /// Traffic class associated with outgoing packets |
409 | Ipv6TClass, |
410 | Both, |
411 | libc::IPPROTO_IPV6, |
412 | libc::IPV6_TCLASS, |
413 | libc::c_int |
414 | ); |
415 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ))] |
416 | #[cfg (feature = "net" )] |
417 | sockopt_impl!( |
418 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
419 | /// If enabled, this boolean option allows binding to an IP address that |
420 | /// is nonlocal or does not (yet) exist. |
421 | IpFreebind, |
422 | Both, |
423 | libc::IPPROTO_IP, |
424 | libc::IP_FREEBIND, |
425 | bool |
426 | ); |
427 | sockopt_impl!( |
428 | /// Specify the receiving timeout until reporting an error. |
429 | ReceiveTimeout, |
430 | Both, |
431 | libc::SOL_SOCKET, |
432 | libc::SO_RCVTIMEO, |
433 | TimeVal |
434 | ); |
435 | sockopt_impl!( |
436 | /// Specify the sending timeout until reporting an error. |
437 | SendTimeout, |
438 | Both, |
439 | libc::SOL_SOCKET, |
440 | libc::SO_SNDTIMEO, |
441 | TimeVal |
442 | ); |
443 | sockopt_impl!( |
444 | /// Set or get the broadcast flag. |
445 | Broadcast, |
446 | Both, |
447 | libc::SOL_SOCKET, |
448 | libc::SO_BROADCAST, |
449 | bool |
450 | ); |
451 | sockopt_impl!( |
452 | /// If this option is enabled, out-of-band data is directly placed into |
453 | /// the receive data stream. |
454 | OobInline, |
455 | Both, |
456 | libc::SOL_SOCKET, |
457 | libc::SO_OOBINLINE, |
458 | bool |
459 | ); |
460 | sockopt_impl!( |
461 | /// Get and clear the pending socket error. |
462 | SocketError, |
463 | GetOnly, |
464 | libc::SOL_SOCKET, |
465 | libc::SO_ERROR, |
466 | i32 |
467 | ); |
468 | sockopt_impl!( |
469 | /// Set or get the don't route flag. |
470 | DontRoute, |
471 | Both, |
472 | libc::SOL_SOCKET, |
473 | libc::SO_DONTROUTE, |
474 | bool |
475 | ); |
476 | sockopt_impl!( |
477 | /// Enable sending of keep-alive messages on connection-oriented sockets. |
478 | KeepAlive, |
479 | Both, |
480 | libc::SOL_SOCKET, |
481 | libc::SO_KEEPALIVE, |
482 | bool |
483 | ); |
484 | #[cfg (any( |
485 | target_os = "dragonfly" , |
486 | target_os = "freebsd" , |
487 | target_os = "macos" , |
488 | target_os = "ios" |
489 | ))] |
490 | sockopt_impl!( |
491 | /// Get the credentials of the peer process of a connected unix domain |
492 | /// socket. |
493 | LocalPeerCred, |
494 | GetOnly, |
495 | 0, |
496 | libc::LOCAL_PEERCRED, |
497 | super::XuCred |
498 | ); |
499 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
500 | sockopt_impl!( |
501 | /// Return the credentials of the foreign process connected to this socket. |
502 | PeerCredentials, |
503 | GetOnly, |
504 | libc::SOL_SOCKET, |
505 | libc::SO_PEERCRED, |
506 | super::UnixCredentials |
507 | ); |
508 | #[cfg (any(target_os = "ios" , target_os = "macos" ))] |
509 | #[cfg (feature = "net" )] |
510 | sockopt_impl!( |
511 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
512 | /// Specify the amount of time, in seconds, that the connection must be idle |
513 | /// before keepalive probes (if enabled) are sent. |
514 | TcpKeepAlive, |
515 | Both, |
516 | libc::IPPROTO_TCP, |
517 | libc::TCP_KEEPALIVE, |
518 | u32 |
519 | ); |
520 | #[cfg (any( |
521 | target_os = "android" , |
522 | target_os = "dragonfly" , |
523 | target_os = "freebsd" , |
524 | target_os = "linux" |
525 | ))] |
526 | #[cfg (feature = "net" )] |
527 | sockopt_impl!( |
528 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
529 | /// The time (in seconds) the connection needs to remain idle before TCP |
530 | /// starts sending keepalive probes |
531 | TcpKeepIdle, |
532 | Both, |
533 | libc::IPPROTO_TCP, |
534 | libc::TCP_KEEPIDLE, |
535 | u32 |
536 | ); |
537 | cfg_if! { |
538 | if #[cfg(any(target_os = "android" , target_os = "linux" ))] { |
539 | sockopt_impl!( |
540 | /// The maximum segment size for outgoing TCP packets. |
541 | TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); |
542 | } else { |
543 | sockopt_impl!( |
544 | /// The maximum segment size for outgoing TCP packets. |
545 | TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); |
546 | } |
547 | } |
548 | #[cfg (not(any(target_os = "openbsd" , target_os = "haiku" )))] |
549 | #[cfg (feature = "net" )] |
550 | sockopt_impl!( |
551 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
552 | /// The maximum number of keepalive probes TCP should send before |
553 | /// dropping the connection. |
554 | TcpKeepCount, |
555 | Both, |
556 | libc::IPPROTO_TCP, |
557 | libc::TCP_KEEPCNT, |
558 | u32 |
559 | ); |
560 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ))] |
561 | sockopt_impl!( |
562 | #[allow (missing_docs)] |
563 | // Not documented by Linux! |
564 | TcpRepair, |
565 | Both, |
566 | libc::IPPROTO_TCP, |
567 | libc::TCP_REPAIR, |
568 | u32 |
569 | ); |
570 | #[cfg (not(any(target_os = "openbsd" , target_os = "haiku" )))] |
571 | #[cfg (feature = "net" )] |
572 | sockopt_impl!( |
573 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
574 | /// The time (in seconds) between individual keepalive probes. |
575 | TcpKeepInterval, |
576 | Both, |
577 | libc::IPPROTO_TCP, |
578 | libc::TCP_KEEPINTVL, |
579 | u32 |
580 | ); |
581 | #[cfg (any(target_os = "fuchsia" , target_os = "linux" ))] |
582 | #[cfg (feature = "net" )] |
583 | sockopt_impl!( |
584 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
585 | /// Specifies the maximum amount of time in milliseconds that transmitted |
586 | /// data may remain unacknowledged before TCP will forcibly close the |
587 | /// corresponding connection |
588 | TcpUserTimeout, |
589 | Both, |
590 | libc::IPPROTO_TCP, |
591 | libc::TCP_USER_TIMEOUT, |
592 | u32 |
593 | ); |
594 | sockopt_impl!( |
595 | /// Sets or gets the maximum socket receive buffer in bytes. |
596 | RcvBuf, |
597 | Both, |
598 | libc::SOL_SOCKET, |
599 | libc::SO_RCVBUF, |
600 | usize |
601 | ); |
602 | sockopt_impl!( |
603 | /// Sets or gets the maximum socket send buffer in bytes. |
604 | SndBuf, |
605 | Both, |
606 | libc::SOL_SOCKET, |
607 | libc::SO_SNDBUF, |
608 | usize |
609 | ); |
610 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
611 | sockopt_impl!( |
612 | /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can |
613 | /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be |
614 | /// overridden. |
615 | RcvBufForce, |
616 | SetOnly, |
617 | libc::SOL_SOCKET, |
618 | libc::SO_RCVBUFFORCE, |
619 | usize |
620 | ); |
621 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
622 | sockopt_impl!( |
623 | /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can |
624 | /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be |
625 | /// overridden. |
626 | SndBufForce, |
627 | SetOnly, |
628 | libc::SOL_SOCKET, |
629 | libc::SO_SNDBUFFORCE, |
630 | usize |
631 | ); |
632 | sockopt_impl!( |
633 | /// Gets the socket type as an integer. |
634 | SockType, |
635 | GetOnly, |
636 | libc::SOL_SOCKET, |
637 | libc::SO_TYPE, |
638 | super::SockType, |
639 | GetStruct<i32> |
640 | ); |
641 | sockopt_impl!( |
642 | /// Returns a value indicating whether or not this socket has been marked to |
643 | /// accept connections with `listen(2)`. |
644 | AcceptConn, |
645 | GetOnly, |
646 | libc::SOL_SOCKET, |
647 | libc::SO_ACCEPTCONN, |
648 | bool |
649 | ); |
650 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
651 | sockopt_impl!( |
652 | /// Bind this socket to a particular device like “eth0”. |
653 | BindToDevice, |
654 | Both, |
655 | libc::SOL_SOCKET, |
656 | libc::SO_BINDTODEVICE, |
657 | OsString<[u8; libc::IFNAMSIZ]> |
658 | ); |
659 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
660 | #[cfg (feature = "net" )] |
661 | sockopt_impl!( |
662 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
663 | #[allow (missing_docs)] |
664 | // Not documented by Linux! |
665 | OriginalDst, |
666 | GetOnly, |
667 | libc::SOL_IP, |
668 | libc::SO_ORIGINAL_DST, |
669 | libc::sockaddr_in |
670 | ); |
671 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
672 | sockopt_impl!( |
673 | #[allow (missing_docs)] |
674 | // Not documented by Linux! |
675 | Ip6tOriginalDst, |
676 | GetOnly, |
677 | libc::SOL_IPV6, |
678 | libc::IP6T_SO_ORIGINAL_DST, |
679 | libc::sockaddr_in6 |
680 | ); |
681 | #[cfg (target_os = "linux" )] |
682 | sockopt_impl!( |
683 | /// Specifies exact type of timestamping information collected by the kernel |
684 | /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) |
685 | Timestamping, |
686 | Both, |
687 | libc::SOL_SOCKET, |
688 | libc::SO_TIMESTAMPING, |
689 | super::TimestampingFlag |
690 | ); |
691 | #[cfg (not(target_os = "haiku" ))] |
692 | sockopt_impl!( |
693 | /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. |
694 | ReceiveTimestamp, |
695 | Both, |
696 | libc::SOL_SOCKET, |
697 | libc::SO_TIMESTAMP, |
698 | bool |
699 | ); |
700 | #[cfg (target_os = "linux" )] |
701 | sockopt_impl!( |
702 | /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. |
703 | ReceiveTimestampns, |
704 | Both, |
705 | libc::SOL_SOCKET, |
706 | libc::SO_TIMESTAMPNS, |
707 | bool |
708 | ); |
709 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
710 | #[cfg (feature = "net" )] |
711 | sockopt_impl!( |
712 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
713 | /// Setting this boolean option enables transparent proxying on this socket. |
714 | IpTransparent, |
715 | Both, |
716 | libc::SOL_IP, |
717 | libc::IP_TRANSPARENT, |
718 | bool |
719 | ); |
720 | #[cfg (target_os = "openbsd" )] |
721 | #[cfg (feature = "net" )] |
722 | sockopt_impl!( |
723 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
724 | /// Allows the socket to be bound to addresses which are not local to the |
725 | /// machine, so it can be used to make a transparent proxy. |
726 | BindAny, |
727 | Both, |
728 | libc::SOL_SOCKET, |
729 | libc::SO_BINDANY, |
730 | bool |
731 | ); |
732 | #[cfg (target_os = "freebsd" )] |
733 | #[cfg (feature = "net" )] |
734 | sockopt_impl!( |
735 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
736 | /// Can `bind(2)` to any address, even one not bound to any available |
737 | /// network interface in the system. |
738 | BindAny, |
739 | Both, |
740 | libc::IPPROTO_IP, |
741 | libc::IP_BINDANY, |
742 | bool |
743 | ); |
744 | #[cfg (target_os = "linux" )] |
745 | sockopt_impl!( |
746 | /// Set the mark for each packet sent through this socket (similar to the |
747 | /// netfilter MARK target but socket-based). |
748 | Mark, |
749 | Both, |
750 | libc::SOL_SOCKET, |
751 | libc::SO_MARK, |
752 | u32 |
753 | ); |
754 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
755 | sockopt_impl!( |
756 | /// Enable or disable the receiving of the `SCM_CREDENTIALS` control |
757 | /// message. |
758 | PassCred, |
759 | Both, |
760 | libc::SOL_SOCKET, |
761 | libc::SO_PASSCRED, |
762 | bool |
763 | ); |
764 | #[cfg (any(target_os = "freebsd" , target_os = "linux" ))] |
765 | #[cfg (feature = "net" )] |
766 | sockopt_impl!( |
767 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
768 | /// This option allows the caller to set the TCP congestion control |
769 | /// algorithm to be used, on a per-socket basis. |
770 | TcpCongestion, |
771 | Both, |
772 | libc::IPPROTO_TCP, |
773 | libc::TCP_CONGESTION, |
774 | OsString<[u8; TCP_CA_NAME_MAX]> |
775 | ); |
776 | #[cfg (any( |
777 | target_os = "android" , |
778 | target_os = "ios" , |
779 | target_os = "linux" , |
780 | target_os = "macos" , |
781 | target_os = "netbsd" , |
782 | ))] |
783 | #[cfg (feature = "net" )] |
784 | sockopt_impl!( |
785 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
786 | /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo |
787 | /// structure that supplies some information about the incoming packet. |
788 | Ipv4PacketInfo, |
789 | Both, |
790 | libc::IPPROTO_IP, |
791 | libc::IP_PKTINFO, |
792 | bool |
793 | ); |
794 | #[cfg (any( |
795 | target_os = "android" , |
796 | target_os = "freebsd" , |
797 | target_os = "ios" , |
798 | target_os = "linux" , |
799 | target_os = "macos" , |
800 | target_os = "netbsd" , |
801 | target_os = "openbsd" , |
802 | ))] |
803 | #[cfg (feature = "net" )] |
804 | sockopt_impl!( |
805 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
806 | /// Set delivery of the `IPV6_PKTINFO` control message on incoming |
807 | /// datagrams. |
808 | Ipv6RecvPacketInfo, |
809 | Both, |
810 | libc::IPPROTO_IPV6, |
811 | libc::IPV6_RECVPKTINFO, |
812 | bool |
813 | ); |
814 | #[cfg (any( |
815 | target_os = "freebsd" , |
816 | target_os = "ios" , |
817 | target_os = "macos" , |
818 | target_os = "netbsd" , |
819 | target_os = "openbsd" , |
820 | ))] |
821 | #[cfg (feature = "net" )] |
822 | sockopt_impl!( |
823 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
824 | /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to |
825 | /// the interface on which the packet was received. |
826 | Ipv4RecvIf, |
827 | Both, |
828 | libc::IPPROTO_IP, |
829 | libc::IP_RECVIF, |
830 | bool |
831 | ); |
832 | #[cfg (any( |
833 | target_os = "freebsd" , |
834 | target_os = "ios" , |
835 | target_os = "macos" , |
836 | target_os = "netbsd" , |
837 | target_os = "openbsd" , |
838 | ))] |
839 | #[cfg (feature = "net" )] |
840 | sockopt_impl!( |
841 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
842 | /// The `recvmsg(2)` call will return the destination IP address for a UDP |
843 | /// datagram. |
844 | Ipv4RecvDstAddr, |
845 | Both, |
846 | libc::IPPROTO_IP, |
847 | libc::IP_RECVDSTADDR, |
848 | bool |
849 | ); |
850 | #[cfg (any(target_os = "android" , target_os = "freebsd" , target_os = "linux" ))] |
851 | #[cfg (feature = "net" )] |
852 | sockopt_impl!( |
853 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
854 | /// The `recvmsg(2)` call will return the destination IP address for a UDP |
855 | /// datagram. |
856 | Ipv4OrigDstAddr, |
857 | Both, |
858 | libc::IPPROTO_IP, |
859 | libc::IP_ORIGDSTADDR, |
860 | bool |
861 | ); |
862 | #[cfg (target_os = "linux" )] |
863 | #[cfg (feature = "net" )] |
864 | sockopt_impl!( |
865 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
866 | #[allow (missing_docs)] |
867 | // Not documented by Linux! |
868 | UdpGsoSegment, |
869 | Both, |
870 | libc::SOL_UDP, |
871 | libc::UDP_SEGMENT, |
872 | libc::c_int |
873 | ); |
874 | #[cfg (target_os = "linux" )] |
875 | #[cfg (feature = "net" )] |
876 | sockopt_impl!( |
877 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
878 | #[allow (missing_docs)] |
879 | // Not documented by Linux! |
880 | UdpGroSegment, |
881 | Both, |
882 | libc::IPPROTO_UDP, |
883 | libc::UDP_GRO, |
884 | bool |
885 | ); |
886 | #[cfg (target_os = "linux" )] |
887 | sockopt_impl!( |
888 | /// Configures the behavior of time-based transmission of packets, for use |
889 | /// with the `TxTime` control message. |
890 | TxTime, |
891 | Both, |
892 | libc::SOL_SOCKET, |
893 | libc::SO_TXTIME, |
894 | libc::sock_txtime |
895 | ); |
896 | #[cfg (any(target_os = "android" , target_os = "fuchsia" , target_os = "linux" ))] |
897 | sockopt_impl!( |
898 | /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should |
899 | /// be attached to received skbs indicating the number of packets dropped by |
900 | /// the socket since its creation. |
901 | RxqOvfl, |
902 | Both, |
903 | libc::SOL_SOCKET, |
904 | libc::SO_RXQ_OVFL, |
905 | libc::c_int |
906 | ); |
907 | #[cfg (feature = "net" )] |
908 | sockopt_impl!( |
909 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
910 | /// The socket is restricted to sending and receiving IPv6 packets only. |
911 | Ipv6V6Only, |
912 | Both, |
913 | libc::IPPROTO_IPV6, |
914 | libc::IPV6_V6ONLY, |
915 | bool |
916 | ); |
917 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
918 | sockopt_impl!( |
919 | /// Enable extended reliable error message passing. |
920 | Ipv4RecvErr, |
921 | Both, |
922 | libc::IPPROTO_IP, |
923 | libc::IP_RECVERR, |
924 | bool |
925 | ); |
926 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
927 | sockopt_impl!( |
928 | /// Control receiving of asynchronous error options. |
929 | Ipv6RecvErr, |
930 | Both, |
931 | libc::IPPROTO_IPV6, |
932 | libc::IPV6_RECVERR, |
933 | bool |
934 | ); |
935 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
936 | sockopt_impl!( |
937 | /// Fetch the current system-estimated Path MTU. |
938 | IpMtu, |
939 | GetOnly, |
940 | libc::IPPROTO_IP, |
941 | libc::IP_MTU, |
942 | libc::c_int |
943 | ); |
944 | #[cfg (any(target_os = "android" , target_os = "freebsd" , target_os = "linux" ))] |
945 | sockopt_impl!( |
946 | /// Set or retrieve the current time-to-live field that is used in every |
947 | /// packet sent from this socket. |
948 | Ipv4Ttl, |
949 | Both, |
950 | libc::IPPROTO_IP, |
951 | libc::IP_TTL, |
952 | libc::c_int |
953 | ); |
954 | #[cfg (any(target_os = "android" , target_os = "freebsd" , target_os = "linux" ))] |
955 | sockopt_impl!( |
956 | /// Set the unicast hop limit for the socket. |
957 | Ipv6Ttl, |
958 | Both, |
959 | libc::IPPROTO_IPV6, |
960 | libc::IPV6_UNICAST_HOPS, |
961 | libc::c_int |
962 | ); |
963 | #[cfg (any(target_os = "android" , target_os = "freebsd" , target_os = "linux" ))] |
964 | #[cfg (feature = "net" )] |
965 | sockopt_impl!( |
966 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
967 | /// The `recvmsg(2)` call will return the destination IP address for a UDP |
968 | /// datagram. |
969 | Ipv6OrigDstAddr, |
970 | Both, |
971 | libc::IPPROTO_IPV6, |
972 | libc::IPV6_ORIGDSTADDR, |
973 | bool |
974 | ); |
975 | #[cfg (any(target_os = "ios" , target_os = "macos" ))] |
976 | sockopt_impl!( |
977 | /// Set "don't fragment packet" flag on the IP packet. |
978 | IpDontFrag, |
979 | Both, |
980 | libc::IPPROTO_IP, |
981 | libc::IP_DONTFRAG, |
982 | bool |
983 | ); |
984 | #[cfg (any( |
985 | target_os = "android" , |
986 | target_os = "ios" , |
987 | target_os = "linux" , |
988 | target_os = "macos" , |
989 | ))] |
990 | sockopt_impl!( |
991 | /// Set "don't fragment packet" flag on the IPv6 packet. |
992 | Ipv6DontFrag, |
993 | Both, |
994 | libc::IPPROTO_IPV6, |
995 | libc::IPV6_DONTFRAG, |
996 | bool |
997 | ); |
998 | |
999 | #[allow (missing_docs)] |
1000 | // Not documented by Linux! |
1001 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1002 | #[derive (Copy, Clone, Debug)] |
1003 | pub struct AlgSetAeadAuthSize; |
1004 | |
1005 | // ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` |
1006 | // See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 |
1007 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1008 | impl SetSockOpt for AlgSetAeadAuthSize { |
1009 | type Val = usize; |
1010 | |
1011 | fn set(&self, fd: RawFd, val: &usize) -> Result<()> { |
1012 | unsafe { |
1013 | let res: i32 = libc::setsockopt( |
1014 | socket:fd, |
1015 | level:libc::SOL_ALG, |
1016 | name:libc::ALG_SET_AEAD_AUTHSIZE, |
1017 | ::std::ptr::null(), |
1018 | *val as libc::socklen_t, |
1019 | ); |
1020 | Errno::result(res).map(op:drop) |
1021 | } |
1022 | } |
1023 | } |
1024 | |
1025 | #[allow (missing_docs)] |
1026 | // Not documented by Linux! |
1027 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1028 | #[derive (Clone, Debug)] |
1029 | pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); |
1030 | |
1031 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1032 | impl<T> Default for AlgSetKey<T> { |
1033 | fn default() -> Self { |
1034 | AlgSetKey(Default::default()) |
1035 | } |
1036 | } |
1037 | |
1038 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1039 | impl<T> SetSockOpt for AlgSetKey<T> |
1040 | where |
1041 | T: AsRef<[u8]> + Clone, |
1042 | { |
1043 | type Val = T; |
1044 | |
1045 | fn set(&self, fd: RawFd, val: &T) -> Result<()> { |
1046 | unsafe { |
1047 | let res: i32 = libc::setsockopt( |
1048 | socket:fd, |
1049 | level:libc::SOL_ALG, |
1050 | name:libc::ALG_SET_KEY, |
1051 | value:val.as_ref().as_ptr() as *const _, |
1052 | option_len:val.as_ref().len() as libc::socklen_t, |
1053 | ); |
1054 | Errno::result(res).map(op:drop) |
1055 | } |
1056 | } |
1057 | } |
1058 | |
1059 | /* |
1060 | * |
1061 | * ===== Accessor helpers ===== |
1062 | * |
1063 | */ |
1064 | |
1065 | /// Helper trait that describes what is expected from a `GetSockOpt` getter. |
1066 | trait Get<T> { |
1067 | /// Returns an uninitialized value. |
1068 | fn uninit() -> Self; |
1069 | /// Returns a pointer to the stored value. This pointer will be passed to the system's |
1070 | /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). |
1071 | fn ffi_ptr(&mut self) -> *mut c_void; |
1072 | /// Returns length of the stored value. This pointer will be passed to the system's |
1073 | /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). |
1074 | fn ffi_len(&mut self) -> *mut socklen_t; |
1075 | /// Returns the hopefully initialized inner value. |
1076 | unsafe fn assume_init(self) -> T; |
1077 | } |
1078 | |
1079 | /// Helper trait that describes what is expected from a `SetSockOpt` setter. |
1080 | trait Set<'a, T> { |
1081 | /// Initialize the setter with a given value. |
1082 | fn new(val: &'a T) -> Self; |
1083 | /// Returns a pointer to the stored value. This pointer will be passed to the system's |
1084 | /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). |
1085 | fn ffi_ptr(&self) -> *const c_void; |
1086 | /// Returns length of the stored value. This pointer will be passed to the system's |
1087 | /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). |
1088 | fn ffi_len(&self) -> socklen_t; |
1089 | } |
1090 | |
1091 | /// Getter for an arbitrary `struct`. |
1092 | struct GetStruct<T> { |
1093 | len: socklen_t, |
1094 | val: MaybeUninit<T>, |
1095 | } |
1096 | |
1097 | impl<T> Get<T> for GetStruct<T> { |
1098 | fn uninit() -> Self { |
1099 | GetStruct { |
1100 | len: mem::size_of::<T>() as socklen_t, |
1101 | val: MaybeUninit::uninit(), |
1102 | } |
1103 | } |
1104 | |
1105 | fn ffi_ptr(&mut self) -> *mut c_void { |
1106 | self.val.as_mut_ptr() as *mut c_void |
1107 | } |
1108 | |
1109 | fn ffi_len(&mut self) -> *mut socklen_t { |
1110 | &mut self.len |
1111 | } |
1112 | |
1113 | unsafe fn assume_init(self) -> T { |
1114 | assert_eq!( |
1115 | self.len as usize, |
1116 | mem::size_of::<T>(), |
1117 | "invalid getsockopt implementation" |
1118 | ); |
1119 | self.val.assume_init() |
1120 | } |
1121 | } |
1122 | |
1123 | /// Setter for an arbitrary `struct`. |
1124 | struct SetStruct<'a, T: 'static> { |
1125 | ptr: &'a T, |
1126 | } |
1127 | |
1128 | impl<'a, T> Set<'a, T> for SetStruct<'a, T> { |
1129 | fn new(ptr: &'a T) -> SetStruct<'a, T> { |
1130 | SetStruct { ptr } |
1131 | } |
1132 | |
1133 | fn ffi_ptr(&self) -> *const c_void { |
1134 | self.ptr as *const T as *const c_void |
1135 | } |
1136 | |
1137 | fn ffi_len(&self) -> socklen_t { |
1138 | mem::size_of::<T>() as socklen_t |
1139 | } |
1140 | } |
1141 | |
1142 | /// Getter for a boolean value. |
1143 | struct GetBool { |
1144 | len: socklen_t, |
1145 | val: MaybeUninit<c_int>, |
1146 | } |
1147 | |
1148 | impl Get<bool> for GetBool { |
1149 | fn uninit() -> Self { |
1150 | GetBool { |
1151 | len: mem::size_of::<c_int>() as socklen_t, |
1152 | val: MaybeUninit::uninit(), |
1153 | } |
1154 | } |
1155 | |
1156 | fn ffi_ptr(&mut self) -> *mut c_void { |
1157 | self.val.as_mut_ptr() as *mut c_void |
1158 | } |
1159 | |
1160 | fn ffi_len(&mut self) -> *mut socklen_t { |
1161 | &mut self.len |
1162 | } |
1163 | |
1164 | unsafe fn assume_init(self) -> bool { |
1165 | assert_eq!( |
1166 | self.len as usize, |
1167 | mem::size_of::<c_int>(), |
1168 | "invalid getsockopt implementation" |
1169 | ); |
1170 | self.val.assume_init() != 0 |
1171 | } |
1172 | } |
1173 | |
1174 | /// Setter for a boolean value. |
1175 | struct SetBool { |
1176 | val: c_int, |
1177 | } |
1178 | |
1179 | impl<'a> Set<'a, bool> for SetBool { |
1180 | fn new(val: &'a bool) -> SetBool { |
1181 | SetBool { |
1182 | val: i32::from(*val), |
1183 | } |
1184 | } |
1185 | |
1186 | fn ffi_ptr(&self) -> *const c_void { |
1187 | &self.val as *const c_int as *const c_void |
1188 | } |
1189 | |
1190 | fn ffi_len(&self) -> socklen_t { |
1191 | mem::size_of::<c_int>() as socklen_t |
1192 | } |
1193 | } |
1194 | |
1195 | /// Getter for an `u8` value. |
1196 | struct GetU8 { |
1197 | len: socklen_t, |
1198 | val: MaybeUninit<u8>, |
1199 | } |
1200 | |
1201 | impl Get<u8> for GetU8 { |
1202 | fn uninit() -> Self { |
1203 | GetU8 { |
1204 | len: mem::size_of::<u8>() as socklen_t, |
1205 | val: MaybeUninit::uninit(), |
1206 | } |
1207 | } |
1208 | |
1209 | fn ffi_ptr(&mut self) -> *mut c_void { |
1210 | self.val.as_mut_ptr() as *mut c_void |
1211 | } |
1212 | |
1213 | fn ffi_len(&mut self) -> *mut socklen_t { |
1214 | &mut self.len |
1215 | } |
1216 | |
1217 | unsafe fn assume_init(self) -> u8 { |
1218 | assert_eq!( |
1219 | self.len as usize, |
1220 | mem::size_of::<u8>(), |
1221 | "invalid getsockopt implementation" |
1222 | ); |
1223 | self.val.assume_init() |
1224 | } |
1225 | } |
1226 | |
1227 | /// Setter for an `u8` value. |
1228 | struct SetU8 { |
1229 | val: u8, |
1230 | } |
1231 | |
1232 | impl<'a> Set<'a, u8> for SetU8 { |
1233 | fn new(val: &'a u8) -> SetU8 { |
1234 | SetU8 { val: *val } |
1235 | } |
1236 | |
1237 | fn ffi_ptr(&self) -> *const c_void { |
1238 | &self.val as *const u8 as *const c_void |
1239 | } |
1240 | |
1241 | fn ffi_len(&self) -> socklen_t { |
1242 | mem::size_of::<c_int>() as socklen_t |
1243 | } |
1244 | } |
1245 | |
1246 | /// Getter for an `usize` value. |
1247 | struct GetUsize { |
1248 | len: socklen_t, |
1249 | val: MaybeUninit<c_int>, |
1250 | } |
1251 | |
1252 | impl Get<usize> for GetUsize { |
1253 | fn uninit() -> Self { |
1254 | GetUsize { |
1255 | len: mem::size_of::<c_int>() as socklen_t, |
1256 | val: MaybeUninit::uninit(), |
1257 | } |
1258 | } |
1259 | |
1260 | fn ffi_ptr(&mut self) -> *mut c_void { |
1261 | self.val.as_mut_ptr() as *mut c_void |
1262 | } |
1263 | |
1264 | fn ffi_len(&mut self) -> *mut socklen_t { |
1265 | &mut self.len |
1266 | } |
1267 | |
1268 | unsafe fn assume_init(self) -> usize { |
1269 | assert_eq!( |
1270 | self.len as usize, |
1271 | mem::size_of::<c_int>(), |
1272 | "invalid getsockopt implementation" |
1273 | ); |
1274 | self.val.assume_init() as usize |
1275 | } |
1276 | } |
1277 | |
1278 | /// Setter for an `usize` value. |
1279 | struct SetUsize { |
1280 | val: c_int, |
1281 | } |
1282 | |
1283 | impl<'a> Set<'a, usize> for SetUsize { |
1284 | fn new(val: &'a usize) -> SetUsize { |
1285 | SetUsize { val: *val as c_int } |
1286 | } |
1287 | |
1288 | fn ffi_ptr(&self) -> *const c_void { |
1289 | &self.val as *const c_int as *const c_void |
1290 | } |
1291 | |
1292 | fn ffi_len(&self) -> socklen_t { |
1293 | mem::size_of::<c_int>() as socklen_t |
1294 | } |
1295 | } |
1296 | |
1297 | /// Getter for a `OsString` value. |
1298 | struct GetOsString<T: AsMut<[u8]>> { |
1299 | len: socklen_t, |
1300 | val: MaybeUninit<T>, |
1301 | } |
1302 | |
1303 | impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { |
1304 | fn uninit() -> Self { |
1305 | GetOsString { |
1306 | len: mem::size_of::<T>() as socklen_t, |
1307 | val: MaybeUninit::uninit(), |
1308 | } |
1309 | } |
1310 | |
1311 | fn ffi_ptr(&mut self) -> *mut c_void { |
1312 | self.val.as_mut_ptr() as *mut c_void |
1313 | } |
1314 | |
1315 | fn ffi_len(&mut self) -> *mut socklen_t { |
1316 | &mut self.len |
1317 | } |
1318 | |
1319 | unsafe fn assume_init(self) -> OsString { |
1320 | let len: usize = self.len as usize; |
1321 | let mut v: T = self.val.assume_init(); |
1322 | OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() |
1323 | } |
1324 | } |
1325 | |
1326 | /// Setter for a `OsString` value. |
1327 | struct SetOsString<'a> { |
1328 | val: &'a OsStr, |
1329 | } |
1330 | |
1331 | impl<'a> Set<'a, OsString> for SetOsString<'a> { |
1332 | fn new(val: &'a OsString) -> SetOsString { |
1333 | SetOsString { |
1334 | val: val.as_os_str(), |
1335 | } |
1336 | } |
1337 | |
1338 | fn ffi_ptr(&self) -> *const c_void { |
1339 | self.val.as_bytes().as_ptr() as *const c_void |
1340 | } |
1341 | |
1342 | fn ffi_len(&self) -> socklen_t { |
1343 | self.val.len() as socklen_t |
1344 | } |
1345 | } |
1346 | |
1347 | #[cfg (test)] |
1348 | mod test { |
1349 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
1350 | #[test ] |
1351 | fn can_get_peercred_on_unix_socket() { |
1352 | use super::super::*; |
1353 | |
1354 | let (a, b) = socketpair( |
1355 | AddressFamily::Unix, |
1356 | SockType::Stream, |
1357 | None, |
1358 | SockFlag::empty(), |
1359 | ) |
1360 | .unwrap(); |
1361 | let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); |
1362 | let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); |
1363 | assert_eq!(a_cred, b_cred); |
1364 | assert_ne!(a_cred.pid(), 0); |
1365 | } |
1366 | |
1367 | #[test ] |
1368 | fn is_socket_type_unix() { |
1369 | use super::super::*; |
1370 | use crate::unistd::close; |
1371 | |
1372 | let (a, b) = socketpair( |
1373 | AddressFamily::Unix, |
1374 | SockType::Stream, |
1375 | None, |
1376 | SockFlag::empty(), |
1377 | ) |
1378 | .unwrap(); |
1379 | let a_type = getsockopt(a, super::SockType).unwrap(); |
1380 | assert_eq!(a_type, SockType::Stream); |
1381 | close(a).unwrap(); |
1382 | close(b).unwrap(); |
1383 | } |
1384 | |
1385 | #[test ] |
1386 | fn is_socket_type_dgram() { |
1387 | use super::super::*; |
1388 | use crate::unistd::close; |
1389 | |
1390 | let s = socket( |
1391 | AddressFamily::Inet, |
1392 | SockType::Datagram, |
1393 | SockFlag::empty(), |
1394 | None, |
1395 | ) |
1396 | .unwrap(); |
1397 | let s_type = getsockopt(s, super::SockType).unwrap(); |
1398 | assert_eq!(s_type, SockType::Datagram); |
1399 | close(s).unwrap(); |
1400 | } |
1401 | |
1402 | #[cfg (any(target_os = "freebsd" , target_os = "linux" ))] |
1403 | #[test ] |
1404 | fn can_get_listen_on_tcp_socket() { |
1405 | use super::super::*; |
1406 | use crate::unistd::close; |
1407 | |
1408 | let s = socket( |
1409 | AddressFamily::Inet, |
1410 | SockType::Stream, |
1411 | SockFlag::empty(), |
1412 | None, |
1413 | ) |
1414 | .unwrap(); |
1415 | let s_listening = getsockopt(s, super::AcceptConn).unwrap(); |
1416 | assert!(!s_listening); |
1417 | listen(s, 10).unwrap(); |
1418 | let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); |
1419 | assert!(s_listening2); |
1420 | close(s).unwrap(); |
1421 | } |
1422 | } |
1423 | |