use libc::*;
use std::{
ffi::CString,
fmt, io, mem,
os::raw::{c_int, c_void},
ptr,
time::Duration,
};
pub fn raw_open_socket(addr: &CanAddr) -> io::Result<c_int> {
let fd = unsafe { socket(PF_CAN, SOCK_RAW, CAN_RAW) };
if fd == -1 {
return Err(io::Error::last_os_error());
}
let ret = unsafe { bind(fd, addr.as_sockaddr_ptr(), CanAddr::len() as u32) };
if ret == -1 {
let err = io::Error::last_os_error();
unsafe { close(fd) };
Err(err)
} else {
Ok(fd)
}
}
pub fn set_fd_mode(fd: c_int, enable: bool) -> io::Result<c_int> {
let enable = enable as c_int;
let ret = unsafe {
setsockopt(
fd,
SOL_CAN_RAW,
CAN_RAW_FD_FRAMES,
&enable as *const _ as *const c_void,
mem::size_of::<c_int>() as u32,
)
};
if ret == -1 {
Err(io::Error::last_os_error())
} else {
Ok(fd)
}
}
pub fn raw_write_frame<T>(fd: c_int, frame_ptr: *const T, n: usize) -> io::Result<()> {
let ret = unsafe { write(fd, frame_ptr.cast(), n) };
if ret as usize == n {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[inline]
pub fn set_socket_option<T>(fd: c_int, level: c_int, name: c_int, val: &T) -> io::Result<()> {
let ret = unsafe {
setsockopt(
fd,
level,
name,
val as *const _ as *const c_void,
mem::size_of::<T>() as socklen_t,
)
};
if ret != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn set_socket_option_mult<T>(
fd: c_int,
level: c_int,
name: c_int,
values: &[T],
) -> io::Result<()> {
let ret = if values.is_empty() {
unsafe { setsockopt(fd, level, name, ptr::null(), 0) }
} else {
unsafe {
setsockopt(
fd,
level,
name,
values.as_ptr().cast(),
mem::size_of_val(values) as socklen_t,
)
}
};
if ret != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[inline(always)]
pub fn can_frame_default() -> can_frame {
unsafe { mem::zeroed() }
}
#[inline(always)]
pub fn canfd_frame_default() -> canfd_frame {
unsafe { mem::zeroed() }
}
pub trait ShouldRetry {
fn should_retry(&self) -> bool;
}
impl ShouldRetry for io::Error {
fn should_retry(&self) -> bool {
match self.kind() {
io::ErrorKind::WouldBlock => true,
io::ErrorKind::Other => {
matches!(self.raw_os_error(), Some(errno) if errno == EINPROGRESS)
}
_ => false,
}
}
}
impl<E: fmt::Debug> ShouldRetry for io::Result<E> {
fn should_retry(&self) -> bool {
if let Err(ref e) = *self {
e.should_retry()
} else {
false
}
}
}
#[derive(Clone, Copy)]
pub struct CanAddr(sockaddr_can);
impl CanAddr {
pub fn new(ifindex: u32) -> Self {
let mut addr = Self::default();
addr.0.can_ifindex = ifindex as c_int;
addr
}
pub fn from_iface(ifname: &str) -> io::Result<Self> {
let ifname = CString::new(ifname)?;
let ifindex = unsafe { if_nametoindex(ifname.as_ptr()) };
if ifindex == 0 {
Err(io::Error::last_os_error())
} else {
Ok(Self::new(ifindex))
}
}
pub fn as_ptr(&self) -> *const sockaddr_can {
&self.0
}
pub fn as_sockaddr_ptr(&self) -> *const sockaddr {
self.as_ptr().cast()
}
pub fn len() -> usize {
mem::size_of::<sockaddr_can>()
}
pub fn into_storage(self) -> (sockaddr_storage, socklen_t) {
let mut storage: sockaddr_storage = unsafe { mem::zeroed() };
unsafe {
ptr::copy_nonoverlapping(&self.0, &mut storage as *mut _ as *mut sockaddr_can, 1);
}
(storage, Self::len() as socklen_t)
}
}
impl Default for CanAddr {
fn default() -> Self {
let mut addr: sockaddr_can = unsafe { mem::zeroed() };
addr.can_family = AF_CAN as sa_family_t;
Self(addr)
}
}
impl fmt::Debug for CanAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CanAddr {{ can_family: {}, can_ifindex: {} }}",
self.0.can_family, self.0.can_ifindex
)
}
}
impl From<sockaddr_can> for CanAddr {
fn from(addr: sockaddr_can) -> Self {
Self(addr)
}
}
impl AsRef<sockaddr_can> for CanAddr {
fn as_ref(&self) -> &sockaddr_can {
&self.0
}
}
pub fn c_timeval_new(t: Duration) -> timeval {
timeval {
tv_sec: t.as_secs() as time_t,
tv_usec: t.subsec_micros() as suseconds_t,
}
}