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