Skip to main content

rusty_acse/
lib.rs

1pub(crate) mod api;
2pub(crate) mod messages;
3pub(crate) mod service;
4
5pub use api::*;
6use rusty_copp::{RustyCoppInitiatorIsoStack, RustyCoppReaderIsoStack, RustyCoppResponderIsoStack, RustyCoppWriterIsoStack};
7pub use service::*;
8
9pub type RustyOsiSingleValueAcseReaderIsoStack<R> = RustyOsiSingleValueAcseReader<RustyCoppReaderIsoStack<R>>;
10pub type RustyOsiSingleValueAcseWriterIsoStack<W> = RustyOsiSingleValueAcseWriter<RustyCoppWriterIsoStack<W>>;
11pub type RustyOsiSingleValueAcseInitiatorIsoStack<R, W> = RustyOsiSingleValueAcseInitiator<RustyCoppInitiatorIsoStack<R, W>, RustyCoppReaderIsoStack<R>, RustyCoppWriterIsoStack<W>>;
12pub type RustyOsiSingleValueAcseListenerIsoStack<R, W> = RustyOsiSingleValueAcseListener<RustyCoppResponderIsoStack<R, W>, RustyCoppReaderIsoStack<R>, RustyCoppWriterIsoStack<W>>;
13pub type RustyOsiSingleValueAcseResponderIsoStack<R, W> = RustyOsiSingleValueAcseResponder<RustyCoppResponderIsoStack<R, W>, RustyCoppReaderIsoStack<R>, RustyCoppWriterIsoStack<W>>;
14pub type RustyOsiSingleValueAcseConnectionIsoStack<R, W> = RustyAcseConnection<RustyCoppReaderIsoStack<R>, RustyCoppWriterIsoStack<W>>;
15
16#[cfg(test)]
17mod tests {
18    use der_parser::num_bigint::BigInt;
19    use std::time::Duration;
20
21    use der_parser::Oid;
22    use rusty_copp::{CoppError, RustyCoppListener};
23    use rusty_cosp::{TcpCospInitiator, TcpCospListener, TcpCospReader, TcpCospResponder, TcpCospWriter};
24    use rusty_cotp::{CotpAcceptInformation, CotpConnectInformation, CotpResponder, TcpCotpAcceptor, TcpCotpConnection, TcpCotpReader, TcpCotpWriter};
25    use rusty_tpkt::{TcpTpktConnection, TcpTpktReader, TcpTpktServer, TcpTpktWriter};
26    use tokio::join;
27    use tracing_test::traced_test;
28
29    use super::*;
30
31    #[tokio::test]
32    #[traced_test]
33    async fn it_should_create_connection() -> Result<(), anyhow::Error> {
34        let (client, server) = create_acse_connection_pair_with_options(
35            AcseRequestInformation {
36                application_context_name: Oid::from(&[1, 0, 9506, 2, 1])?,
37                called_ap_title: Some(ApTitle::Form2(Oid::from(&[1, 2, 3, 4, 5])?)),
38                called_ae_qualifier: Some(AeQualifier::Form2(vec![100])),
39                called_ap_invocation_identifier: Some(vec![101]),
40                called_ae_invocation_identifier: Some(vec![102]),
41                calling_ap_title: Some(ApTitle::Form2(Oid::from(&[2, 2, 3, 4, 5])?)),
42                calling_ae_qualifier: Some(AeQualifier::Form2(BigInt::from(200u32).to_signed_bytes_be())),
43                calling_ap_invocation_identifier: Some(BigInt::from(201u32).to_signed_bytes_be()),
44                calling_ae_invocation_identifier: Some(BigInt::from(202u32).to_signed_bytes_be()),
45                implementation_information: Some("This Guy".into()),
46            },
47            AcseResponseInformation {
48                associate_result: AssociateResult::Accepted,
49                associate_source_diagnostic: AssociateSourceDiagnostic::User(AssociateSourceDiagnosticUserCategory::Null),
50                application_context_name: Oid::from(&[1, 0, 9506, 2, 1])?,
51                responding_ap_title: Some(ApTitle::Form2(Oid::from(&[1, 2, 3, 4, 5])?)),
52                responding_ae_qualifier: Some(AeQualifier::Form2(vec![100])),
53                responding_ap_invocation_identifier: Some(vec![101]),
54                responding_ae_invocation_identifier: Some(vec![102]),
55                implementation_information: Some("This Other Guy".into()),
56            },
57            vec![0xa8, 0x00],
58            vec![0xa9, 0x00],
59        )
60        .await?;
61
62        let (mut client_reader, mut client_writer) = client.split().await?;
63        let (mut server_reader, mut server_writer) = server.split().await?;
64
65        client_writer.send(vec![0xa0, 0x03, 0x02, 0x01, 0x01]).await?;
66        assert_eq!(AcseRecvResult::Data(vec![160, 3, 2, 1, 1]), server_reader.recv().await?);
67        server_writer.send(vec![0xa0, 0x03, 0x02, 0x01, 0x02]).await?;
68        assert_eq!(AcseRecvResult::Data(vec![160, 3, 2, 1, 2]), client_reader.recv().await?);
69
70        Ok(())
71    }
72
73    async fn create_acse_connection_pair_with_options(
74        reqeust_options: AcseRequestInformation,
75        response_options: AcseResponseInformation,
76        connect_data: Vec<u8>,
77        accept_data: Vec<u8>,
78    ) -> Result<(impl OsiSingleValueAcseConnection, impl OsiSingleValueAcseConnection), anyhow::Error> {
79        // let test_address = format!("127.0.0.1:{}", rand::random_range::<u16, Range<u16>>(20000..30000)).parse()?;
80        let test_address = "127.0.0.1:10002".parse()?;
81
82        let connect_information = CotpConnectInformation::default();
83
84        let client_path = async {
85            tokio::time::sleep(Duration::from_millis(1)).await; // Give the server time to start
86            let tpkt_client = TcpTpktConnection::connect(test_address).await?;
87            let cotp_client = TcpCotpConnection::<TcpTpktReader, TcpTpktWriter>::initiate(tpkt_client, connect_information.clone()).await?;
88            let cosp_client = TcpCospInitiator::<TcpCotpReader<TcpTpktReader>, TcpCotpWriter<TcpTpktWriter>>::new(cotp_client, Default::default()).await?;
89            let copp_client = RustyCoppInitiatorIsoStack::<TcpTpktReader, TcpTpktWriter>::new(cosp_client, Default::default());
90            let acse_client = RustyOsiSingleValueAcseInitiatorIsoStack::<TcpTpktReader, TcpTpktWriter>::new(copp_client, reqeust_options.clone());
91            Ok(acse_client.initiate(Oid::from(&[1, 0, 9506, 2, 1]).map_err(|e| CoppError::InternalError(e.to_string()))?, connect_data.clone()).await?)
92        };
93        let server_path = async {
94            let tpkt_server = TcpTpktServer::listen(test_address).await?;
95            let (tpkt_connection, _) = tpkt_server.accept().await?;
96            let (cotp_server, _) = TcpCotpAcceptor::<TcpTpktReader, TcpTpktWriter>::new(tpkt_connection).await?;
97            let cotp_connection = cotp_server.accept(CotpAcceptInformation::default()).await?;
98            let (cosp_listener, _) = TcpCospListener::<TcpCotpReader<TcpTpktReader>, TcpCotpWriter<TcpTpktWriter>>::new(cotp_connection).await?;
99            let (copp_listener, _) =
100                RustyCoppListener::<TcpCospResponder<TcpCotpReader<TcpTpktReader>, TcpCotpWriter<TcpTpktWriter>>, TcpCospReader<TcpCotpReader<TcpTpktReader>>, TcpCospWriter<TcpCotpWriter<TcpTpktWriter>>>::new(cosp_listener).await?;
101            let (mut acse_listener, received_request_information) = RustyOsiSingleValueAcseListenerIsoStack::<TcpTpktReader, TcpTpktWriter>::new(copp_listener).await?;
102            acse_listener.set_response(Some(response_options.clone()));
103            let (acse_responder, received_connect_data) = acse_listener.responder().await?;
104
105            Ok((acse_responder.accept(accept_data.clone()).await?, received_request_information, received_connect_data))
106        };
107
108        let (copp_client, copp_server): (Result<_, anyhow::Error>, Result<_, anyhow::Error>) = join!(client_path, server_path);
109        let (copp_server, received_request_information, received_connect_data) = copp_server?;
110        let (copp_client, received_response_information, received_accept_data) = copp_client?;
111
112        assert_eq!(reqeust_options, received_request_information);
113        assert_eq!(connect_data, received_connect_data);
114        assert_eq!(response_options, received_response_information);
115        assert_eq!(accept_data, received_accept_data);
116
117        Ok((copp_client, copp_server))
118    }
119}