netsvc_proto/
debuglog.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Debuglog messaging types.
//!
//! The debuglog protocol is used to multicast log messages.

use crate::ValidStr;
use const_unwrap::const_unwrap_option;
use packet::{
    BufferView, BufferViewMut, FragmentedBytesMut, InnerPacketBuilder, PacketBuilder,
    PacketConstraints, ParsablePacket, ParseMetadata, SerializeTarget,
};
use std::num::NonZeroU16;
use zerocopy::byteorder::little_endian::U32;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};

pub const MULTICAST_PORT: NonZeroU16 = const_unwrap_option(NonZeroU16::new(33337));
pub const ACK_PORT: NonZeroU16 = const_unwrap_option(NonZeroU16::new(33338));

const MAGIC: u32 = 0xAEAE1123;
const MAX_LOG_DATA: usize = 1216;
const MAX_NODENAME_LENGTH: usize = 64;

pub const ACK_SIZE: usize = std::mem::size_of::<PacketHead>();

#[repr(C)]
#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
pub struct PacketHead {
    magic: U32,
    seqno: U32,
}

pub struct DebugLogPacket<B> {
    head: Ref<B, PacketHead>,
    nodename: ValidStr<B>,
    data: ValidStr<B>,
}

impl<B: SplitByteSlice> DebugLogPacket<B> {
    pub fn seqno(&self) -> u32 {
        self.head.seqno.get()
    }

    pub fn nodename(&self) -> &str {
        self.nodename.as_str()
    }

    pub fn data(&self) -> &str {
        self.data.as_str()
    }
}

#[derive(Debug)]
pub enum ParseError {
    BadMagic,
    Malformed,
    Encoding(std::str::Utf8Error),
}

impl<B> ParsablePacket<B, ()> for DebugLogPacket<B>
where
    B: SplitByteSlice,
{
    type Error = ParseError;

    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
        let head = buffer.take_obj_front::<PacketHead>().ok_or(ParseError::Malformed)?;
        if head.magic.get() != MAGIC {
            return Err(ParseError::BadMagic);
        }
        let nodename = buffer.take_front(MAX_NODENAME_LENGTH).ok_or(ParseError::Malformed)?;
        let nodename = ValidStr::new(nodename).map_err(ParseError::Encoding)?;
        let (nodename, _rest) = nodename.truncate_null();
        let data = ValidStr::new(buffer.into_rest()).map_err(ParseError::Encoding)?;

        Ok(Self { head, nodename, data })
    }

    fn parse_metadata(&self) -> ParseMetadata {
        // we only need ParseMetadata to undo parsing, not necessary to implement it for now
        unimplemented!()
    }
}

#[derive(Debug)]
pub struct AckPacketBuilder {
    seqno: u32,
}

impl AckPacketBuilder {
    pub fn new(seqno: u32) -> Self {
        Self { seqno }
    }
}

impl InnerPacketBuilder for AckPacketBuilder {
    fn bytes_len(&self) -> usize {
        std::mem::size_of::<PacketHead>()
    }

    fn serialize(&self, mut buffer: &mut [u8]) {
        let mut bv = crate::as_buffer_view_mut(&mut buffer);
        let mut head = bv.take_obj_front::<PacketHead>().unwrap();
        head.magic.set(MAGIC);
        head.seqno.set(self.seqno);
    }
}

#[derive(Debug)]
pub struct LogPacketBuilder<'a> {
    seqno: u32,
    nodename: &'a str,
}

impl<'a> LogPacketBuilder<'a> {
    pub fn new(seqno: u32, nodename: &'a str) -> Option<Self> {
        if nodename.len() <= MAX_NODENAME_LENGTH {
            Some(Self { seqno, nodename })
        } else {
            None
        }
    }
}

impl<'a> PacketBuilder for LogPacketBuilder<'a> {
    fn constraints(&self) -> PacketConstraints {
        PacketConstraints::new(
            /* header_len */ std::mem::size_of::<PacketHead>() + MAX_NODENAME_LENGTH,
            /* footer_len */ 0,
            /* min_body_len */ 0,
            /* max_body_len */ MAX_LOG_DATA,
        )
    }

    fn serialize(&self, target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {
        let mut bv = crate::as_buffer_view_mut(&mut target.header);
        let mut head = bv.take_obj_front::<PacketHead>().unwrap();
        head.magic.set(MAGIC);
        head.seqno.set(self.seqno);
        let nodename_bytes = self.nodename.as_bytes();
        let nodename = bv.take_front_zero(MAX_NODENAME_LENGTH).unwrap();
        let (nodename, _rest) = nodename.split_at_mut(nodename_bytes.len());
        nodename.copy_from_slice(nodename_bytes);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use packet::{ParseBuffer as _, Serializer as _};

    /// Helper to convince the compiler we're holding buffer views.
    fn as_buffer_view<'a, B: packet::BufferView<&'a [u8]>>(
        v: B,
    ) -> impl packet::BufferView<&'a [u8]> {
        v
    }

    #[test]
    fn test_log_packet() {
        const LOG_DATA: &'static str = "some log data";
        const NODENAME: &'static str = "my node";
        let mut log = LOG_DATA
            .as_bytes()
            .into_serializer()
            .encapsulate(LogPacketBuilder::new(3, NODENAME).unwrap())
            .serialize_vec_outer()
            .unwrap_or_else(|_| panic!("Failed to serialize"));
        let packet = log.parse::<DebugLogPacket<_>>().expect("Failed to parse");
        assert_eq!(packet.seqno(), 3);
        assert_eq!(packet.nodename(), NODENAME);
        assert_eq!(packet.data(), LOG_DATA);
    }

    #[test]
    fn test_ack_packet() {
        const SEQNO: u32 = 4;
        let ack = AckPacketBuilder::new(SEQNO)
            .into_serializer()
            .serialize_vec_outer()
            .unwrap_or_else(|_| panic!("Failed to serialize"));
        let mut bv = ack.as_ref();
        let head = as_buffer_view(&mut bv)
            .take_obj_front::<PacketHead>()
            .expect("failed to get serialized head");
        assert_eq!(head.magic.get(), MAGIC);
        assert_eq!(head.seqno.get(), SEQNO);
    }
}