1use std::os::fd::{self, AsFd as _};
2
3pub use addr::{
4 Addr,
5 inet::{Inet, Listener},
6 prepared::Prepared,
7 unix::Unix,
8};
9pub use backlog::Backlog;
10use dope_sys::{
11 Cloexec, Errno, Nonblock,
12 io::{
13 socket,
14 socket::{SetupOrigin, Socket as _, addr::Local},
15 },
16};
17pub use error::Error;
18use install::adopt;
19
20use crate::{
21 Backend, driver,
22 driver::{
23 life::native::{
24 request,
25 request::{bound, permits},
26 },
27 result,
28 retained::flight,
29 route,
30 route::kind,
31 },
32 io::fd::handles,
33};
34
35mod addr;
36pub(crate) mod adoption;
37mod backlog;
38mod error;
39
40pub mod install;
41pub mod msg;
42pub mod option;
43pub mod pending;
44
45#[derive(Clone, Copy, PartialEq, Eq)]
46#[repr(transparent)]
47pub struct StreamSpec(socket::Domain);
48
49impl StreamSpec {
50 pub(crate) const fn domain(self) -> socket::Domain {
51 self.0
52 }
53}
54
55#[derive(Clone, Copy, PartialEq, Eq)]
56#[repr(u8)]
57pub enum Reuse {
58 Address,
59 Port,
60}
61
62pub(crate) trait ReuseStep: Sized {
64 const ADDRESS: Self;
66 const PORT: Self;
68}
69
70pub(crate) const fn reuse_step<S: ReuseStep>(reuse: Reuse) -> S {
72 match reuse {
73 Reuse::Address => S::ADDRESS,
74 Reuse::Port => S::PORT,
75 }
76}
77
78#[derive(Clone, Copy)]
79pub struct Config {
80 pub reuse: Option<Reuse>,
81 pub(crate) fast_open: Option<Backlog>,
82}
83
84impl Default for Config {
85 fn default() -> Self {
86 Self {
87 reuse: Some(Reuse::Address),
88 fast_open: None,
89 }
90 }
91}
92
93impl Config {
94 pub const fn for_datagram(reuse: Option<Reuse>) -> Self {
95 Self {
96 reuse,
97 fast_open: None,
98 }
99 }
100
101 pub fn for_tcp(reuse: Option<Reuse>, fast: Option<Backlog>) -> Self {
105 Self {
106 reuse,
107 fast_open: fast,
108 }
109 }
110
111 pub(crate) const fn fast_open(&self) -> Option<Backlog> {
112 self.fast_open
113 }
114
115 pub(crate) const fn has_addr(&self) -> bool {
116 matches!(self.reuse, Some(Reuse::Address | Reuse::Port))
117 }
118
119 pub(crate) const fn has_port(&self) -> bool {
120 matches!(self.reuse, Some(Reuse::Port))
121 }
122}
123
124const _: () = assert!(std::mem::size_of::<Option<Reuse>>() == std::mem::size_of::<bool>());
125
126#[repr(transparent)]
127pub(crate) struct Handle {
128 fd: <Backend as socket::Prepare>::Handle,
129}
130
131impl Handle {
132 pub(crate) const fn new(fd: <Backend as socket::Prepare>::Handle) -> Self {
133 Self { fd }
134 }
135
136 pub(crate) const fn owned(&self) -> &<Backend as socket::Prepare>::Handle {
137 &self.fd
138 }
139
140 pub(crate) fn into_inner(self) -> <Backend as socket::Prepare>::Handle {
141 self.fd
142 }
143
144 pub(crate) fn check_stream(&self) -> Result<(), adoption::Error> {
145 let kind = Backend::kind::<Errno>(self.fd.as_fd()).map_err(adoption::Error::Syscall)?;
146 if !kind.is_stream() {
147 return Err(adoption::Error::Role(adopt::Error::ListenerKind {
148 actual: kind.raw(),
149 }));
150 }
151 if !Backend::is_listening::<Errno>(self.fd.as_fd()).map_err(adoption::Error::Syscall)? {
152 return Err(adoption::Error::Role(adopt::Error::ListenerState {
153 actual: 0,
154 }));
155 }
156 Ok(())
157 }
158
159 pub(crate) fn check_dgram(&self) -> Result<(), adoption::Error> {
160 let kind = Backend::kind::<Errno>(self.fd.as_fd()).map_err(adoption::Error::Syscall)?;
161 if !kind.is_datagram() {
162 return Err(adoption::Error::Role(adopt::Error::DatagramKind {
163 actual: kind.raw(),
164 }));
165 }
166 Ok(())
167 }
168
169 pub(crate) fn bind(&self, addr: &Inet) -> Result<(), Errno> {
170 addr.view()
171 .native()
172 .try_bind::<Backend, Errno>(self.fd.as_fd())
173 }
174
175 pub(crate) fn listen(&self, backlog: i32) -> Result<(), Errno> {
176 Backend::listen(self.fd.as_fd(), backlog)
177 }
178
179 pub(crate) fn try_reuse(&self, config: &Config) -> Result<(), (Reuse, Errno)> {
180 if config.has_addr() {
181 Backend::set_reuse::<Errno>(self.fd.as_fd(), socket::Reuse::Address)
182 .map_err(|error| (Reuse::Address, error))?;
183 }
184 if !config.has_port() {
185 return Ok(());
186 }
187 Backend::set_reuse::<Errno>(self.fd.as_fd(), socket::Reuse::Port)
188 .map_err(|error| (Reuse::Port, error))
189 }
190
191 pub(crate) fn local_addr(&self) -> Result<Addr, Local<Errno>> {
192 Addr::local(self.fd.as_fd())
193 }
194}
195
196const _: () = {
197 assert!(size_of::<Handle>() == size_of::<fd::OwnedFd>());
198 assert!(align_of::<Handle>() == align_of::<fd::OwnedFd>());
199 assert!(size_of::<Result<(), Errno>>() == size_of::<i32>());
200 assert!(size_of::<Result<(), (Reuse, Errno)>>() == 2 * size_of::<i32>());
201};
202
203pub struct Open<'a, 'd: 'a, ID: route::Tag> {
204 raw: request::Lowered,
205 slot: handles::SocketSlot<'d>,
206 flight: flight::Vacant<'a, 'd, ID, kind::Socket>,
207 permit: permits::Admission<'a, 'd>,
208}
209
210impl<'a, 'd, ID: route::Tag + route::Select<kind::Socket>> Open<'a, 'd, ID>
211where
212 'd: 'a,
213{
214 pub fn try_new(
216 driver: &'a mut driver::Context<'_, 'd>,
217 slots: &'a flight::Slots<'d, ID>,
218 req: route::Bound<'d, ID, handles::SocketSlot<'d>>,
219 socket: StreamSpec,
220 ) -> Result<Self, result::SubmitError>
221 where
222 'd: 'a,
223 {
224 let (target, slot) = req.into_parts();
225 let raw = request::Lowered::socket(slot.outbound(), socket);
226 let flight = slots
227 .try_vacancy(target.operation::<kind::Socket>())
228 .map_err(result::SubmitError::from)?;
229 let permit = driver
230 .native()
231 .try_admit()
232 .map_err(result::SubmitError::queue)?;
233 Ok(Open {
234 raw,
235 slot,
236 flight,
237 permit,
238 })
239 }
240
241 pub fn commit(self) -> handles::Creation<'d> {
242 let Self {
243 raw,
244 slot,
245 flight,
246 permit,
247 } = self;
248 let entry = bound::Bound::scoped(raw, flight);
249 let flight = permit.submit(entry);
250 slot.begin(flight)
251 }
252}
253
254#[derive(Clone, Copy, Debug)]
255pub enum BindError {
256 Socket(crate::Errno),
257 DescriptorFlags(crate::Errno),
258 CloseOnExec(crate::Errno),
259 Bind(crate::Errno),
260 Listen(crate::Errno),
261 LocalAddress(Local<Errno>),
262 Address(Error),
263}
264
265impl BindError {
266 fn socket(error: impl Into<socket::Failure>) -> Self {
267 match error.into() {
268 socket::Failure::Socket(error) => Self::Socket(error),
269 socket::Failure::Cloexec(Cloexec::Get(error)) => Self::DescriptorFlags(error),
270 socket::Failure::Cloexec(Cloexec::Set(error)) => Self::CloseOnExec(error),
271 }
272 }
273}
274
275#[derive(Clone, Copy, Debug, PartialEq, Eq)]
277#[repr(u8)]
278pub enum CreationStep {
279 Socket,
280 DescriptorFlags,
281 CloseOnExec,
282 StatusFlags,
283 Nonblocking,
284 Sigpipe,
285}
286
287impl CreationStep {
288 pub(crate) const fn from_origin(origin: socket::Origin) -> (Self, crate::Errno) {
290 match origin {
291 socket::Origin::Socket(fault) => (Self::Socket, fault),
292 socket::Origin::Setup(setup) => match setup.origin() {
293 SetupOrigin::Cloexec(Cloexec::Get(error)) => (Self::DescriptorFlags, error),
294 SetupOrigin::Cloexec(Cloexec::Set(error)) => (Self::CloseOnExec, error),
295 SetupOrigin::Nonblock(Nonblock::Get(error)) => (Self::StatusFlags, error),
296 SetupOrigin::Nonblock(Nonblock::Set(error)) => (Self::Nonblocking, error),
297 SetupOrigin::Sigpipe(error) => (Self::Sigpipe, error),
298 },
299 }
300 }
301}
302
303#[derive(Clone, Copy, Debug, PartialEq, Eq)]
304pub struct Create {
305 fault: crate::Errno,
306 step: CreationStep,
307}
308
309impl Create {
310 pub const fn errno(self) -> crate::Errno {
311 self.fault
312 }
313 pub const fn step(self) -> CreationStep {
314 self.step
315 }
316
317 pub(crate) fn from_native(error: socket::Create) -> Self {
318 let (step, fault) = CreationStep::from_origin(error.origin());
319 Self { step, fault }
320 }
321}