1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
use crate::{sys, Frame}; use std::ffi::CStr; use std::io::{Error, Result}; use std::mem::{self, size_of, size_of_val, MaybeUninit}; use std::os::raw::c_int; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; pub struct Socket(RawFd); impl Socket { pub fn bind<I>(ifname: I) -> Result<Self> where I: AsRef<CStr>, { let ifindex = unsafe { libc::if_nametoindex(ifname.as_ref().as_ptr()) }; if ifindex == 0 { return Err(Error::last_os_error()); } let fd = unsafe { libc::socket(libc::PF_CAN, libc::SOCK_RAW, sys::CAN_RAW as _) }; if fd == -1 { return Err(Error::last_os_error()); } let socket = Self(fd); let mut address = MaybeUninit::<sys::sockaddr_can>::zeroed(); let address = unsafe { (*address.as_mut_ptr()).can_family = libc::AF_CAN as _; (*address.as_mut_ptr()).can_ifindex = ifindex as _; address.assume_init() }; if unsafe { libc::bind( socket.as_raw_fd(), &address as *const _ as _, size_of_val(&address) as _, ) != 0 } { return Err(Error::last_os_error()); } Ok(socket) } pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> { if unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &(nonblocking as c_int)) } != 0 { return Err(Error::last_os_error()); } Ok(()) } unsafe fn setsockopt<T>(&self, name: c_int, value: &T) -> Result<()> { if libc::setsockopt( self.as_raw_fd(), sys::SOL_CAN_RAW as _, name, value as *const _ as _, size_of_val(value) as _, ) != 0 { return Err(Error::last_os_error()); } Ok(()) } pub fn set_recv_own_msgs(&self, enable: bool) -> Result<()> { unsafe { self.setsockopt(sys::CAN_RAW_RECV_OWN_MSGS as _, &(enable as c_int)) } } pub fn set_fd_frames(&self, enable: bool) -> Result<()> { unsafe { self.setsockopt(sys::CAN_RAW_FD_FRAMES as _, &(enable as c_int)) } } pub fn recv(&self) -> Result<Frame> { #[repr(C)] union Inner { can: sys::can_frame, canfd: sys::canfd_frame, } let mut inner = MaybeUninit::<Inner>::uninit(); let size = unsafe { libc::read( self.as_raw_fd(), inner.as_mut_ptr() as _, size_of::<Inner>(), ) } as usize; if size == size_of::<sys::can_frame>() { Ok(Frame::from_can_frame(unsafe { inner.assume_init().can })) } else if size == size_of::<sys::canfd_frame>() { Ok(Frame::from_canfd_frame(unsafe { inner.assume_init().canfd })) } else { Err(Error::last_os_error()) } } pub fn send(&self, frame: &Frame) -> Result<()> { if unsafe { libc::write(self.as_raw_fd(), frame.as_ptr(), frame.size()) } as usize != frame.size() { return Err(Error::last_os_error()); } Ok(()) } } impl Drop for Socket { fn drop(&mut self) { unsafe { libc::close(self.as_raw_fd()) }; } } impl AsRawFd for Socket { fn as_raw_fd(&self) -> RawFd { self.0 } } impl FromRawFd for Socket { unsafe fn from_raw_fd(fd: RawFd) -> Self { Self(fd) } } impl IntoRawFd for Socket { fn into_raw_fd(self) -> RawFd { let fd = self.0; mem::forget(self); fd } } #[cfg(test)] mod tests;