portus/serialize/
measure.rs

1//! When the datapath program specifies, the datapath sends a Report message containing
2//! measurements to CCP. Use the `Scope` returned from compiling the program to query the values.
3
4use super::{AsRawMsg, HDR_LENGTH, RawMsg, u32_to_u8s, u64_from_u8s, u64_to_u8s};
5use crate::{Error, Result};
6use std::io::prelude::*;
7
8pub(crate) const MEASURE: u8 = 1;
9
10#[derive(Clone, Debug, PartialEq)]
11pub struct Msg {
12    pub sid: u32,
13    pub program_uid: u32,
14    // This is actually a u32 in libccp for struct alignment purposes. It *should* be a u8
15    // (as it is here), to help enforce the maximum number of fields, but it's much easier
16    // to keep everything 4-byte-aligned for de-serialization.
17    pub num_fields: u8,
18    pub fields: Vec<u64>,
19}
20
21fn deserialize_fields(buf: &[u8]) -> Result<Vec<u64>> {
22    buf.chunks(8)
23        .map(|sl| {
24            if sl.len() < 8 {
25                Err(Error(format!("not long enough: {:?}", sl)))
26            } else {
27                Ok(u64_from_u8s(sl))
28            }
29        })
30        .collect()
31}
32
33impl AsRawMsg for Msg {
34    fn get_hdr(&self) -> (u8, u32, u32) {
35        (
36            MEASURE,
37            HDR_LENGTH + 8 + u32::from(self.num_fields) * 8,
38            self.sid,
39        )
40    }
41
42    fn get_u32s<W: Write>(&self, w: &mut W) -> Result<()> {
43        let mut buf = [0u8; 4];
44        u32_to_u8s(&mut buf, self.program_uid);
45        w.write_all(&buf[..])?;
46        u32_to_u8s(&mut buf, u32::from(self.num_fields));
47        w.write_all(&buf[..])?;
48        Ok(())
49    }
50
51    fn get_bytes<W: Write>(&self, w: &mut W) -> Result<()> {
52        let mut buf = [0u8; 8];
53        for f in &self.fields {
54            u64_to_u8s(&mut buf, *f);
55            w.write_all(&buf[..])?;
56        }
57
58        Ok(())
59    }
60
61    fn from_raw_msg(msg: RawMsg) -> Result<Self> {
62        let u32s = unsafe { msg.get_u32s() }?;
63        let b = msg.get_bytes()?;
64
65        Ok(Msg {
66            sid: msg.sid,
67            program_uid: u32s[0],
68            num_fields: u32s[1] as u8,
69            fields: deserialize_fields(b)?,
70        })
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    macro_rules! check_measure_msg {
77        ($id: ident, $sid:expr_2021, $program_uid:expr_2021, $fields:expr_2021) => {
78            check_msg!(
79                $id,
80                super::Msg,
81                super::Msg {
82                    sid: $sid,
83                    program_uid: $program_uid,
84                    num_fields: $fields.len() as u8,
85                    fields: $fields,
86                },
87                crate::serialize::Msg::Ms(mes),
88                mes
89            );
90        };
91    }
92
93    check_measure_msg!(
94        test_measure_1,
95        15,
96        72,
97        vec![424242, 65535, 65530, 200000, 150000]
98    );
99    check_measure_msg!(
100        test_measure_2,
101        256,
102        19,
103        vec![42424242, 65536, 65531, 100000, 50000]
104    );
105    check_measure_msg!(
106        test_measure_3,
107        32,
108        3,
109        vec![
110            42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242,
111            42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242,
112            42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242,
113            42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242, 42424242
114        ]
115    );
116}