1#![cfg(any(
2 target_os = "macos",
3 target_os = "freebsd",
4 target_os = "netbsd",
5 target_os = "openbsd",
6 target_os = "dragonfly"
7))]
8#![allow(clippy::missing_safety_doc)]
9
10mod driver_config;
11mod errno;
12
13pub mod driver;
14
15use std::future::Future;
16use std::io;
17use std::os::fd::{AsRawFd, RawFd};
18use std::pin::Pin;
19use std::task::{Context, Poll};
20
21use dope_core::Fd;
22use dope_core::addr::SockAddr;
23use dope_core::driver::DriverOps;
24use dope_core::submit::{RecvMsgPacket, SendMsgPacket, SubmitOps};
25
26pub use driver::{
27 CurrentSlot, Driver, ProvidedBuf, ProvidedRing, Request, Token, current, current_driver_mut,
28 set_current,
29};
30pub use driver_config::DriverConfig;
31pub use errno::Errno;
32
33pub fn new_driver(cfg: DriverConfig) -> io::Result<Driver> {
34 Driver::new(cfg)
35}
36
37#[derive(Clone, Copy, Debug, Default)]
38pub struct KqueueBackend;
39
40impl dope_core::driver::Backend for KqueueBackend {
41 type Driver = driver::Driver;
42 type Config = DriverConfig;
43 type RecvMsgOut = driver::RecvMsgOut;
44 type ProvidedBuf = driver::ProvidedBuf;
45
46 fn new_driver(cfg: Self::Config) -> io::Result<Self::Driver> {
47 Driver::new(cfg)
48 }
49}
50
51thread_local! {
52 static AUX: std::cell::Cell<Option<dope_core::driver::ExternalDispatch<KqueueBackend>>> =
53 const { std::cell::Cell::new(None) };
54}
55
56impl dope_core::driver::CompletionBackend for KqueueBackend {
57 type Token = driver::Token;
58
59 fn current_slot() -> Option<dope_core::driver::CurrentSlot<Self>> {
60 driver::current()
61 }
62
63 fn set_slot(slot: Option<dope_core::driver::CurrentSlot<Self>>) {
64 driver::set_current(slot);
65 }
66
67 fn install_external(
68 aux: Option<dope_core::driver::ExternalDispatch<Self>>,
69 ) -> Option<dope_core::driver::ExternalDispatch<Self>> {
70 AUX.with(|c| c.replace(aux))
71 }
72
73 fn current_external() -> Option<dope_core::driver::ExternalDispatch<Self>> {
74 AUX.with(|c| c.get())
75 }
76
77 fn drive_with<R: dope_core::driver::CompletionRouter<Self>>(
78 driver: &mut Self::Driver,
79 router: &mut R,
80 ) -> io::Result<bool> {
81 driver.drive_with(router)
82 }
83
84 fn dispatch_completions<R: dope_core::driver::CompletionRouter<Self>>(
85 driver: &mut Self::Driver,
86 router: &mut R,
87 ) {
88 driver.dispatch_completions(router)
89 }
90}
91
92impl SubmitOps for &mut Driver {
93 fn submit_accept(
94 self,
95 fd: Fd,
96 ) -> impl Future<Output = io::Result<(RawFd, SockAddr)>> + 'static {
97 let raw = fd.as_raw_fd();
98 driver::Sock::set_nonblocking(raw);
99 AcceptFuture::new(raw)
100 }
101
102 fn submit_read<B>(self, fd: Fd, buf: B) -> impl Future<Output = (io::Result<u32>, B)> + 'static
103 where
104 B: AsMut<[u8]> + Unpin + 'static,
105 {
106 let raw = fd.as_raw_fd();
107 async move {
108 let mut buf = buf;
109 let slice = buf.as_mut();
110 let n = unsafe { libc::read(raw, slice.as_mut_ptr().cast(), slice.len()) };
111 (Errno::syscall_result(n), buf)
112 }
113 }
114
115 fn submit_send_raw<B>(
116 self,
117 fd: Fd,
118 buf: B,
119 len: usize,
120 ) -> impl Future<Output = (io::Result<u32>, B)> + 'static
121 where
122 B: AsRef<[u8]> + Unpin + 'static,
123 {
124 let raw = fd.as_raw_fd();
125 async move {
126 let bytes = buf.as_ref();
127 let n = len.min(bytes.len());
128 let r = unsafe { libc::send(raw, bytes.as_ptr().cast(), n, 0) };
129 (Errno::syscall_result(r), buf)
130 }
131 }
132
133 fn submit_sendmsg_raw<P>(
134 self,
135 fd: Fd,
136 packet: P,
137 ) -> impl Future<Output = (io::Result<u32>, P)> + 'static
138 where
139 P: SendMsgPacket + Unpin + 'static,
140 {
141 let req = self.try_submit_sendmsg_raw(fd, packet);
142 Request::await_or_err(req)
143 }
144
145 fn submit_recvmsg_raw<P>(
146 self,
147 fd: Fd,
148 packet: P,
149 ) -> impl Future<Output = (io::Result<u32>, P)> + 'static
150 where
151 P: RecvMsgPacket + Unpin + 'static,
152 {
153 let raw = fd.as_raw_fd();
154 async move {
155 let mut packet = packet;
156 let msg = packet.msg_mut_ptr();
157 let n = unsafe { libc::recvmsg(raw, msg, 0) };
158 (Errno::syscall_result(n), packet)
159 }
160 }
161}
162
163enum AcceptState {
164 Idle,
165 Waiting(Request<()>),
166 Done,
167}
168
169pub struct AcceptFuture {
170 fd: RawFd,
171 state: AcceptState,
172}
173
174impl AcceptFuture {
175 fn new(fd: RawFd) -> Self {
176 Self {
177 fd,
178 state: AcceptState::Idle,
179 }
180 }
181
182 fn try_accept(&mut self) -> Option<io::Result<(RawFd, SockAddr)>> {
183 let mut addr = SockAddr::empty();
184 let r = unsafe { libc::accept(self.fd, addr.addr_mut_ptr(), addr.addr_len_ptr()) };
185 if r >= 0 {
186 return Some(Ok((r as RawFd, addr)));
187 }
188 let err = io::Error::last_os_error();
189 if matches!(err.raw_os_error(), Some(libc::EAGAIN)) {
190 return None;
191 }
192 Some(Err(err))
193 }
194}
195
196impl Future for AcceptFuture {
197 type Output = io::Result<(RawFd, SockAddr)>;
198
199 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
200 let me = self.get_mut();
201 loop {
202 match &mut me.state {
203 AcceptState::Done => panic!("AcceptFuture polled after completion"),
204 AcceptState::Idle => {
205 if let Some(out) = me.try_accept() {
206 me.state = AcceptState::Done;
207 return Poll::Ready(out);
208 }
209 let driver = driver::current_driver_mut();
210 let req = driver.register_read_oneshot(me.fd);
211 me.state = AcceptState::Waiting(req);
212 }
213 AcceptState::Waiting(req) => match Pin::new(req).poll(cx) {
214 Poll::Pending => {
215 return Poll::Pending;
216 }
217 Poll::Ready((res, _flags, _)) => {
218 res?;
219 me.state = AcceptState::Idle;
220 }
221 },
222 }
223 }
224 }
225}