dvb_gse/
bbframe.rs

1//! DVB-S2 Base-Band Frame (BBFRAME).
2//!
3//! The DVB-S2 BBFRAME corresponds to the input of the BCH encoder. It is
4//! composed by a BBHEADER, a data field, and padding reach to the BCH codeword
5//! size (which depends on the coding rate and the short or normal FECFRAMES are
6//! used). See Section 5 in [EN 302
7//! 307-1](https://www.etsi.org/deliver/etsi_en/302300_302399/30230701/01.04.01_60/en_30230701v010401p.pdf).
8
9use super::bbheader::{BBHeader, SisMis, TsGs};
10use bytes::Bytes;
11use std::io::{Read, Result};
12use std::net::UdpSocket;
13
14// This import is used by rustdoc
15#[allow(unused_imports)]
16use std::net::TcpStream;
17
18/// Maximum header length in bytes.
19///
20/// This is used to allocate buffers for the BBFRAMEs, taking into account that
21/// they can optionally be preceded by a header whose maximum length is given by
22/// this constant. The value of the constant is set to a somewhat arbitrary
23/// choice that should be good for most use cases.
24pub const HEADER_MAX_LEN: usize = 64;
25
26/// Maximum BBFRAME length in bytes (including header).
27///
28/// The maximum BBFRAME size possible corresponds to r=9/10 DVB-S2 with normal
29/// FECFRAMEs, which is 58192 bits or 7274 bytes.
30///
31/// The constant includes the [`HEADER_MAX_LEN`] in the calculation of the
32/// maximum BBFRAME length.
33pub const BBFRAME_MAX_LEN: usize = 7274 + HEADER_MAX_LEN;
34
35/// BBFRAME defragmenter.
36///
37/// This receives BBFRAME fragments from an object that implements the
38/// [`RecvFragment`] trait and performs defragmentation and validation to obtain
39/// and return full BBFRAMES.
40#[derive(Debug)]
41pub struct BBFrameDefrag<R> {
42    recv_fragment: R,
43    buffer: Box<[u8; BBFRAME_MAX_LEN]>,
44    occupied_bytes: usize,
45    validator: BBFrameValidator,
46    header_bytes: usize,
47}
48
49/// BBFRAME receiver.
50///
51/// This receives complete BBFRAMEs from an object that implements the
52/// [`RecvBBFrame`] trait and performs validation to return valid BBFRAMES.
53#[derive(Debug)]
54pub struct BBFrameRecv<R> {
55    recv_bbframe: R,
56    buffer: Box<[u8; BBFRAME_MAX_LEN]>,
57    validator: BBFrameValidator,
58    header_bytes: usize,
59}
60
61/// BBFRAME stream receiver.
62///
63/// This receives BBFRAMEs from a stream object that implements the
64/// [`RecvStream`] trait and performs validation to return valid BBFRAMES.
65#[derive(Debug)]
66pub struct BBFrameStream<R> {
67    recv_stream: R,
68    buffer: Box<[u8; BBFRAME_MAX_LEN]>,
69    validator: BBFrameValidator,
70    header_bytes: usize,
71}
72
73/// Receiver of BBFrames.
74///
75/// This trait generalizes reception of BBFRAMEs and provides a method to
76/// receive validated BBFRAMEs one by one.
77pub trait BBFrameReceiver {
78    /// Get and return a new validated BBFRAME.
79    fn get_bbframe(&mut self) -> Result<BBFrame>;
80}
81
82/// BBFRAME validator.
83///
84/// This object checks if a BBFRAME is a valid BBFRAME containing GSE data in
85/// the appropriate ISI (Input Stream Indicator).
86#[derive(Debug, Default)]
87pub struct BBFrameValidator {
88    isi: Option<u8>,
89    log_bbheader_crc_errors: bool,
90}
91
92impl BBFrameValidator {
93    /// Creates a BBFRAME validator.
94    pub fn new() -> BBFrameValidator {
95        BBFrameValidator::default()
96    }
97
98    /// Set the ISI (Input Stream Indicator) to process.
99    ///
100    /// When this function is called with `Some(n)`, the validator will expect
101    /// an MIS (Multiple Input Stream) signal and only declare as valid BBFRAMEs
102    /// from the the indicated ISI. When this function is called with `None`,
103    /// the validator will expect a SIS (Single Input Stream) signal.
104    ///
105    /// The default after the construction of the validator is SIS mode.
106    pub fn set_isi(&mut self, isi: Option<u8>) {
107        self.isi = isi;
108    }
109
110    /// Set the logging of BBHEADER CRC errors.
111    ///
112    /// BBHEADER CRC errors are not logged by default, because [`BBFrameDefrag`]
113    /// relies on checking the CRC of packets at which pontentially there is no
114    /// BBHEADER in order to achieve synchronization, and this would cause
115    /// spurious CRC error logs. For other BBFRAME receivers, logging of
116    /// BBHEADER CRC errors can be enabled by setting `log_bbheader_crc_errors`
117    /// to `true` in this call.
118    pub fn set_log_bbheader_crc_errors(&mut self, log_bbheader_crc_errors: bool) {
119        self.log_bbheader_crc_errors = log_bbheader_crc_errors;
120    }
121
122    /// Checks if a BBHEADER is valid.
123    ///
124    /// The following conditions are tested:
125    ///
126    /// - CRC of the BBHEADER.
127    ///
128    /// - TS/GS type matching generic continuous or GSE-HEM.
129    ///
130    /// - SIS/MIS and ISI matching what expected according to the last
131    ///   [`BBFrameValidator::set_isi`] call.
132    ///
133    /// - If the BBFRAME is not GSE-HEM, then ISSYI disabled.
134    ///
135    /// - The DFL is a multiple of 8 bits and not larger than the maximum
136    ///   BBFRAME length.
137    ///
138    /// If the BBFRAME is not valid, this function logs the reason using
139    /// the [`log`] crate.
140    pub fn bbheader_is_valid(&self, bbheader: BBHeader) -> bool {
141        if !bbheader.crc_is_valid() {
142            if self.log_bbheader_crc_errors {
143                log::warn!("BBHEADER CRC error");
144            }
145            return false;
146        }
147        log::trace!("received {} with valid CRC", bbheader);
148        if !matches!(bbheader.tsgs(), TsGs::GenericContinuous | TsGs::GseHem) {
149            log::error!(
150                "unsupported TS/GS type '{}' (only 'Generic continous' and 'GSE-HEM' are supported)",
151                bbheader.tsgs()
152            );
153            return false;
154        }
155        match self.isi {
156            None => {
157                if !matches!(bbheader.sismis(), SisMis::Sis) {
158                    log::error!("MIS (multiple input stream) BBFRAME unsupported in SIS mode");
159                    return false;
160                }
161            }
162            Some(isi) => {
163                if !matches!(bbheader.sismis(), SisMis::Mis) {
164                    log::error!("SIS (single input stream) BBFRAME unsupported in MIS mode");
165                    return false;
166                }
167                if bbheader.isi() != isi {
168                    log::debug!("dropping BBFRAME with ISI = {}", bbheader.isi());
169                    return false;
170                }
171            }
172        }
173        if !matches!(bbheader.tsgs(), TsGs::GseHem) && bbheader.issyi() {
174            log::error!("ISSYI only supported in GSE-HEM mode");
175            return false;
176        }
177        if bbheader.dfl() % 8 != 0 {
178            log::error!("unsupported data field length not a multiple of 8 bits");
179            return false;
180        }
181        if usize::from(bbheader.dfl() / 8) > BBFRAME_MAX_LEN - BBHeader::LEN - HEADER_MAX_LEN {
182            log::error!("DFL value {} too large", bbheader.dfl());
183            return false;
184        }
185        true
186    }
187}
188
189/// BBFRAME (Base-Band Frame).
190///
191/// This is an alias for [`Bytes`]. BBFRAMES are represented by the `Bytes` that
192/// contains their data.
193pub type BBFrame = Bytes;
194
195/// Receiver of BBFRAME fragments.
196///
197/// This trait is modeled around [`UdpSocket::recv_from`], since the main way to
198/// receive BBFRAME fragments is as datagrams received from a UDP socket.
199///
200/// The BBFRAME fragments are required to be such that the start of each BBFRAME
201/// is always at the start of a fragment. The BBFRAMEs may or may not have
202/// padding at the end. The `recv_fragment` function is allowed to skip
203/// supplying some fragments, which happens for instance if UDP packets are lost
204/// (when this trait is implemented by a UDP socket).
205pub trait RecvFragment {
206    /// Receives a single fragment into the buffer. On success, returns the
207    /// number of bytes read.
208    ///
209    /// The function must be called with a valid byte slice `buf` of sufficient
210    /// size to hold the fragment. If a fragment is too long to fit in the
211    /// supplied buffer, excess bytes may be discarded.
212    fn recv_fragment(&mut self, buf: &mut [u8]) -> Result<usize>;
213}
214
215impl RecvFragment for UdpSocket {
216    fn recv_fragment(&mut self, buf: &mut [u8]) -> Result<usize> {
217        self.recv_from(buf).map(|x| x.0)
218    }
219}
220
221impl<F> RecvFragment for F
222where
223    F: FnMut(&mut [u8]) -> Result<usize>,
224{
225    fn recv_fragment(&mut self, buf: &mut [u8]) -> Result<usize> {
226        self(buf)
227    }
228}
229
230/// Receiver of complete BBFRAMEs.
231///
232/// This trait is modeled around [`UdpSocket::recv_from`], since the main way to
233/// receive complete BBFRAMEs is as jumbo datagrams received from a UDP socket.
234///
235/// The BBFRAMEs may or may not have padding at the end. The `recv_fragment`
236/// function is allowed to skip suppyling some complete BBFRAMEs, which happens
237/// for instance if UDP packets are lost (when this trait is implemented by a
238/// UDP socket).
239pub trait RecvBBFrame {
240    /// Receives a single fragment into the buffer. On success, returns the
241    /// number of bytes read.
242    ///
243    /// The function is called with a byte array `buf` of sufficient
244    /// size to hold the message bytes.
245    fn recv_bbframe(&mut self, buf: &mut [u8; BBFRAME_MAX_LEN]) -> Result<usize>;
246}
247
248impl RecvBBFrame for UdpSocket {
249    fn recv_bbframe(&mut self, buf: &mut [u8; BBFRAME_MAX_LEN]) -> Result<usize> {
250        self.recv_from(&mut buf[..]).map(|x| x.0)
251    }
252}
253
254impl<F> RecvBBFrame for F
255where
256    F: FnMut(&mut [u8; BBFRAME_MAX_LEN]) -> Result<usize>,
257{
258    fn recv_bbframe(&mut self, buf: &mut [u8; BBFRAME_MAX_LEN]) -> Result<usize> {
259        self(buf)
260    }
261}
262
263/// Receiver of a stream of BBFRAMEs.
264///
265/// This trait is modeled around [`TcpStream::read_exact`], since it is the main
266/// way to receive a stream of BBFRAMEs.
267///
268/// The BBFRAMEs cannot have padding at the end (the length of the BBFRAME must
269/// be equal to the DFL plus the BBHEADER). They need to be present back-to-back
270/// in the stream.  The stream is allowed to skip supplying some complete
271/// BBFRAMEs (this may happened with a TCP stream if BBFRAMEs overflow a buffer
272/// before being written to the TCP socket).
273pub trait RecvStream {
274    /// Reads the exact number of bytes required to fill `buf`.
275    fn recv_stream(&mut self, buf: &mut [u8]) -> Result<()>;
276}
277
278impl<R: Read> RecvStream for R {
279    fn recv_stream(&mut self, buf: &mut [u8]) -> Result<()> {
280        self.read_exact(buf)
281    }
282}
283
284trait BBFrameRecvCommon {
285    fn buffer(&self) -> &[u8; BBFRAME_MAX_LEN];
286
287    fn bbheader(&self) -> BBHeader {
288        BBHeader::new(self.buffer()[..BBHeader::LEN].try_into().unwrap())
289    }
290}
291
292macro_rules! impl_recv_common {
293    ($($id:ident),*) => {
294        $(
295            impl<R> BBFrameRecvCommon for $id<R> {
296                fn buffer(&self) -> &[u8; BBFRAME_MAX_LEN] {
297                    &self.buffer
298                }
299            }
300        )*
301    }
302}
303
304impl_recv_common!(BBFrameDefrag, BBFrameRecv, BBFrameStream);
305
306macro_rules! impl_set_isi {
307    ($t:ident) => {
308        /// Set the ISI (Input Stream Indicator) to process.
309        ///
310        /// When this function is called with `Some(n)`, the BBFRAME receiver
311        /// will expect an MIS (Multiple Input Stream) signal and will only
312        /// process the indicated ISI. When this function is called with `None`,
313        /// the defragmenter will expect a SIS (Single Input Stream) signal.
314        ///
315        /// The default after the construction of the receiver is SIS mode.
316        pub fn set_isi(&mut self, isi: Option<u8>) {
317            self.validator.set_isi(isi);
318        }
319    };
320}
321
322impl<R> BBFrameDefrag<R> {
323    /// Creates a new BBFRAME defragmenter.
324    ///
325    /// The `recv_fragment` object is intended to be an implementor of
326    /// [`RecvFragment`] that will be used to receive BBFRAME fragments.
327    pub fn new(recv_fragment: R) -> BBFrameDefrag<R> {
328        BBFrameDefrag {
329            recv_fragment,
330            buffer: Box::new([0; BBFRAME_MAX_LEN]),
331            occupied_bytes: 0,
332            validator: BBFrameValidator::new(),
333            header_bytes: 0,
334        }
335    }
336
337    impl_set_isi!(BBFrameDefrag);
338
339    /// Sets the number of bytes used in the header in each fragment.
340    ///
341    /// The header is removed before reading the rest of the fragment, which
342    /// should correpond to a BBFRAME fragment. By default, a header length of
343    /// zero bytes is assumed.
344    ///
345    /// The function returns an error if `header_bytes` is larger than
346    /// [`HEADER_MAX_LEN`].
347    pub fn set_header_bytes(&mut self, header_bytes: usize) -> Result<()> {
348        if header_bytes > HEADER_MAX_LEN {
349            log::error!("header bytes larger than maximum header size");
350            return Err(std::io::Error::new(
351                std::io::ErrorKind::InvalidData,
352                "header bytes larger than maximum header size",
353            ));
354        }
355        self.header_bytes = header_bytes;
356        Ok(())
357    }
358}
359
360impl<R: RecvFragment> BBFrameReceiver for BBFrameDefrag<R> {
361    /// Get and return a new validated BBFRAME.
362    ///
363    /// This function calls the [`RecvFragment::recv_fragment`] method of the
364    /// `RecvFragment` object owned by the defragmenter until a complete BBFRAME
365    /// has been reassembled. On success, the BBFRAME is returned.
366    fn get_bbframe(&mut self) -> Result<BBFrame> {
367        loop {
368            self.occupied_bytes = 0;
369            // Get UDP packets until we have a full BBHEADER (typically a single
370            // packet will suffice).
371            while self.occupied_bytes < BBHeader::LEN {
372                self.recv()?;
373            }
374            if !self.validator.bbheader_is_valid(self.bbheader()) {
375                continue;
376            }
377            let bbframe_len = usize::from(self.bbheader().dfl() / 8) + BBHeader::LEN;
378            while self.occupied_bytes < bbframe_len {
379                self.recv()?;
380            }
381            let bbframe = Bytes::copy_from_slice(&self.buffer[..bbframe_len]);
382            log::trace!("completed BBFRAME {}", faster_hex::hex_string(&bbframe));
383            return Ok(bbframe);
384        }
385    }
386}
387
388impl<R: RecvFragment> BBFrameDefrag<R> {
389    fn recv(&mut self) -> Result<()> {
390        let n = self
391            .recv_fragment
392            .recv_fragment(&mut self.buffer[self.occupied_bytes..])?;
393        if self.header_bytes != 0 {
394            if self.header_bytes > n {
395                log::error!("received a fragment smaller than the header size");
396                return Err(std::io::Error::new(
397                    std::io::ErrorKind::InvalidData,
398                    "BBFRAME is too short",
399                ));
400            }
401            // overwrite the header with the rest of the data
402            self.buffer.copy_within(
403                self.occupied_bytes + self.header_bytes..self.occupied_bytes + n,
404                self.occupied_bytes,
405            );
406        }
407        self.occupied_bytes += n - self.header_bytes;
408        Ok(())
409    }
410}
411
412impl<R> BBFrameRecv<R> {
413    /// Creates a new BBFRAME receiver.
414    ///
415    /// The `recv_bbframe` object is intended to be an implementor of
416    /// [`RecvBBFrame`] that will be used to receive complete BBFRAMEs.
417    pub fn new(recv_bbframe: R) -> BBFrameRecv<R> {
418        let mut validator = BBFrameValidator::new();
419        validator.set_log_bbheader_crc_errors(true);
420        BBFrameRecv {
421            recv_bbframe,
422            buffer: Box::new([0; BBFRAME_MAX_LEN]),
423            validator,
424            header_bytes: 0,
425        }
426    }
427
428    impl_set_isi!(BBFrameRecv);
429
430    /// Sets the number of bytes used in the header in each BBFRAME.
431    ///
432    /// The header is removed before reading the BBFRAME. By default, a header
433    /// length of zero bytes is assumed.
434    ///
435    /// The function returns an error if `header_bytes` is larger than
436    /// [`HEADER_MAX_LEN`].
437    pub fn set_header_bytes(&mut self, header_bytes: usize) -> Result<()> {
438        if header_bytes > HEADER_MAX_LEN {
439            log::error!("header bytes larger than maximum header size");
440            return Err(std::io::Error::new(
441                std::io::ErrorKind::InvalidData,
442                "header bytes larger than maximum header size",
443            ));
444        }
445        self.header_bytes = header_bytes;
446        Ok(())
447    }
448}
449
450impl<R: RecvBBFrame> BBFrameReceiver for BBFrameRecv<R> {
451    /// Get and return a new validated BBFRAME.
452    ///
453    /// This function calls the [`RecvBBFrame::recv_bbframe`] method of the
454    /// `RecvBBFrame` object owned by the receiver and validates the received
455    /// BBFRAME, returning an error if the BBFRAME is not valid or if there is
456    /// an error in reception.
457    fn get_bbframe(&mut self) -> Result<BBFrame> {
458        let recv_len = self.recv_bbframe.recv_bbframe(&mut self.buffer)?;
459        if self.header_bytes != 0 {
460            if self.header_bytes > recv_len {
461                log::error!("received a fragment smaller than the header size");
462                return Err(std::io::Error::new(
463                    std::io::ErrorKind::InvalidData,
464                    "BBFRAME is too short",
465                ));
466            }
467            // This could be removed if we allowed the functions below to use an
468            // offset in the buffer to access the BBFRAME.
469            self.buffer.copy_within(self.header_bytes..recv_len, 0);
470        }
471        let recv_len = recv_len - self.header_bytes;
472        if recv_len < BBHeader::LEN {
473            log::error!("received BBFRAME is too short (length {recv_len})");
474            return Err(std::io::Error::new(
475                std::io::ErrorKind::InvalidData,
476                "BBFRAME is too short",
477            ));
478        }
479        if !self.validator.bbheader_is_valid(self.bbheader()) {
480            return Err(std::io::Error::new(
481                std::io::ErrorKind::InvalidData,
482                "invalid BBFRAME received",
483            ));
484        }
485        let bbframe_len = usize::from(self.bbheader().dfl() / 8) + BBHeader::LEN;
486        if recv_len < bbframe_len {
487            log::error!(
488                "received BBFRAME has length {recv_len}, \
489                         but according to DFL it should have length {bbframe_len}"
490            );
491            return Err(std::io::Error::new(
492                std::io::ErrorKind::InvalidData,
493                "BBFRAME is too short",
494            ));
495        }
496        let bbframe = Bytes::copy_from_slice(&self.buffer[..bbframe_len]);
497        log::trace!("completed BBFRAME {}", faster_hex::hex_string(&bbframe));
498        Ok(bbframe)
499    }
500}
501
502impl<R> BBFrameStream<R> {
503    /// Creates a new BBFRAME stream receiver.
504    ///
505    /// The `recv_stream` object is intended to be an implementor of
506    /// [`RecvStream`] that will be used to receive BBFRAMEs from a stream.
507    pub fn new(recv_stream: R) -> BBFrameStream<R> {
508        let mut validator = BBFrameValidator::new();
509        validator.set_log_bbheader_crc_errors(true);
510        BBFrameStream {
511            recv_stream,
512            buffer: Box::new([0; BBFRAME_MAX_LEN]),
513            validator,
514            header_bytes: 0,
515        }
516    }
517
518    impl_set_isi!(BBFrameStream);
519
520    /// Sets the number of bytes used in the header in each BBFRAME.
521    ///
522    /// The function returns an error if `header_bytes` is larger than
523    /// [`HEADER_MAX_LEN`].
524    pub fn set_header_bytes(&mut self, header_bytes: usize) -> Result<()> {
525        if header_bytes > HEADER_MAX_LEN {
526            log::error!("header bytes larger than maximum header size");
527            return Err(std::io::Error::new(
528                std::io::ErrorKind::InvalidData,
529                "header bytes larger than maximum header size",
530            ));
531        }
532        self.header_bytes = header_bytes;
533        Ok(())
534    }
535}
536
537impl<R: RecvStream> BBFrameReceiver for BBFrameStream<R> {
538    /// Get and return a new validated BBFRAME.
539    ///
540    /// This function calls the [`RecvStream::recv_stream] method of the
541    /// `RecvStream` object owned by the receiver and validates the received
542    /// BBFRAME, returning an error if the BBFRAME is not valid or if there is
543    /// an error in reception.
544    fn get_bbframe(&mut self) -> Result<BBFrame> {
545        if self.header_bytes != 0 {
546            // read header (will be discarded)
547            self.recv_stream
548                .recv_stream(&mut self.buffer[..self.header_bytes])?;
549        }
550        // read full BBHEADER
551        self.recv_stream
552            .recv_stream(&mut self.buffer[..BBHeader::LEN])?;
553        if !self.validator.bbheader_is_valid(self.bbheader()) {
554            // BBHeader is invalid, but we try to honor its DFL and read the
555            // data field to recover from the error, unless the DFL is too large
556            let bbframe_len = usize::from(self.bbheader().dfl() / 8) + BBHeader::LEN;
557            if bbframe_len <= BBFRAME_MAX_LEN {
558                self.recv_stream
559                    .recv_stream(&mut self.buffer[BBHeader::LEN..bbframe_len])?;
560            }
561            return Err(std::io::Error::new(
562                std::io::ErrorKind::InvalidData,
563                "invalid BBHEADER received",
564            ));
565        }
566        let bbframe_len = usize::from(self.bbheader().dfl() / 8) + BBHeader::LEN;
567        // read data field
568        self.recv_stream
569            .recv_stream(&mut self.buffer[BBHeader::LEN..bbframe_len])?;
570        let bbframe = Bytes::copy_from_slice(&self.buffer[..bbframe_len]);
571        log::trace!("completed BBFRAME {}", faster_hex::hex_string(&bbframe));
572        Ok(bbframe)
573    }
574}
575
576#[cfg(test)]
577mod test {
578    use super::*;
579    use hex_literal::hex;
580
581    pub const SINGLE_FRAGMENT: [u8; 104] = hex!(
582        "72 00 00 00 02 f0 00 00 00 15 c0 5c 08 00 02 00
583         48 55 4c 4b 45 00 00 54 6f aa 40 00 40 01 72 fc
584         2c 00 00 01 2c 00 00 02 08 00 4e 94 00 3b 00 04
585         19 7d 6b 63 00 00 00 00 5d 79 08 00 00 00 00 00
586         10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
587         20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
588         30 31 32 33 34 35 36 37"
589    );
590
591    static FRAGMENT0: [u8; 510] = hex!(
592        "72 00 00 00 26 b0 00 00 00 66 c4 d4 08 00 02 00
593         48 55 4c 4b 45 00 04 cc a2 89 40 00 40 01 3b a5
594         2c 00 00 01 2c 00 00 02 08 00 3e b0 00 3c 00 01
595         b7 88 6b 63 00 00 00 00 ba 09 0d 00 00 00 00 00
596         10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
597         20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
598         30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
599         40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
600         50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
601         60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
602         70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
603         80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
604         90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f
605         a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af
606         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
607         c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf
608         d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df
609         e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef
610         f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
611         00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
612         10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
613         20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
614         30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
615         40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
616         50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
617         60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
618         70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
619         80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
620         90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f
621         a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af
622         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
623         c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd"
624    );
625
626    static FRAGMENT1: [u8; 510] = hex!(
627        "ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd
628         de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed
629         ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd
630         fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
631         0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d
632         1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d
633         2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d
634         3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d
635         4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d
636         5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d
637         6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d
638         7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d
639         8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d
640         9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad
641         ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd
642         be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd
643         ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd
644         de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed
645         ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd
646         fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
647         0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d
648         1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d
649         2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d
650         3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d
651         4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d
652         5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d
653         6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d
654         7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d
655         8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d
656         9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad
657         ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd
658         be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb"
659    );
660
661    static FRAGMENT2: [u8; 228] = hex!(
662        "cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db
663         dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb
664         ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb
665         fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b
666         0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b
667         1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b
668         2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b
669         3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b
670         4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b
671         5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b
672         6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b
673         7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b
674         8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b
675         9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab
676         ac ad ae af"
677    );
678
679    const SINGLE_FRAGMENT_MIS: [u8; 104] = hex!(
680        "52 2a 00 00 02 f0 00 00 00 dc c0 5c 08 00 02 00
681         48 55 4c 4b 45 00 00 54 6f aa 40 00 40 01 72 fc
682         2c 00 00 01 2c 00 00 02 08 00 4e 94 00 3b 00 04
683         19 7d 6b 63 00 00 00 00 5d 79 08 00 00 00 00 00
684         10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
685         20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
686         30 31 32 33 34 35 36 37"
687    );
688
689    const SINGLE_FRAGMENT_MIS_OTHER_STREAM: [u8; 104] = hex!(
690        "52 2b 00 00 02 f0 00 00 00 9f c0 5c 08 00 02 00
691         48 55 4c 4b 45 00 00 54 6f aa 40 00 40 01 72 fc
692         2c 00 00 01 2c 00 00 02 08 00 4e 94 00 3b 00 04
693         19 7d 6b 63 00 00 00 00 5d 79 08 00 00 00 00 00
694         10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
695         20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
696         30 31 32 33 34 35 36 37"
697    );
698
699    static MULTIPLE_FRAGMENTS: [&[u8]; 3] = [&FRAGMENT0, &FRAGMENT1, &FRAGMENT2];
700
701    #[test]
702    fn single_fragment_defrag() {
703        let times_called = std::cell::Cell::new(0);
704        let mut defrag = BBFrameDefrag::new(|buff: &mut [u8]| {
705            times_called.replace(times_called.get() + 1);
706            buff[..SINGLE_FRAGMENT.len()].copy_from_slice(&SINGLE_FRAGMENT);
707            Ok(SINGLE_FRAGMENT.len())
708        });
709        assert_eq!(
710            defrag.get_bbframe().unwrap(),
711            Bytes::from_static(&SINGLE_FRAGMENT)
712        );
713        assert_eq!(times_called.get(), 1);
714    }
715
716    #[test]
717    fn single_fragment_defrag_mis() {
718        let isi = 0x2a;
719        let times_called = std::cell::Cell::new(0);
720        let mut defrag = BBFrameDefrag::new(|buff: &mut [u8]| {
721            let fragment = if times_called.get() % 2 == 0 {
722                &SINGLE_FRAGMENT_MIS_OTHER_STREAM
723            } else {
724                &SINGLE_FRAGMENT_MIS
725            };
726            times_called.replace(times_called.get() + 1);
727            buff[..fragment.len()].copy_from_slice(fragment);
728            Ok(fragment.len())
729        });
730        defrag.set_isi(Some(isi));
731        assert_eq!(
732            defrag.get_bbframe().unwrap(),
733            Bytes::from_static(&SINGLE_FRAGMENT_MIS)
734        );
735        assert_eq!(times_called.get(), 2);
736    }
737
738    #[test]
739    fn multiple_fragments_defrag() {
740        let times_called = std::cell::Cell::new(0);
741        let mut defrag = BBFrameDefrag::new(|buff: &mut [u8]| {
742            let fragment = MULTIPLE_FRAGMENTS[times_called.get()];
743            times_called.replace(times_called.get() + 1);
744            buff[..fragment.len()].copy_from_slice(fragment);
745            Ok(fragment.len())
746        });
747        let mut expected = bytes::BytesMut::new();
748        for fragment in &MULTIPLE_FRAGMENTS {
749            expected.extend_from_slice(fragment);
750        }
751        assert_eq!(defrag.get_bbframe().unwrap(), expected);
752        assert_eq!(times_called.get(), 3);
753    }
754
755    #[test]
756    fn recv_one_bbframe() {
757        let times_called = std::cell::Cell::new(0);
758        let mut defrag = BBFrameRecv::new(|buff: &mut [u8; BBFRAME_MAX_LEN]| {
759            times_called.replace(times_called.get() + 1);
760            buff[..SINGLE_FRAGMENT.len()].copy_from_slice(&SINGLE_FRAGMENT);
761            Ok(SINGLE_FRAGMENT.len())
762        });
763        assert_eq!(
764            defrag.get_bbframe().unwrap(),
765            Bytes::from_static(&SINGLE_FRAGMENT)
766        );
767        assert_eq!(times_called.get(), 1);
768    }
769
770    #[test]
771    fn recv_one_bbframe_with_header() {
772        let header_bytes = 4;
773        let times_called = std::cell::Cell::new(0);
774        let mut defrag = BBFrameRecv::new(|buff: &mut [u8; BBFRAME_MAX_LEN]| {
775            times_called.replace(times_called.get() + 1);
776            buff[..header_bytes].fill(0);
777            let total_len = header_bytes + SINGLE_FRAGMENT.len();
778            buff[header_bytes..total_len].copy_from_slice(&SINGLE_FRAGMENT);
779            Ok(total_len)
780        });
781        defrag.set_header_bytes(header_bytes).unwrap();
782        assert_eq!(
783            defrag.get_bbframe().unwrap(),
784            Bytes::from_static(&SINGLE_FRAGMENT)
785        );
786        assert_eq!(times_called.get(), 1);
787    }
788
789    #[test]
790    fn stream_one_bbframe() {
791        let stream = &SINGLE_FRAGMENT[..];
792        let mut defrag = BBFrameStream::new(stream);
793        assert_eq!(
794            defrag.get_bbframe().unwrap(),
795            Bytes::from_static(&SINGLE_FRAGMENT)
796        );
797    }
798
799    #[test]
800    fn validator() {
801        let valid_header = hex!("72 00 00 00 02 f0 00 00 00 15");
802        let mut validator = BBFrameValidator::new();
803        assert!(validator.bbheader_is_valid(BBHeader::new(&valid_header)));
804
805        let valid_hem_header = hex!("b2 00 00 00 02 f0 00 00 00 87");
806        assert!(validator.bbheader_is_valid(BBHeader::new(&valid_hem_header)));
807
808        let valid_hem_issy_header = hex!("ba 00 12 34 02 f0 56 02 11 7c");
809        assert!(validator.bbheader_is_valid(BBHeader::new(&valid_hem_issy_header)));
810
811        let wrong_crc = hex!("72 00 00 00 02 f0 00 00 00 14");
812        assert!(!BBHeader::new(&wrong_crc).crc_is_valid());
813        assert!(!validator.bbheader_is_valid(BBHeader::new(&wrong_crc)));
814
815        fn test_invalid(validator: &BBFrameValidator, bbheader: &[u8; 10]) {
816            let bbheader = BBHeader::new(bbheader);
817            assert!(bbheader.crc_is_valid());
818            assert!(!validator.bbheader_is_valid(bbheader));
819        }
820
821        let ts_header = hex!("f2 00 00 00 02 f0 00 00 00 44");
822        test_invalid(&validator, &ts_header);
823        let packetized_header = hex!("32 00 00 00 02 f0 00 00 00 d7");
824        test_invalid(&validator, &packetized_header);
825        let mis_header = hex!("52 2a 00 00 02 f0 00 00 00 dc");
826        test_invalid(&validator, &mis_header);
827        let issyi_header = hex!("7a 00 00 00 02 f0 00 00 00 78");
828        test_invalid(&validator, &issyi_header);
829        let dfl_not_divisible = hex!("72 00 00 00 02 f1 00 00 00 50");
830        test_invalid(&validator, &dfl_not_divisible);
831        let dfl_too_large = hex!("72 00 00 00 e3 08 00 00 00 36");
832        test_invalid(&validator, &dfl_too_large);
833
834        let isi = 0x2a;
835        validator.set_isi(Some(isi));
836        assert!(!validator.bbheader_is_valid(BBHeader::new(&valid_header)));
837        assert!(validator.bbheader_is_valid(BBHeader::new(&mis_header)));
838        let other_isi_header = hex!("52 2b 00 00 02 f0 00 00 00 9f");
839        test_invalid(&validator, &other_isi_header);
840
841        validator.set_isi(None);
842        assert!(validator.bbheader_is_valid(BBHeader::new(&valid_header)));
843        assert!(!validator.bbheader_is_valid(BBHeader::new(&mis_header)));
844    }
845}
846
847#[cfg(test)]
848mod proptests {
849    use super::test::SINGLE_FRAGMENT;
850    use super::*;
851    use proptest::prelude::*;
852
853    fn garbage() -> impl Strategy<Value = Vec<Vec<u8>>> {
854        proptest::collection::vec(proptest::collection::vec(any::<u8>(), 1..10000), 0..100)
855    }
856
857    proptest! {
858        /// Supplies garbage fragments from a Vec until all the garbage
859        /// fragments are exhausted. Then it supplies a valid single
860        /// fragment. The defragmenter must obtain the good frame without
861        /// failing.
862        #[test]
863        fn bbframe_defrag_garbage(garbage_data in garbage()) {
864            let times_called = std::cell::Cell::new(0);
865            let single_fragment = SINGLE_FRAGMENT.to_vec();
866            let mut defrag = BBFrameDefrag::new(|buff: &mut [u8]| {
867                let j = times_called.get();
868                let fragment = if j < garbage_data.len() {
869                    &garbage_data[j]
870                } else {
871                    // Used to force termination of get_bbframe succesfully
872                    // (sometimes there is an earlier exit if the garbage is a
873                    // valid frame just by chance).
874                    &single_fragment
875                };
876                times_called.replace(times_called.get() + 1);
877                let copy_len = fragment.len().min(buff.len());
878                buff[..copy_len].copy_from_slice(&fragment[..copy_len]);
879                Ok(fragment.len())
880            });
881            let bbframe = defrag.get_bbframe().unwrap();
882            // Sometimes
883            //   times_called.get() == garbage_data.len() + 2
884            // because the SINGLE_FRAGMENT needs to be returned
885            // twice in order to flush a partial BBHEADER left
886            // by the garbage.
887            assert!(times_called.get() <= garbage_data.len() + 2);
888            if times_called.get() > garbage_data.len() {
889                assert_eq!(bbframe, Bytes::from_static(&SINGLE_FRAGMENT));
890            }
891        }
892    }
893
894    proptest! {
895        /// Supplies garbage frames from a Vec until all the garbage frames are
896        /// exhausted, then a valid fragment. The receiver get_bbframe() is
897        /// allowed to fail, but it is called repeatedly until all the garbage
898        /// has been consumed.
899        #[test]
900        fn bbframe_recv_garbage(garbage_data in garbage()) {
901            let times_called = std::cell::Cell::new(0);
902            let single_fragment = SINGLE_FRAGMENT.to_vec();
903            let mut recv = BBFrameRecv::new(|buff: &mut [u8; BBFRAME_MAX_LEN]| {
904                let j = times_called.get();
905                let fragment = if j < garbage_data.len() {
906                    &garbage_data[j]
907                } else {
908                    // Used to force termination of get_bbframe succesfully
909                    // (sometimes there is an earlier exit if the garbage is a
910                    // valid frame just by chance).
911                    &single_fragment
912                };
913                times_called.replace(times_called.get() + 1);
914                let copy_len = fragment.len().min(buff.len());
915                buff[..copy_len].copy_from_slice(&fragment[..copy_len]);
916                Ok(fragment.len())
917            });
918            while times_called.get() <= garbage_data.len() {
919                if let Ok(bbframe) = recv.get_bbframe() {
920                    assert!(times_called.get() <= garbage_data.len() + 1);
921                    if times_called.get() > garbage_data.len() {
922                        assert_eq!(bbframe, Bytes::from_static(&SINGLE_FRAGMENT));
923                    }
924                }
925            }
926        }
927    }
928
929    #[derive(Debug)]
930    struct Garbage {
931        times_called: std::rc::Rc<std::cell::Cell<usize>>,
932        garbage_data: Vec<Vec<u8>>,
933    }
934
935    impl RecvStream for Garbage {
936        fn recv_stream(&mut self, buff: &mut [u8]) -> Result<()> {
937            let j = self.times_called.get();
938            self.times_called.replace(j + 1);
939            let fragment = if j < self.garbage_data.len() {
940                &self.garbage_data[j]
941            } else {
942                return Err(std::io::Error::new(
943                    std::io::ErrorKind::Other,
944                    "no more garbage",
945                ));
946            };
947            let copy_len = fragment.len().min(buff.len());
948            buff[..copy_len].copy_from_slice(&fragment[..copy_len]);
949            Ok(())
950        }
951    }
952
953    proptest! {
954        #[test]
955        fn bbframe_stream_garbage(garbage_data in garbage()) {
956            let times_called = std::rc::Rc::new(std::cell::Cell::new(0));
957            let len_garbage_data = garbage_data.len();
958            let mut stream = BBFrameStream::new(Garbage { times_called: times_called.clone(),
959                                                          garbage_data });
960            while times_called.get() < len_garbage_data {
961                let _ = stream.get_bbframe();
962            }
963        }
964    }
965}