1use num_enum::TryFromPrimitive;
50#[cfg(feature = "async")]
51use std::future::Future;
52use std::io::{Error, ErrorKind, Result};
53use std::os::raw::{c_char, c_void};
54#[cfg(feature = "async")]
55use std::pin::Pin;
56use std::ptr;
57#[cfg(feature = "async")]
58use std::task::{Context, Poll};
59use thiserror::Error;
60
61pub use libdlpi_sys as sys;
62
63#[repr(i32)]
65#[derive(PartialEq, Eq, Error, Debug, Copy, Clone, TryFromPrimitive)]
66pub enum ResultCode {
67 #[error("success")]
68 Success = 10000, #[error("invalid argument")]
70 EInval, #[error("invalid link name")]
72 ELinkNameInval, #[error("link does not exist")]
74 ENoLink, #[error("bad link")]
76 EBadLink, #[error("invalid handle")]
78 EInHandle, #[error("operation timed out")]
80 ETimedout, #[error("unsupported version")]
82 EVerNotSup, #[error("unsupported connection mode")]
84 EModeNotSup, #[error("unavailable service access point")]
86 EUnavailSAP, #[error("failure")]
88 Failure, #[error("style-2 node reports style-1")]
90 ENotStyle2, #[error("bad message")]
92 EBadMsg, #[error("raw mode not supported")]
94 ERawNotSup, #[error("invalid notification type")]
96 ENoteInval, #[error("notification not supported by link")]
98 ENoteNotSup, #[error("invalid notification id")]
100 ENoteIdInval, #[error("ipnetinfo not supported")]
102 EIpNetInfoNotSup, #[error("error max")]
104 ErrMax, }
106
107#[derive(Clone, Copy)]
109pub struct DlpiHandle(pub *mut sys::dlpi_handle_t);
110unsafe impl Send for DlpiHandle {}
111unsafe impl Sync for DlpiHandle {}
112
113pub struct DropHandle(pub DlpiHandle);
115impl Drop for DropHandle {
116 fn drop(&mut self) {
118 close(self.0);
119 }
120}
121
122impl DropHandle {
123 pub fn fd(&self) -> Result<i32> {
125 fd(self.0)
126 }
127}
128
129pub fn open(linkname: impl AsRef<str>, flags: u32) -> Result<DlpiHandle> {
131 let linkname = format!("{}\0", linkname.as_ref());
132
133 let mut dhp = sys::null_dlpi_handle();
134 let ret = unsafe {
135 sys::dlpi_open(
136 linkname.as_str().as_ptr() as *const c_char,
137 &mut dhp,
138 flags,
139 )
140 };
141 check_return(ret)?;
142 Ok(DlpiHandle(dhp))
143}
144
145pub fn send(
147 h: DlpiHandle,
148 dst: &[u8],
149 msg: &[u8],
150 info: Option<&sys::dlpi_sendinfo_t>,
151) -> Result<()> {
152 let ret = unsafe {
153 sys::dlpi_send(
154 h.0,
155 dst.as_ptr() as *const c_void,
156 dst.len(),
157 msg.as_ptr() as *const c_void,
158 msg.len(),
159 match info {
160 Some(info) => info as *const sys::dlpi_sendinfo_t,
161 None => ptr::null(),
162 },
163 )
164 };
165
166 check_return(ret)?;
167 Ok(())
168}
169
170pub fn recv(
180 h: DlpiHandle,
181 src: &mut [u8],
182 msg: &mut [u8],
183 msec: i32,
184 info: Option<&mut sys::dlpi_recvinfo_t>,
185) -> Result<(usize, usize)> {
186 let mut src_read = src.len();
187 let mut msg_read = msg.len();
188 let ret = unsafe {
189 sys::dlpi_recv(
190 h.0,
191 src.as_mut_ptr() as *mut c_void,
192 &mut src_read,
193 msg.as_mut_ptr() as *mut c_void,
194 &mut msg_read,
195 msec,
196 match info {
197 Some(info) => info as *mut sys::dlpi_recvinfo_t,
198 None => ptr::null_mut(),
199 },
200 )
201 };
202
203 check_return(ret)?;
204 Ok((src_read, msg_read))
205}
206
207#[cfg(feature = "async")]
208pub struct DlpiRecv<'a> {
211 h: DlpiHandle,
212 src: &'a mut [u8],
213 msg: &'a mut [u8],
214 info: Option<&'a mut sys::dlpi_recvinfo_t>,
215}
216
217#[cfg(feature = "async")]
232pub async fn recv_async<'a>(
233 h: DlpiHandle,
234 src: &'a mut [u8],
235 msg: &'a mut [u8],
236 info: Option<&'a mut sys::dlpi_recvinfo_t>,
237) -> Result<(usize, usize)> {
238 let afd = tokio::io::unix::AsyncFd::new(fd(h)?)?;
239 let mut _guard = afd.readable().await?;
240 recv(
241 h, src, msg, 0, info,
243 )
244}
245
246#[cfg(feature = "async")]
247impl<'a> Future for DlpiRecv<'a> {
248 type Output = Result<(usize, usize)>;
249
250 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
251 let mut src_read = self.src.len();
252 let mut msg_read = self.msg.len();
253 let s = self.get_mut();
254
255 let ret = unsafe {
256 sys::dlpi_recv(
257 s.h.0,
258 s.src.as_mut_ptr() as *mut c_void,
259 &mut src_read,
260 s.msg.as_mut_ptr() as *mut c_void,
261 &mut msg_read,
262 0, match s.info {
264 Some(ref mut info) => *info as *mut sys::dlpi_recvinfo_t,
265 None => ptr::null_mut(),
266 },
267 )
268 };
269
270 if ret == ResultCode::Success as i32 {
271 Poll::Ready(Ok((src_read, msg_read)))
272 } else if ret == ResultCode::ETimedout as i32 {
273 cx.waker().wake_by_ref();
274 Poll::Pending
275 } else {
276 Poll::Ready(Err(to_io_error(ret)))
277 }
278 }
279}
280
281pub fn bind(h: DlpiHandle, sap: u32) -> Result<u32> {
286 let mut bound_sap = 0;
287 let ret = unsafe { sys::dlpi_bind(h.0, sap, &mut bound_sap) };
288
289 check_return(ret)?;
290 Ok(bound_sap)
291}
292
293pub fn enable_multicast(h: DlpiHandle, addr: &[u8]) -> Result<()> {
299 let ret = unsafe {
300 sys::dlpi_enabmulti(h.0, addr.as_ptr() as *const c_void, addr.len())
301 };
302
303 check_return(ret)?;
304 Ok(())
305}
306
307pub fn disable_multicast(h: DlpiHandle, addr: &[u8]) -> Result<()> {
313 let ret = unsafe {
314 sys::dlpi_disabmulti(h.0, addr.as_ptr() as *const c_void, addr.len())
315 };
316
317 check_return(ret)?;
318 Ok(())
319}
320
321pub fn promisc_on(h: DlpiHandle, level: u32) -> Result<()> {
324 let ret = unsafe { sys::dlpi_promiscon(h.0, level) };
325 match ret {
326 -1 => Err(Error::from_raw_os_error(libc::EINVAL)),
327 _ => Ok(()),
328 }
329}
330
331pub fn promisc_off(h: DlpiHandle, level: u32) -> Result<()> {
334 let ret = unsafe { sys::dlpi_promiscoff(h.0, level) };
335 match ret {
336 -1 => Err(Error::from_raw_os_error(libc::EINVAL)),
337 _ => Ok(()),
338 }
339}
340
341pub fn fd(h: DlpiHandle) -> Result<i32> {
343 let ret = unsafe { sys::dlpi_fd(h.0) };
344 match ret {
345 -1 => Err(Error::from_raw_os_error(libc::EINVAL)),
346 _ => Ok(ret),
347 }
348}
349
350pub fn close(h: DlpiHandle) {
352 unsafe { sys::dlpi_close(h.0) };
353}
354
355fn check_return(ret: i32) -> Result<()> {
356 if ret == ResultCode::Success as i32 {
357 return Ok(());
358 }
359
360 Err(to_io_error(ret))
361}
362
363fn to_io_error(ret: i32) -> Error {
364 if ret == sys::DL_SYSERR {
365 return Error::last_os_error();
366 }
367
368 match ResultCode::try_from(ret) {
369 Ok(rc) => Error::new(ErrorKind::Other, rc),
370 Err(_) => Error::from_raw_os_error(ret),
371 }
372}
373
374#[cfg(test)]
375mod test;