xvc_server/
server.rs

1use std::{
2    io::{ErrorKind, Write},
3    net::{TcpListener, TcpStream, ToSocketAddrs},
4    time::Duration,
5};
6
7use crate::XvcServer;
8use xvc_protocol::error::ReadError;
9use xvc_protocol::{Message, Version, XvcInfo};
10
11#[derive(Debug, Clone)]
12pub struct Config {
13    pub max_vector_size: u32,
14    pub read_write_timeout: Duration,
15}
16
17impl Default for Config {
18    fn default() -> Self {
19        Self {
20            max_vector_size: 10 * 1024 * 1024,
21            read_write_timeout: Duration::from_secs(30),
22        }
23    }
24}
25
26#[derive(Debug)]
27pub struct Server<T: XvcServer> {
28    server: T,
29    config: Config,
30}
31
32impl<T: XvcServer> Server<T> {
33    pub fn new(server: T, config: Config) -> Server<T> {
34        Server { server, config }
35    }
36
37    pub fn listen(&self, addr: impl ToSocketAddrs) -> Result<(), Box<dyn std::error::Error>> {
38        let listener = TcpListener::bind(addr)?;
39        log::info!("Server listening for connections");
40
41        for stream in listener.incoming() {
42            match stream {
43                Ok(tcp) => {
44                    let peer_addr = tcp.peer_addr().ok();
45                    if let Some(addr) = peer_addr {
46                        log::info!("New client connection from {}", addr);
47                    }
48                    if let Err(e) = self.handle_client(tcp) {
49                        log::error!("Client error: {}", e);
50                    }
51                }
52                Err(e) => log::error!("Connection error: {}", e),
53            }
54        }
55        Ok(())
56    }
57
58    fn handle_client(&self, mut tcp: TcpStream) -> Result<(), ReadError> {
59        tcp.set_read_timeout(Some(self.config.read_write_timeout))?;
60        tcp.set_write_timeout(Some(self.config.read_write_timeout))?;
61
62        loop {
63            match Message::from_reader(&mut tcp, self.config.max_vector_size as usize) {
64                Ok(message) => self.process_message(message, &mut tcp)?,
65                Err(ReadError::IoError(err)) if err.kind() == ErrorKind::TimedOut => {
66                    log::error!("Client read timeout, closing connection");
67                    break;
68                }
69                Err(ReadError::IoError(err))
70                    if err.kind() == ErrorKind::ConnectionAborted
71                        || err.kind() == ErrorKind::ConnectionReset =>
72                {
73                    break;
74                } // Client disconnected
75                Err(other) => return Err(other),
76            }
77        }
78        Ok(())
79    }
80
81    /// Process each message, forwarding the implementation to the server.
82    fn process_message(&self, message: Message, tcp: &mut TcpStream) -> Result<(), ReadError> {
83        match message {
84            Message::GetInfo => {
85                log::info!("Received GetInfo message");
86                let info = XvcInfo::new(Version::V1_0, self.config.max_vector_size);
87                info.write_to(tcp)?;
88                log::debug!("Sent XVC info response");
89            }
90            Message::SetTck { period_ns } => {
91                log::debug!("Received SetTck message: period_ns={}", period_ns);
92                let ret_period = self.server.set_tck(period_ns);
93                log::debug!("Set TCK returned: period_ns={}", ret_period);
94                tcp.write_all(&ret_period.to_le_bytes())?;
95            }
96            Message::Shift { num_bits, tms, tdi } => {
97                log::debug!(
98                    "Received Shift message: num_bits={}, tms_len={}, tdi_len={}",
99                    num_bits,
100                    tms.len(),
101                    tdi.len()
102                );
103                log::trace!("Shift TMS data: {:02x?}", &tms[..]);
104                log::trace!("Shift TDI data: {:02x?}", &tdi[..]);
105                let tdo = self.server.shift(num_bits, tms, tdi);
106                log::trace!("Shift result TDO data: {:02x?}", &tdo[..]);
107                tcp.write_all(&tdo)?;
108            }
109        }
110        Ok(())
111    }
112}