socketcan_alt/
socket.rs

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            // frame will be moved
128            (*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;