Skip to main content

netsvc_proto/
debuglog.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Debuglog messaging types.
6//!
7//! The debuglog protocol is used to multicast log messages.
8
9use crate::ValidStr;
10use packet::{
11    BufferView, BufferViewMut, FragmentedBytesMut, InnerPacketBuilder, NestablePacketBuilder,
12    PacketBuilder, PacketConstraints, ParsablePacket, ParseMetadata, SerializationContext,
13    SerializeTarget,
14};
15use std::num::NonZeroU16;
16use zerocopy::byteorder::little_endian::U32;
17use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
18
19pub const MULTICAST_PORT: NonZeroU16 = NonZeroU16::new(33337).unwrap();
20pub const ACK_PORT: NonZeroU16 = NonZeroU16::new(33338).unwrap();
21
22const MAGIC: u32 = 0xAEAE1123;
23const MAX_LOG_DATA: usize = 1216;
24const MAX_NODENAME_LENGTH: usize = 64;
25
26pub const ACK_SIZE: usize = std::mem::size_of::<PacketHead>();
27
28#[repr(C)]
29#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
30pub struct PacketHead {
31    magic: U32,
32    seqno: U32,
33}
34
35pub struct DebugLogPacket<B> {
36    head: Ref<B, PacketHead>,
37    nodename: ValidStr<B>,
38    data: ValidStr<B>,
39}
40
41impl<B: SplitByteSlice> DebugLogPacket<B> {
42    pub fn seqno(&self) -> u32 {
43        self.head.seqno.get()
44    }
45
46    pub fn nodename(&self) -> &str {
47        self.nodename.as_str()
48    }
49
50    pub fn data(&self) -> &str {
51        self.data.as_str()
52    }
53}
54
55#[derive(Debug)]
56pub enum ParseError {
57    BadMagic,
58    Malformed,
59    Encoding(std::str::Utf8Error),
60}
61
62impl<B> ParsablePacket<B, ()> for DebugLogPacket<B>
63where
64    B: SplitByteSlice,
65{
66    type Error = ParseError;
67
68    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
69        let head = buffer.take_obj_front::<PacketHead>().ok_or(ParseError::Malformed)?;
70        if head.magic.get() != MAGIC {
71            return Err(ParseError::BadMagic);
72        }
73        let nodename = buffer.take_front(MAX_NODENAME_LENGTH).ok_or(ParseError::Malformed)?;
74        let nodename = ValidStr::new(nodename).map_err(ParseError::Encoding)?;
75        let (nodename, _rest) = nodename.truncate_null();
76        let data = ValidStr::new(buffer.into_rest()).map_err(ParseError::Encoding)?;
77
78        Ok(Self { head, nodename, data })
79    }
80
81    fn parse_metadata(&self) -> ParseMetadata {
82        // we only need ParseMetadata to undo parsing, not necessary to implement it for now
83        unimplemented!()
84    }
85}
86
87#[derive(Debug)]
88pub struct AckPacketBuilder {
89    seqno: u32,
90}
91
92impl AckPacketBuilder {
93    pub fn new(seqno: u32) -> Self {
94        Self { seqno }
95    }
96}
97
98impl InnerPacketBuilder for AckPacketBuilder {
99    fn bytes_len(&self) -> usize {
100        std::mem::size_of::<PacketHead>()
101    }
102
103    fn serialize(&self, mut buffer: &mut [u8]) {
104        let mut bv = crate::as_buffer_view_mut(&mut buffer);
105        let mut head = bv.take_obj_front::<PacketHead>().unwrap();
106        head.magic.set(MAGIC);
107        head.seqno.set(self.seqno);
108    }
109}
110
111#[derive(Debug)]
112pub struct LogPacketBuilder<'a> {
113    seqno: u32,
114    nodename: &'a str,
115}
116
117impl<'a> LogPacketBuilder<'a> {
118    pub fn new(seqno: u32, nodename: &'a str) -> Option<Self> {
119        if nodename.len() <= MAX_NODENAME_LENGTH { Some(Self { seqno, nodename }) } else { None }
120    }
121}
122
123impl<'a> NestablePacketBuilder for LogPacketBuilder<'a> {
124    fn constraints(&self) -> PacketConstraints {
125        PacketConstraints::new(
126            /* header_len */ std::mem::size_of::<PacketHead>() + MAX_NODENAME_LENGTH,
127            /* footer_len */ 0,
128            /* min_body_len */ 0,
129            /* max_body_len */ MAX_LOG_DATA,
130        )
131    }
132}
133
134impl<'a, C: SerializationContext> PacketBuilder<C> for LogPacketBuilder<'a> {
135    fn serialize(
136        &self,
137        _context: &mut C,
138        target: &mut SerializeTarget<'_>,
139        _body: FragmentedBytesMut<'_, '_>,
140    ) {
141        let mut bv = crate::as_buffer_view_mut(&mut target.header);
142        let mut head = bv.take_obj_front::<PacketHead>().unwrap();
143        head.magic.set(MAGIC);
144        head.seqno.set(self.seqno);
145        let nodename_bytes = self.nodename.as_bytes();
146        let nodename = bv.take_front_zero(MAX_NODENAME_LENGTH).unwrap();
147        let (nodename, _rest) = nodename.split_at_mut(nodename_bytes.len());
148        nodename.copy_from_slice(nodename_bytes);
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use packet::{NoOpSerializationContext, ParseBuffer as _, Serializer as _};
156
157    /// Helper to convince the compiler we're holding buffer views.
158    fn as_buffer_view<'a, B: packet::BufferView<&'a [u8]>>(
159        v: B,
160    ) -> impl packet::BufferView<&'a [u8]> {
161        v
162    }
163
164    #[test]
165    fn test_log_packet() {
166        const LOG_DATA: &'static str = "some log data";
167        const NODENAME: &'static str = "my node";
168        let mut log = LogPacketBuilder::new(3, NODENAME)
169            .unwrap()
170            .wrap_body(LOG_DATA.as_bytes().into_serializer())
171            .serialize_vec_outer(&mut NoOpSerializationContext)
172            .unwrap_or_else(|_| panic!("Failed to serialize"));
173        let packet = log.parse::<DebugLogPacket<_>>().expect("Failed to parse");
174        assert_eq!(packet.seqno(), 3);
175        assert_eq!(packet.nodename(), NODENAME);
176        assert_eq!(packet.data(), LOG_DATA);
177    }
178
179    #[test]
180    fn test_ack_packet() {
181        const SEQNO: u32 = 4;
182        let ack = AckPacketBuilder::new(SEQNO)
183            .into_serializer()
184            .serialize_vec_outer(&mut NoOpSerializationContext)
185            .unwrap_or_else(|_| panic!("Failed to serialize"));
186        let mut bv = ack.as_ref();
187        let head = as_buffer_view(&mut bv)
188            .take_obj_front::<PacketHead>()
189            .expect("failed to get serialized head");
190        assert_eq!(head.magic.get(), MAGIC);
191        assert_eq!(head.seqno.get(), SEQNO);
192    }
193}