s2n_quic_platform/socket/
options.rs1use crate::syscall;
5use s2n_quic_core::inet::SocketAddress;
6use std::{
7 io,
8 net::{SocketAddr, TcpListener, UdpSocket},
9};
10
11#[derive(Clone, Copy, Debug, Default)]
12pub enum ReusePort {
13 #[default]
14 Disabled,
15 BeforeBind,
19 AfterBind,
21}
22
23#[derive(Clone, Debug)]
24#[non_exhaustive]
25pub struct Options {
26 pub addr: SocketAddr,
27 pub reuse_address: bool,
28 pub reuse_port: ReusePort,
29 pub gro: bool,
30 pub blocking: bool,
31 pub delay: bool,
32 pub send_buffer: Option<usize>,
33 pub recv_buffer: Option<usize>,
34 pub backlog: usize,
35 pub only_v6: bool,
36}
37
38impl Default for Options {
39 #[inline]
40 fn default() -> Self {
41 Self {
42 addr: SocketAddress::default().into(),
43 reuse_address: false,
44 reuse_port: Default::default(),
45 gro: true,
46 blocking: false,
47 send_buffer: None,
48 recv_buffer: None,
49 delay: false,
50 backlog: 4096,
51 only_v6: false,
52 }
53 }
54}
55
56impl Options {
57 #[inline]
58 pub fn new(addr: SocketAddr) -> Self {
59 Self {
60 addr,
61 ..Default::default()
62 }
63 }
64
65 #[inline]
66 pub fn build_udp(&self) -> io::Result<UdpSocket> {
67 let socket = syscall::udp_socket(self.addr, self.only_v6)?;
68
69 if self.gro {
70 let _ = syscall::configure_gro(&socket);
71 }
72
73 let _ = syscall::configure_tos(&socket);
74 let _ = syscall::configure_mtu_disc(&socket);
75
76 self.build_common(&socket)?;
77
78 let socket = socket.into();
79 Ok(socket)
80 }
81
82 #[inline]
83 pub fn build_tcp_listener(&self) -> io::Result<TcpListener> {
84 let domain = socket2::Domain::for_address(self.addr);
85 let ty = socket2::Type::STREAM;
86 let protocol = socket2::Protocol::TCP;
87
88 let socket = socket2::Socket::new(domain, ty, Some(protocol))?;
89
90 socket.set_tcp_nodelay(!self.delay)?;
91
92 self.build_common(&socket)?;
93
94 socket.listen(self.backlog.try_into().unwrap_or(core::ffi::c_int::MAX))?;
95
96 Ok(socket.into())
97 }
98
99 fn build_common(&self, socket: &socket2::Socket) -> io::Result<()> {
100 socket.set_reuse_address(self.reuse_address)?;
101 socket.set_nonblocking(!self.blocking)?;
102
103 if let Some(send_buffer) = self.send_buffer {
104 let _ = socket.set_send_buffer_size(send_buffer);
105 }
106
107 if let Some(recv_buffer) = self.recv_buffer {
108 let _ = socket.set_recv_buffer_size(recv_buffer);
109 }
110
111 if let ReusePort::BeforeBind = self.reuse_port {
112 assert_ne!(self.addr.port(), 0);
113 set_reuse_port(socket)?;
114 }
115
116 socket.bind(&self.addr.into())?;
117
118 if let ReusePort::AfterBind = self.reuse_port {
119 set_reuse_port(socket)?;
120 }
121
122 Ok(())
123 }
124}
125
126#[cfg(windows)]
127fn set_reuse_port(_socket: &socket2::Socket) -> io::Result<()> {
128 Err(io::Error::new(
129 io::ErrorKind::InvalidInput,
130 "reuse port is not supported on windows",
131 ))
132}
133
134#[cfg(not(windows))]
135fn set_reuse_port(socket: &socket2::Socket) -> io::Result<()> {
136 socket.set_reuse_port(true)
137}