Skip to main content

dope_sys/io/socket/
raw.rs

1use std::{
2    os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd},
3    slice,
4};
5
6use libc::socklen_t;
7use o3::{base::num::bounded, buffer, buffer::pool};
8
9use crate::{
10    Errno,
11    io::{
12        fd,
13        socket::{Create, Domain, Kind, Setup, accept, msg},
14    },
15    kernel::{self, errno},
16    memory,
17};
18
19/// Receives streams or datagrams into caller-owned native storage.
20pub trait Receive {
21    fn recv<'a>(
22        &self,
23        output: buffer::raw::Output<'a>,
24    ) -> Result<Option<pool::Complete<'a>>, Errno>;
25
26    /// # Safety
27    /// Output belongs to a datagram pool with at least sixteen metadata bytes
28    /// followed by sockaddr_storage and the admitted payload capacity.
29    unsafe fn receive<'a>(
30        &self,
31        output: buffer::raw::Output<'a>,
32    ) -> Result<pool::Complete<'a>, Errno>;
33}
34
35pub trait Open: AsFd + Sized {
36    fn open(domain: Domain, kind: Kind) -> Result<Self, Create>;
37
38    fn adopt(file: OwnedFd) -> Result<Self, Setup>;
39
40    /// # Safety
41    /// Both pointers are null, or name writable full address storage and its returned length.
42    /// The caller retains that storage through the returned completion.
43    unsafe fn accept(
44        &self,
45        addr: *mut libc::sockaddr_storage,
46        len: *mut socklen_t,
47    ) -> Result<Self, accept::Error>;
48}
49
50/// Native access to operations retaining caller-owned socket storage.
51pub trait Source: errno::Source {
52    /// # Safety
53    /// Both pointers are null, or name writable sockaddr storage and its capacity
54    /// for this call. The caller retains that storage through the returned completion.
55    unsafe fn accept<E: From<Errno>>(
56        file: BorrowedFd<'_>,
57        addr: *mut libc::sockaddr,
58        len: *mut socklen_t,
59    ) -> Result<OwnedFd, E> {
60        let raw = unsafe { libc::accept(file.as_raw_fd(), addr, len) };
61        unsafe {
62            <OwnedFd as fd::raw::Adopt>::try_adopt(raw, || kernel::raw::Code::last::<Self>().into())
63        }
64    }
65
66    /// # Safety
67    /// The pointer retains a readable input prefix of exactly `len` bytes for this
68    /// call. Its original extent preserves the ABI bound and owns the input graph.
69    unsafe fn send<X: memory::raw::Extent, E: From<Errno>>(
70        file: BorrowedFd<'_>,
71        ptr: *const u8,
72        len: X::Length,
73    ) -> Result<X::Length, E> {
74        let len: bounded::U32<0, { i32::MAX as u32 }> = len.into();
75        let capacity = len.get() as usize;
76        let raw = unsafe { libc::send(file.as_raw_fd(), ptr.cast(), capacity, 0) };
77        // SAFETY: send completes at most the admitted c_int-bounded input extent.
78        Ok(unsafe {
79            kernel::raw::Status::from_count(raw)
80                .try_count::<E>(|| kernel::raw::Code::last::<Self>().into())
81        }?
82        .bounded()
83        .into())
84    }
85
86    /// # Safety
87    /// Header is the frozen root of a live input graph, with a total byte count
88    /// bounded by `i32::MAX`; its pointees outlive this call.
89    unsafe fn sendmsg<E: From<Errno>>(
90        file: BorrowedFd<'_>,
91        header: &msg::Header,
92        flags: libc::c_int,
93    ) -> Result<bounded::U32<0, { i32::MAX as u32 }>, E> {
94        let raw = unsafe { libc::sendmsg(file.as_raw_fd(), header.as_raw(), flags) };
95        // SAFETY: the retained header has a total extent bounded by c_int.
96        Ok(unsafe {
97            kernel::raw::Status::from_count(raw)
98                .try_count::<E>(|| kernel::raw::Code::last::<Self>().into())
99        }?
100        .bounded())
101    }
102}
103
104impl<T: errno::Source> Source for T {}
105
106/// Projection of a native iovec whose retained input graph proves its lifetime.
107pub trait Iovec {
108    /// # Safety
109    /// The descriptor must point to initialized bytes retained for the returned lifetime.
110    unsafe fn as_slice<'a>(&self) -> &'a [u8];
111}
112
113impl Iovec for msg::Iovec {
114    unsafe fn as_slice<'a>(&self) -> &'a [u8] {
115        if self.is_empty() {
116            return &[];
117        }
118        // SAFETY: the caller retains this nonempty descriptor's complete input bytes.
119        unsafe { slice::from_raw_parts(self.0.iov_base.cast(), self.0.iov_len) }
120    }
121}