copt/
packet.rs

1use crate::{
2    builder::ConnectBuilder, error::*,
3    DtDataBuilder
4};
5use bytes::{Buf, BufMut, BytesMut};
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7use std::fmt::Debug;
8
9#[derive(Debug, Eq, PartialEq)]
10pub struct CoptFrame<F: Debug + Eq + PartialEq> {
11    pub pdu_type: PduType<F>
12}
13
14impl<F: Debug + Eq + PartialEq> CoptFrame<F> {
15    pub fn builder_of_dt_data(
16        payload: F
17    ) -> DtDataBuilder<F> {
18        DtDataBuilder::new(payload)
19    }
20
21    pub fn builder_of_connect()
22    -> ConnectBuilder<F> {
23        ConnectBuilder::<F>::default()
24    }
25
26    pub fn length(&self) -> u8 {
27        self.pdu_type.length()
28    }
29}
30
31#[derive(Debug, Eq, PartialEq)]
32pub enum PduType<F: Debug + Eq + PartialEq> {
33    /// 0x0e
34    ConnectRequest(ConnectComm),
35    /// 0x0d
36    ConnectConfirm(ConnectComm),
37    /// 0x0f
38    DtData(DtData<F>)
39}
40
41impl<F: Debug + Eq + PartialEq> PduType<F> {
42    pub fn length(&self) -> u8 {
43        match self {
44            PduType::ConnectRequest(conn) => {
45                conn.length()
46            },
47            PduType::ConnectConfirm(conn) => {
48                conn.length()
49            },
50            PduType::DtData(_) => 2
51        }
52    }
53}
54#[derive(Debug, Eq, PartialEq)]
55pub struct DtData<F: Debug + Eq + PartialEq> {
56    pub(crate) tpdu_number:    u8,
57    pub(crate) last_data_unit: bool,
58    pub(crate) payload:        F
59}
60
61impl<F: Debug + Eq + PartialEq> DtData<F> {
62    pub fn tpdu_number(&self) -> u8 {
63        self.tpdu_number
64    }
65
66    pub fn last_data_unit(&self) -> bool {
67        self.last_data_unit
68    }
69
70    pub fn payload(self) -> F {
71        self.payload
72    }
73}
74
75#[derive(Debug, Eq, PartialEq)]
76pub struct ConnectComm {
77    pub destination_ref:          [u8; 2],
78    pub source_ref:               [u8; 2],
79    pub class:                    u8,
80    pub extended_formats:         bool,
81    pub no_explicit_flow_control: bool,
82    pub parameters:               Vec<Parameter>
83}
84
85impl ConnectComm {
86    pub fn length(&self) -> u8 {
87        6 + self
88            .parameters
89            .iter()
90            .fold(0, |x, item| x + item.length())
91    }
92
93    pub(crate) fn decode(
94        src: &mut BytesMut
95    ) -> Result<Self> {
96        if src.len() < 5 {
97            return Err(Error::Error(
98                "data not enough".to_string()
99            ));
100        }
101        let destination_ref =
102            [src.get_u8(), src.get_u8()];
103        let source_ref =
104            [src.get_u8(), src.get_u8()];
105        let merge = src.get_u8();
106        let class = merge >> 4;
107        let extended_formats =
108            merge << 6 >> 7 > 0;
109        let no_explicit_flow_control =
110            merge & 1 > 0;
111
112        let mut parameters = Vec::new();
113        while let Some(parameter) =
114            Parameter::decode(src)?
115        {
116            parameters.push(parameter);
117        }
118        Ok(Self {
119            destination_ref,
120            source_ref,
121            class,
122            extended_formats,
123            no_explicit_flow_control,
124            parameters
125        })
126    }
127
128    pub(crate) fn encode(
129        &self,
130        dst: &mut BytesMut
131    ) {
132        dst.put_slice(
133            self.destination_ref.as_ref()
134        );
135        dst.put_slice(self.source_ref.as_ref());
136
137        let merge = self.class << 4
138            & if self.extended_formats {
139                2
140            } else {
141                0
142            }
143            & if self.no_explicit_flow_control {
144                1
145            } else {
146                0
147            };
148        dst.put_u8(merge);
149        self.parameters
150            .iter()
151            .for_each(|x| x.encode(dst));
152    }
153}
154
155/// https://datatracker.ietf.org/doc/html/rfc905 13.3.4
156#[derive(Debug, Eq, PartialEq)]
157pub enum Parameter {
158    /// 0xc0
159    ///            0000 1101  8192 octets (not
160    /// allowed in Class 0)
161    //             0000 1100  4096 octets (not
162    // allowed in Class 0)             0000
163    // 1011  2048 octets             0000
164    // 1010  1024 octets             0000
165    // 1001   512 octets             0000
166    // 1000   256 octets             0000
167    // 0111   128 octets
168    TpduSize(TpduSize),
169    /// 0xc1    todo?
170    SrcTsap(Vec<u8>),
171    /// 0xc2    todo?
172    DstTsap(Vec<u8>)
173}
174
175#[derive(
176    Debug,
177    Clone,
178    Copy,
179    Eq,
180    PartialEq,
181    TryFromPrimitive,
182    IntoPrimitive,
183)]
184#[repr(u8)]
185pub enum TpduSize {
186    L8192 = 0b0000_1101,
187    L4096 = 0b0000_1100,
188    L2048 = 0b0000_1011,
189    L1024 = 0b0000_1010,
190    L512  = 0b0000_1001,
191    L256  = 0b0000_1000,
192    L128  = 0b0000_0111
193}
194
195impl TpduSize {
196    pub fn pdu_ref(&self) -> u16 {
197        match self {
198            TpduSize::L8192 => 8192,
199            TpduSize::L4096 => 4096,
200            TpduSize::L2048 => 2048,
201            TpduSize::L1024 => 1024,
202            TpduSize::L512 => 512,
203            TpduSize::L256 => 256,
204            TpduSize::L128 => 128
205        }
206    }
207}
208
209impl Parameter {
210    pub fn new_dst_tsap(data: Vec<u8>) -> Self {
211        Self::DstTsap(data)
212    }
213
214    pub fn new_src_tsap(data: Vec<u8>) -> Self {
215        Self::SrcTsap(data)
216    }
217
218    pub fn new_tpdu_size(size: TpduSize) -> Self {
219        Self::TpduSize(size)
220    }
221
222    pub fn length(&self) -> u8 {
223        match self {
224            Parameter::TpduSize(_) => 3u8,
225            Parameter::SrcTsap(data) => {
226                2 + data.len() as u8
227            },
228            Parameter::DstTsap(data) => {
229                2 + data.len() as u8
230            },
231        }
232    }
233
234    fn decode(
235        dst: &mut BytesMut
236    ) -> Result<Option<Self>> {
237        if dst.len() == 0 {
238            return Ok(None);
239        }
240        let (Some(ty), Some(length)) = (dst.get(0), dst.get(1)) else {
241            return Err(Error::Error("data not enough".to_string()));
242        };
243        let length = (length + 2) as usize;
244        let ty = *ty;
245        if dst.len() < length {
246            return Err(Error::Error(
247                "data not enough".to_string()
248            ));
249        }
250        let mut data =
251            dst.split_to(length).split_off(2);
252        match ty {
253            0xc0 => {
254                let size = data.get_u8();
255                Ok(Some(Self::TpduSize(
256                    size.try_into()?
257                )))
258            },
259            0xc1 => Ok(Some(Self::SrcTsap(
260                data.to_vec()
261            ))),
262            0xc2 => Ok(Some(Self::DstTsap(
263                data.to_vec()
264            ))),
265            _ => {
266                return Err(Error::Error(
267                    format!(
268                        "not support parameter: \
269                         {}",
270                        ty
271                    )
272                ));
273            }
274        }
275    }
276
277    fn encode(&self, dst: &mut BytesMut) {
278        match self {
279            Parameter::TpduSize(data) => {
280                dst.put_u8(0xc0);
281                dst.put_u8(1u8);
282                dst.put_u8(data.clone().into())
283            },
284            Parameter::SrcTsap(data) => {
285                dst.put_u8(0xc1);
286                dst.put_u8(data.len() as u8);
287                dst.extend_from_slice(
288                    data.as_ref()
289                )
290            },
291            Parameter::DstTsap(data) => {
292                dst.put_u8(0xc2);
293                dst.put_u8(data.len() as u8);
294                dst.extend_from_slice(
295                    data.as_ref()
296                )
297            }
298        }
299    }
300}