1#![cfg_attr(not(feature = "std"), no_std)]
2
3extern crate alloc;
4use alloc::collections::vec_deque::VecDeque;
5use alloc::format;
6use alloc::vec::Vec;
7
8use core::str;
9use core::task::Poll;
10
11use libredox::flag;
12use syscall::error::{Error, Result, EINTR};
13use syscall::flag::{FobtainFdFlags, SendFdFlags};
14use syscall::schemev2::{Cqe, CqeOpcode, NewFdFlags, Opcode, Sqe};
15
16pub mod scheme;
17
18#[cfg(feature = "std")]
19pub mod wrappers;
20
21pub struct CallerCtx {
22 pub pid: usize,
23 pub uid: u32,
24 pub gid: u32,
25 pub id: Id,
26}
27
28pub enum OpenResult {
29 ThisScheme { number: usize, flags: NewFdFlags },
30 OtherScheme { fd: usize },
31}
32
33use core::mem::{size_of, MaybeUninit};
34
35use self::scheme::IntoTag;
36
37#[repr(transparent)]
38#[derive(Debug, Default)]
39pub struct Request {
40 sqe: Sqe,
41}
42
43#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
44pub struct Id(u32);
45
46#[derive(Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
47pub struct Tag(Id);
48
49impl Tag {
50 pub fn id(&self) -> Id {
51 self.0
52 }
53}
54
55#[derive(Debug)]
56pub struct CancellationRequest {
57 pub id: Id,
58}
59
60#[repr(transparent)]
61#[derive(Debug)]
62pub struct CallRequest {
63 inner: Request,
64}
65
66#[repr(transparent)]
67#[derive(Debug)]
68pub struct SendFdRequest {
69 inner: Request,
70}
71
72pub enum RequestKind {
73 Call(CallRequest),
74 Cancellation(CancellationRequest),
75 SendFd(SendFdRequest),
76 MsyncMsg,
77 MunmapMsg,
78 MmapMsg,
79 OnClose { id: usize },
80}
81
82impl CallRequest {
83 #[inline]
84 pub fn request(&self) -> &Request {
85 &self.inner
86 }
87 #[inline]
88 pub fn request_id(&self) -> Id {
89 Id(self.inner.sqe.tag)
90 }
91}
92
93impl SendFdRequest {
94 #[inline]
95 pub fn request(&self) -> &Request {
96 &self.inner
97 }
98 #[inline]
99 pub fn request_id(&self) -> Id {
100 Id(self.inner.sqe.tag)
101 }
102
103 pub fn id(&self) -> usize {
104 self.inner.sqe.args[0] as usize
105 }
106
107 pub fn flags(&self) -> SendFdFlags {
108 SendFdFlags::from_bits_retain(self.inner.sqe.args[1] as usize)
109 }
110
111 pub fn obtain_fd(
112 &self,
113 socket: &Socket,
114 flags: FobtainFdFlags,
115 dst_fd_or_ptr: Result<usize, &mut usize>,
116 ) -> Result<()> {
117 assert!(!flags.contains(FobtainFdFlags::MANUAL_FD));
118 match dst_fd_or_ptr {
119 Ok(dst_fd) => {
120 socket.inner.write(&Cqe {
121 flags: CqeOpcode::ObtainFd as u8,
122 extra_raw: usize::to_ne_bytes((flags | FobtainFdFlags::MANUAL_FD).bits())[..3]
123 .try_into()
124 .unwrap(),
125 tag: self.request_id().0,
126 result: dst_fd as u64,
127 })?;
128 }
129 Err(ptr) => {
130 socket.inner.write(&Cqe {
131 flags: CqeOpcode::ObtainFd as u8,
132 extra_raw: usize::to_ne_bytes(flags.bits())[..3].try_into().unwrap(),
133 tag: self.request_id().0,
134 result: ptr as *mut usize as u64,
135 })?;
136 }
137 }
138 Ok(())
139 }
140}
141
142impl Request {
143 #[inline]
144 pub fn context_id(&self) -> usize {
145 self.sqe.caller as usize
146 }
147 pub fn kind(self) -> RequestKind {
148 match Opcode::try_from_raw(self.sqe.opcode) {
149 Some(Opcode::Cancel) => RequestKind::Cancellation(CancellationRequest {
150 id: Id(self.sqe.tag),
151 }),
152 Some(Opcode::Sendfd) => RequestKind::SendFd(SendFdRequest {
153 inner: Request { sqe: self.sqe },
154 }),
155 Some(Opcode::Msync) => RequestKind::MsyncMsg,
156 Some(Opcode::RequestMmap) => RequestKind::MmapMsg,
158 Some(Opcode::CloseMsg) => RequestKind::OnClose {
159 id: self.sqe.args[0] as usize,
160 },
161
162 _ => RequestKind::Call(CallRequest {
163 inner: Request { sqe: self.sqe },
164 }),
165 }
166 }
167}
168
169pub struct Socket {
170 inner: libredox::Fd,
171}
172
173impl Socket {
174 fn create_inner(name: &str, nonblock: bool) -> Result<Self> {
175 let mut flags = flag::O_FSYNC | 0x0020_0000 ;
176
177 if nonblock {
178 flags |= flag::O_NONBLOCK;
179 }
180
181 let fd = libredox::Fd::open(
182 &format!(":{name}"),
183 flag::O_CLOEXEC | flag::O_CREAT | flags,
184 0,
185 )?;
186 Ok(Self { inner: fd })
187 }
188 pub fn create(name: impl AsRef<str>) -> Result<Self> {
189 Self::create_inner(name.as_ref(), false)
190 }
191 pub fn nonblock(name: impl AsRef<str>) -> Result<Self> {
192 Self::create_inner(name.as_ref(), true)
193 }
194 pub fn read_requests(&self, buf: &mut Vec<Request>, behavior: SignalBehavior) -> Result<()> {
196 let num_read = read_requests(self.inner.raw(), buf.spare_capacity_mut(), behavior)?;
197 unsafe {
198 buf.set_len(buf.len() + num_read);
199 }
200 Ok(())
201 }
202 pub fn next_request(&self, behavior: SignalBehavior) -> Result<Option<Request>> {
203 let mut buf = MaybeUninit::uninit();
204 Ok(
205 if read_requests(self.inner.raw(), core::slice::from_mut(&mut buf), behavior)? > 0 {
206 Some(unsafe { buf.assume_init() })
207 } else {
208 None
209 },
210 )
211 }
212 pub fn write_responses(
214 &self,
215 buf: &mut VecDeque<Response>,
216 behavior: SignalBehavior,
217 ) -> Result<()> {
218 let (slice, _) = buf.as_slices();
219
220 let n = unsafe { write_responses(self.inner.raw(), slice, behavior)? };
222 assert!(buf.len() >= n);
223 buf.drain(..n).for_each(core::mem::forget);
224
225 Ok(())
226 }
227 pub fn write_response(&self, resp: Response, behavior: SignalBehavior) -> Result<bool> {
228 Ok(unsafe { write_responses(self.inner.raw(), &[resp], behavior)? } > 0)
229 }
230 pub fn inner(&self) -> &libredox::Fd {
231 &self.inner
232 }
233}
234
235#[repr(transparent)]
236#[derive(Clone, Copy, Default)]
237pub struct Response(Cqe);
238
239impl Response {
240 #[inline]
241 pub fn err(err: i32, req: impl IntoTag) -> Self {
242 Self::new(Err(Error::new(err)), req)
243 }
244 #[inline]
245 pub fn ok(status: usize, req: impl IntoTag) -> Self {
246 Self::new(Ok(status), req)
247 }
248 #[inline]
249 pub fn ready_ok(status: usize, req: impl IntoTag) -> Poll<Self> {
250 Poll::Ready(Self::ok(status, req))
251 }
252 #[inline]
253 pub fn ready_err(err: i32, req: impl IntoTag) -> Poll<Self> {
254 Poll::Ready(Self::err(err, req))
255 }
256
257 pub fn new(status: Result<usize>, req: impl IntoTag) -> Self {
258 Self(Cqe {
259 flags: CqeOpcode::RespondRegular as u8,
260 extra_raw: [0_u8; 3],
261 result: Error::mux(status) as u64,
262 tag: req.into_tag().0 .0,
263 })
264 }
265 pub fn open_dup_like(res: Result<OpenResult>, req: impl IntoTag) -> Response {
266 match res {
267 Ok(OpenResult::ThisScheme { number, flags }) => {
268 Response::new(Ok(number), req).with_extra([flags.bits(), 0, 0])
269 }
270 Err(e) => Response::new(Err(e), req),
271 Ok(OpenResult::OtherScheme { fd }) => Response::return_external_fd(fd, req),
272 }
273 }
274 pub fn return_external_fd(fd: usize, req: impl IntoTag) -> Self {
275 Self(Cqe {
276 flags: CqeOpcode::RespondWithFd as u8,
277 extra_raw: [0_u8; 3],
278 result: fd as u64,
279 tag: req.into_tag().0 .0,
280 })
281 }
282 pub fn with_extra(self, extra: [u8; 3]) -> Self {
283 Self(Cqe {
284 extra_raw: extra,
285 ..self.0
286 })
287 }
288 pub fn post_fevent(id: usize, flags: usize) -> Self {
289 Self(Cqe {
290 flags: CqeOpcode::SendFevent as u8,
291 extra_raw: [0_u8; 3],
292 tag: flags as u32,
293 result: id as u64,
294 })
295 }
296}
297
298pub enum SignalBehavior {
299 Interrupt,
300 Restart,
301}
302
303#[inline]
305pub fn read_requests(
306 socket: usize,
307 buf: &mut [MaybeUninit<Request>],
308 behavior: SignalBehavior,
309) -> Result<usize> {
310 let len = buf.len().checked_mul(size_of::<Request>()).unwrap();
311
312 let bytes_read = loop {
313 match libredox::call::read(socket, unsafe {
314 core::slice::from_raw_parts_mut(buf.as_mut_ptr().cast(), len)
315 }) {
316 Ok(n) => break n,
317 Err(error) if error.errno() == EINTR => match behavior {
318 SignalBehavior::Restart => continue,
319 SignalBehavior::Interrupt => return Err(error.into()),
320 },
321 Err(err) => return Err(err.into()),
322 }
323 };
324
325 debug_assert_eq!(bytes_read % size_of::<Request>(), 0);
326
327 Ok(bytes_read / size_of::<Request>())
328}
329
330#[inline]
336pub unsafe fn write_responses(
337 socket: usize,
338 buf: &[Response],
339 behavior: SignalBehavior,
340) -> Result<usize> {
341 let bytes = unsafe {
342 core::slice::from_raw_parts(
343 buf.as_ptr().cast(),
344 buf.len().checked_mul(size_of::<Response>()).unwrap(),
345 )
346 };
347
348 let bytes_written = loop {
349 match libredox::call::write(socket, bytes) {
350 Ok(n) => break n,
351 Err(error) if error.errno() == EINTR => match behavior {
352 SignalBehavior::Restart => continue,
353 SignalBehavior::Interrupt => return Err(error.into()),
354 },
355 Err(err) => return Err(err.into()),
356 }
357 };
358 debug_assert_eq!(bytes_written % size_of::<Response>(), 0);
359 Ok(bytes_written / size_of::<Response>())
360}