falco_plugin/plugin/tables/vtable/
writer.rs

1use crate::plugin::error::last_error::LastError;
2use crate::plugin::tables::vtable::TableError;
3use crate::plugin::tables::vtable::TableError::BadVtable;
4use falco_plugin_api::{
5    ss_plugin_rc, ss_plugin_state_data, ss_plugin_table_entry_t, ss_plugin_table_field_t,
6    ss_plugin_table_t, ss_plugin_table_writer_vtable_ext,
7};
8use std::marker::PhantomData;
9
10/// A vtable containing table write access methods
11///
12/// It's used as a token to prove you're allowed to write tables in a particular context
13/// The default implementation is [`crate::tables::LazyTableWriter`].
14pub trait TableWriter: private::TableWriterImpl {}
15
16impl<T: private::TableWriterImpl> TableWriter for T {}
17
18pub(crate) mod private {
19    use super::*;
20
21    pub trait TableWriterImpl {
22        type Error: std::error::Error + Send + Sync + 'static;
23
24        unsafe fn clear_table(
25            &self,
26            t: *mut ss_plugin_table_t,
27        ) -> Result<ss_plugin_rc, Self::Error>;
28
29        unsafe fn erase_table_entry(
30            &self,
31            t: *mut ss_plugin_table_t,
32            key: *const ss_plugin_state_data,
33        ) -> Result<ss_plugin_rc, Self::Error>;
34
35        unsafe fn create_table_entry(
36            &self,
37            t: *mut ss_plugin_table_t,
38        ) -> Result<*mut ss_plugin_table_entry_t, Self::Error>;
39
40        unsafe fn destroy_table_entry(
41            &self,
42            t: *mut ss_plugin_table_t,
43            e: *mut ss_plugin_table_entry_t,
44        );
45
46        fn destroy_table_entry_fn(
47            &self,
48        ) -> Option<
49            unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
50        >;
51
52        unsafe fn add_table_entry(
53            &self,
54            t: *mut ss_plugin_table_t,
55            key: *const ss_plugin_state_data,
56            entry: *mut ss_plugin_table_entry_t,
57        ) -> Result<*mut ss_plugin_table_entry_t, Self::Error>;
58
59        unsafe fn write_entry_field(
60            &self,
61            t: *mut ss_plugin_table_t,
62            e: *mut ss_plugin_table_entry_t,
63            f: *const ss_plugin_table_field_t,
64            in_: *const ss_plugin_state_data,
65        ) -> Result<ss_plugin_rc, Self::Error>;
66
67        fn last_error(&self) -> &LastError;
68    }
69}
70
71/// A TableWriter that performs validation on demand
72///
73/// This has no overhead when not actively using tables, but after a few accesses
74/// the repeated null checks might add up
75#[derive(Debug)]
76pub struct LazyTableWriter<'t> {
77    writer_ext: &'t ss_plugin_table_writer_vtable_ext,
78    pub(in crate::plugin::tables) last_error: LastError,
79}
80
81impl<'t> LazyTableWriter<'t> {
82    pub(crate) fn try_from(
83        writer_ext: &'t ss_plugin_table_writer_vtable_ext,
84        last_error: LastError,
85    ) -> Result<Self, TableError> {
86        Ok(LazyTableWriter {
87            writer_ext,
88            last_error,
89        })
90    }
91
92    /// Validate all vtable entries and skip further NULL checks
93    ///
94    /// This method validates all possible vtable methods to make future
95    /// table accesses faster. If your plugin method does more than a few
96    /// (say, 10) calls to methods that take a `TableWriter`, it might be
97    /// faster to get a `ValidatedTableWriter`
98    pub fn validate(&self) -> Result<ValidatedTableWriter, TableError> {
99        Ok(ValidatedTableWriter {
100            clear_table: self
101                .writer_ext
102                .clear_table
103                .ok_or(BadVtable("clear_table"))?,
104            erase_table_entry: self
105                .writer_ext
106                .erase_table_entry
107                .ok_or(BadVtable("erase_table_entry"))?,
108            create_table_entry: self
109                .writer_ext
110                .create_table_entry
111                .ok_or(BadVtable("create_table_entry"))?,
112            destroy_table_entry: self
113                .writer_ext
114                .destroy_table_entry
115                .ok_or(BadVtable("destroy_table_entry"))?,
116            add_table_entry: self
117                .writer_ext
118                .add_table_entry
119                .ok_or(BadVtable("add_table_entry"))?,
120            write_entry_field: self
121                .writer_ext
122                .write_entry_field
123                .ok_or(BadVtable("write_entry_field"))?,
124            last_error: self.last_error.clone(),
125            lifetime: PhantomData,
126        })
127    }
128}
129
130impl private::TableWriterImpl for LazyTableWriter<'_> {
131    type Error = TableError;
132
133    unsafe fn clear_table(&self, t: *mut ss_plugin_table_t) -> Result<ss_plugin_rc, TableError> {
134        unsafe {
135            Ok(self
136                .writer_ext
137                .clear_table
138                .ok_or(BadVtable("clear_table"))?(t))
139        }
140    }
141
142    unsafe fn erase_table_entry(
143        &self,
144        t: *mut ss_plugin_table_t,
145        key: *const ss_plugin_state_data,
146    ) -> Result<ss_plugin_rc, TableError> {
147        unsafe {
148            Ok(self
149                .writer_ext
150                .erase_table_entry
151                .ok_or(BadVtable("erase_table_entry"))?(
152                t, key
153            ))
154        }
155    }
156
157    unsafe fn create_table_entry(
158        &self,
159        t: *mut ss_plugin_table_t,
160    ) -> Result<*mut ss_plugin_table_entry_t, TableError> {
161        unsafe {
162            Ok(self
163                .writer_ext
164                .create_table_entry
165                .ok_or(BadVtable("create_table_entry"))?(t))
166        }
167    }
168
169    unsafe fn destroy_table_entry(
170        &self,
171        t: *mut ss_plugin_table_t,
172        e: *mut ss_plugin_table_entry_t,
173    ) {
174        let Some(destroy_table_entry) = self.writer_ext.destroy_table_entry else {
175            return;
176        };
177
178        unsafe { destroy_table_entry(t, e) }
179    }
180
181    fn destroy_table_entry_fn(
182        &self,
183    ) -> Option<
184        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
185    > {
186        self.writer_ext.destroy_table_entry
187    }
188
189    unsafe fn add_table_entry(
190        &self,
191        t: *mut ss_plugin_table_t,
192        key: *const ss_plugin_state_data,
193        entry: *mut ss_plugin_table_entry_t,
194    ) -> Result<*mut ss_plugin_table_entry_t, TableError> {
195        unsafe {
196            Ok(self
197                .writer_ext
198                .add_table_entry
199                .ok_or(BadVtable("add_table_entry"))?(
200                t, key, entry
201            ))
202        }
203    }
204
205    unsafe fn write_entry_field(
206        &self,
207        t: *mut ss_plugin_table_t,
208        e: *mut ss_plugin_table_entry_t,
209        f: *const ss_plugin_table_field_t,
210        in_: *const ss_plugin_state_data,
211    ) -> Result<ss_plugin_rc, TableError> {
212        unsafe {
213            Ok(self
214                .writer_ext
215                .write_entry_field
216                .ok_or(BadVtable("write_entry_field"))?(
217                t, e, f, in_
218            ))
219        }
220    }
221
222    fn last_error(&self) -> &LastError {
223        &self.last_error
224    }
225}
226
227/// A vtable containing table write access methods
228///
229/// It's used as a token to prove you're allowed to write tables in a particular context
230#[derive(Debug)]
231pub struct ValidatedTableWriter<'t> {
232    clear_table: unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t) -> ss_plugin_rc,
233    erase_table_entry: unsafe extern "C-unwind" fn(
234        t: *mut ss_plugin_table_t,
235        key: *const ss_plugin_state_data,
236    ) -> ss_plugin_rc,
237    create_table_entry:
238        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t) -> *mut ss_plugin_table_entry_t,
239    destroy_table_entry:
240        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
241    add_table_entry: unsafe extern "C-unwind" fn(
242        t: *mut ss_plugin_table_t,
243        key: *const ss_plugin_state_data,
244        entry: *mut ss_plugin_table_entry_t,
245    ) -> *mut ss_plugin_table_entry_t,
246    write_entry_field: unsafe extern "C-unwind" fn(
247        t: *mut ss_plugin_table_t,
248        e: *mut ss_plugin_table_entry_t,
249        f: *const ss_plugin_table_field_t,
250        in_: *const ss_plugin_state_data,
251    ) -> ss_plugin_rc,
252
253    pub(in crate::plugin::tables) last_error: LastError,
254    lifetime: PhantomData<&'t ()>,
255}
256
257impl private::TableWriterImpl for ValidatedTableWriter<'_> {
258    type Error = std::convert::Infallible;
259
260    unsafe fn clear_table(&self, t: *mut ss_plugin_table_t) -> Result<ss_plugin_rc, Self::Error> {
261        unsafe { Ok((self.clear_table)(t)) }
262    }
263
264    unsafe fn erase_table_entry(
265        &self,
266        t: *mut ss_plugin_table_t,
267        key: *const ss_plugin_state_data,
268    ) -> Result<ss_plugin_rc, Self::Error> {
269        unsafe { Ok((self.erase_table_entry)(t, key)) }
270    }
271
272    unsafe fn create_table_entry(
273        &self,
274        t: *mut ss_plugin_table_t,
275    ) -> Result<*mut ss_plugin_table_entry_t, Self::Error> {
276        unsafe { Ok((self.create_table_entry)(t)) }
277    }
278
279    unsafe fn destroy_table_entry(
280        &self,
281        t: *mut ss_plugin_table_t,
282        e: *mut ss_plugin_table_entry_t,
283    ) {
284        unsafe { (self.destroy_table_entry)(t, e) }
285    }
286
287    fn destroy_table_entry_fn(
288        &self,
289    ) -> Option<
290        unsafe extern "C-unwind" fn(t: *mut ss_plugin_table_t, e: *mut ss_plugin_table_entry_t),
291    > {
292        Some(self.destroy_table_entry)
293    }
294
295    unsafe fn add_table_entry(
296        &self,
297        t: *mut ss_plugin_table_t,
298        key: *const ss_plugin_state_data,
299        entry: *mut ss_plugin_table_entry_t,
300    ) -> Result<*mut ss_plugin_table_entry_t, Self::Error> {
301        unsafe { Ok((self.add_table_entry)(t, key, entry)) }
302    }
303
304    unsafe fn write_entry_field(
305        &self,
306        t: *mut ss_plugin_table_t,
307        e: *mut ss_plugin_table_entry_t,
308        f: *const ss_plugin_table_field_t,
309        in_: *const ss_plugin_state_data,
310    ) -> Result<ss_plugin_rc, Self::Error> {
311        unsafe { Ok((self.write_entry_field)(t, e, f, in_)) }
312    }
313
314    fn last_error(&self) -> &LastError {
315        &self.last_error
316    }
317}