candid_server 0.3.0

A server for reading and relaying messages on a CAN bus
Documentation
use std::io::{BufReader, Read, Write};
use std::net::TcpStream;
use std::sync::mpsc;
use std::thread;

use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};

use socketcan::{CANFrame, CANSocket};

/// Spawns two threads: one to read incoming frames from the client (and write them to the
/// CANSocket), and one to read incoming frames from the `CANReader` (and write them to the client)
pub fn new_client_handler(
    mut connection: TcpStream,
    can_interface: String,
    can_reader: mpsc::Receiver<CANFrame>,
) -> (thread::JoinHandle<()>, thread::JoinHandle<()>) {
    let connection_clone = connection.try_clone().unwrap();
    // Thread to pass frames from the server to the client
    let tx_handle = thread::spawn(move || {
        let ip = connection.peer_addr().unwrap();

        loop {
            // Get an incoming frame from the reader
            let frame = can_reader.recv().unwrap();

            // Relay to the client
            if let Err(_) = write_frame(&mut connection, frame) {
                println!("Connection to client {:?} dropped.", ip);
                break;
            }
        }
    });

    // Thread to pass frames from the client to the CAN socket
    let rx_handle = thread::spawn(move || {
        let ip = connection_clone.peer_addr().unwrap();
        let mut connection = BufReader::new(connection_clone);

        // Possible issue: There is a new socket for each thread
        let can_socket = CANSocket::open(&can_interface).unwrap();

        loop {
            // Get an incoming frame from the client
            let id;
            if let Ok(inner) = connection.read_u32::<NetworkEndian>() {
                id = inner;
            } else {
                println!("Connection to client {:?} dropped.", ip);
                break;
            }

            let mut data = [0 as u8; 8];
            if let Err(_) = connection.read_exact(&mut data) {
                println!("Connection to client {:?} dropped.", ip);
                break;
            }

            // Write the frame to the CAN Socket
            let frame = CANFrame::new(id, &data, false, false).unwrap();
            can_socket.write_frame_insist(&frame).unwrap();
        }
    });

    (tx_handle, rx_handle)
}

fn write_frame(connection: &mut TcpStream, frame: CANFrame) -> Result<(), std::io::Error> {
    connection.write_u32::<NetworkEndian>(frame.id())?;
    connection.write(&frame.data())?;
    connection.flush().unwrap();
    Ok(())
}