falco_event/events/
raw_event.rs

1use crate::events::payload::PayloadFromBytesError;
2use crate::events::{AnyEventPayload, Event, EventMetadata, EventToBytes};
3use crate::fields::{FromBytes, 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
61impl<'a, T: LengthField> ParamIter<'a, T> {
62    #[inline]
63    pub fn next_field<U>(&mut self) -> Result<U, FromBytesError>
64    where
65        U: FromBytes<'a>,
66    {
67        let mut maybe_next_field = self.next().transpose()?;
68        let val = FromBytes::from_maybe_bytes(maybe_next_field.as_mut())?;
69        if let Some(buf) = maybe_next_field {
70            if !buf.is_empty() {
71                return Err(FromBytesError::LeftoverData);
72            }
73        }
74
75        Ok(val)
76    }
77}
78
79#[derive(Debug)]
80pub struct RawEvent<'a> {
81    pub metadata: EventMetadata,
82    pub len: u32,
83    pub event_type: u16,
84    pub nparams: u32,
85    pub payload: &'a [u8],
86}
87
88impl<'e> RawEvent<'e> {
89    fn from_impl(mut buf: &[u8]) -> Option<RawEvent<'_>> {
90        let ts_buf = buf.split_off(..8)?;
91        let ts = u64::from_ne_bytes(ts_buf.try_into().unwrap());
92
93        let tid_buf = buf.split_off(..8)?;
94        let tid = i64::from_ne_bytes(tid_buf.try_into().unwrap());
95
96        let len_buf = buf.split_off(..4)?;
97        let len = u32::from_ne_bytes(len_buf.try_into().unwrap());
98
99        let event_type_buf = buf.split_off(..2)?;
100        let event_type = u16::from_ne_bytes(event_type_buf.try_into().unwrap());
101
102        let nparams_buf = buf.split_off(..4)?;
103        let nparams = u32::from_ne_bytes(nparams_buf.try_into().unwrap());
104
105        Some(RawEvent {
106            metadata: EventMetadata { ts, tid },
107            len,
108            event_type,
109            nparams,
110            payload: buf,
111        })
112    }
113
114    /// Parse a byte slice into a RawEvent
115    ///
116    /// This decodes the header while leaving the payload as a raw byte buffer.
117    pub fn from(buf: &[u8]) -> std::io::Result<RawEvent<'_>> {
118        Self::from_impl(buf).ok_or(std::io::ErrorKind::InvalidData.into())
119    }
120
121    /// Trim event payload
122    ///
123    /// This limits the payload to the length actually indicated in the `len` field
124    /// and returns the excess data. Useful when reading a raw event stream without
125    /// any external structure
126    ///
127    /// Example
128    /// ```
129    /// use falco_event::events::{PayloadFromBytesError, RawEvent};
130    /// # fn main() -> anyhow::Result<()> {
131    /// let mut events: &[u8] = &[ /* raw event bytes */ ];
132    ///
133    /// while !events.is_empty() {
134    ///     let mut event = RawEvent::from(events)?;
135    ///     match event.trim() {
136    ///         Some(tail) => events = tail,
137    ///         None => return Err(PayloadFromBytesError::TruncatedEvent {
138    ///             wanted: event.len as usize,
139    ///             got: events.len(),
140    ///         })?
141    ///     }
142    /// }
143    ///
144    /// # Ok(())
145    /// # }
146    /// ```
147    pub fn trim(&mut self) -> Option<&'e [u8]> {
148        let payload_len = self.len as usize - 26;
149        self.payload.split_off(payload_len..)
150    }
151
152    /// Iterate over a buffer with multiple raw events
153    ///
154    /// This function takes a byte slice and returns an iterator that yields `RawEvent` instances
155    /// until the whole buffer is consumed.
156    pub fn scan(mut buf: &'e [u8]) -> impl Iterator<Item = Result<RawEvent<'e>, std::io::Error>> {
157        std::iter::from_fn(move || {
158            if buf.is_empty() {
159                return None;
160            }
161            match Self::from(buf) {
162                Ok(mut raw_event) => {
163                    if let Some(tail) = raw_event.trim() {
164                        buf = tail;
165                    }
166                    Some(Ok(raw_event))
167                }
168
169                Err(err) => Some(Err(err)),
170            }
171        })
172    }
173
174    /// Parse a byte buffer (from a raw pointer) into a RawEvent
175    ///
176    /// # Safety
177    ///
178    /// `buf` must point to a complete event, i.e.
179    ///  - include the length field
180    ///  - include `nparams` lengths
181    ///  - have enough data bytes for all the fields (sum of lengths)
182    pub unsafe fn from_ptr<'a>(buf: *const u8) -> std::io::Result<RawEvent<'a>> {
183        let len_buf = unsafe { std::slice::from_raw_parts(buf.offset(16), 4) };
184        let len = u32::from_ne_bytes(len_buf.try_into().unwrap());
185
186        let buf: &'a [u8] = unsafe { std::slice::from_raw_parts(buf, len as usize) };
187        Self::from(buf)
188    }
189
190    pub fn load<'a, T: FromRawEvent<'e>>(&'a self) -> Result<Event<T>, PayloadFromBytesError> {
191        #[allow(clippy::question_mark)]
192        let params = match T::parse(self) {
193            Ok(p) => p,
194            Err(e) => return Err(e),
195        };
196        Ok(Event {
197            metadata: self.metadata.clone(),
198            params,
199        })
200    }
201
202    /// Get an iterator over the event parameters
203    ///
204    /// `T` must correspond to the type of the length field (u16 or u32, depending on the event type)
205    pub fn params<T: LengthField>(&self) -> Result<ParamIter<'e, T>, PayloadFromBytesError> {
206        let length_size = size_of::<T>();
207        let ll = self.nparams as usize * length_size;
208
209        if self.payload.len() < ll {
210            return Err(PayloadFromBytesError::TruncatedEvent {
211                wanted: ll,
212                got: self.payload.len(),
213            });
214        }
215
216        let (lengths, params) = self.payload.split_at(ll);
217
218        Ok(ParamIter {
219            lengths,
220            params,
221            length_type: PhantomData,
222        })
223    }
224}
225
226impl<'a, 'b> From<&'a RawEvent<'b>> for RawEvent<'b> {
227    fn from(event: &'a RawEvent<'b>) -> Self {
228        Self {
229            metadata: event.metadata.clone(),
230            len: event.len,
231            event_type: event.event_type,
232            nparams: event.nparams,
233            payload: event.payload,
234        }
235    }
236}
237
238impl EventToBytes for RawEvent<'_> {
239    fn binary_size(&self) -> usize {
240        self.len as usize
241    }
242
243    fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
244        self.metadata
245            .write_header(self.len, self.event_type, self.nparams, &mut writer)?;
246        writer.write_all(self.payload)
247    }
248}
249
250impl AnyEventPayload for RawEvent<'_> {
251    const SOURCES: &'static [Option<&'static str>] = &[];
252    const EVENT_TYPES: &'static [u16] = &[];
253}