socketcan-alt 0.1.0

Rust binding for SocketCAN
Documentation
use super::Socket;
use crate::{sys, DataFrame, FdDataFrame, Frame, Id};
use rand::Rng;
use spin::RwLock;
use std::env;
use std::ffi::CString;
#[allow(unused_imports)]
use std::io::ErrorKind;
use std::io::Result;
use std::os::unix::ffi::OsStrExt;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

#[allow(dead_code)]
static LOCK: RwLock<()> = RwLock::new(());

#[allow(dead_code)]
fn ifname() -> CString {
    let ifname = env::var_os("IFNAME").expect("IFNAME environment variable is not set");
    CString::new(ifname.as_bytes()).unwrap()
}

#[allow(unused_macros)]
macro_rules! lock {
    (shared) => {
        let _lock = LOCK.read();
    };
    (exclusive) => {
        let _lock = LOCK.write();
    };
}

#[allow(dead_code)]
fn recv(socket: Socket, frame: Option<Frame>) -> Option<Result<Frame>> {
    struct Context(Arc<AtomicBool>);
    impl Drop for Context {
        fn drop(&mut self) {
            self.0.store(true, Ordering::Relaxed);
        }
    }

    let is_done = Arc::new(AtomicBool::new(false));
    let handle = {
        let is_done = is_done.clone();
        thread::spawn(move || {
            let _cxt = Context(is_done);
            loop {
                let f = socket.recv()?;
                if frame.as_ref().map(|frame| &f == frame).unwrap_or(true) {
                    break Ok(f);
                }
            }
        })
    };

    thread::sleep(Duration::from_millis(100));
    if is_done.load(Ordering::Relaxed) {
        handle.join().ok()
    } else {
        None
    }
}

#[allow(dead_code)]
fn random_data_standard() -> Frame {
    let mut rng = rand::thread_rng();
    let id = Id::Standard(rng.gen_range(0, sys::CAN_SFF_MASK));
    let data = (0..rng.gen_range(0, sys::CAN_MAX_DLEN))
        .map(|_| rng.gen())
        .collect::<Vec<_>>();
    Frame::Data(DataFrame::new(id, &data))
}

#[allow(dead_code)]
fn random_fd_data_standard() -> Frame {
    let mut rng = rand::thread_rng();
    let id = Id::Standard(rng.gen_range(0, sys::CAN_SFF_MASK));
    let data = (0..rng.gen_range(0, sys::CANFD_MAX_DLEN))
        .map(|_| rng.gen())
        .collect::<Vec<_>>();
    Frame::FdData(FdDataFrame::new(id, false, false, &data))
}

#[cfg(feature = "test_all")]
#[test]
fn test_bind() {
    Socket::bind(ifname()).unwrap();
}

#[test]
fn test_bind_no_device() {
    let ifname = CString::new("NO DEVICE").unwrap();
    assert!(Socket::bind(ifname).is_err());
}

#[cfg(feature = "test_all")]
#[test]
fn test_default_nonblocking_off() {
    lock!(exclusive);
    let socket = Socket::bind(ifname()).unwrap();

    assert!(recv(socket, None).is_none());
}

#[cfg(feature = "test_all")]
#[test]
fn test_set_nonblocking_on() {
    lock!(exclusive);
    let socket = Socket::bind(ifname()).unwrap();
    socket.set_nonblocking(true).unwrap();

    assert_eq!(
        recv(socket, None).unwrap().unwrap_err().kind(),
        ErrorKind::WouldBlock
    );
}

#[cfg(feature = "test_all")]
#[test]
fn test_default_loopback_on() {
    lock!(shared);
    let socket_tx = Socket::bind(ifname()).unwrap();
    let socket_rx = Socket::bind(ifname()).unwrap();

    let frame = random_data_standard();
    socket_tx.send(&frame).unwrap();
    recv(socket_rx, Some(frame)).unwrap().unwrap();
}

#[cfg(feature = "test_all")]
#[test]
fn test_default_recv_own_msgs_off() {
    lock!(shared);
    let socket = Socket::bind(ifname()).unwrap();

    let frame = random_data_standard();
    socket.send(&frame).unwrap();
    assert!(recv(socket, Some(frame)).is_none());
}

#[cfg(feature = "test_all")]
#[test]
fn test_set_recv_own_msgs_on() {
    lock!(shared);
    let socket = Socket::bind(ifname()).unwrap();
    socket.set_recv_own_msgs(true).unwrap();

    let frame = random_data_standard();
    socket.send(&frame).unwrap();
    recv(socket, Some(frame)).unwrap().unwrap();
}

#[cfg(feature = "test_all")]
#[test]
fn test_default_fd_frames_off() {
    lock!(shared);
    let socket = Socket::bind(ifname()).unwrap();

    let frame = random_fd_data_standard();
    assert_eq!(
        socket.send(&frame).unwrap_err().kind(),
        ErrorKind::InvalidInput
    );
}

#[cfg(feature = "test_all")]
#[test]
fn test_set_fd_frames_on() {
    lock!(shared);
    let socket_tx = Socket::bind(ifname()).unwrap();
    let socket_rx = Socket::bind(ifname()).unwrap();
    socket_tx.set_fd_frames(true).unwrap();
    socket_rx.set_fd_frames(true).unwrap();

    let frame = random_fd_data_standard();
    socket_tx.send(&frame).unwrap();
    recv(socket_rx, Some(frame)).unwrap().unwrap();
}