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 Some(plugin) = plugin.as_mut() else {
79        return std::ptr::null();
80    };
81    let Some(ref mut actual_plugin) = &mut plugin.plugin else {
82        return std::ptr::null();
83    };
84
85    match actual_plugin.plugin.list_open_params() {
86        Ok(s) => {
87            unsafe {
88                *rc = ss_plugin_rc_SS_PLUGIN_SUCCESS;
89            }
90            s.as_ptr()
91        }
92        Err(e) => {
93            unsafe {
94                *rc = e.status_code();
95            }
96            e.set_last_error(&mut plugin.error_buf);
97            std::ptr::null()
98        }
99    }
100}
101
102/// # Safety
103///
104/// All pointers must be valid
105pub unsafe extern "C-unwind" fn plugin_open<T: SourcePlugin>(
106    plugin: *mut ss_plugin_t,
107    params: *const c_char,
108    rc: *mut ss_plugin_rc,
109) -> *mut ss_instance_t {
110    let plugin = plugin as *mut PluginWrapper<T>;
111    unsafe {
112        let Some(plugin) = plugin.as_mut() else {
113            return std::ptr::null_mut();
114        };
115        let Some(ref mut actual_plugin) = &mut plugin.plugin else {
116            return std::ptr::null_mut();
117        };
118
119        let Some(rc) = rc.as_mut() else {
120            return std::ptr::null_mut();
121        };
122
123        let params = if params.is_null() {
124            None
125        } else {
126            match try_str_from_ptr(&params) {
127                Ok(params) => Some(params),
128                Err(e) => {
129                    plugin
130                        .error_buf
131                        .write_into(|w| w.write_all(e.to_string().as_bytes()))
132                        .ok();
133                    *rc = ss_plugin_rc_SS_PLUGIN_FAILURE;
134
135                    return std::ptr::null_mut();
136                }
137            }
138        };
139
140        match actual_plugin.plugin.open(params) {
141            Ok(instance) => {
142                *rc = ss_plugin_rc_SS_PLUGIN_SUCCESS;
143                Box::into_raw(Box::new(SourcePluginInstanceWrapper {
144                    instance,
145                    batch: Default::default(),
146                }))
147                .cast()
148            }
149            Err(e) => {
150                e.set_last_error(&mut plugin.error_buf);
151                *rc = e.status_code();
152                std::ptr::null_mut()
153            }
154        }
155    }
156}
157
158/// # Safety
159///
160/// All pointers must be valid
161pub unsafe extern "C-unwind" fn plugin_close<T: SourcePlugin>(
162    plugin: *mut ss_plugin_t,
163    instance: *mut ss_instance_t,
164) {
165    let plugin = plugin as *mut PluginWrapper<T>;
166    let Some(plugin) = plugin.as_mut() else {
167        return;
168    };
169    let Some(ref mut actual_plugin) = &mut plugin.plugin else {
170        return;
171    };
172
173    let instance = instance as *mut SourcePluginInstanceWrapper<T::Instance>;
174    if instance.is_null() {
175        return;
176    }
177    unsafe {
178        let mut inst = Box::from_raw(instance);
179        actual_plugin.plugin.close(&mut inst.instance);
180    }
181}
182
183/// # Safety
184///
185/// All pointers must be valid
186pub unsafe extern "C-unwind" fn plugin_next_batch<T: SourcePlugin>(
187    plugin: *mut ss_plugin_t,
188    instance: *mut ss_instance_t,
189    nevts: *mut u32,
190    evts: *mut *mut *mut ss_plugin_event,
191) -> ss_plugin_rc {
192    let plugin = plugin as *mut PluginWrapper<T>;
193    let instance = instance as *mut SourcePluginInstanceWrapper<T::Instance>;
194    unsafe {
195        let Some(plugin) = plugin.as_mut() else {
196            return ss_plugin_rc_SS_PLUGIN_FAILURE;
197        };
198        let Some(ref mut actual_plugin) = &mut plugin.plugin else {
199            return ss_plugin_rc_SS_PLUGIN_FAILURE;
200        };
201
202        let Some(instance) = instance.as_mut() else {
203            return ss_plugin_rc_SS_PLUGIN_FAILURE;
204        };
205
206        instance.batch.reset();
207        let mut batch = EventBatch::new(&mut instance.batch);
208        match instance
209            .instance
210            .next_batch(&mut actual_plugin.plugin, &mut batch)
211        {
212            Ok(()) => {
213                let events = batch.get_events();
214                *nevts = events.len() as u32;
215                *evts = events as *const _ as *mut _;
216                ss_plugin_rc_SS_PLUGIN_SUCCESS
217            }
218            Err(e) => {
219                *nevts = 0;
220                *evts = std::ptr::null_mut();
221                e.set_last_error(&mut plugin.error_buf);
222                e.status_code()
223            }
224        }
225    }
226}
227
228/// # Safety
229///
230/// All pointers must be valid
231pub unsafe extern "C-unwind" fn plugin_get_progress<T: SourcePlugin>(
232    _plugin: *mut ss_plugin_t,
233    instance: *mut ss_instance_t,
234    progress_pct: *mut u32,
235) -> *const c_char {
236    let instance = instance as *mut SourcePluginInstanceWrapper<T::Instance>;
237    let progress = unsafe { instance.as_mut() }.map(|instance| instance.instance.get_progress());
238
239    if let Some(progress) = progress {
240        unsafe {
241            *progress_pct = (progress.value * 100.0) as u32;
242        }
243
244        match progress.detail {
245            Some(s) => s.as_ptr(),
246            None => std::ptr::null(),
247        }
248    } else {
249        unsafe {
250            *progress_pct = 0;
251        }
252
253        std::ptr::null()
254    }
255}
256
257/// # Safety
258///
259/// All pointers must be valid
260pub unsafe extern "C-unwind" fn plugin_event_to_string<T: SourcePlugin>(
261    plugin: *mut ss_plugin_t,
262    event: *const ss_plugin_event_input,
263) -> *const c_char {
264    let plugin = plugin as *mut PluginWrapper<T>;
265    unsafe {
266        let Some(plugin) = plugin.as_mut() else {
267            return std::ptr::null();
268        };
269        let Some(ref mut actual_plugin) = &mut plugin.plugin else {
270            return std::ptr::null();
271        };
272
273        let Some(event) = event.as_ref() else {
274            return std::ptr::null();
275        };
276        let event = EventInput(*event);
277
278        match actual_plugin.plugin.event_to_string(&event) {
279            Ok(s) => {
280                plugin.string_storage = s;
281                plugin.string_storage.as_ptr()
282            }
283            Err(_) => std::ptr::null(),
284        }
285    }
286}
287
288/// # Register a source plugin
289///
290/// This macro must be called at most once in a crate (it generates public functions with fixed
291/// `#[no_mangle]` names) with a type implementing [`SourcePlugin`] as the sole parameter.
292#[macro_export]
293macro_rules! source_plugin {
294    ($ty:ty) => {
295        unsafe impl $crate::internals::source::wrappers::SourcePluginExported for $ty {}
296
297        $crate::wrap_ffi! {
298            #[no_mangle]
299            use $crate::internals::source::wrappers: <$ty>;
300            unsafe fn plugin_next_batch(
301                plugin: *mut falco_plugin::api::ss_plugin_t,
302                instance: *mut falco_plugin::api::ss_instance_t,
303                nevts: *mut u32,
304                evts: *mut *mut *mut falco_plugin::api::ss_plugin_event,
305            ) -> i32;
306            unsafe fn plugin_get_progress(
307                plugin: *mut falco_plugin::api::ss_plugin_t,
308                instance: *mut falco_plugin::api::ss_instance_t,
309                progress_pct: *mut u32,
310            ) -> *const ::std::ffi::c_char;
311            unsafe fn plugin_get_id() -> u32;
312            unsafe fn plugin_get_event_source() -> *const ::std::ffi::c_char;
313            unsafe fn plugin_list_open_params(
314                plugin: *mut falco_plugin::api::ss_plugin_t,
315                rc: *mut i32,
316            ) -> *const ::std::ffi::c_char;
317            unsafe fn plugin_open(
318                plugin: *mut falco_plugin::api::ss_plugin_t,
319                params: *const ::std::ffi::c_char,
320                rc: *mut i32,
321            ) -> *mut falco_plugin::api::ss_instance_t;
322            unsafe fn plugin_close(
323                plugin: *mut falco_plugin::api::ss_plugin_t,
324                instance: *mut falco_plugin::api::ss_instance_t,
325            ) -> ();
326            unsafe fn plugin_event_to_string(
327                plugin: *mut falco_plugin::api::ss_plugin_t,
328                event_input: *const falco_plugin::api::ss_plugin_event_input,
329            ) -> *const std::ffi::c_char;
330        }
331
332        #[allow(dead_code)]
333        fn __typecheck_plugin_source_api() -> falco_plugin::api::plugin_api__bindgen_ty_1 {
334            falco_plugin::api::plugin_api__bindgen_ty_1 {
335                next_batch: Some(plugin_next_batch),
336                get_progress: Some(plugin_get_progress),
337                get_id: Some(plugin_get_id),
338                get_event_source: Some(plugin_get_event_source),
339                list_open_params: Some(plugin_list_open_params),
340                open: Some(plugin_open),
341                close: Some(plugin_close),
342                event_to_string: Some(plugin_event_to_string),
343            }
344        }
345    };
346}