falco_event/events/
raw_event.rs

1use crate::events::payload::PayloadFromBytesError;
2use crate::events::{Event, EventMetadata, EventToBytes};
3use crate::fields::FromBytesError;
4use std::io::Write;
5use std::marker::PhantomData;
6use std::num::TryFromIntError;
7
8pub trait FromRawEvent<'a>: Sized {
9    fn parse(raw_event: &RawEvent<'a>) -> Result<Self, PayloadFromBytesError>;
10}
11
12pub trait LengthField: TryFrom<usize, Error = TryFromIntError> {
13    fn read(buf: &mut &[u8]) -> Option<usize>;
14
15    fn to_usize(&self) -> usize;
16}
17
18impl LengthField for u16 {
19    fn read(buf: &mut &[u8]) -> Option<usize> {
20        let len = buf.split_off(..size_of::<u16>())?;
21        Some(u16::from_ne_bytes(len.try_into().unwrap()) as usize)
22    }
23
24    fn to_usize(&self) -> usize {
25        *self as usize
26    }
27}
28
29impl LengthField for u32 {
30    fn read(buf: &mut &[u8]) -> Option<usize> {
31        let len = buf.split_off(..size_of::<u32>())?;
32        Some(u32::from_ne_bytes(len.try_into().unwrap()) as usize)
33    }
34
35    fn to_usize(&self) -> usize {
36        *self as usize
37    }
38}
39
40pub struct ParamIter<'a, T: LengthField> {
41    lengths: &'a [u8],
42    params: &'a [u8],
43    length_type: PhantomData<T>,
44}
45
46impl<'a, T: LengthField> Iterator for ParamIter<'a, T> {
47    type Item = Result<&'a [u8], FromBytesError>;
48
49    fn next(&mut self) -> Option<Self::Item> {
50        let len = T::read(&mut self.lengths)?;
51        match self.params.split_off(..len) {
52            Some(param) => Some(Ok(param)),
53            None => Some(Err(FromBytesError::TruncatedField {
54                wanted: len,
55                got: self.params.len(),
56            })),
57        }
58    }
59}
60
61#[derive(Debug)]
62pub struct RawEvent<'a> {
63    pub metadata: EventMetadata,
64    pub len: u32,
65    pub event_type: u16,
66    pub nparams: u32,
67    pub payload: &'a [u8],
68}
69
70impl<'e> RawEvent<'e> {
71    fn from_impl(mut buf: &[u8]) -> Option<RawEvent> {
72        let ts_buf = buf.split_off(..8)?;
73        let ts = u64::from_ne_bytes(ts_buf.try_into().unwrap());
74
75        let tid_buf = buf.split_off(..8)?;
76        let tid = i64::from_ne_bytes(tid_buf.try_into().unwrap());
77
78        let len_buf = buf.split_off(..4)?;
79        let len = u32::from_ne_bytes(len_buf.try_into().unwrap());
80
81        let event_type_buf = buf.split_off(..2)?;
82        let event_type = u16::from_ne_bytes(event_type_buf.try_into().unwrap());
83
84        let nparams_buf = buf.split_off(..4)?;
85        let nparams = u32::from_ne_bytes(nparams_buf.try_into().unwrap());
86
87        Some(RawEvent {
88            metadata: EventMetadata { ts, tid },
89            len,
90            event_type,
91            nparams,
92            payload: buf,
93        })
94    }
95
96    /// Parse a byte slice into a RawEvent
97    ///
98    /// This decodes the header while leaving the payload as a raw byte buffer.
99    pub fn from(buf: &[u8]) -> std::io::Result<RawEvent> {
100        Self::from_impl(buf).ok_or(std::io::ErrorKind::InvalidData.into())
101    }
102
103    /// Trim event payload
104    ///
105    /// This limits the payload to the length actually indicated in the `len` field
106    /// and returns the excess data. Useful when reading a raw event stream without
107    /// any external structure
108    ///
109    /// Example
110    /// ```
111    /// use falco_event::events::{PayloadFromBytesError, RawEvent};
112    /// # fn main() -> anyhow::Result<()> {
113    /// let mut events: &[u8] = &[ /* raw event bytes */ ];
114    ///
115    /// while !events.is_empty() {
116    ///     let mut event = RawEvent::from(events)?;
117    ///     match event.trim() {
118    ///         Some(tail) => events = tail,
119    ///         None => return Err(PayloadFromBytesError::TruncatedEvent {
120    ///             wanted: event.len as usize,
121    ///             got: events.len(),
122    ///         })?
123    ///     }
124    /// }
125    ///
126    /// # Ok(())
127    /// # }
128    /// ```
129    pub fn trim(&mut self) -> Option<&'e [u8]> {
130        let payload_len = self.len as usize - 26;
131        self.payload.split_off(payload_len..)
132    }
133
134    /// Iterate over a buffer with multiple raw events
135    ///
136    /// This function takes a byte slice and returns an iterator that yields `RawEvent` instances
137    /// until the whole buffer is consumed.
138    pub fn scan(mut buf: &'e [u8]) -> impl Iterator<Item = Result<RawEvent<'e>, std::io::Error>> {
139        std::iter::from_fn(move || {
140            if buf.is_empty() {
141                return None;
142            }
143            match Self::from(buf) {
144                Ok(mut raw_event) => {
145                    if let Some(tail) = raw_event.trim() {
146                        buf = tail;
147                    }
148                    Some(Ok(raw_event))
149                }
150
151                Err(err) => Some(Err(err)),
152            }
153        })
154    }
155
156    /// Parse a byte buffer (from a raw pointer) into a RawEvent
157    ///
158    /// # Safety
159    ///
160    /// `buf` must point to a complete event, i.e.
161    ///  - include the length field
162    ///  - include `nparams` lengths
163    ///  - have enough data bytes for all the fields (sum of lengths)
164    pub unsafe fn from_ptr<'a>(buf: *const u8) -> std::io::Result<RawEvent<'a>> {
165        let len_buf = unsafe { std::slice::from_raw_parts(buf.offset(16), 4) };
166        let len = u32::from_ne_bytes(len_buf.try_into().unwrap());
167
168        let buf: &'a [u8] = unsafe { std::slice::from_raw_parts(buf, len as usize) };
169        Self::from(buf)
170    }
171
172    pub fn load<'a, T: FromRawEvent<'e>>(&'a self) -> Result<Event<T>, PayloadFromBytesError> {
173        #[allow(clippy::question_mark)]
174        let params = match T::parse(self) {
175            Ok(p) => p,
176            Err(e) => return Err(e),
177        };
178        Ok(Event {
179            metadata: self.metadata.clone(),
180            params,
181        })
182    }
183
184    /// Get an iterator over the event parameters
185    ///
186    /// `T` must correspond to the type of the length field (u16 or u32, depending on the event type)
187    pub fn params<T: LengthField>(&self) -> Result<ParamIter<'e, T>, PayloadFromBytesError> {
188        let length_size = size_of::<T>();
189        let ll = self.nparams as usize * length_size;
190
191        if self.payload.len() < ll {
192            return Err(PayloadFromBytesError::TruncatedEvent {
193                wanted: ll,
194                got: self.payload.len(),
195            });
196        }
197
198        let (lengths, params) = self.payload.split_at(ll);
199
200        Ok(ParamIter {
201            lengths,
202            params,
203            length_type: PhantomData,
204        })
205    }
206}
207
208impl EventToBytes for RawEvent<'_> {
209    fn binary_size(&self) -> usize {
210        self.len as usize
211    }
212
213    fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
214        self.metadata
215            .write_header(self.len, self.event_type, self.nparams, &mut writer)?;
216        writer.write_all(self.payload)
217    }
218}