rama_net/socket/opts.rs
1//! Options and types in function of creating [`Socket`]s.
2
3use std::{
4 io,
5 net::{Ipv4Addr, SocketAddr},
6 time::Duration,
7};
8
9use super::core::{
10 Domain as SocketDomain, Protocol as SocketProtocol, SockAddr, Socket,
11 TcpKeepalive as SocketTcpKeepAlive, Type as SocketType,
12};
13use crate::address::SocketAddress;
14
15use serde::{Deserialize, Serialize};
16
17/// Specification of the communication domain for a [`Socket`].
18#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, Eq, PartialEq)]
19pub enum Domain {
20 /// Domain for IPv4 communication, corresponding to `AF_INET`.
21 #[default]
22 IPv4,
23 /// Domain for IPv6 communication, corresponding to `AF_INET6`.
24 IPv6,
25 /// Domain for Unix socket communication, corresponding to `AF_UNIX`.
26 Unix,
27}
28
29impl From<SocketAddr> for Domain {
30 fn from(value: SocketAddr) -> Self {
31 if value.is_ipv4() {
32 Self::IPv4
33 } else {
34 Self::IPv6
35 }
36 }
37}
38
39impl From<SocketAddress> for Domain {
40 fn from(value: SocketAddress) -> Self {
41 if value.ip_addr.is_ipv4() {
42 Self::IPv4
43 } else {
44 Self::IPv6
45 }
46 }
47}
48
49impl Domain {
50 #[inline]
51 #[must_use]
52 pub fn as_socket_domain(self) -> SocketDomain {
53 self.into()
54 }
55}
56
57impl From<Domain> for SocketDomain {
58 fn from(value: Domain) -> Self {
59 match value {
60 Domain::IPv4 => Self::IPV4,
61 Domain::IPv6 => Self::IPV6,
62 Domain::Unix => Self::UNIX,
63 }
64 }
65}
66
67/// Protocol specification used for creating [`Socket`]s.
68#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, Eq, PartialEq)]
69pub enum Protocol {
70 /// Protocol corresponding to `ICMPv4` (`sys::IPPROTO_ICMP`)
71 ICMPV4,
72 /// Protocol corresponding to `ICMPv6` (`sys::IPPROTO_ICMPV6`)
73 ICMPV6,
74 #[default]
75 /// Protocol corresponding to `TCP` (`sys::IPPROTO_TCP`)
76 TCP,
77 /// Protocol corresponding to `UDP` (`sys::IPPROTO_UDP`)
78 UDP,
79 #[cfg(target_os = "linux")]
80 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
81 /// Protocol corresponding to `MPTCP` (`sys::IPPROTO_MPTCP`)
82 MPTCP,
83 #[cfg(target_os = "linux")]
84 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
85 /// Protocol corresponding to `DCCP` (`sys::IPPROTO_DCCP`)
86 DCCP,
87 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
88 #[cfg_attr(docsrs, doc(cfg(any(target_os = "freebsd", target_os = "linux"))))]
89 /// Protocol corresponding to `SCTP` (`sys::IPPROTO_SCTP`)
90 SCTP,
91}
92
93impl Protocol {
94 #[inline]
95 #[must_use]
96 pub fn as_socket_protocol(self) -> SocketProtocol {
97 self.into()
98 }
99}
100
101impl From<Protocol> for SocketProtocol {
102 fn from(value: Protocol) -> Self {
103 match value {
104 Protocol::ICMPV4 => Self::ICMPV4,
105 Protocol::ICMPV6 => Self::ICMPV6,
106 Protocol::TCP => Self::TCP,
107 Protocol::UDP => Self::UDP,
108 #[cfg(target_os = "linux")]
109 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
110 Protocol::MPTCP => Self::MPTCP,
111 #[cfg(target_os = "linux")]
112 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
113 Protocol::DCCP => Self::DCCP,
114 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
115 #[cfg_attr(docsrs, doc(cfg(any(target_os = "freebsd", target_os = "linux"))))]
116 Protocol::SCTP => Self::SCTP,
117 }
118 }
119}
120
121/// Specification of communication semantics on a [`Socket`].
122#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, Eq, PartialEq)]
123pub enum Type {
124 /// Type corresponding to `SOCK_STREAM`.
125 ///
126 /// Used for protocols such as [`Protocol::TCP`].
127 #[default]
128 Stream,
129 /// Type corresponding to `SOCK_DGRAM`.
130 ///
131 /// Used for protocols such as [`Protocol::UDP`].
132 Datagram,
133 #[cfg(target_os = "linux")]
134 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
135 /// Type corresponding to `SOCK_DCCP`.
136 ///
137 /// Used for the [`Protocol::DCCP`].
138 DCCP,
139 #[cfg(not(target_os = "espidf"))]
140 #[cfg_attr(docsrs, doc(cfg(not(target_os = "espidf"))))]
141 /// Type corresponding to `SOCK_SEQPACKET`.
142 SequencePacket,
143 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
144 #[cfg_attr(docsrs, doc(cfg(not(any(target_os = "redox", target_os = "espidf")))))]
145 /// Type corresponding to `SOCK_RAW`.
146 Raw,
147}
148
149impl Type {
150 #[inline]
151 #[must_use]
152 pub fn as_socket_type(self) -> SocketType {
153 self.into()
154 }
155}
156
157impl From<Type> for SocketType {
158 fn from(value: Type) -> Self {
159 match value {
160 Type::Stream => Self::STREAM,
161 Type::Datagram => Self::DGRAM,
162 #[cfg(target_os = "linux")]
163 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
164 Type::DCCP => Self::DCCP,
165 #[cfg(not(target_os = "espidf"))]
166 #[cfg_attr(docsrs, doc(cfg(not(target_os = "espidf"))))]
167 Type::SequencePacket => Self::SEQPACKET,
168 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
169 #[cfg_attr(docsrs, doc(cfg(not(any(target_os = "redox", target_os = "espidf")))))]
170 Type::Raw => Self::RAW,
171 }
172 }
173}
174
175#[derive(Debug, Clone, Default, Serialize)]
176/// Configures a [`Socket`]'s TCP keepalive parameters.
177///
178/// See [`SocketOptions::tcp_keep_alive`].
179pub struct TcpKeepAlive {
180 /// Set the amount of time after which TCP keepalive probes will be sent on
181 /// idle connections.
182 ///
183 /// This will set `TCP_KEEPALIVE` on macOS and iOS, and
184 /// `TCP_KEEPIDLE` on all other Unix operating systems, except
185 /// OpenBSD and Haiku which don't support any way to set this
186 /// option. On Windows, this sets the value of the `tcp_keepalive`
187 /// struct's `keepalivetime` field.
188 ///
189 /// Some platforms specify this value in seconds, so sub-second
190 /// specifications may be omitted.
191 pub time: Option<Duration>,
192
193 #[cfg(not(any(
194 target_os = "openbsd",
195 target_os = "redox",
196 target_os = "solaris",
197 target_os = "nto",
198 target_os = "espidf",
199 target_os = "vita",
200 target_os = "haiku",
201 )))]
202 #[cfg_attr(
203 docsrs,
204 doc(cfg(not(any(
205 target_os = "openbsd",
206 target_os = "redox",
207 target_os = "solaris",
208 target_os = "nto",
209 target_os = "espidf",
210 target_os = "vita",
211 target_os = "haiku",
212 ))))
213 )]
214 /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
215 /// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
216 ///
217 /// Sets the time interval between TCP keepalive probes.
218 ///
219 /// Some platforms specify this value in seconds, so sub-second
220 /// specifications may be omitted.
221 pub interval: Option<Duration>,
222
223 #[cfg(not(any(
224 target_os = "openbsd",
225 target_os = "redox",
226 target_os = "solaris",
227 target_os = "windows",
228 target_os = "nto",
229 target_os = "espidf",
230 target_os = "vita",
231 target_os = "haiku",
232 )))]
233 #[cfg_attr(
234 docsrs,
235 doc(cfg(not(any(
236 target_os = "openbsd",
237 target_os = "redox",
238 target_os = "solaris",
239 target_os = "windows",
240 target_os = "nto",
241 target_os = "espidf",
242 target_os = "vita",
243 target_os = "haiku",
244 ))))
245 )]
246 /// Set the value of the `TCP_KEEPCNT` option.
247 ///
248 /// Set the maximum number of TCP keepalive probes that will be sent before
249 /// dropping a connection, if TCP keepalive is enabled on this [`Socket`].
250 pub retries: Option<u32>,
251}
252
253impl<'de> Deserialize<'de> for TcpKeepAlive {
254 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
255 where
256 D: serde::Deserializer<'de>,
257 {
258 #[derive(Deserialize)]
259 #[serde(untagged)]
260 enum Variants {
261 Time(Option<Duration>),
262 Options {
263 time: Option<Duration>,
264 #[cfg(not(any(
265 target_os = "openbsd",
266 target_os = "redox",
267 target_os = "solaris",
268 target_os = "nto",
269 target_os = "espidf",
270 target_os = "vita",
271 target_os = "haiku",
272 )))]
273 interval: Option<Duration>,
274 #[cfg(not(any(
275 target_os = "openbsd",
276 target_os = "redox",
277 target_os = "solaris",
278 target_os = "windows",
279 target_os = "nto",
280 target_os = "espidf",
281 target_os = "vita",
282 target_os = "haiku",
283 )))]
284 retries: Option<u32>,
285 },
286 }
287
288 match Variants::deserialize(deserializer)? {
289 Variants::Time(time) => Ok(Self {
290 time,
291 ..Default::default()
292 }),
293 Variants::Options {
294 time,
295 #[cfg(not(any(
296 target_os = "openbsd",
297 target_os = "redox",
298 target_os = "solaris",
299 target_os = "nto",
300 target_os = "espidf",
301 target_os = "vita",
302 target_os = "haiku",
303 )))]
304 interval,
305 #[cfg(not(any(
306 target_os = "openbsd",
307 target_os = "redox",
308 target_os = "solaris",
309 target_os = "windows",
310 target_os = "nto",
311 target_os = "espidf",
312 target_os = "vita",
313 target_os = "haiku",
314 )))]
315 retries,
316 } => Ok(Self {
317 time,
318 #[cfg(not(any(
319 target_os = "openbsd",
320 target_os = "redox",
321 target_os = "solaris",
322 target_os = "nto",
323 target_os = "espidf",
324 target_os = "vita",
325 target_os = "haiku",
326 )))]
327 interval,
328 #[cfg(not(any(
329 target_os = "openbsd",
330 target_os = "redox",
331 target_os = "solaris",
332 target_os = "windows",
333 target_os = "nto",
334 target_os = "espidf",
335 target_os = "vita",
336 target_os = "haiku",
337 )))]
338 retries,
339 }),
340 }
341 }
342}
343
344impl TcpKeepAlive {
345 #[inline]
346 #[must_use]
347 pub fn into_socket_keep_alive(self) -> SocketTcpKeepAlive {
348 self.into()
349 }
350}
351
352impl From<TcpKeepAlive> for SocketTcpKeepAlive {
353 fn from(value: TcpKeepAlive) -> Self {
354 let ka = Self::new();
355
356 let ka = match value.time {
357 Some(time) => ka.with_time(time),
358 None => ka,
359 };
360
361 #[cfg(not(any(
362 target_os = "openbsd",
363 target_os = "redox",
364 target_os = "solaris",
365 target_os = "nto",
366 target_os = "espidf",
367 target_os = "vita",
368 target_os = "haiku",
369 )))]
370 let ka = match value.interval {
371 Some(interval) => ka.with_interval(interval),
372 None => ka,
373 };
374
375 #[cfg(not(any(
376 target_os = "openbsd",
377 target_os = "redox",
378 target_os = "solaris",
379 target_os = "windows",
380 target_os = "nto",
381 target_os = "espidf",
382 target_os = "vita",
383 target_os = "haiku",
384 )))]
385 let ka = match value.retries {
386 Some(retries) => ka.with_retries(retries),
387 None => ka,
388 };
389
390 ka
391 }
392}
393
394impl SocketOptions {
395 /// Create a default TCP [`SocketOptions`].
396 #[inline]
397 #[must_use]
398 pub fn default_tcp() -> Self {
399 Default::default()
400 }
401
402 /// Create a default UDP [`SocketOptions`].
403 #[inline]
404 #[must_use]
405 pub fn default_udp() -> Self {
406 Self {
407 r#type: Type::Datagram,
408 protocol: Some(Protocol::UDP),
409 ..Default::default()
410 }
411 }
412}
413
414#[derive(Debug, Clone, Serialize, Deserialize, Default)]
415pub struct SocketOptions {
416 pub r#type: Type,
417 pub protocol: Option<Protocol>,
418
419 /// Bind the [`Socket`] to the specified address.
420 pub address: Option<SocketAddress>,
421
422 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
423 #[cfg_attr(
424 docsrs,
425 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
426 )]
427 /// Bind the [`Socket`] to the specified device.
428 ///
429 /// Sets the value for the `SO_BINDTODEVICE` option on this [`Socket`]].
430 ///
431 /// If a socket is bound to an interface, only packets received from
432 /// that particular interface are processed by the socket.
433 /// Note that this only works for some socket types, particularly [`Domain::IPv4`] [`Socket`]s.
434 pub device: Option<super::DeviceName>,
435
436 /// Set the value of the `SO_BROADCAST` option for this [`Socket`].
437 ///
438 /// When enabled, this [`Socket`] is allowed to send packets to a broadcast address.
439 pub broadcast: Option<bool>,
440
441 /// Set value for the `SO_KEEPALIVE` option on this [`Socket`].
442 ///
443 /// Enable sending of keep-alive messages on connection-oriented [`Socket`]s.
444 pub keep_alive: Option<bool>,
445
446 /// Set value for the `SO_LINGER` option on this socket.
447 ///
448 /// If linger is not None, a close(2) or shutdown(2)
449 /// will not return until all queued messages for the socket have
450 /// been successfully sent or the linger timeout has been reached.
451 /// Otherwise, the call returns immediately and the closing is done in
452 /// the background. When the socket is closed as part of exit(2),
453 /// it always lingers in the background.
454 ///
455 /// ## Notes
456 ///
457 /// On most OSs the duration only has a precision of seconds and will be silently truncated.
458 ///
459 /// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
460 pub linger: Option<Duration>,
461
462 #[cfg(not(target_os = "redox"))]
463 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
464 /// Set value for the SO_OOBINLINE option on this [`Socket`].
465 ///
466 /// If this option is enabled,
467 /// out-of-band data is directly placed into the receive data stream.
468 /// Otherwise, out-of-band data is passed only when the `MSG_OOB` flag
469 /// is set during receiving. As per [RFC6093], TCP [`Socket`]s using the Urgent
470 /// mechanism are encouraged to set this flag.
471 ///
472 /// [RFC6093]: https://datatracker.ietf.org/doc/html/rfc6093
473 pub out_of_band_inline: Option<bool>,
474
475 #[cfg(all(target_family = "unix", target_os = "linux"))]
476 #[cfg_attr(docsrs, doc(cfg(all(target_family = "unix", target_os = "linux"))))]
477 /// Set value for the `SO_PASSCRED` option on this [`Socket`].
478 ///
479 /// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS` control messages.
480 pub passcred: Option<bool>,
481
482 /// Set value for the `SO_RCVBUF` option on this [`Socket`].
483 ///
484 /// Changes the size of the operating system’s receive buffer associated with the [`Socket`].
485 pub recv_buffer_size: Option<usize>,
486
487 /// Set value for the `SO_RCVTIMEO` option on this [`Socket`].
488 ///
489 /// If timeout is None, then read and recv calls will block indefinitely.
490 pub read_timeout: Option<Duration>,
491
492 /// Set value for the `SO_REUSEADDR` option on this [`Socket`].
493 ///
494 /// This indicates that further calls to bind may allow reuse of local addresses.
495 /// For IPv4 [`Socket`]s this means that a [`Socket`] may bind even when there’s a [`Socket`] already
496 /// listening on this port.
497 pub reuse_address: Option<bool>,
498
499 /// Set value for the `SO_SNDBUF` option on this [`Socket`].
500 ///
501 /// Changes the size of the operating system’s send buffer
502 /// associated with the [`Socket`].
503 pub send_buffer_size: Option<usize>,
504
505 /// Set value for the SO_SNDTIMEO option on this [`Socket`].
506 ///
507 /// If timeout is None, then write and send calls will block indefinitely.
508 pub write_timeout: Option<Duration>,
509
510 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
511 #[cfg_attr(docsrs, doc(cfg(not(any(target_os = "redox", target_os = "espidf")))))]
512 /// Set the value of the `IP_HDRINCL` option on this [`Socket`].
513 ///
514 /// If enabled, the user supplies an IP header in front of the user data.
515 /// Valid only for [`Type::Raw`] [`Socket`]s; see [raw(7)] for more information.
516 ///
517 /// When this flag is enabled, the values set by
518 /// `IP_OPTIONS`, [`IP_TTL`], and [`IP_TOS`] are ignored.
519 ///
520 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
521 /// [`IP_TTL`]: SocketOptions::ttl
522 /// [`IP_TOS`]: SocketOptions::tos
523 pub header_included: Option<bool>,
524
525 #[cfg(not(any(
526 target_os = "redox",
527 target_os = "espidf",
528 target_os = "openbsd",
529 target_os = "freebsd",
530 target_os = "dragonfly",
531 target_os = "netbsd"
532 )))]
533 #[cfg_attr(
534 docsrs,
535 doc(cfg(not(any(
536 target_os = "redox",
537 target_os = "espidf",
538 target_os = "openbsd",
539 target_os = "freebsd",
540 target_os = "dragonfly",
541 target_os = "netbsd"
542 ))))
543 )]
544 /// Set the value of the `IP_HDRINCL` option on this [`Socket`].
545 ///
546 /// If enabled, the user supplies an IP header in front of the user data.
547 /// Valid only for [`Type::Raw`] [`Socket`]s; see [raw(7)] for more information.
548 ///
549 /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
550 ///
551 /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
552 pub header_included_v6: Option<bool>,
553
554 #[cfg(target_os = "linux")]
555 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
556 /// Set the value of the `IP_TRANSPARENT` option on this [`Socket`].
557 ///
558 /// Setting this boolean option enables transparent proxying on this [`Socket`].
559 ///
560 /// This [`Socket`] option allows the calling application to bind to a
561 /// nonlocal IP address and operate both as a client and a server with
562 /// the foreign address as the local endpoint.
563 ///
564 /// ## NOTE
565 ///
566 /// This requires that routing be set up in a way that packets
567 /// going to the foreign address are routed through the TProxy box
568 /// (i.e., the system hosting the application that employs the `IP_TRANSPARENT` socket option).
569 /// Enabling this [`Socket`] option requires superuser privileges (the `CAP_NET_ADMIN` capability).
570 ///
571 /// TProxy redirection with the iptables `TPROXY` target also requires
572 /// that this option be set on the redirected socket.
573 pub ip_transparent: Option<bool>,
574
575 #[cfg(target_os = "linux")]
576 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
577 /// Set the value of the `IPV6_TRANSPARENT` option on this [`Socket`].
578 ///
579 /// This is the IPv6 counterpart of [`ip_transparent`] (which sets
580 /// `IP_TRANSPARENT`, governing IPv4 sockets only). A dual-stack TProxy
581 /// listener must set both: `IP_TRANSPARENT` for the IPv4 path and
582 /// `IPV6_TRANSPARENT` for the IPv6 path. See [`ip_transparent`] for the
583 /// routing and privilege (`CAP_NET_ADMIN`) requirements, which are
584 /// identical.
585 ///
586 /// [`ip_transparent`]: SocketOptions::ip_transparent
587 pub ip_transparent_v6: Option<bool>,
588
589 /// Set the value of the `IP_TTL` option for this [`Socket`].
590 ///
591 /// This value sets the time-to-live field that
592 /// is used in every packet sent from this [`Socket`].
593 pub ttl: Option<u32>,
594
595 #[cfg(not(any(
596 target_os = "fuchsia",
597 target_os = "redox",
598 target_os = "solaris",
599 target_os = "illumos",
600 target_os = "haiku",
601 )))]
602 #[cfg_attr(
603 docsrs,
604 doc(cfg(not(any(
605 target_os = "fuchsia",
606 target_os = "redox",
607 target_os = "solaris",
608 target_os = "illumos",
609 target_os = "haiku",
610 ))))
611 )]
612 /// Set the value of the `IP_TOS` option for this [`Socket`].
613 ///
614 /// This value sets the type-of-service field that is used in every packet sent from this [`Socket`].
615 ///
616 /// ## NOTE
617 ///
618 /// <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
619 /// documents that not all versions of windows support `IP_TOS`.
620 pub tos: Option<u32>,
621
622 #[cfg(not(any(
623 target_os = "aix",
624 target_os = "dragonfly",
625 target_os = "fuchsia",
626 target_os = "hurd",
627 target_os = "illumos",
628 target_os = "netbsd",
629 target_os = "openbsd",
630 target_os = "redox",
631 target_os = "solaris",
632 target_os = "haiku",
633 target_os = "nto",
634 target_os = "espidf",
635 target_os = "vita",
636 )))]
637 #[cfg_attr(
638 docsrs,
639 doc(cfg(not(any(
640 target_os = "aix",
641 target_os = "dragonfly",
642 target_os = "fuchsia",
643 target_os = "hurd",
644 target_os = "illumos",
645 target_os = "netbsd",
646 target_os = "openbsd",
647 target_os = "redox",
648 target_os = "solaris",
649 target_os = "haiku",
650 target_os = "nto",
651 target_os = "espidf",
652 target_os = "vita",
653 ))))
654 )]
655 /// Set the value of the `IP_RECVTOS` option for this [`Socket`].
656 ///
657 /// If enabled, the `IP_TOS` ancillary message is passed with incoming packets.
658 /// It contains a byte which specifies the Type of Service/Precedence field of the packet header.
659 pub recv_tos: Option<bool>,
660
661 /// Set the value of the `IPV6_MULTICAST_HOPS` option for this [`Socket`].
662 ///
663 /// Indicates the number of "routers" multicast packets will transit for this [`Socket`].
664 /// The default value is 1 which means that multicast packets don’t leave the local network unless
665 /// explicitly requested.
666 pub multicast_hops_v6: Option<u32>,
667
668 #[cfg(target_os = "linux")]
669 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
670 /// Set the value of the `IP_MULTICAST_ALL` option for this [`Socket`].
671 ///
672 /// This option can be used to modify the delivery policy of
673 /// multicast messages. The argument is a boolean (defaults to true).
674 /// If set to true, the socket will receive messages from all the groups
675 /// that have been joined globally on the whole system.
676 /// Otherwise, it will deliver messages only from the groups
677 /// that have been explicitly joined
678 /// (for example via the `IP_ADD_MEMBERSHIP` option)
679 /// on this particular socket.
680 pub multicast_all_v4: Option<bool>,
681
682 #[cfg(target_os = "linux")]
683 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
684 /// Set the value of the `IPV6_MULTICAST_ALL` option for this [`Socket`].
685 ///
686 /// This option can be used to modify the delivery policy of multicast messages.
687 /// The argument is a boolean (defaults to true). If set to true,
688 /// the socket will receive messages from all the groups that have been
689 /// joined globally on the whole system. Otherwise, it will deliver messages
690 /// only from the groups that have been explicitly joined (for example via the
691 /// `IPV6_ADD_MEMBERSHIP` option) on this particular socket.
692 pub multicast_all_v6: Option<bool>,
693
694 /// Set the value of the `IP_MULTICAST_IF` option for this [`Socket`].
695 ///
696 /// If enabled, multicast packets will be looped back to the local socket.
697 /// Note that this may not have any affect on IPv6 sockets.
698 pub multicast_interface_v4: Option<Ipv4Addr>,
699
700 /// Set the value of the `IPV6_MULTICAST_IF` option for this [`Socket`].
701 ///
702 /// Specifies the interface to use for routing multicast packets.
703 /// Unlike ipv4, this is generally required in ipv6 contexts where
704 /// network routing prefixes may overlap.
705 pub multicast_interface_v6: Option<u32>,
706
707 /// Set the value of the `IP_MULTICAST_LOOP` option for this [`Socket`].
708 ///
709 /// If enabled, multicast packets will be looped back to the local [`Socket`].
710 /// Note that this may not have any affect on IPv6 [`Socket`]s.
711 pub multicast_loop_v4: Option<bool>,
712
713 /// Set the value of the `IPV6_MULTICAST_LOOP` option for this [`Socket`].
714 ///
715 /// Controls whether this [`Socket`] sees the multicast packets
716 /// it sends itself. Note that this may not have any affect on IPv4 [`Socket`]s.
717 pub multicast_loop_v6: Option<bool>,
718
719 /// Set the value of the `IP_MULTICAST_TTL` option for this [`Socket`].
720 ///
721 /// Indicates the time-to-live value of outgoing multicast packets
722 /// for this [`Socket`]. The default value is 1 which means that multicast
723 /// packets don’t leave the local network unless explicitly requested.
724 ///
725 /// Note that this may not have any affect on IPv6 [`Socket`]s.
726 pub multicast_ttl_v4: Option<u32>,
727
728 /// Set the value for the `IPV6_UNICAST_HOPS` option on this [`Socket`].
729 ///
730 /// Specifies the hop limit for ipv6 unicast packets
731 pub unicast_hops_v6: Option<u32>,
732
733 /// Set the value for the IPV6_V6ONLY option on this [`Socket`].
734 ///
735 /// If this is set to true then the socket is restricted to
736 /// sending and receiving IPv6 packets only.
737 /// In this case two IPv4 and IPv6 applications can bind the same port at the same time.
738 ///
739 /// If this is set to false then the socket can be used to send
740 /// and receive packets from an IPv4-mapped IPv6 address.
741 pub only_v6: Option<bool>,
742
743 #[cfg(not(any(
744 target_os = "dragonfly",
745 target_os = "fuchsia",
746 target_os = "illumos",
747 target_os = "netbsd",
748 target_os = "openbsd",
749 target_os = "redox",
750 target_os = "solaris",
751 target_os = "haiku",
752 target_os = "hurd",
753 target_os = "espidf",
754 target_os = "vita",
755 )))]
756 #[cfg_attr(
757 docsrs,
758 doc(cfg(not(any(
759 target_os = "dragonfly",
760 target_os = "fuchsia",
761 target_os = "illumos",
762 target_os = "netbsd",
763 target_os = "openbsd",
764 target_os = "redox",
765 target_os = "solaris",
766 target_os = "haiku",
767 target_os = "hurd",
768 target_os = "espidf",
769 target_os = "vita",
770 ))))
771 )]
772 /// Set the value of the `IPV6_RECVTCLASS` option for this [`Socket`].
773 ///
774 /// If enabled, the `IPV6_TCLASS` ancillary message is passed
775 /// with incoming packets. It contains a byte which specifies
776 /// the traffic class field of the packet header.
777 pub recv_tclass_v6: Option<bool>,
778
779 #[cfg(any(
780 target_os = "android",
781 target_os = "dragonfly",
782 target_os = "freebsd",
783 target_os = "fuchsia",
784 target_os = "linux",
785 target_os = "macos",
786 target_os = "netbsd",
787 target_os = "openbsd"
788 ))]
789 #[cfg_attr(
790 docsrs,
791 doc(cfg(any(
792 target_os = "android",
793 target_os = "dragonfly",
794 target_os = "freebsd",
795 target_os = "fuchsia",
796 target_os = "linux",
797 target_os = "macos",
798 target_os = "netbsd",
799 target_os = "openbsd"
800 )))
801 )]
802 /// Set the value of the `IPV6_TCLASS` option for this [`Socket`].
803 ///
804 /// Specifies the traffic class field that is used in every packets
805 /// sent from this [`Socket`].
806 pub tclass_v6: Option<u32>,
807
808 #[cfg(not(any(
809 target_os = "windows",
810 target_os = "dragonfly",
811 target_os = "fuchsia",
812 target_os = "illumos",
813 target_os = "netbsd",
814 target_os = "openbsd",
815 target_os = "redox",
816 target_os = "solaris",
817 target_os = "haiku",
818 target_os = "hurd",
819 target_os = "espidf",
820 target_os = "vita",
821 )))]
822 #[cfg_attr(
823 docsrs,
824 doc(cfg(not(any(
825 target_os = "windows",
826 target_os = "dragonfly",
827 target_os = "fuchsia",
828 target_os = "illumos",
829 target_os = "netbsd",
830 target_os = "openbsd",
831 target_os = "redox",
832 target_os = "solaris",
833 target_os = "haiku",
834 target_os = "hurd",
835 target_os = "espidf",
836 target_os = "vita",
837 ))))
838 )]
839 /// Set the value of the `IPV6_RECVHOPLIMIT` option for this [`Socket`].
840 ///
841 /// The received hop limit is returned as ancillary data by `recvmsg()`
842 /// only if the application has enabled the `IPV6_RECVHOPLIMIT` [`Socket`] option.
843 pub recv_hoplimit_v6: Option<bool>,
844
845 /// Set parameters configuring TCP keepalive probes for this [`Socket`].
846 ///
847 /// The supported parameters depend on the operating system, and are
848 /// configured using the [`TcpKeepAlive`] struct. At a minimum, all systems
849 /// support configuring the [keepalive time]: the time after which the OS
850 /// will start sending keepalive messages on an idle connection.
851 ///
852 /// [keepalive time]: TcpKeepAlive::time
853 ///
854 /// # Notes
855 ///
856 /// * This will enable `SO_KEEPALIVE` on this [`Socket`], if it is not already
857 /// enabled.
858 /// * On some platforms, such as Windows, any keepalive parameters *not*
859 /// configured by the `TcpKeepalive` struct passed to this function may be
860 /// overwritten with their default values. Therefore, this function should
861 /// either only be called once per [`Socket`], or the same parameters should
862 /// be passed every time it is called.
863 pub tcp_keep_alive: Option<TcpKeepAlive>,
864
865 /// Set the value of the `TCP_NODELAY` option on this [`Socket`].
866 ///
867 /// If set, this option disables the Nagle algorithm.
868 /// This means that segments are always sent as soon as possible,
869 /// even if there is only a small amount of data. When not set,
870 /// data is buffered until there is a sufficient amount to send out,
871 /// thereby avoiding the frequent sending of small packets.
872 pub tcp_no_delay: Option<bool>,
873
874 #[cfg(all(target_family = "unix", not(target_os = "redox")))]
875 #[cfg_attr(
876 docsrs,
877 doc(cfg(all(target_family = "unix", not(target_os = "redox"))))
878 )]
879 /// Sets the value of the `TCP_MAXSEG` option on this [`Socket`].
880 ///
881 /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment Size
882 /// and is only available on TCP [`Socket`]s.
883 pub tcp_max_segments: Option<u32>,
884
885 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
886 #[cfg_attr(docsrs, doc(cfg(any(target_os = "freebsd", target_os = "linux"))))]
887 /// Set the value of the `TCP_CONGESTION` option for this [`Socket`].
888 ///
889 /// Specifies the TCP congestion control algorithm to use for this socket.
890 ///
891 /// The value must be a valid TCP congestion control algorithm name of the
892 /// platform. For example, Linux may supports "reno", "cubic".
893 pub tcp_congestion: Option<String>,
894
895 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
896 #[cfg_attr(
897 docsrs,
898 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
899 )]
900 /// Sets the value for the `SO_MARK` option on this [`Socket`].
901 ///
902 /// This value sets the socket mark field for each packet sent through this [`Socket`].
903 /// Changing the mark can be used for mark-based routing without netfilter or for packet filtering.
904 ///
905 /// On Linux this function requires the CAP_NET_ADMIN capability.
906 pub mark: Option<u32>,
907
908 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
909 #[cfg_attr(
910 docsrs,
911 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
912 )]
913 /// Set the value of the `TCP_CORK` option on this [`Socket`].
914 ///
915 /// If set, don't send out partial frames. All queued partial frames are
916 /// sent when the option is cleared again. There is a 200 millisecond ceiling on
917 /// the time for which output is corked by `TCP_CORK`. If this ceiling is reached,
918 /// then queued data is automatically transmitted.
919 pub tcp_cork: Option<bool>,
920
921 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
922 #[cfg_attr(
923 docsrs,
924 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
925 )]
926 /// Set the value of the `TCP_QUICKACK` option on this [`Socket`].
927 ///
928 /// If set, acks are sent immediately, rather than delayed if needed in accordance to normal
929 /// TCP operation. This flag is not permanent, it only enables a switch to or from quickack mode.
930 /// Subsequent operation of the TCP protocol will once again enter/leave quickack mode depending on
931 /// internal protocol processing and factors such as delayed ack timeouts occurring and data transfer.
932 pub tcp_quick_ack: Option<bool>,
933
934 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
935 #[cfg_attr(
936 docsrs,
937 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
938 )]
939 /// Set the value of the `TCP_THIN_LINEAR_TIMEOUTS` option on this [`Socket`].
940 ///
941 /// If set, the kernel will dynamically detect a thin-stream connection
942 /// if there are less than four packets in flight.
943 /// With less than four packets in flight the normal TCP fast retransmission will not be effective.
944 /// The kernel will modify the retransmission to avoid the very high latencies that thin stream
945 /// suffer because of exponential backoff.
946 pub tcp_thin_linear_timeouts: Option<bool>,
947
948 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
949 #[cfg_attr(
950 docsrs,
951 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
952 )]
953 /// Set the value of the `TCP_USER_TIMEOUT` option on this [`Socket`].
954 ///
955 /// If set, this specifies the maximum amount of time that transmitted data may remain
956 /// unacknowledged or buffered data may remain untransmitted before TCP will forcibly close the
957 /// corresponding connection.
958 ///
959 /// Setting `timeout` to `None` or a zero duration causes the system default timeouts to
960 /// be used. If `timeout` in milliseconds is larger than `c_uint::MAX`, the timeout is clamped
961 /// to `c_uint::MAX`. For example, when `c_uint` is a 32-bit value, this limits the timeout to
962 /// approximately 49.71 days.
963 pub tcp_user_timeout: Option<Duration>,
964
965 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
966 #[cfg_attr(
967 docsrs,
968 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
969 )]
970 /// Set value for the `IP_FREEBIND` option on this [`Socket`].
971 ///
972 /// If enabled, this boolean option allows binding to an IP address that is
973 /// nonlocal or does not (yet) exist. This permits listening on a [`Socket`],
974 /// without requiring the underlying network interface or the specified
975 /// dynamic IP address to be up at the time that the application is trying
976 /// to bind to it.
977 pub freebind: Option<bool>,
978
979 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
980 #[cfg_attr(
981 docsrs,
982 doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))
983 )]
984 /// Set value for the `IPV6_FREEBIND` option on this [`Socket`].
985 ///
986 /// This is an IPv6 counterpart of `IP_FREEBIND` [`Socket`] option on
987 /// Android/Linux. For more information about this option, see
988 /// [`set_freebind`].
989 ///
990 /// [`set_freebind`]: SocketOptions::freebind
991 pub freebind_ipv6: Option<bool>,
992
993 #[cfg(target_os = "linux")]
994 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
995 /// Set value for the `SO_INCOMING_CPU` option on this [`Socket`].
996 ///
997 /// Sets the CPU affinity of the [`Socket`].
998 pub cpu_affinity: Option<usize>,
999
1000 #[cfg(all(
1001 target_family = "unix",
1002 not(any(target_os = "solaris", target_os = "illumos"))
1003 ))]
1004 #[cfg_attr(
1005 docsrs,
1006 doc(cfg(all(
1007 target_family = "unix",
1008 not(any(target_os = "solaris", target_os = "illumos"))
1009 )))
1010 )]
1011 /// Set value for the `SO_REUSEPORT` option on this [`Socket`].
1012 ///
1013 /// This indicates that further calls to `bind` may allow reuse of local
1014 /// addresses. For IPv4 [`Socket`]s this means that a [`Socket`] may bind even when
1015 /// there's a [`Socket`] already listening on this port.
1016 pub reuse_port: Option<bool>,
1017
1018 #[cfg(target_os = "linux")]
1019 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
1020 /// Set value for the `DCCP_SOCKOPT_SERVICE` option on this [`Socket`].
1021 ///
1022 /// Sets the DCCP service. The specification mandates use of service codes.
1023 /// If this [`Socket`] option is not set, the [`Socket`] will fall back to 0 (which
1024 /// means that no meaningful service code is present). On active [`Socket`]s
1025 /// this is set before [`connect`]. On passive [`Socket`]s up to 32 service
1026 /// codes can be set before calling [`bind`]
1027 ///
1028 /// [`connect`]: Socket::connect
1029 /// [`bind`]: Socket::bind
1030 pub dccp_service: Option<u32>,
1031
1032 #[cfg(target_os = "linux")]
1033 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
1034 /// Set value for the `DCCP_SOCKOPT_CCID` option on this [`Socket`].
1035 ///
1036 /// This option sets both the TX and RX CCIDs at the same time.
1037 pub dccp_ccid: Option<u8>,
1038
1039 #[cfg(target_os = "linux")]
1040 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
1041 /// Set value for the `DCCP_SOCKOPT_SERVER_TIMEWAIT` option on this [`Socket`].
1042 ///
1043 /// Enables a listening [`Socket`] to hold timewait state when closing the
1044 /// connection. This option must be set after `accept` returns.
1045 pub dccp_server_timewait: Option<bool>,
1046
1047 #[cfg(target_os = "linux")]
1048 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
1049 /// Set value for the `DCCP_SOCKOPT_SEND_CSCOV` option on this [`Socket`].
1050 ///
1051 /// Both this option and `DCCP_SOCKOPT_RECV_CSCOV` are used for setting the
1052 /// partial checksum coverage. The default is that checksums always cover
1053 /// the entire packet and that only fully covered application data is
1054 /// accepted by the receiver. Hence, when using this feature on the sender,
1055 /// it must be enabled at the receiver too, with suitable choice of CsCov.
1056 pub dccp_send_cscov: Option<u32>,
1057
1058 #[cfg(target_os = "linux")]
1059 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
1060 /// Set the value of the `DCCP_SOCKOPT_RECV_CSCOV` option on this [`Socket`].
1061 ///
1062 /// This option is only useful when combined with [`dccp_send_cscov`].
1063 ///
1064 /// [`dccp_send_cscov`]: Socket::dccp_send_cscov
1065 pub dccp_recv_cscov: Option<u32>,
1066
1067 #[cfg(target_os = "linux")]
1068 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
1069 /// Set value for the `DCCP_SOCKOPT_QPOLICY_TXQLEN` option on this [`Socket`].
1070 ///
1071 /// This option sets the maximum length of the output queue. A zero value is
1072 /// interpreted as unbounded queue length.
1073 pub dccp_qpolicy_txqlen: Option<u32>,
1074}
1075
1076impl SocketOptions {
1077 pub fn try_build_socket(&self, domain: Domain) -> io::Result<Socket> {
1078 let socket = Socket::new(
1079 domain.into(),
1080 self.r#type.into(),
1081 self.protocol.map(Into::into),
1082 )?;
1083
1084 if let Some(broadcast) = self.broadcast {
1085 socket.set_broadcast(broadcast)?;
1086 }
1087 if let Some(keep_alive) = self.keep_alive {
1088 socket.set_keepalive(keep_alive)?;
1089 }
1090 if let Some(linger) = self.linger {
1091 socket.set_linger(Some(linger))?;
1092 }
1093 #[cfg(not(target_os = "redox"))]
1094 if let Some(oob) = self.out_of_band_inline {
1095 socket.set_out_of_band_inline(oob)?;
1096 }
1097 #[cfg(all(target_family = "unix", target_os = "linux"))]
1098 if let Some(passcred) = self.passcred {
1099 socket.set_passcred(passcred)?;
1100 }
1101 if let Some(n) = self.recv_buffer_size {
1102 socket.set_recv_buffer_size(n)?;
1103 }
1104 if let Some(duration) = self.read_timeout {
1105 socket.set_read_timeout(Some(duration))?;
1106 }
1107 if let Some(reuse) = self.reuse_address {
1108 socket.set_reuse_address(reuse)?;
1109 }
1110 if let Some(n) = self.send_buffer_size {
1111 socket.set_send_buffer_size(n)?;
1112 }
1113 if let Some(duration) = self.write_timeout {
1114 socket.set_write_timeout(Some(duration))?;
1115 }
1116 #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
1117 if let Some(header_included) = self.header_included {
1118 socket.set_header_included_v4(header_included)?;
1119 }
1120 #[cfg(not(any(
1121 target_os = "redox",
1122 target_os = "espidf",
1123 target_os = "openbsd",
1124 target_os = "freebsd",
1125 target_os = "dragonfly",
1126 target_os = "netbsd"
1127 )))]
1128 if let Some(header_included) = self.header_included {
1129 socket.set_header_included_v6(header_included)?;
1130 }
1131 #[cfg(target_os = "linux")]
1132 if let Some(transparent) = self.ip_transparent {
1133 socket.set_ip_transparent_v4(transparent)?;
1134 }
1135 #[cfg(target_os = "linux")]
1136 if let Some(transparent) = self.ip_transparent_v6 {
1137 socket.set_ip_transparent_v6(transparent)?;
1138 }
1139 if let Some(ttl) = self.ttl {
1140 socket.set_ttl_v4(ttl)?;
1141 }
1142 #[cfg(not(any(
1143 target_os = "fuchsia",
1144 target_os = "redox",
1145 target_os = "solaris",
1146 target_os = "illumos",
1147 target_os = "haiku",
1148 )))]
1149 if let Some(tos) = self.tos {
1150 socket.set_tos_v4(tos)?;
1151 }
1152 #[cfg(not(any(
1153 target_os = "aix",
1154 target_os = "dragonfly",
1155 target_os = "fuchsia",
1156 target_os = "hurd",
1157 target_os = "illumos",
1158 target_os = "netbsd",
1159 target_os = "openbsd",
1160 target_os = "redox",
1161 target_os = "solaris",
1162 target_os = "haiku",
1163 target_os = "nto",
1164 target_os = "espidf",
1165 target_os = "vita",
1166 )))]
1167 if let Some(recv_tos) = self.recv_tos {
1168 socket.set_recv_tos_v4(recv_tos)?;
1169 }
1170 if let Some(loop_v4) = self.multicast_loop_v4 {
1171 socket.set_multicast_loop_v4(loop_v4)?;
1172 }
1173 if let Some(loop_v6) = self.multicast_loop_v6 {
1174 socket.set_multicast_loop_v6(loop_v6)?;
1175 }
1176 if let Some(ttl) = self.multicast_ttl_v4 {
1177 socket.set_multicast_ttl_v4(ttl)?;
1178 }
1179 if let Some(hops) = self.multicast_hops_v6 {
1180 socket.set_multicast_hops_v6(hops)?;
1181 }
1182 #[cfg(target_os = "linux")]
1183 if let Some(all) = self.multicast_all_v4 {
1184 socket.set_multicast_all_v4(all)?;
1185 }
1186 #[cfg(target_os = "linux")]
1187 if let Some(all) = self.multicast_all_v6 {
1188 socket.set_multicast_all_v6(all)?;
1189 }
1190 if let Some(interface) = self.multicast_interface_v4.as_ref() {
1191 socket.set_multicast_if_v4(interface)?;
1192 }
1193 if let Some(interface) = self.multicast_interface_v6 {
1194 socket.set_multicast_if_v6(interface)?;
1195 }
1196 if let Some(hops) = self.unicast_hops_v6 {
1197 socket.set_unicast_hops_v6(hops)?;
1198 }
1199 if let Some(only_v6) = self.only_v6 {
1200 socket.set_only_v6(only_v6)?;
1201 }
1202
1203 #[cfg(not(any(
1204 target_os = "windows",
1205 target_os = "dragonfly",
1206 target_os = "fuchsia",
1207 target_os = "illumos",
1208 target_os = "netbsd",
1209 target_os = "openbsd",
1210 target_os = "redox",
1211 target_os = "solaris",
1212 target_os = "haiku",
1213 target_os = "hurd",
1214 target_os = "espidf",
1215 target_os = "vita",
1216 )))]
1217 if let Some(recv) = self.recv_hoplimit_v6 {
1218 socket.set_recv_hoplimit_v6(recv)?;
1219 }
1220
1221 #[cfg(not(any(
1222 target_os = "windows",
1223 target_os = "dragonfly",
1224 target_os = "fuchsia",
1225 target_os = "illumos",
1226 target_os = "netbsd",
1227 target_os = "openbsd",
1228 target_os = "redox",
1229 target_os = "solaris",
1230 target_os = "haiku",
1231 target_os = "hurd",
1232 target_os = "espidf",
1233 target_os = "vita",
1234 )))]
1235 if let Some(recv) = self.recv_tclass_v6 {
1236 socket.set_recv_tclass_v6(recv)?;
1237 }
1238
1239 #[cfg(any(
1240 target_os = "android",
1241 target_os = "dragonfly",
1242 target_os = "freebsd",
1243 target_os = "fuchsia",
1244 target_os = "linux",
1245 target_os = "macos",
1246 target_os = "netbsd",
1247 target_os = "openbsd"
1248 ))]
1249 if let Some(tclass_v6) = self.tclass_v6 {
1250 socket.set_tclass_v6(tclass_v6)?;
1251 }
1252
1253 if let Some(keep_alive) = self.tcp_keep_alive.clone() {
1254 socket.set_tcp_keepalive(&keep_alive.into_socket_keep_alive())?;
1255 }
1256 if let Some(no_delay) = self.tcp_no_delay {
1257 socket.set_tcp_nodelay(no_delay)?;
1258 }
1259
1260 #[cfg(all(target_family = "unix", not(target_os = "redox")))]
1261 if let Some(mss) = self.tcp_max_segments {
1262 socket.set_tcp_mss(mss)?;
1263 }
1264
1265 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1266 if let Some(algo) = self.tcp_congestion.as_ref() {
1267 socket.set_tcp_congestion(algo.as_bytes())?;
1268 }
1269
1270 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1271 {
1272 if let Some(mark) = self.mark {
1273 socket.set_mark(mark)?;
1274 }
1275 if let Some(cork) = self.tcp_cork {
1276 socket.set_tcp_cork(cork)?;
1277 }
1278 if let Some(quickack) = self.tcp_quick_ack {
1279 socket.set_tcp_quickack(quickack)?;
1280 }
1281 if let Some(timeouts) = self.tcp_thin_linear_timeouts {
1282 socket.set_tcp_thin_linear_timeouts(timeouts)?;
1283 }
1284 if let Some(tcp_user_timeout) = self.tcp_user_timeout {
1285 socket.set_tcp_user_timeout(Some(tcp_user_timeout))?;
1286 }
1287 if let Some(freebind) = self.freebind {
1288 socket.set_freebind_v4(freebind)?;
1289 }
1290 if let Some(freebind_ipv6) = self.freebind_ipv6 {
1291 socket.set_freebind_v6(freebind_ipv6)?;
1292 }
1293 }
1294
1295 #[cfg(target_os = "linux")]
1296 if let Some(cpu) = self.cpu_affinity {
1297 socket.set_cpu_affinity(cpu)?;
1298 }
1299
1300 #[cfg(all(
1301 target_family = "unix",
1302 not(any(target_os = "solaris", target_os = "illumos"))
1303 ))]
1304 if let Some(reuse) = self.reuse_port {
1305 socket.set_reuse_port(reuse)?;
1306 }
1307
1308 #[cfg(target_os = "linux")]
1309 {
1310 if let Some(service) = self.dccp_service {
1311 socket.set_dccp_service(service)?;
1312 }
1313 if let Some(ccid) = self.dccp_ccid {
1314 socket.set_dccp_ccid(ccid)?;
1315 }
1316 if let Some(timewait) = self.dccp_server_timewait {
1317 socket.set_dccp_server_timewait(timewait)?;
1318 }
1319 if let Some(send_cscov) = self.dccp_send_cscov {
1320 socket.set_dccp_send_cscov(send_cscov)?;
1321 }
1322 if let Some(recv_cscov) = self.dccp_recv_cscov {
1323 socket.set_dccp_recv_cscov(recv_cscov)?;
1324 }
1325 if let Some(txqlen) = self.dccp_qpolicy_txqlen {
1326 socket.set_dccp_qpolicy_txqlen(txqlen)?;
1327 }
1328 }
1329
1330 if let Some(addr) = self.address {
1331 let std_addr: SocketAddr = addr.into();
1332 let socket_addr: SockAddr = std_addr.into();
1333 socket.bind(&socket_addr)?;
1334 }
1335
1336 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1337 if let Some(ref device) = self.device {
1338 socket.bind_device(Some(device.as_bytes()))?;
1339 }
1340
1341 Ok(socket)
1342 }
1343}