satrs_core/hal/std/
udp_server.rs

1//! Generic UDP TC server.
2use crate::tmtc::{ReceivesTc, ReceivesTcCore};
3use std::boxed::Box;
4use std::io::{Error, ErrorKind};
5use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
6use std::vec;
7use std::vec::Vec;
8
9/// This UDP server can be used to receive CCSDS space packet telecommands or any other telecommand
10/// format.
11///
12/// It caches all received telecomands into a vector. The maximum expected telecommand size should
13/// be declared upfront. This avoids dynamic allocation during run-time. The user can specify a TC
14/// receiver in form of a special trait object which implements [ReceivesTc]. Please note that the
15/// receiver should copy out the received data if it the data is required past the
16/// [ReceivesTcCore::pass_tc] call.
17///
18/// # Examples
19///
20/// ```
21/// use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
22/// use spacepackets::ecss::WritablePusPacket;
23/// use satrs_core::hal::std::udp_server::UdpTcServer;
24/// use satrs_core::tmtc::{ReceivesTc, ReceivesTcCore};
25/// use spacepackets::SpHeader;
26/// use spacepackets::ecss::tc::PusTcCreator;
27///
28/// #[derive (Default)]
29/// struct PingReceiver {}
30/// impl ReceivesTcCore for PingReceiver {
31///    type Error = ();
32///    fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
33///         assert_eq!(tc_raw.len(), 13);
34///         Ok(())
35///     }
36/// }
37///
38/// let mut buf = [0; 32];
39/// let dest_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777);
40/// let ping_receiver = PingReceiver::default();
41/// let mut udp_tc_server = UdpTcServer::new(dest_addr, 2048, Box::new(ping_receiver))
42///       .expect("Creating UDP TMTC server failed");
43/// let mut sph = SpHeader::tc_unseg(0x02, 0, 0).unwrap();
44/// let pus_tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, true);
45/// let len = pus_tc
46///     .write_to_bytes(&mut buf)
47///     .expect("Error writing PUS TC packet");
48/// assert_eq!(len, 13);
49/// let client = UdpSocket::bind("127.0.0.1:7778").expect("Connecting to UDP server failed");
50/// client
51///     .send_to(&buf[0..len], dest_addr)
52///     .expect("Error sending PUS TC via UDP");
53/// ```
54///
55/// The [satrs-example crate](https://egit.irs.uni-stuttgart.de/rust/fsrc-launchpad/src/branch/main/satrs-example)
56/// server code also includes
57/// [example code](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/tmtc.rs#L67)
58/// on how to use this TC server. It uses the server to receive PUS telecommands on a specific port
59/// and then forwards them to a generic CCSDS packet receiver.
60pub struct UdpTcServer<E> {
61    pub socket: UdpSocket,
62    recv_buf: Vec<u8>,
63    sender_addr: Option<SocketAddr>,
64    tc_receiver: Box<dyn ReceivesTc<Error = E>>,
65}
66
67#[derive(Debug)]
68pub enum ReceiveResult<E> {
69    NothingReceived,
70    IoError(Error),
71    ReceiverError(E),
72}
73
74impl<E> From<Error> for ReceiveResult<E> {
75    fn from(e: Error) -> Self {
76        ReceiveResult::IoError(e)
77    }
78}
79
80impl<E: PartialEq> PartialEq for ReceiveResult<E> {
81    fn eq(&self, other: &Self) -> bool {
82        use ReceiveResult::*;
83        match (self, other) {
84            (IoError(ref e), IoError(ref other_e)) => e.kind() == other_e.kind(),
85            (NothingReceived, NothingReceived) => true,
86            (ReceiverError(e), ReceiverError(other_e)) => e == other_e,
87            _ => false,
88        }
89    }
90}
91
92impl<E: Eq + PartialEq> Eq for ReceiveResult<E> {}
93
94impl<E: 'static> ReceivesTcCore for UdpTcServer<E> {
95    type Error = E;
96
97    fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
98        self.tc_receiver.pass_tc(tc_raw)
99    }
100}
101
102impl<E: 'static> UdpTcServer<E> {
103    pub fn new<A: ToSocketAddrs>(
104        addr: A,
105        max_recv_size: usize,
106        tc_receiver: Box<dyn ReceivesTc<Error = E>>,
107    ) -> Result<Self, Error> {
108        let server = Self {
109            socket: UdpSocket::bind(addr)?,
110            recv_buf: vec![0; max_recv_size],
111            sender_addr: None,
112            tc_receiver,
113        };
114        server.socket.set_nonblocking(true)?;
115        Ok(server)
116    }
117
118    pub fn try_recv_tc(&mut self) -> Result<(usize, SocketAddr), ReceiveResult<E>> {
119        let res = match self.socket.recv_from(&mut self.recv_buf) {
120            Ok(res) => res,
121            Err(e) => {
122                return if e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::TimedOut {
123                    Err(ReceiveResult::NothingReceived)
124                } else {
125                    Err(e.into())
126                }
127            }
128        };
129        let (num_bytes, from) = res;
130        self.sender_addr = Some(from);
131        self.tc_receiver
132            .pass_tc(&self.recv_buf[0..num_bytes])
133            .map_err(|e| ReceiveResult::ReceiverError(e))?;
134        Ok(res)
135    }
136
137    pub fn last_sender(&self) -> Option<SocketAddr> {
138        self.sender_addr
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use crate::hal::std::udp_server::{ReceiveResult, UdpTcServer};
145    use crate::tmtc::ReceivesTcCore;
146    use spacepackets::ecss::tc::PusTcCreator;
147    use spacepackets::ecss::WritablePusPacket;
148    use spacepackets::SpHeader;
149    use std::boxed::Box;
150    use std::collections::VecDeque;
151    use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
152    use std::vec::Vec;
153
154    fn is_send<T: Send>(_: &T) {}
155
156    #[derive(Default)]
157    struct PingReceiver {
158        pub sent_cmds: VecDeque<Vec<u8>>,
159    }
160
161    impl ReceivesTcCore for PingReceiver {
162        type Error = ();
163
164        fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
165            let mut sent_data = Vec::new();
166            sent_data.extend_from_slice(tc_raw);
167            self.sent_cmds.push_back(sent_data);
168            Ok(())
169        }
170    }
171
172    #[test]
173    fn basic_test() {
174        let mut buf = [0; 32];
175        let dest_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777);
176        let ping_receiver = PingReceiver::default();
177        is_send(&ping_receiver);
178        let mut udp_tc_server = UdpTcServer::new(dest_addr, 2048, Box::new(ping_receiver))
179            .expect("Creating UDP TMTC server failed");
180        is_send(&udp_tc_server);
181        let mut sph = SpHeader::tc_unseg(0x02, 0, 0).unwrap();
182        let pus_tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, true);
183        let len = pus_tc
184            .write_to_bytes(&mut buf)
185            .expect("Error writing PUS TC packet");
186        let client = UdpSocket::bind("127.0.0.1:7778").expect("Connecting to UDP server failed");
187        client
188            .send_to(&buf[0..len], dest_addr)
189            .expect("Error sending PUS TC via UDP");
190        let local_addr = client.local_addr().unwrap();
191        udp_tc_server
192            .try_recv_tc()
193            .expect("Error receiving sent telecommand");
194        assert_eq!(
195            udp_tc_server.last_sender().expect("No sender set"),
196            local_addr
197        );
198        let ping_receiver: &mut PingReceiver = udp_tc_server.tc_receiver.downcast_mut().unwrap();
199        assert_eq!(ping_receiver.sent_cmds.len(), 1);
200        let sent_cmd = ping_receiver.sent_cmds.pop_front().unwrap();
201        assert_eq!(sent_cmd, buf[0..len]);
202    }
203
204    #[test]
205    fn test_nothing_received() {
206        let dest_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7779);
207        let ping_receiver = PingReceiver::default();
208        let mut udp_tc_server = UdpTcServer::new(dest_addr, 2048, Box::new(ping_receiver))
209            .expect("Creating UDP TMTC server failed");
210        let res = udp_tc_server.try_recv_tc();
211        assert!(res.is_err());
212        let err = res.unwrap_err();
213        assert_eq!(err, ReceiveResult::NothingReceived);
214    }
215}