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