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