#![allow(clippy::doc_markdown)]
mod err;
pub use err::{CanError, CanErrorDecodingFailure, CanSocketOpenError, ConstructionError};
pub mod dump;
mod util;
#[cfg(feature = "netlink")]
mod nl;
#[cfg(feature = "netlink")]
pub use nl::CanInterface;
#[cfg(test)]
mod tests;
use libc::{socket, SOCK_RAW, close, bind, sockaddr, read,
write, SOL_SOCKET, SO_RCVTIMEO, timespec, timeval, EINPROGRESS, SO_SNDTIMEO, time_t,
suseconds_t, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
use itertools::Itertools;
use nix::net::if_::if_nametoindex;
use std::{
os::raw::{c_int, c_short, c_void, c_uint, c_ulong},
fmt,
io,
time,
mem::size_of,
};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use util::{set_socket_option, set_socket_option_mult};
pub trait ShouldRetry {
fn should_retry(&self) -> bool;
}
impl ShouldRetry for io::Error {
fn should_retry(&self) -> bool {
match self.kind() {
io::ErrorKind::WouldBlock => true,
io::ErrorKind::Other => {
if let Some(i) = self.raw_os_error() {
i == EINPROGRESS
} else {
false
}
}
_ => false,
}
}
}
impl<E: fmt::Debug> ShouldRetry for io::Result<E> {
fn should_retry(&self) -> bool {
if let Err(ref e) = *self {
e.should_retry()
} else {
false
}
}
}
const AF_CAN: c_int = 29;
const PF_CAN: c_int = 29;
const CAN_RAW: c_int = 1;
const SOL_CAN_BASE: c_int = 100;
const SOL_CAN_RAW: c_int = SOL_CAN_BASE + CAN_RAW;
const CAN_RAW_FILTER: c_int = 1;
const CAN_RAW_ERR_FILTER: c_int = 2;
const CAN_RAW_LOOPBACK: c_int = 3;
const CAN_RAW_RECV_OWN_MSGS: c_int = 4;
const CAN_RAW_JOIN_FILTERS: c_int = 6;
const SIOCGSTAMPNS: c_int = 0x8907;
pub const EFF_FLAG: u32 = 0x80000000;
pub const RTR_FLAG: u32 = 0x40000000;
pub const ERR_FLAG: u32 = 0x20000000;
pub const SFF_MASK: u32 = 0x000007ff;
pub const EFF_MASK: u32 = 0x1fffffff;
pub const ERR_MASK: u32 = 0x1fffffff;
pub const ERR_MASK_ALL: u32 = ERR_MASK;
pub const ERR_MASK_NONE: u32 = 0;
fn c_timeval_new(t: time::Duration) -> timeval {
timeval {
tv_sec: t.as_secs() as time_t,
tv_usec: t.subsec_micros() as suseconds_t,
}
}
#[derive(Debug)]
#[repr(C)]
struct CanAddr {
_af_can: c_short,
if_index: c_int, rx_id: u32,
tx_id: u32,
}
#[derive(Debug)]
pub struct CanSocket {
fd: c_int,
}
impl CanSocket {
pub fn open(ifname: &str) -> Result<CanSocket, CanSocketOpenError> {
let if_index = if_nametoindex(ifname)?;
CanSocket::open_if(if_index)
}
pub fn open_if(if_index: c_uint) -> Result<CanSocket, CanSocketOpenError> {
let addr = CanAddr {
_af_can: AF_CAN as c_short,
if_index: if_index as c_int,
rx_id: 0, tx_id: 0, };
let sock_fd;
unsafe {
sock_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
}
if sock_fd == -1 {
return Err(CanSocketOpenError::from(io::Error::last_os_error()));
}
let bind_rv;
unsafe {
let sockaddr_ptr = &addr as *const CanAddr;
bind_rv = bind(sock_fd,
sockaddr_ptr as *const sockaddr,
size_of::<CanAddr>() as u32);
}
if bind_rv == -1 {
let e = io::Error::last_os_error();
unsafe {
close(sock_fd);
}
return Err(CanSocketOpenError::from(e));
}
Ok(CanSocket { fd: sock_fd })
}
fn close(&mut self) -> io::Result<()> {
unsafe {
let rv = close(self.fd);
if rv != -1 {
return Err(io::Error::last_os_error());
}
}
Ok(())
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let oldfl = unsafe { fcntl(self.fd, F_GETFL) };
if oldfl == -1 {
return Err(io::Error::last_os_error());
}
let newfl = if nonblocking {
oldfl | O_NONBLOCK
} else {
oldfl & !O_NONBLOCK
};
let rv = unsafe { fcntl(self.fd, F_SETFL, newfl) };
if rv != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn set_read_timeout(&self, duration: time::Duration) -> io::Result<()> {
set_socket_option(self.fd, SOL_SOCKET, SO_RCVTIMEO, &c_timeval_new(duration))
}
pub fn set_write_timeout(&self, duration: time::Duration) -> io::Result<()> {
set_socket_option(self.fd, SOL_SOCKET, SO_SNDTIMEO, &c_timeval_new(duration))
}
pub fn read_frame(&self) -> io::Result<CanFrame> {
let mut frame = CanFrame {
_id: 0,
_data_len: 0,
_pad: 0,
_res0: 0,
_res1: 0,
_data: [0; 8],
};
let read_rv = unsafe {
let frame_ptr = &mut frame as *mut CanFrame;
read(self.fd, frame_ptr as *mut c_void, size_of::<CanFrame>())
};
if read_rv as usize != size_of::<CanFrame>() {
return Err(io::Error::last_os_error());
}
Ok(frame)
}
pub fn read_frame_with_timestamp(&mut self) -> io::Result<(CanFrame, time::SystemTime)> {
let frame = self.read_frame()?;
let mut ts = timespec { tv_sec: 0, tv_nsec: 0 };
let rval = unsafe {
libc::ioctl(self.fd, SIOCGSTAMPNS as c_ulong, &mut ts as *mut timespec)
};
if rval == -1 {
return Err(io::Error::last_os_error());
}
Ok((frame, util::system_time_from_timespec(ts)))
}
pub fn write_frame(&self, frame: &CanFrame) -> io::Result<()> {
let write_rv = unsafe {
let frame_ptr = frame as *const CanFrame;
write(self.fd, frame_ptr as *const c_void, size_of::<CanFrame>())
};
if write_rv as usize != size_of::<CanFrame>() {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn write_frame_insist(&self, frame: &CanFrame) -> io::Result<()> {
loop {
match self.write_frame(frame) {
Ok(v) => return Ok(v),
Err(e) => {
if !e.should_retry() {
return Err(e);
}
}
}
}
}
pub fn set_filters(&self, filters: &[CanFilter]) -> io::Result<()> {
set_socket_option_mult(self.fd, SOL_CAN_RAW, CAN_RAW_FILTER, filters)
}
#[inline]
pub fn set_error_mask(&self, mask: u32) -> io::Result<()> {
set_socket_option(self.fd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &mask)
}
#[inline]
pub fn set_loopback(&self, enabled: bool) -> io::Result<()> {
let loopback: c_int = if enabled { 1 } else { 0 };
set_socket_option(self.fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback)
}
pub fn set_recv_own_msgs(&self, enabled: bool) -> io::Result<()> {
let recv_own_msgs: c_int = if enabled { 1 } else { 0 };
set_socket_option(self.fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs)
}
pub fn set_join_filters(&self, enabled: bool) -> io::Result<()> {
let join_filters: c_int = if enabled { 1 } else { 0 };
set_socket_option(self.fd, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS, &join_filters)
}
}
impl AsRawFd for CanSocket {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl FromRawFd for CanSocket {
unsafe fn from_raw_fd(fd: RawFd) -> CanSocket {
CanSocket { fd, }
}
}
impl IntoRawFd for CanSocket {
fn into_raw_fd(self) -> RawFd {
self.fd
}
}
impl Drop for CanSocket {
fn drop(&mut self) {
self.close().ok(); }
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct CanFrame {
_id: u32,
_data_len: u8,
_pad: u8,
_res0: u8,
_res1: u8,
_data: [u8; 8],
}
impl CanFrame {
pub fn new(id: u32, data: &[u8], rtr: bool, err: bool) -> Result<CanFrame, ConstructionError> {
let mut _id = id;
if data.len() > 8 {
return Err(ConstructionError::TooMuchData);
}
if id > EFF_MASK {
return Err(ConstructionError::IDTooLarge);
}
if id > SFF_MASK {
_id |= EFF_FLAG;
}
if rtr {
_id |= RTR_FLAG;
}
if err {
_id |= ERR_FLAG;
}
let mut full_data = [0; 8];
for (n, c) in data.iter().enumerate() {
full_data[n] = *c;
}
Ok(CanFrame {
_id,
_data_len: data.len() as u8,
_pad: 0,
_res0: 0,
_res1: 0,
_data: full_data,
})
}
#[inline]
pub fn id(&self) -> u32 {
if self.is_extended() {
self._id & EFF_MASK
} else {
self._id & SFF_MASK
}
}
#[inline]
pub fn err(&self) -> u32 {
self._id & ERR_MASK
}
#[inline]
pub fn is_extended(&self) -> bool {
self._id & EFF_FLAG != 0
}
#[inline]
pub fn is_error(&self) -> bool {
self._id & ERR_FLAG != 0
}
#[inline]
pub fn is_rtr(&self) -> bool {
self._id & RTR_FLAG != 0
}
#[inline]
pub fn data(&self) -> &[u8] {
&self._data[..(self._data_len as usize)]
}
#[inline]
pub fn error(&self) -> Result<CanError, CanErrorDecodingFailure> {
CanError::from_frame(self)
}
}
impl fmt::UpperHex for CanFrame {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:X}#", self.id())?;
let mut parts = self.data().iter().map(|v| format!("{:02X}", v));
let sep = if f.alternate() { " " } else { "" };
write!(f, "{}", parts.join(sep))
}
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct CanFilter {
_id: u32,
_mask: u32,
}
impl CanFilter {
pub fn new(id: u32, mask: u32) -> Result<CanFilter, ConstructionError> {
Ok(CanFilter {
_id: id,
_mask: mask,
})
}
}