1use std::{ffi::CString, fmt, io, mem, os::raw::{c_int, c_void}, time::Duration, ptr};
4use libc::*;
5
6pub fn raw_open_socket(addr: &CanAddr) -> io::Result<c_int> {
8 let fd = unsafe { socket(PF_CAN, SOCK_RAW, CAN_RAW) };
9
10 if fd == -1 {
11 return Err(io::Error::last_os_error());
12 }
13
14 let ret = unsafe { bind(fd, addr.as_sockaddr_ptr(), CanAddr::len() as u32) };
15
16 if ret == -1 {
17 let err = io::Error::last_os_error();
18 unsafe { close(fd) };
19 Err(err)
20 } else {
21 Ok(fd)
22 }
23}
24
25pub fn set_fd_mode(fd: c_int, enable: bool) -> io::Result<c_int> {
27 let enable = enable as c_int;
28
29 let ret = unsafe {
30 setsockopt(
31 fd,
32 SOL_CAN_RAW,
33 CAN_RAW_FD_FRAMES,
34 &enable as *const _ as *const c_void,
35 mem::size_of::<c_int>() as u32,
36 )
37 };
38
39 if ret == -1 {
40 Err(io::Error::last_os_error())
41 } else {
42 Ok(fd)
43 }
44}
45
46pub fn raw_write_frame<T>(fd: c_int, frame_ptr: *const T, n: usize) -> io::Result<()> {
48 let ret = unsafe { write(fd, frame_ptr.cast(), n) };
49
50 if ret as usize == n {
51 Ok(())
52 } else {
53 Err(io::Error::last_os_error())
54 }
55}
56
57#[inline]
76pub fn set_socket_option<T>(fd: c_int, level: c_int, name: c_int, val: &T) -> io::Result<()> {
77 let ret = unsafe {
78 setsockopt(
79 fd,
80 level,
81 name,
82 val as *const _ as *const c_void,
83 mem::size_of::<T>() as socklen_t,
84 )
85 };
86
87 if ret != 0 {
88 return Err(io::Error::last_os_error());
89 }
90
91 Ok(())
92}
93
94pub fn set_socket_option_mult<T>(
96 fd: c_int,
97 level: c_int,
98 name: c_int,
99 values: &[T],
100) -> io::Result<()> {
101 let ret = if values.is_empty() {
102 unsafe { setsockopt(fd, level, name, ptr::null(), 0) }
104 } else {
105 unsafe {
106 setsockopt(
107 fd,
108 level,
109 name,
110 values.as_ptr().cast(),
111 mem::size_of_val(values) as socklen_t,
112 )
113 }
114 };
115
116 if ret != 0 {
117 return Err(io::Error::last_os_error());
118 }
119
120 Ok(())
121}
122
123#[inline(always)]
128pub fn can_frame_default() -> can_frame {
129 unsafe { mem::zeroed() }
130}
131
132#[inline(always)]
135pub fn canfd_frame_default() -> canfd_frame {
136 unsafe { mem::zeroed() }
137}
138
139pub trait ShouldRetry {
146 fn should_retry(&self) -> bool;
150}
151
152impl ShouldRetry for io::Error {
153 fn should_retry(&self) -> bool {
154 match self.kind() {
155 io::ErrorKind::WouldBlock => true,
159 io::ErrorKind::Other => {
161 matches!(self.raw_os_error(), Some(errno) if errno == EINPROGRESS)
162 }
163 _ => false,
164 }
165 }
166}
167
168impl<E: fmt::Debug> ShouldRetry for io::Result<E> {
169 fn should_retry(&self) -> bool {
170 if let Err(ref e) = *self {
171 e.should_retry()
172 } else {
173 false
174 }
175 }
176}
177
178#[derive(Clone, Copy)]
190pub struct CanAddr(sockaddr_can);
191
192impl CanAddr {
193 pub fn new(ifindex: u32) -> Self {
196 let mut addr = Self::default();
197 addr.0.can_ifindex = ifindex as c_int;
198 addr
199 }
200
201 pub fn from_iface(ifname: &str) -> io::Result<Self> {
203 let ifname = CString::new(ifname)?;
204 let ifindex = unsafe { if_nametoindex(ifname.as_ptr()) };
205 if ifindex == 0 {
206 Err(io::Error::last_os_error())
207 }
208 else {
209 Ok(Self::new(ifindex))
210 }
211 }
212
213 pub fn as_ptr(&self) -> *const sockaddr_can {
215 &self.0
216 }
217
218 pub fn as_sockaddr_ptr(&self) -> *const sockaddr {
220 self.as_ptr().cast()
221 }
222
223 pub fn len() -> usize {
225 mem::size_of::<sockaddr_can>()
226 }
227
228 pub fn into_storage(self) -> (sockaddr_storage, socklen_t) {
232 let mut storage: sockaddr_storage = unsafe { mem::zeroed() };
233 unsafe {
234 ptr::copy_nonoverlapping(&self.0, &mut storage as *mut _ as *mut sockaddr_can, 1);
235 }
236 (storage, Self::len() as socklen_t)
237 }
238}
239
240impl Default for CanAddr {
241 fn default() -> Self {
242 let mut addr: sockaddr_can = unsafe { mem::zeroed() };
243 addr.can_family = AF_CAN as sa_family_t;
244 Self(addr)
245 }
246}
247
248impl fmt::Debug for CanAddr {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 write!(
251 f,
252 "CanAddr {{ can_family: {}, can_ifindex: {} }}",
253 self.0.can_family, self.0.can_ifindex
254 )
255 }
256}
257
258impl From<sockaddr_can> for CanAddr {
259 fn from(addr: sockaddr_can) -> Self {
260 Self(addr)
261 }
262}
263
264impl AsRef<sockaddr_can> for CanAddr {
265 fn as_ref(&self) -> &sockaddr_can {
266 &self.0
267 }
268}
269
270pub fn c_timeval_new(t: Duration) -> timeval {
271 timeval {
272 tv_sec: t.as_secs() as time_t,
273 tv_usec: t.subsec_micros() as suseconds_t,
274 }
275}