basic interop test works
All checks were successful
Rust/cfdp/pipeline/head This commit looks good

This commit is contained in:
Robin Müller 2024-08-29 11:54:04 +02:00
parent 6771787e49
commit 5d2cd6d383
Signed by: muellerr
GPG Key ID: A649FB78196E3849
4 changed files with 90 additions and 52 deletions

View File

@ -19,7 +19,10 @@ use cfdp::{
}; };
use log::{debug, info, warn}; use log::{debug, info, warn};
use spacepackets::{ use spacepackets::{
cfdp::{pdu::PduError, ChecksumType, ConditionCode, TransmissionMode}, cfdp::{
pdu::{file_data::FileDataPdu, metadata::MetadataPduReader, PduError},
ChecksumType, ConditionCode, TransmissionMode,
},
seq_count::SeqCountProviderSyncU16, seq_count::SeqCountProviderSyncU16,
util::{UnsignedByteFieldU16, UnsignedEnum}, util::{UnsignedByteFieldU16, UnsignedEnum},
}; };
@ -166,7 +169,7 @@ impl CfdpUser for ExampleCfdpUser {
pub struct UdpServer { pub struct UdpServer {
pub socket: UdpSocket, pub socket: UdpSocket,
recv_buf: Vec<u8>, recv_buf: Vec<u8>,
sender_addr: Option<SocketAddr>, remote_addr: SocketAddr,
source_tc_tx: mpsc::Sender<PduOwnedWithInfo>, source_tc_tx: mpsc::Sender<PduOwnedWithInfo>,
dest_tc_tx: mpsc::Sender<PduOwnedWithInfo>, dest_tc_tx: mpsc::Sender<PduOwnedWithInfo>,
source_tm_rx: mpsc::Receiver<PduOwnedWithInfo>, source_tm_rx: mpsc::Receiver<PduOwnedWithInfo>,
@ -186,6 +189,7 @@ pub enum UdpServerError {
impl UdpServer { impl UdpServer {
pub fn new<A: ToSocketAddrs>( pub fn new<A: ToSocketAddrs>(
addr: A, addr: A,
remote_addr: SocketAddr,
max_recv_size: usize, max_recv_size: usize,
source_tc_tx: mpsc::Sender<PduOwnedWithInfo>, source_tc_tx: mpsc::Sender<PduOwnedWithInfo>,
dest_tc_tx: mpsc::Sender<PduOwnedWithInfo>, dest_tc_tx: mpsc::Sender<PduOwnedWithInfo>,
@ -197,7 +201,7 @@ impl UdpServer {
recv_buf: vec![0; max_recv_size], recv_buf: vec![0; max_recv_size],
source_tc_tx, source_tc_tx,
dest_tc_tx, dest_tc_tx,
sender_addr: None, remote_addr,
source_tm_rx, source_tm_rx,
dest_tm_rx, dest_tm_rx,
}; };
@ -219,7 +223,7 @@ impl UdpServer {
} }
}; };
let (_, from) = res; let (_, from) = res;
self.sender_addr = Some(from); self.remote_addr = from;
let pdu_owned = PduOwnedWithInfo::new_from_raw_packet(&self.recv_buf)?; let pdu_owned = PduOwnedWithInfo::new_from_raw_packet(&self.recv_buf)?;
match pdu_owned.packet_target()? { match pdu_owned.packet_target()? {
cfdp::PacketTarget::SourceEntity => { cfdp::PacketTarget::SourceEntity => {
@ -237,12 +241,11 @@ impl UdpServer {
} }
pub fn recv_and_send_telemetry(&mut self) { pub fn recv_and_send_telemetry(&mut self) {
if self.last_sender().is_none() {
return;
}
let tm_handler = |receiver: &mpsc::Receiver<PduOwnedWithInfo>| { let tm_handler = |receiver: &mpsc::Receiver<PduOwnedWithInfo>| {
while let Ok(tm) = receiver.try_recv() { while let Ok(tm) = receiver.try_recv() {
let result = self.socket.send_to(tm.pdu(), self.last_sender().unwrap()); debug!("Sending PDU: {:?}", tm);
pdu_printout(&tm);
let result = self.socket.send_to(tm.pdu(), self.remote_addr());
if let Err(e) = result { if let Err(e) = result {
warn!("Sending TM with UDP socket failed: {e}") warn!("Sending TM with UDP socket failed: {e}")
} }
@ -252,8 +255,30 @@ impl UdpServer {
tm_handler(&self.dest_tm_rx); tm_handler(&self.dest_tm_rx);
} }
pub fn last_sender(&self) -> Option<SocketAddr> { pub fn remote_addr(&self) -> SocketAddr {
self.sender_addr self.remote_addr
}
}
fn pdu_printout(pdu: &PduOwnedWithInfo) {
match pdu.pdu_type() {
spacepackets::cfdp::PduType::FileDirective => match pdu.file_directive_type().unwrap() {
spacepackets::cfdp::pdu::FileDirectiveType::EofPdu => (),
spacepackets::cfdp::pdu::FileDirectiveType::FinishedPdu => (),
spacepackets::cfdp::pdu::FileDirectiveType::AckPdu => (),
spacepackets::cfdp::pdu::FileDirectiveType::MetadataPdu => {
let meta_pdu =
MetadataPduReader::new(pdu.pdu()).expect("creating metadata pdu failed");
debug!("Metadata PDU: {:?}", meta_pdu)
}
spacepackets::cfdp::pdu::FileDirectiveType::NakPdu => (),
spacepackets::cfdp::pdu::FileDirectiveType::PromptPdu => (),
spacepackets::cfdp::pdu::FileDirectiveType::KeepAlivePdu => (),
},
spacepackets::cfdp::PduType::FileData => {
let fd_pdu = FileDataPdu::from_bytes(pdu.pdu()).expect("creating file data pdu failed");
debug!("File data PDU: {:?}", fd_pdu);
}
} }
} }
@ -275,19 +300,20 @@ fn main() {
// Simplified event handling using atomic signals. // Simplified event handling using atomic signals.
let stop_signal_source = Arc::new(AtomicBool::new(false)); let stop_signal_source = Arc::new(AtomicBool::new(false));
let stop_signal_dest = stop_signal_source.clone(); let stop_signal_dest = stop_signal_source.clone();
let stop_signal_ctrl = stop_signal_source.clone(); // let stop_signal_ctrl = stop_signal_source.clone();
let completion_signal_source = Arc::new(AtomicBool::new(false)); let completion_signal_source = Arc::new(AtomicBool::new(false));
let completion_signal_source_main = completion_signal_source.clone(); // let completion_signal_source_main = completion_signal_source.clone();
let completion_signal_dest = Arc::new(AtomicBool::new(false)); let completion_signal_dest = Arc::new(AtomicBool::new(false));
let completion_signal_dest_main = completion_signal_dest.clone(); // let completion_signal_dest_main = completion_signal_dest.clone();
let srcfile = tempfile::NamedTempFile::new().unwrap().into_temp_path(); let srcfile = tempfile::NamedTempFile::new().unwrap().into_temp_path();
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.write(true) .write(true)
.open(&srcfile) .open(&srcfile)
.expect("opening file failed"); .expect("opening file failed");
info!("created test source file {:?}", srcfile);
file.write_all(FILE_DATA.as_bytes()) file.write_all(FILE_DATA.as_bytes())
.expect("writing file content failed"); .expect("writing file content failed");
let destdir = tempfile::tempdir().expect("creating temp directory failed"); let destdir = tempfile::tempdir().expect("creating temp directory failed");
@ -307,7 +333,7 @@ fn main() {
true, true,
false, false,
spacepackets::cfdp::TransmissionMode::Unacknowledged, spacepackets::cfdp::TransmissionMode::Unacknowledged,
ChecksumType::Crc32, ChecksumType::Crc32C,
); );
let seq_count_provider = SeqCountProviderSyncU16::default(); let seq_count_provider = SeqCountProviderSyncU16::default();
let mut source_handler = SourceHandler::new( let mut source_handler = SourceHandler::new(
@ -348,9 +374,11 @@ fn main() {
let (source_tc_tx, source_tc_rx) = mpsc::channel(); let (source_tc_tx, source_tc_rx) = mpsc::channel();
let (dest_tc_tx, dest_tc_rx) = mpsc::channel(); let (dest_tc_tx, dest_tc_rx) = mpsc::channel();
let sock_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), RUST_PORT); let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), RUST_PORT);
let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), PY_PORT);
let mut udp_server = UdpServer::new( let mut udp_server = UdpServer::new(
sock_addr, local_addr,
remote_addr,
2048, 2048,
source_tc_tx, source_tc_tx,
dest_tc_tx, dest_tc_tx,
@ -359,7 +387,6 @@ fn main() {
) )
.expect("creating UDP server failed"); .expect("creating UDP server failed");
let start = std::time::Instant::now();
let jh_source = thread::Builder::new() let jh_source = thread::Builder::new()
.name("cfdp src entity".to_string()) .name("cfdp src entity".to_string())
.spawn(move || { .spawn(move || {
@ -386,7 +413,7 @@ fn main() {
} }
} }
Err(e) => { Err(e) => {
println!("Source handler error: {}", e); warn!("cfdp src entity error: {}", e);
next_delay = Some(Duration::from_millis(50)); next_delay = Some(Duration::from_millis(50));
} }
} }
@ -452,13 +479,14 @@ fn main() {
let jh_udp_server = thread::Builder::new() let jh_udp_server = thread::Builder::new()
.name("cfdp udp server".to_string()) .name("cfdp udp server".to_string())
.spawn(move || { .spawn(move || {
info!("Starting UDP server on {}", sock_addr); info!("Starting UDP server on {}", remote_addr);
loop { loop {
loop { loop {
match udp_server.try_recv_tc() { match udp_server.try_recv_tc() {
Ok(result) => match result { Ok(result) => match result {
Some((pdu, _addr)) => { Some((pdu, _addr)) => {
debug!("Received PDU on UDP server: {:?}", pdu); debug!("Received PDU on UDP server: {:?}", pdu);
pdu_printout(&pdu);
} }
None => break, None => break,
}, },
@ -474,7 +502,8 @@ fn main() {
}) })
.unwrap(); .unwrap();
loop { //loop {
/*
if completion_signal_source_main.load(std::sync::atomic::Ordering::Relaxed) if completion_signal_source_main.load(std::sync::atomic::Ordering::Relaxed)
&& completion_signal_dest_main.load(std::sync::atomic::Ordering::Relaxed) && completion_signal_dest_main.load(std::sync::atomic::Ordering::Relaxed)
{ {
@ -484,11 +513,12 @@ fn main() {
stop_signal_ctrl.store(true, std::sync::atomic::Ordering::Relaxed); stop_signal_ctrl.store(true, std::sync::atomic::Ordering::Relaxed);
break; break;
} }
if std::time::Instant::now() - start > Duration::from_secs(2) { if std::time::Instant::now() - start > Duration::from_secs(20) {
panic!("file transfer not finished in 2 seconds"); panic!("file transfer not finished in 20 seconds");
}
std::thread::sleep(Duration::from_millis(50));
} }
*/
//std::thread::sleep(Duration::from_millis(50));
//}
jh_source.join().unwrap(); jh_source.join().unwrap();
jh_dest.join().unwrap(); jh_dest.join().unwrap();

View File

@ -1,6 +1,5 @@
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use core::fmt::Display; use core::fmt::Display;
use crc::{Crc, CRC_32_CKSUM};
use spacepackets::cfdp::ChecksumType; use spacepackets::cfdp::ChecksumType;
use spacepackets::ByteConversionError; use spacepackets::ByteConversionError;
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -9,8 +8,6 @@ use std::path::Path;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std_mod::*; pub use std_mod::*;
pub const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_CKSUM);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum FilestoreError { pub enum FilestoreError {
FileDoesNotExist, FileDoesNotExist,
@ -171,6 +168,10 @@ pub trait VirtualFilestore {
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod std_mod { pub mod std_mod {
use crc::Crc;
use crate::{CRC_32, CRC_32C};
use super::*; use super::*;
use std::{ use std::{
fs::{self, File, OpenOptions}, fs::{self, File, OpenOptions},
@ -306,10 +307,8 @@ pub mod std_mod {
checksum_type: ChecksumType, checksum_type: ChecksumType,
verification_buf: &mut [u8], verification_buf: &mut [u8],
) -> Result<u32, FilestoreError> { ) -> Result<u32, FilestoreError> {
match checksum_type { let mut calc_with_crc_lib = |crc: Crc<u32>| -> Result<u32, FilestoreError> {
ChecksumType::Modular => self.calc_modular_checksum(file_path), let mut digest = crc.digest();
ChecksumType::Crc32 => {
let mut digest = CRC_32.digest();
let file_to_check = File::open(file_path)?; let file_to_check = File::open(file_path)?;
let mut buf_reader = BufReader::new(file_to_check); let mut buf_reader = BufReader::new(file_to_check);
loop { loop {
@ -320,7 +319,11 @@ pub mod std_mod {
digest.update(&verification_buf[0..bytes_read]); digest.update(&verification_buf[0..bytes_read]);
} }
Ok(digest.finalize()) Ok(digest.finalize())
} };
match checksum_type {
ChecksumType::Modular => self.calc_modular_checksum(file_path),
ChecksumType::Crc32 => calc_with_crc_lib(CRC_32),
ChecksumType::Crc32C => calc_with_crc_lib(CRC_32C),
ChecksumType::NullChecksum => Ok(0), ChecksumType::NullChecksum => Ok(0),
_ => Err(FilestoreError::ChecksumTypeNotImplemented(checksum_type)), _ => Err(FilestoreError::ChecksumTypeNotImplemented(checksum_type)),
} }

View File

@ -19,7 +19,7 @@ pub mod user;
use crate::time::CountdownProvider; use crate::time::CountdownProvider;
use core::{cell::RefCell, fmt::Debug, hash::Hash}; use core::{cell::RefCell, fmt::Debug, hash::Hash};
use crc::{Crc, CRC_32_CKSUM}; use crc::{Crc, CRC_32_ISCSI, CRC_32_ISO_HDLC};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use hashbrown::HashMap; use hashbrown::HashMap;
@ -682,7 +682,12 @@ pub enum State {
Suspended = 2, Suspended = 2,
} }
pub const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_CKSUM); /// SANA registry entry: https://sanaregistry.org/r/checksum_identifiers/records/4
/// Entry in CRC catalogue: https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.cat.crc-32
pub const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
/// SANA registry entry: https://sanaregistry.org/r/checksum_identifiers/records/3
/// Entry in CRC catalogue: https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.cat.crc-32-iscsi
pub const CRC_32C: Crc<u32> = Crc::<u32>::new(&CRC_32_ISCSI);
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View File

@ -113,7 +113,7 @@ pub enum SourceError {
SourceFileNotValidUtf8(Utf8Error), SourceFileNotValidUtf8(Utf8Error),
#[error("destination file does not have valid UTF8 format: {0}")] #[error("destination file does not have valid UTF8 format: {0}")]
DestFileNotValidUtf8(Utf8Error), DestFileNotValidUtf8(Utf8Error),
#[error("error related to PDU creation")] #[error("error related to PDU creation: {0}")]
Pdu(#[from] PduError), Pdu(#[from] PduError),
#[error("cfdp feature not implemented")] #[error("cfdp feature not implemented")]
NotImplemented, NotImplemented,