falco_plugin/plugin/source/
wrappers.rs

1use crate::plugin::base::PluginWrapper;
2use crate::plugin::error::ffi_result::FfiResult;
3use crate::plugin::source::SourcePluginInstanceWrapper;
4use crate::source::{EventBatch, EventInput, SourcePlugin, SourcePluginInstance};
5use crate::strings::cstring_writer::WriteIntoCString;
6use crate::strings::from_ptr::try_str_from_ptr;
7use falco_plugin_api::plugin_api__bindgen_ty_1 as source_plugin_api;
8use falco_plugin_api::{
9    ss_instance_t, ss_plugin_event, ss_plugin_event_input, ss_plugin_rc,
10    ss_plugin_rc_SS_PLUGIN_FAILURE, ss_plugin_rc_SS_PLUGIN_SUCCESS, ss_plugin_t,
11};
12use std::ffi::c_char;
13use std::io::Write;
14
15/// Marker trait to mark a source plugin as exported to the API
16///
17/// # Safety
18///
19/// Only implement this trait if you export the plugin either statically or dynamically
20/// to the plugin API. This is handled by the `source_plugin!` and `static_plugin!` macros, so you
21/// should never need to implement this trait manually.
22#[diagnostic::on_unimplemented(
23    message = "Source plugin is not exported",
24    note = "use either `source_plugin!` or `static_plugin!`"
25)]
26pub unsafe trait SourcePluginExported {}
27
28pub trait SourcePluginFallbackApi {
29    const SOURCE_API: source_plugin_api = source_plugin_api {
30        get_id: None,
31        get_event_source: None,
32        open: None,
33        close: None,
34        list_open_params: None,
35        get_progress: None,
36        event_to_string: None,
37        next_batch: None,
38    };
39
40    const IMPLEMENTS_SOURCE: bool = false;
41}
42impl<T> SourcePluginFallbackApi for T {}
43
44#[allow(missing_debug_implementations)]
45pub struct SourcePluginApi<T>(std::marker::PhantomData<T>);
46
47impl<T: SourcePlugin> SourcePluginApi<T> {
48    pub const SOURCE_API: source_plugin_api = source_plugin_api {
49        get_id: Some(plugin_get_id::<T>),
50        get_event_source: Some(plugin_get_event_source::<T>),
51        open: Some(plugin_open::<T>),
52        close: Some(plugin_close::<T>),
53        list_open_params: Some(plugin_list_open_params::<T>),
54        get_progress: Some(plugin_get_progress::<T>),
55        event_to_string: Some(plugin_event_to_string::<T>),
56        next_batch: Some(plugin_next_batch::<T>),
57    };
58
59    pub const IMPLEMENTS_SOURCE: bool = true;
60}
61
62pub extern "C-unwind" fn plugin_get_event_source<T: SourcePlugin>() -> *const c_char {
63    T::EVENT_SOURCE.as_ptr()
64}
65
66pub extern "C-unwind" fn plugin_get_id<T: SourcePlugin>() -> u32 {
67    T::PLUGIN_ID
68}
69
70/// # Safety
71///
72/// All pointers must be valid
73pub unsafe extern "C-unwind" fn plugin_list_open_params<T: SourcePlugin>(
74    plugin: *mut ss_plugin_t,
75    rc: *mut i32,
76) -> *const c_char {
77    let plugin = plugin as *mut PluginWrapper<T>;
78    let plugin = unsafe {
79        let Some(plugin) = plugin.as_mut() else {
80            return std::ptr::null();
81        };
82        plugin
83    };
84    let Some(actual_plugin) = &mut plugin.plugin else {
85        return std::ptr::null();
86    };
87
88    match actual_plugin.plugin.list_open_params() {
89        Ok(s) => {
90            unsafe {
91                *rc = ss_plugin_rc_SS_PLUGIN_SUCCESS;
92            }
93            s.as_ptr()
94        }
95        Err(e) => {
96            unsafe {
97                *rc = e.status_code();
98            }
99            e.set_last_error(&mut plugin.error_buf);
100            std::ptr::null()
101        }
102    }
103}
104
105/// # Safety
106///
107/// All pointers must be valid
108pub unsafe extern "C-unwind" fn plugin_open<T: SourcePlugin>(
109    plugin: *mut ss_plugin_t,
110    params: *const c_char,
111    rc: *mut ss_plugin_rc,
112) -> *mut ss_instance_t {
113    let plugin = plugin as *mut PluginWrapper<T>;
114    unsafe {
115        let Some(plugin) = plugin.as_mut() else {
116            return std::ptr::null_mut();
117        };
118        let Some(actual_plugin) = &mut plugin.plugin else {
119            return std::ptr::null_mut();
120        };
121
122        let Some(rc) = rc.as_mut() else {
123            return std::ptr::null_mut();
124        };
125
126        let params = if params.is_null() {
127            None
128        } else {
129            match try_str_from_ptr(&params) {
130                Ok(params) => Some(params),
131                Err(e) => {
132                    plugin
133                        .error_buf
134                        .write_into(|w| w.write_all(e.to_string().as_bytes()))
135                        .ok();
136                    *rc = ss_plugin_rc_SS_PLUGIN_FAILURE;
137
138                    return std::ptr::null_mut();
139                }
140            }
141        };
142
143        match actual_plugin.plugin.open(params) {
144            Ok(instance) => {
145                *rc = ss_plugin_rc_SS_PLUGIN_SUCCESS;
146                Box::into_raw(Box::new(SourcePluginInstanceWrapper {
147                    instance,
148                    batch: Default::default(),
149                }))
150                .cast()
151            }
152            Err(e) => {
153                e.set_last_error(&mut plugin.error_buf);
154                *rc = e.status_code();
155                std::ptr::null_mut()
156            }
157        }
158    }
159}
160
161/// # Safety
162///
163/// All pointers must be valid
164pub unsafe extern "C-unwind" fn plugin_close<T: SourcePlugin>(
165    plugin: *mut ss_plugin_t,
166    instance: *mut ss_instance_t,
167) {
168    let plugin = plugin as *mut PluginWrapper<T>;
169    let plugin = unsafe {
170        let Some(plugin) = plugin.as_mut() else {
171            return;
172        };
173        plugin
174    };
175    let Some(actual_plugin) = &mut plugin.plugin else {
176        return;
177    };
178
179    let instance = instance as *mut SourcePluginInstanceWrapper<T::Instance>;
180    if instance.is_null() {
181        return;
182    }
183    unsafe {
184        let mut inst = Box::from_raw(instance);
185        actual_plugin.plugin.close(&mut inst.instance);
186    }
187}
188
189/// # Safety
190///
191/// All pointers must be valid
192pub unsafe extern "C-unwind" fn plugin_next_batch<T: SourcePlugin>(
193    plugin: *mut ss_plugin_t,
194    instance: *mut ss_instance_t,
195    nevts: *mut u32,
196    evts: *mut *mut *mut ss_plugin_event,
197) -> ss_plugin_rc {
198    let plugin = plugin as *mut PluginWrapper<T>;
199    let instance = instance as *mut SourcePluginInstanceWrapper<T::Instance>;
200    unsafe {
201        let Some(plugin) = plugin.as_mut() else {
202            return ss_plugin_rc_SS_PLUGIN_FAILURE;
203        };
204        let Some(actual_plugin) = &mut plugin.plugin else {
205            return ss_plugin_rc_SS_PLUGIN_FAILURE;
206        };
207
208        let Some(instance) = instance.as_mut() else {
209            return ss_plugin_rc_SS_PLUGIN_FAILURE;
210        };
211
212        instance.batch.reset();
213        let mut batch = EventBatch::new(&instance.batch);
214        let batch_result = instance
215            .instance
216            .next_batch(&mut actual_plugin.plugin, &mut batch);
217        match batch_result {
218            Ok(()) => {
219                let events = batch.get_events();
220                *nevts = events.len() as u32;
221                *evts = events as *const _ as *mut _;
222                ss_plugin_rc_SS_PLUGIN_SUCCESS
223            }
224            Err(e) => {
225                *nevts = 0;
226                *evts = std::ptr::null_mut();
227                e.set_last_error(&mut plugin.error_buf);
228                e.status_code()
229            }
230        }
231    }
232}
233
234/// # Safety
235///
236/// All pointers must be valid
237pub unsafe extern "C-unwind" fn plugin_get_progress<T: SourcePlugin>(
238    _plugin: *mut ss_plugin_t,
239    instance: *mut ss_instance_t,
240    progress_pct: *mut u32,
241) -> *const c_char {
242    let instance = instance as *mut SourcePluginInstanceWrapper<T::Instance>;
243    let progress = unsafe { instance.as_mut() }.map(|instance| instance.instance.get_progress());
244
245    if let Some(progress) = progress {
246        unsafe {
247            *progress_pct = (progress.value * 100.0) as u32;
248        }
249
250        match progress.detail {
251            Some(s) => s.as_ptr(),
252            None => std::ptr::null(),
253        }
254    } else {
255        unsafe {
256            *progress_pct = 0;
257        }
258
259        std::ptr::null()
260    }
261}
262
263/// # Safety
264///
265/// All pointers must be valid
266pub unsafe extern "C-unwind" fn plugin_event_to_string<T: SourcePlugin>(
267    plugin: *mut ss_plugin_t,
268    event: *const ss_plugin_event_input,
269) -> *const c_char {
270    let plugin = plugin as *mut PluginWrapper<T>;
271    unsafe {
272        let Some(plugin) = plugin.as_mut() else {
273            return std::ptr::null();
274        };
275        let Some(actual_plugin) = &mut plugin.plugin else {
276            return std::ptr::null();
277        };
278
279        let Some(event) = event.as_ref() else {
280            return std::ptr::null();
281        };
282        let event = EventInput(*event);
283
284        match actual_plugin.plugin.event_to_string(&event) {
285            Ok(s) => {
286                plugin.string_storage = s;
287                plugin.string_storage.as_ptr()
288            }
289            Err(_) => std::ptr::null(),
290        }
291    }
292}
293
294/// # Register a source plugin
295///
296/// This macro must be called at most once in a crate (it generates public functions with fixed
297/// `#[unsafe(no_mangle)]` names) with a type implementing [`SourcePlugin`] as the sole parameter.
298#[macro_export]
299macro_rules! source_plugin {
300    ($ty:ty) => {
301        unsafe impl $crate::internals::source::wrappers::SourcePluginExported for $ty {}
302
303        $crate::wrap_ffi! {
304            #[unsafe(no_mangle)]
305            use $crate::internals::source::wrappers: <$ty>;
306            unsafe fn plugin_next_batch(
307                plugin: *mut falco_plugin::api::ss_plugin_t,
308                instance: *mut falco_plugin::api::ss_instance_t,
309                nevts: *mut u32,
310                evts: *mut *mut *mut falco_plugin::api::ss_plugin_event,
311            ) -> i32;
312            unsafe fn plugin_get_progress(
313                plugin: *mut falco_plugin::api::ss_plugin_t,
314                instance: *mut falco_plugin::api::ss_instance_t,
315                progress_pct: *mut u32,
316            ) -> *const ::std::ffi::c_char;
317            unsafe fn plugin_get_id() -> u32;
318            unsafe fn plugin_get_event_source() -> *const ::std::ffi::c_char;
319            unsafe fn plugin_list_open_params(
320                plugin: *mut falco_plugin::api::ss_plugin_t,
321                rc: *mut i32,
322            ) -> *const ::std::ffi::c_char;
323            unsafe fn plugin_open(
324                plugin: *mut falco_plugin::api::ss_plugin_t,
325                params: *const ::std::ffi::c_char,
326                rc: *mut i32,
327            ) -> *mut falco_plugin::api::ss_instance_t;
328            unsafe fn plugin_close(
329                plugin: *mut falco_plugin::api::ss_plugin_t,
330                instance: *mut falco_plugin::api::ss_instance_t,
331            ) -> ();
332            unsafe fn plugin_event_to_string(
333                plugin: *mut falco_plugin::api::ss_plugin_t,
334                event_input: *const falco_plugin::api::ss_plugin_event_input,
335            ) -> *const std::ffi::c_char;
336        }
337
338        #[allow(dead_code)]
339        fn __typecheck_plugin_source_api() -> falco_plugin::api::plugin_api__bindgen_ty_1 {
340            falco_plugin::api::plugin_api__bindgen_ty_1 {
341                next_batch: Some(plugin_next_batch),
342                get_progress: Some(plugin_get_progress),
343                get_id: Some(plugin_get_id),
344                get_event_source: Some(plugin_get_event_source),
345                list_open_params: Some(plugin_list_open_params),
346                open: Some(plugin_open),
347                close: Some(plugin_close),
348                event_to_string: Some(plugin_event_to_string),
349            }
350        }
351    };
352}