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