1use std::io;
2use std::net::SocketAddr;
3
4use super::DriverContext;
5use crate::io::fd::{Fd, FdSlot};
6use crate::io::ffi::Handle;
7use crate::io::socket::addr::Addr;
8use crate::io::socket::{Domain, Kind, ListenerConfig};
9
10pub trait Bootstrap<'d> {
11 fn bind_listener_slot(
12 &mut self,
13 addr: SocketAddr,
14 backlog: i32,
15 config: &ListenerConfig,
16 ) -> io::Result<(Fd<'d>, SocketAddr)>;
17 fn bind_datagram_slot(&mut self, addr: SocketAddr) -> io::Result<(Fd<'d>, SocketAddr)>;
18}
19
20cfg_select! {
21 target_os = "linux" => {
22 use std::io::Error;
23 use std::os::fd::{AsRawFd, RawFd};
24
25 use io_uring::opcode::FilesUpdate;
26
27 use super::control::ContextControl;
28 use super::submission::Submission;
29 use super::token::{Epoch, ROUTE_FRAMEWORK, SlotIndex, Token};
30 use crate::backend::uring::sqe::{self, Sqe};
31
32 const BOOTSTRAP_UD: Token = Token::new(ROUTE_FRAMEWORK, SlotIndex::new(0), Epoch::ZERO);
33
34 impl<'a, 'd> Bootstrap<'d> for DriverContext<'a, 'd> {
35 fn bind_listener_slot(
36 &mut self,
37 addr: SocketAddr,
38 backlog: i32,
39 config: &ListenerConfig,
40 ) -> io::Result<(Fd<'d>, SocketAddr)> {
41 let reference = self.driver_ref();
42 let (idx, bound) = if addr.port() == 0 {
43 bootstrap_bound_via_syscall(self, addr, Kind::Stream, config, Some(backlog))
44 } else {
45 let idx = bootstrap_bind_slot(
46 self,
47 Domain::for_addr(&addr),
48 Kind::Stream,
49 addr,
50 Some(config),
51 )?;
52 bootstrap_perform(
53 self,
54 Sqe::listen_at(FdSlot::new(idx), backlog, BOOTSTRAP_UD),
55 )?;
56 Ok((idx, addr))
57 }?;
58 Ok((
59 unsafe { Fd::from_raw_slot(FdSlot::new(idx), reference) },
60 bound,
61 ))
62 }
63
64 fn bind_datagram_slot(&mut self, addr: SocketAddr) -> io::Result<(Fd<'d>, SocketAddr)> {
65 let reference = self.driver_ref();
66 let config = ListenerConfig::for_datagram(&addr);
67 let (idx, bound) = if addr.port() == 0 {
68 bootstrap_bound_via_syscall(self, addr, Kind::Dgram, &config, None)
69 } else {
70 let idx = bootstrap_bind_slot(
71 self,
72 Domain::for_addr(&addr),
73 Kind::Dgram,
74 addr,
75 Some(&config),
76 )?;
77 Ok((idx, addr))
78 }?;
79 Ok((
80 unsafe { Fd::from_raw_slot(FdSlot::new(idx), reference) },
81 bound,
82 ))
83 }
84 }
85
86 fn bootstrap_await(
87 driver: &mut DriverContext<'_, '_>,
88 min: i32,
89 fallback: i32,
90 ) -> io::Result<()> {
91 let rc = driver.backend().await_one()?;
92 if rc < min {
93 return Err(Error::from_raw_os_error(if rc < 0 {
94 -rc
95 } else {
96 fallback
97 }));
98 }
99 Ok(())
100 }
101
102 fn bootstrap_perform(driver: &mut DriverContext<'_, '_>, sqe: sqe::Sqe) -> io::Result<()> {
103 Submission::push(driver, sqe)?;
104 bootstrap_await(driver, 0, 0)
105 }
106
107 fn bootstrap_bind_slot(
108 driver: &mut DriverContext<'_, '_>,
109 domain: Domain,
110 kind: Kind,
111 addr: SocketAddr,
112 config: Option<&ListenerConfig>,
113 ) -> io::Result<u32> {
114 let idx = driver.backend().alloc_fixed_range(1)?;
115 let slot = FdSlot::new(idx);
116 bootstrap_perform(
117 driver,
118 Sqe::socket_at(domain.raw(), kind.raw(), 0, slot, BOOTSTRAP_UD)?,
119 )?;
120 if let Some(config) = config {
121 bootstrap_apply_config(driver, idx, config)?;
122 }
123 let bound = Addr::from_std(addr);
124 bootstrap_perform(
125 driver,
126 Sqe::bind_at(slot, bound.ptr(), bound.socklen(), BOOTSTRAP_UD),
127 )?;
128 Ok(idx)
129 }
130
131 fn bootstrap_apply_config(
132 driver: &mut DriverContext<'_, '_>,
133 slot: u32,
134 config: &ListenerConfig,
135 ) -> io::Result<()> {
136 if config.reuse_addr {
137 bootstrap_setsockopt(
138 driver,
139 slot,
140 libc::SOL_SOCKET as u32,
141 libc::SO_REUSEADDR as u32,
142 1,
143 )?;
144 }
145 if config.reuse_port {
146 bootstrap_setsockopt(
147 driver,
148 slot,
149 libc::SOL_SOCKET as u32,
150 libc::SO_REUSEPORT as u32,
151 1,
152 )?;
153 }
154 if let Some(qlen) = config.fast_open_backlog {
155 bootstrap_setsockopt(
156 driver,
157 slot,
158 libc::IPPROTO_TCP as u32,
159 libc::TCP_FASTOPEN as u32,
160 qlen as i32,
161 )?;
162 }
163 if let Some(secs) = config.defer_accept_secs {
164 bootstrap_setsockopt(
165 driver,
166 slot,
167 libc::IPPROTO_TCP as u32,
168 libc::TCP_DEFER_ACCEPT as u32,
169 secs as i32,
170 )?;
171 }
172 Ok(())
173 }
174
175 fn bootstrap_setsockopt(
176 driver: &mut DriverContext<'_, '_>,
177 slot: u32,
178 level: u32,
179 optname: u32,
180 value: i32,
181 ) -> io::Result<()> {
182 ContextControl::set(driver, slot, level, optname, value)?;
183 bootstrap_await(driver, 0, 0)
184 }
185
186 fn bootstrap_register_raw(
187 driver: &mut DriverContext<'_, '_>,
188 raw: RawFd,
189 slot: u32,
190 ) -> io::Result<()> {
191 let mut fds = [raw];
192 let entry = FilesUpdate::new(fds.as_mut_ptr().cast_const(), 1)
193 .offset(slot as i32)
194 .build()
195 .user_data(BOOTSTRAP_UD.raw());
196 Submission::push(driver, Sqe::from_entry(entry))?;
197 bootstrap_await(driver, 1, libc::EMFILE)?;
198 driver.backend().files.set_live(FdSlot::new(slot));
199 Ok(())
200 }
201
202 fn bootstrap_bound_via_syscall(
203 driver: &mut DriverContext<'_, '_>,
204 addr: SocketAddr,
205 kind: Kind,
206 config: &ListenerConfig,
207 backlog: Option<i32>,
208 ) -> io::Result<(u32, SocketAddr)> {
209 let handle = Handle::open(Domain::for_addr(&addr), kind)?;
210 handle.apply_reuse(config)?;
211 handle.bind(&Addr::from_std(addr))?;
212 match backlog {
213 Some(backlog) => handle.listen(backlog)?,
214 None => handle.set_nonblocking()?,
215 }
216 let actual = handle.local_addr()?;
217 let slot = driver.backend().alloc_fixed_range(1)?;
218 bootstrap_register_raw(driver, handle.as_raw_fd(), slot)?;
219 drop(handle);
220 Ok((slot, actual))
221 }
222 }
223 _ => {
224 use std::os::fd::IntoRawFd;
225
226 use crate::backend::kqueue::driver::Kqueue;
227
228 impl<'a, 'd> Bootstrap<'d> for DriverContext<'a, 'd> {
229 fn bind_listener_slot(
230 &mut self,
231 addr: SocketAddr,
232 backlog: i32,
233 config: &ListenerConfig,
234 ) -> io::Result<(Fd<'d>, SocketAddr)> {
235 let reference = self.driver_ref();
236 let state = self.backend();
237 let handle = Handle::open(Domain::for_addr(&addr), Kind::Stream)?;
238 handle.apply_reuse(config)?;
239 handle.bind(&Addr::from_std(addr))?;
240 handle.listen(backlog)?;
241 let actual = handle.local_addr()?;
242 let idx = register(state, handle)?;
243 Ok((
244 unsafe { Fd::from_raw_slot(FdSlot::new(idx), reference) },
245 actual,
246 ))
247 }
248
249 fn bind_datagram_slot(
250 &mut self,
251 addr: SocketAddr,
252 ) -> io::Result<(Fd<'d>, SocketAddr)> {
253 let reference = self.driver_ref();
254 let state = self.backend();
255 let handle = Handle::open(Domain::for_addr(&addr), Kind::Dgram)?;
256 handle.set_nonblocking()?;
257 handle.apply_reuse(&ListenerConfig::for_datagram(&addr))?;
258 handle.bind(&Addr::from_std(addr))?;
259 let actual = handle.local_addr()?;
260 let idx = register(state, handle)?;
261 Ok((
262 unsafe { Fd::from_raw_slot(FdSlot::new(idx), reference) },
263 actual,
264 ))
265 }
266 }
267
268 fn register(state: &mut Kqueue, handle: Handle) -> io::Result<u32> {
269 let slot = state.alloc_fixed_range(1)?;
270 state.register_raw_fd(slot, handle.into_raw_fd())?;
271 Ok(slot)
272 }
273 }
274}