Skip to main content

falco_plugin/tables/vtable/
writer.rs

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