Skip to main content

dope_core/io/socket/install/
mod.rs

1pub mod adopt;
2pub mod receive;
3pub mod slot;
4
5mod error;
6
7use std::{mem, net, os::fd};
8
9use dope_sys::io::socket::{Domain, Kind, Origin, Prepare};
10pub use error::Error;
11use fd::AsFd as _;
12
13use crate::{
14    driver,
15    io::{
16        datagram,
17        fd::handles::{Datagram, Descriptor},
18        socket,
19    },
20};
21
22/// Operating-system operation that failed while bootstrapping a descriptor.
23#[derive(Clone, Copy, PartialEq, Eq, Debug)]
24#[repr(u8)]
25pub enum Operation {
26    Socket,
27    ReuseAddress,
28    ReusePort,
29    FastOpen,
30    Bind,
31    Listen,
32    Validate,
33    FixedFile,
34}
35
36impl socket::ReuseStep for Operation {
37    const ADDRESS: Self = Self::ReuseAddress;
38    const PORT: Self = Self::ReusePort;
39}
40
41pub struct Install<'borrow, 'context, 'd> {
42    driver: &'borrow mut driver::Context<'context, 'd>,
43    reservation: slot::Reserved<'d>,
44}
45
46fn reserve<'context, 'd, 'a>(
47    driver: &'a mut driver::Context<'context, 'd>,
48) -> Result<Install<'a, 'context, 'd>, Error> {
49    Ok(Install {
50        reservation: slot::Reserved::try_new(driver.driver_ref()).map_err(Error::Slot)?,
51        driver,
52    })
53}
54
55fn reserve_datagram<'context, 'd, 'a>(
56    driver: &'a mut driver::Context<'context, 'd>,
57) -> Result<(Install<'a, 'context, 'd>, receive::Capacity<'d>), Error> {
58    let capacity = receive::Capacity::try_new(driver.driver_ref()).map_err(Error::Receive)?;
59    Ok((reserve(driver)?, capacity))
60}
61
62impl<'borrow, 'context, 'd> Install<'borrow, 'context, 'd> {
63    fn bind<F>(
64        self,
65        addr: net::SocketAddr,
66        config: &socket::Config,
67        depth: Option<socket::Backlog>,
68    ) -> Result<(Descriptor<'d>, net::SocketAddr), Error>
69    where
70        crate::Backend: Prepare<Fast = F>,
71    {
72        let fast = crate::Backend::fast_open(config.fast_open().map(Into::into))
73            .map_err(|error| Error::FastOpen(error.0))?;
74        let domain = Domain::for_addr(&addr);
75        let handle = if depth.is_some() {
76            crate::Backend::listener(domain)
77        } else {
78            crate::Backend::open(domain, Kind::Dgram)
79        }
80        .map_err(|error| match error.origin() {
81            Origin::Socket(errno) => Error::syscall(Operation::Socket, errno),
82            Origin::Setup(error) => Error::setup(error),
83        })?;
84        let handle = socket::Handle::new(handle);
85        handle.try_reuse(config).map_err(Error::reuse)?;
86        if let Some(fast) = fast {
87            crate::Backend::set_fast(handle.owned().as_fd(), fast)
88                .map_err(|errno| Error::syscall(Operation::FastOpen, errno))?;
89        }
90        handle
91            .bind(&socket::Addr::from_std(addr))
92            .map_err(|errno| Error::syscall(Operation::Bind, errno))?;
93        if let Some(depth) = depth {
94            handle
95                .listen(depth.get())
96                .map_err(|errno| Error::syscall(Operation::Listen, errno))?;
97        }
98        self.finish(handle)
99    }
100
101    fn adopt(
102        self,
103        file: fd::OwnedFd,
104        kind: Kind,
105    ) -> Result<(Descriptor<'d>, net::SocketAddr), Error> {
106        let handle = socket::Handle::new(crate::Backend::adopt(file).map_err(Error::setup)?);
107        match kind {
108            Kind::Stream => handle.check_stream(),
109            Kind::Dgram => handle.check_dgram(),
110        }
111        .map_err(Error::validation)?;
112        self.finish(handle)
113    }
114
115    fn finish(self, handle: socket::Handle) -> Result<(Descriptor<'d>, net::SocketAddr), Error> {
116        let local = handle.local_addr().map_err(Error::LocalAddress)?;
117        let local = local.into_std().map_err(Error::Address)?;
118        self.finish_at(handle, local)
119    }
120
121    fn finish_at(
122        self,
123        handle: socket::Handle,
124        local: net::SocketAddr,
125    ) -> Result<(Descriptor<'d>, net::SocketAddr), Error> {
126        match self.driver.native().install(self.reservation, handle) {
127            Ok(fd) => Ok((fd, local)),
128            Err(cause) => Err(Error::kernel(Operation::FixedFile, cause)),
129        }
130    }
131}
132
133const _: () = {
134    assert!(
135        mem::size_of::<Install<'static, 'static, 'static>>()
136            == mem::size_of::<usize>() + mem::size_of::<slot::Reserved<'static>>()
137    );
138    assert!(mem::align_of::<Install<'static, 'static, 'static>>() == mem::align_of::<usize>());
139};
140
141impl<'borrow, 'context, 'd> Install<'borrow, 'context, 'd> {
142    pub fn bind_stream(
143        mut driver: driver::Context<'context, 'd>,
144        addr: net::SocketAddr,
145        depth: socket::Backlog,
146        config: &socket::Config,
147    ) -> Result<(Descriptor<'d>, net::SocketAddr), Error> {
148        reserve(&mut driver)?.bind(addr, config, Some(depth))
149    }
150
151    pub fn adopt_stream(
152        mut driver: driver::Context<'context, 'd>,
153        fd: fd::OwnedFd,
154    ) -> Result<(Descriptor<'d>, net::SocketAddr), Error> {
155        reserve(&mut driver)?.adopt(fd, Kind::Stream)
156    }
157
158    /// Installs an owned listener without rechecking its established socket role.
159    pub fn adopt_bound(
160        mut driver: driver::Context<'context, 'd>,
161        listener: socket::Listener,
162    ) -> Result<(Descriptor<'d>, net::SocketAddr), Error> {
163        let entry = reserve(&mut driver)?;
164        let (fd, local) = listener.into_parts();
165        let handle = socket::Handle::new(crate::Backend::adopt(fd).map_err(Error::setup)?);
166        entry.finish_at(handle, local)
167    }
168
169    pub fn adopt_udp(
170        mut driver: driver::Context<'context, 'd>,
171        fd: fd::OwnedFd,
172    ) -> Result<(Datagram<'d>, net::SocketAddr), Error> {
173        let (entry, capacity) = reserve_datagram(&mut driver)?;
174        let (fd, addr) = entry.adopt(fd, Kind::Dgram)?;
175        Ok((Datagram::new(fd, capacity), addr))
176    }
177
178    /// Installs a routed datagram lease with its established socket role.
179    pub fn adopt_routed(
180        mut driver: driver::Context<'context, 'd>,
181        socket: datagram::Lease,
182    ) -> Result<(Datagram<'d>, net::SocketAddr), Error> {
183        let (entry, capacity) = reserve_datagram(&mut driver)?;
184        let (fd, addr) = entry.finish(socket.into_handle())?;
185        Ok((Datagram::new(fd, capacity), addr))
186    }
187
188    pub fn bind_udp(
189        mut driver: driver::Context<'context, 'd>,
190        addr: net::SocketAddr,
191        config: socket::Config,
192    ) -> Result<(Datagram<'d>, net::SocketAddr), Error> {
193        let (entry, capacity) = reserve_datagram(&mut driver)?;
194        let (fd, addr) = entry.bind(addr, &config, None)?;
195        Ok((Datagram::new(fd, capacity), addr))
196    }
197}