1use crate::{sys, CmsgIter, Frame, Timestamping};
2use std::ffi::CStr;
3use std::io::{Error, Result};
4use std::mem::{self, size_of, size_of_val, MaybeUninit};
5use std::os::raw::c_int;
6use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7use std::ptr;
8
9pub struct Socket(RawFd);
10
11impl Socket {
12 pub fn bind<I>(ifname: I) -> Result<Self>
13 where
14 I: AsRef<CStr>,
15 {
16 let ifindex = unsafe { libc::if_nametoindex(ifname.as_ref().as_ptr()) };
17 if ifindex == 0 {
18 return Err(Error::last_os_error());
19 }
20
21 let fd = unsafe { libc::socket(libc::PF_CAN, libc::SOCK_RAW, sys::CAN_RAW as _) };
22 if fd == -1 {
23 return Err(Error::last_os_error());
24 }
25 let socket = Self(fd);
26
27 let mut address = MaybeUninit::<sys::sockaddr_can>::zeroed();
28 let address = unsafe {
29 (*address.as_mut_ptr()).can_family = libc::AF_CAN as _;
30 (*address.as_mut_ptr()).can_ifindex = ifindex as _;
31 address.assume_init()
32 };
33 if unsafe {
34 libc::bind(
35 socket.as_raw_fd(),
36 &address as *const _ as _,
37 size_of_val(&address) as _,
38 ) != 0
39 } {
40 return Err(Error::last_os_error());
41 }
42 Ok(socket)
43 }
44
45 pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
46 if unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &(nonblocking as c_int)) } != 0 {
47 return Err(Error::last_os_error());
48 }
49 Ok(())
50 }
51
52 unsafe fn setsockopt<T>(&self, level: c_int, name: c_int, value: &T) -> Result<()> {
53 if libc::setsockopt(
54 self.as_raw_fd(),
55 level,
56 name,
57 value as *const _ as _,
58 size_of_val(value) as _,
59 ) != 0
60 {
61 return Err(Error::last_os_error());
62 }
63 Ok(())
64 }
65
66 pub fn set_timestamping(&self, timestamping: Timestamping) -> Result<()> {
67 unsafe {
68 self.setsockopt(
69 libc::SOL_SOCKET,
70 libc::SO_TIMESTAMPING,
71 &(timestamping.bits() as c_int),
72 )
73 }
74 }
75
76 pub fn set_recv_own_msgs(&self, enable: bool) -> Result<()> {
77 unsafe {
78 self.setsockopt(
79 sys::SOL_CAN_RAW as _,
80 sys::CAN_RAW_RECV_OWN_MSGS as _,
81 &(enable as c_int),
82 )
83 }
84 }
85
86 pub fn set_fd_frames(&self, enable: bool) -> Result<()> {
87 unsafe {
88 self.setsockopt(
89 sys::SOL_CAN_RAW as _,
90 sys::CAN_RAW_FD_FRAMES as _,
91 &(enable as c_int),
92 )
93 }
94 }
95
96 pub fn recv(&self) -> Result<Frame> {
97 let mut frame = MaybeUninit::<sys::canfd_frame>::uninit();
98 unsafe {
99 let size = libc::read(
100 self.as_raw_fd(),
101 frame.as_mut_ptr() as _,
102 size_of::<sys::canfd_frame>(),
103 );
104 Frame::from_raw(frame, size as _)
105 }
106 .ok_or_else(Error::last_os_error)
107 }
108
109 pub(crate) fn _recv_msg<'a>(
110 &self,
111 cmsg_buf: &'a mut [u8],
112 ) -> std::result::Result<(Frame, Option<CmsgIter<'a>>), (Error, &'a mut [u8])> {
113 let mut frame = MaybeUninit::<sys::canfd_frame>::uninit();
114 let mut iov = MaybeUninit::<libc::iovec>::uninit();
115 let mut msg = MaybeUninit::<libc::msghdr>::uninit();
116 unsafe {
117 (*iov.as_mut_ptr()).iov_base = frame.as_mut_ptr() as _;
118 (*iov.as_mut_ptr()).iov_len = size_of::<sys::canfd_frame>();
119
120 (*msg.as_mut_ptr()).msg_name = ptr::null_mut();
121 (*msg.as_mut_ptr()).msg_iov = iov.as_mut_ptr();
122 (*msg.as_mut_ptr()).msg_iovlen = 1;
123 (*msg.as_mut_ptr()).msg_control = cmsg_buf.as_mut_ptr() as _;
124 (*msg.as_mut_ptr()).msg_controllen = cmsg_buf.len() as _;
125
126 let size = libc::recvmsg(self.as_raw_fd(), msg.as_mut_ptr(), 0);
127 (*iov.as_mut_ptr()).iov_base = ptr::null_mut();
129 let frame = Frame::from_raw(frame, size as _)
130 .ok_or_else(|| (Error::last_os_error(), cmsg_buf))?;
131 let cmsgs = CmsgIter::from_raw(msg.assume_init());
132 Ok((frame, cmsgs))
133 }
134 }
135
136 pub fn recv_msg<'a>(&self, cmsg_buf: &'a mut [u8]) -> Result<(Frame, Option<CmsgIter<'a>>)> {
137 self._recv_msg(cmsg_buf).map_err(|(e, _)| e)
138 }
139
140 pub fn send(&self, frame: &Frame) -> Result<()> {
141 if unsafe { libc::write(self.as_raw_fd(), frame.as_ptr(), frame.size()) } as usize
142 != frame.size()
143 {
144 return Err(Error::last_os_error());
145 }
146 Ok(())
147 }
148}
149
150impl Drop for Socket {
151 fn drop(&mut self) {
152 unsafe { libc::close(self.as_raw_fd()) };
153 }
154}
155
156impl AsRawFd for Socket {
157 fn as_raw_fd(&self) -> RawFd {
158 self.0
159 }
160}
161
162impl FromRawFd for Socket {
163 unsafe fn from_raw_fd(fd: RawFd) -> Self {
164 Self(fd)
165 }
166}
167
168impl IntoRawFd for Socket {
169 fn into_raw_fd(self) -> RawFd {
170 let fd = self.0;
171 mem::forget(self);
172 fd
173 }
174}
175
176#[cfg(test)]
177pub(crate) mod tests;