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