TCP Server #77
@ -13,7 +13,7 @@ use thiserror::Error;
|
|||||||
|
|
||||||
// Re-export the TMTC in COBS server.
|
// Re-export the TMTC in COBS server.
|
||||||
pub use crate::hal::std::tcp_with_cobs_server::{
|
pub use crate::hal::std::tcp_with_cobs_server::{
|
||||||
parse_buffer_for_cobs_encoded_packets, TcpTmtcInCobsServer,
|
parse_buffer_for_cobs_encoded_packets, CobsTcParser, CobsTmSender, TcpTmtcInCobsServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// TCP configuration struct.
|
/// TCP configuration struct.
|
||||||
@ -87,7 +87,10 @@ pub struct ConnectionResult {
|
|||||||
pub num_sent_tms: u32,
|
pub num_sent_tms: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TcpTcHandler<TmError, TcError> {
|
/// Generic parser abstraction for an object which can parse for telecommands given a raw
|
||||||
|
/// bytestream received from a TCP socket and send them to a generic [ReceivesTc] telecommand
|
||||||
|
/// receiver. This allows different encoding schemes for telecommands.
|
||||||
|
pub trait TcpTcParser<TmError, TcError> {
|
||||||
fn handle_tc_parsing(
|
fn handle_tc_parsing(
|
||||||
&mut self,
|
&mut self,
|
||||||
tc_buffer: &mut [u8],
|
tc_buffer: &mut [u8],
|
||||||
@ -97,7 +100,12 @@ pub trait TcpTcHandler<TmError, TcError> {
|
|||||||
next_write_idx: &mut usize,
|
next_write_idx: &mut usize,
|
||||||
) -> Result<(), TcpTmtcError<TmError, TcError>>;
|
) -> Result<(), TcpTmtcError<TmError, TcError>>;
|
||||||
}
|
}
|
||||||
pub trait TcpTmHandler<TmError, TcError> {
|
|
||||||
|
/// Generic sender abstraction for an object which can pull telemetry from a given TM source
|
||||||
|
/// using a [TmPacketSource] and then send them back to a client using a given [TcpStream].
|
||||||
|
/// The concrete implementation can also perform any encoding steps which are necessary before
|
||||||
|
/// sending back the data to a client.
|
||||||
|
pub trait TcpTmSender<TmError, TcError> {
|
||||||
fn handle_tm_sending(
|
fn handle_tm_sending(
|
||||||
&mut self,
|
&mut self,
|
||||||
tm_buffer: &mut [u8],
|
tm_buffer: &mut [u8],
|
||||||
@ -107,11 +115,28 @@ pub trait TcpTmHandler<TmError, TcError> {
|
|||||||
) -> Result<bool, TcpTmtcError<TmError, TcError>>;
|
) -> Result<bool, TcpTmtcError<TmError, TcError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TCP TMTC server implementation for exchange of generic TMTC packets in a generic way which
|
||||||
|
/// stays agnostic to the encoding scheme and format used for both telecommands and telemetry.
|
||||||
|
///
|
||||||
|
/// This server implements a generic TMTC handling logic and allows modifying its behaviour
|
||||||
|
/// through the following 4 core abstractions:
|
||||||
|
///
|
||||||
|
/// 1. [TcpTcParser] to parse for telecommands from the raw bytestream received from a client.
|
||||||
|
/// 2. Parsed telecommands will be sent to the [ReceivesTc] telecommand receiver.
|
||||||
|
/// 3. [TcpTmSender] to send telemetry pulled from a TM source back to the client.
|
||||||
|
/// 4. [TmPacketSource] as a generic TM source used by the [TcpTmSender].
|
||||||
|
///
|
||||||
|
/// It is possible to specify custom abstractions to build a dedicated TCP TMTC server without
|
||||||
|
/// having to re-implement common logic.
|
||||||
|
///
|
||||||
|
/// Currently, this framework offers the following concrete implementations:
|
||||||
|
///
|
||||||
|
/// 1. [TcpTmtcInCobsServer] to exchange TMTC wrapped inside the COBS framing protocol.
|
||||||
pub struct TcpTmtcGenericServer<
|
pub struct TcpTmtcGenericServer<
|
||||||
TmError,
|
TmError,
|
||||||
TcError,
|
TcError,
|
||||||
TmHandler: TcpTmHandler<TmError, TcError>,
|
TmHandler: TcpTmSender<TmError, TcError>,
|
||||||
TcHandler: TcpTcHandler<TmError, TcError>,
|
TcHandler: TcpTcParser<TmError, TcError>,
|
||||||
> {
|
> {
|
||||||
base: TcpTmtcServerBase<TmError, TcError>,
|
base: TcpTmtcServerBase<TmError, TcError>,
|
||||||
tc_handler: TcHandler,
|
tc_handler: TcHandler,
|
||||||
@ -121,31 +146,33 @@ pub struct TcpTmtcGenericServer<
|
|||||||
impl<
|
impl<
|
||||||
TmError: 'static,
|
TmError: 'static,
|
||||||
TcError: 'static,
|
TcError: 'static,
|
||||||
TmHandler: TcpTmHandler<TmError, TcError>,
|
TmSender: TcpTmSender<TmError, TcError>,
|
||||||
TcHandler: TcpTcHandler<TmError, TcError>,
|
TcParser: TcpTcParser<TmError, TcError>,
|
||||||
> TcpTmtcGenericServer<TmError, TcError, TmHandler, TcHandler>
|
> TcpTmtcGenericServer<TmError, TcError, TmSender, TcParser>
|
||||||
{
|
{
|
||||||
/// Create a new TMTC server which exchanges TMTC packets encoded with
|
/// Create a new generic TMTC server instance.
|
||||||
/// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing).
|
|
||||||
///
|
///
|
||||||
/// ## Parameter
|
/// ## Parameter
|
||||||
///
|
///
|
||||||
/// * `cfg` - Configuration of the server.
|
/// * `cfg` - Configuration of the server.
|
||||||
|
/// * `tc_parser` - Parser which extracts telecommands from the raw bytestream received from
|
||||||
|
/// the client.
|
||||||
|
/// * `tm_sender` - Sends back telemetry to the client using the specified TM source.
|
||||||
/// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are
|
/// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are
|
||||||
/// then sent back to the client.
|
/// then sent back to the client.
|
||||||
/// * `tc_receiver` - Any received telecommand which was decoded successfully will be forwarded
|
/// * `tc_receiver` - Any received telecommand which was decoded successfully will be forwarded
|
||||||
/// to this TC receiver.
|
/// to this TC receiver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cfg: ServerConfig,
|
cfg: ServerConfig,
|
||||||
tc_handler: TcHandler,
|
tc_parser: TcParser,
|
||||||
tm_handler: TmHandler,
|
tm_sender: TmSender,
|
||||||
tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
||||||
tc_receiver: Box<dyn ReceivesTc<Error = TcError> + Send>,
|
tc_receiver: Box<dyn ReceivesTc<Error = TcError> + Send>,
|
||||||
) -> Result<TcpTmtcGenericServer<TmError, TcError, TmHandler, TcHandler>, std::io::Error> {
|
) -> Result<TcpTmtcGenericServer<TmError, TcError, TmSender, TcParser>, std::io::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
base: TcpTmtcServerBase::new(cfg, tm_source, tc_receiver)?,
|
base: TcpTmtcServerBase::new(cfg, tm_source, tc_receiver)?,
|
||||||
tc_handler,
|
tc_handler: tc_parser,
|
||||||
tm_handler,
|
tm_handler: tm_sender,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,10 +192,14 @@ impl<
|
|||||||
///
|
///
|
||||||
/// 1. It calls the [std::net::TcpListener::accept] method internally using the blocking API
|
/// 1. It calls the [std::net::TcpListener::accept] method internally using the blocking API
|
||||||
/// until a client connects.
|
/// until a client connects.
|
||||||
/// 2. It reads all the telecommands from the client, which are expected to be COBS
|
/// 2. It reads all the telecommands from the client and parses all received data using the
|
||||||
/// encoded packets.
|
/// user specified [TcpTcParser].
|
||||||
/// 3. After reading and parsing all telecommands, it sends back all telemetry it can retrieve
|
/// 3. After reading and parsing all telecommands, it sends back all telemetry using the
|
||||||
/// from the user specified [TmPacketSource] back to the client.
|
/// user specified [TcpTmSender].
|
||||||
|
///
|
||||||
|
/// The server will delay for a user-specified period if the client connects to the server
|
||||||
|
/// for prolonged periods and there is no traffic for the server. This is the case if the
|
||||||
|
/// client does not send any telecommands and no telemetry needs to be sent back to the client.
|
||||||
pub fn handle_next_connection(
|
pub fn handle_next_connection(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<ConnectionResult, TcpTmtcError<TmError, TcError>> {
|
) -> Result<ConnectionResult, TcpTmtcError<TmError, TcError>> {
|
||||||
|
@ -13,13 +13,13 @@ use crate::tmtc::ReceivesTc;
|
|||||||
use crate::tmtc::TmPacketSource;
|
use crate::tmtc::TmPacketSource;
|
||||||
|
|
||||||
use crate::hal::std::tcp_server::{
|
use crate::hal::std::tcp_server::{
|
||||||
ConnectionResult, ServerConfig, TcpTcHandler, TcpTmHandler, TcpTmtcError, TcpTmtcGenericServer,
|
ConnectionResult, ServerConfig, TcpTcParser, TcpTmSender, TcpTmtcError, TcpTmtcGenericServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct CobsTcParser {}
|
pub struct CobsTcParser {}
|
||||||
|
|
||||||
impl<TmError, TcError> TcpTcHandler<TmError, TcError> for CobsTcParser {
|
impl<TmError, TcError> TcpTcParser<TmError, TcError> for CobsTcParser {
|
||||||
fn handle_tc_parsing(
|
fn handle_tc_parsing(
|
||||||
&mut self,
|
&mut self,
|
||||||
tc_buffer: &mut [u8],
|
tc_buffer: &mut [u8],
|
||||||
@ -39,11 +39,11 @@ impl<TmError, TcError> TcpTcHandler<TmError, TcError> for CobsTcParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CobsTmParser {
|
pub struct CobsTmSender {
|
||||||
tm_encoding_buffer: Vec<u8>,
|
tm_encoding_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CobsTmParser {
|
impl CobsTmSender {
|
||||||
fn new(tm_buffer_size: usize) -> Self {
|
fn new(tm_buffer_size: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
// The buffer should be large enough to hold the maximum expected TM size encoded with
|
// The buffer should be large enough to hold the maximum expected TM size encoded with
|
||||||
@ -53,7 +53,7 @@ impl CobsTmParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TmError, TcError> TcpTmHandler<TmError, TcError> for CobsTmParser {
|
impl<TmError, TcError> TcpTmSender<TmError, TcError> for CobsTmSender {
|
||||||
fn handle_tm_sending(
|
fn handle_tm_sending(
|
||||||
&mut self,
|
&mut self,
|
||||||
tm_buffer: &mut [u8],
|
tm_buffer: &mut [u8],
|
||||||
@ -93,13 +93,10 @@ impl<TmError, TcError> TcpTmHandler<TmError, TcError> for CobsTmParser {
|
|||||||
/// TCP TMTC server implementation for exchange of generic TMTC packets which are framed with the
|
/// TCP TMTC server implementation for exchange of generic TMTC packets which are framed with the
|
||||||
/// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing).
|
/// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing).
|
||||||
///
|
///
|
||||||
/// TCP is stream oriented, so a client can read available telemetry using [std::io::Read] as well.
|
/// Telemetry will be encoded with the COBS protocol using [cobs::encode] in addition to being
|
||||||
/// To allow flexibly specifying the telemetry sent back to clients, a generic TM abstraction
|
/// wrapped with the sentinel value 0 as the packet delimiter as well before being sent back to
|
||||||
/// in form of the [TmPacketSource] trait is used. Telemetry will be encoded with the COBS
|
/// the client. Please note that the server will send as much data as it can retrieve from the
|
||||||
/// protocol using [cobs::encode] in addition to being wrapped with the sentinel value 0 as the
|
/// [TmPacketSource] in its current implementation.
|
||||||
/// packet delimiter as well before being sent back to the client. Please note that the server
|
|
||||||
/// will send as much data as it can retrieve from the [TmPacketSource] in its current
|
|
||||||
/// implementation.
|
|
||||||
///
|
///
|
||||||
/// Using a framing protocol like COBS imposes minimal restrictions on the type of TMTC data
|
/// Using a framing protocol like COBS imposes minimal restrictions on the type of TMTC data
|
||||||
/// exchanged while also allowing packets with flexible size and a reliable way to reconstruct full
|
/// exchanged while also allowing packets with flexible size and a reliable way to reconstruct full
|
||||||
@ -107,10 +104,20 @@ impl<TmError, TcError> TcpTmHandler<TmError, TcError> for CobsTmParser {
|
|||||||
/// [parse_buffer_for_cobs_encoded_packets] function to parse for packets and pass them to a
|
/// [parse_buffer_for_cobs_encoded_packets] function to parse for packets and pass them to a
|
||||||
/// generic TC receiver.
|
/// generic TC receiver.
|
||||||
pub struct TcpTmtcInCobsServer<TmError, TcError> {
|
pub struct TcpTmtcInCobsServer<TmError, TcError> {
|
||||||
generic_server: TcpTmtcGenericServer<TmError, TcError, CobsTmParser, CobsTcParser>,
|
generic_server: TcpTmtcGenericServer<TmError, TcError, CobsTmSender, CobsTcParser>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TmError: 'static, TcError: 'static> TcpTmtcInCobsServer<TmError, TcError> {
|
impl<TmError: 'static, TcError: 'static> TcpTmtcInCobsServer<TmError, TcError> {
|
||||||
|
/// Create a new TCP TMTC server which exchanges TMTC packets encoded with
|
||||||
|
/// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing).
|
||||||
|
///
|
||||||
|
/// ## Parameter
|
||||||
|
///
|
||||||
|
/// * `cfg` - Configuration of the server.
|
||||||
|
/// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are
|
||||||
|
/// then sent back to the client.
|
||||||
|
/// * `tc_receiver` - Any received telecommand which was decoded successfully will be forwarded
|
||||||
|
/// to this TC receiver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cfg: ServerConfig,
|
cfg: ServerConfig,
|
||||||
tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
||||||
@ -120,7 +127,7 @@ impl<TmError: 'static, TcError: 'static> TcpTmtcInCobsServer<TmError, TcError> {
|
|||||||
generic_server: TcpTmtcGenericServer::new(
|
generic_server: TcpTmtcGenericServer::new(
|
||||||
cfg,
|
cfg,
|
||||||
CobsTcParser::default(),
|
CobsTcParser::default(),
|
||||||
CobsTmParser::new(cfg.tm_buffer_size),
|
CobsTmSender::new(cfg.tm_buffer_size),
|
||||||
tm_source,
|
tm_source,
|
||||||
tc_receiver,
|
tc_receiver,
|
||||||
)?,
|
)?,
|
||||||
@ -135,15 +142,7 @@ impl<TmError: 'static, TcError: 'static> TcpTmtcInCobsServer<TmError, TcError> {
|
|||||||
/// useful if using the port number 0 for OS auto-assignment.
|
/// useful if using the port number 0 for OS auto-assignment.
|
||||||
pub fn local_addr(&self) -> std::io::Result<SocketAddr>;
|
pub fn local_addr(&self) -> std::io::Result<SocketAddr>;
|
||||||
|
|
||||||
/// This call is used to handle the next connection to a client. Right now, it performs
|
/// Delegation to the [TcpTmtcGenericServer::handle_next_connection] call.
|
||||||
/// the following steps:
|
|
||||||
///
|
|
||||||
/// 1. It calls the [std::net::TcpListener::accept] method internally using the blocking API
|
|
||||||
/// until a client connects.
|
|
||||||
/// 2. It reads all the telecommands from the client, which are expected to be COBS
|
|
||||||
/// encoded packets.
|
|
||||||
/// 3. After reading and parsing all telecommands, it sends back all telemetry it can retrieve
|
|
||||||
/// from the user specified [TmPacketSource] back to the client.
|
|
||||||
pub fn handle_next_connection(
|
pub fn handle_next_connection(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<ConnectionResult, TcpTmtcError<TmError, TcError>>;
|
) -> Result<ConnectionResult, TcpTmtcError<TmError, TcError>>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user