falco_plugin/plugin/listen/
wrappers.rs

1use crate::listen::CaptureListenPlugin;
2use crate::plugin::base::PluginWrapper;
3use crate::plugin::error::ffi_result::FfiResult;
4use crate::plugin::listen::CaptureListenInput;
5use falco_plugin_api::{
6    plugin_api__bindgen_ty_5 as listen_plugin_api, ss_plugin_capture_listen_input, ss_plugin_rc,
7    ss_plugin_rc_SS_PLUGIN_FAILURE, ss_plugin_rc_SS_PLUGIN_SUCCESS, ss_plugin_t,
8};
9
10/// Marker trait to mark a capture listen plugin as exported to the API
11///
12/// # Safety
13///
14/// Only implement this trait if you export the plugin either statically or dynamically
15/// to the plugin API. This is handled by the `capture_listen_plugin!` and `static_plugin!` macros, so you
16/// should never need to implement this trait manually.
17#[diagnostic::on_unimplemented(
18    message = "Capture listen plugin is not exported",
19    note = "use either `capture_listen_plugin!` or `static_plugin!`"
20)]
21pub unsafe trait CaptureListenPluginExported {}
22
23pub trait CaptureListenFallbackApi {
24    const LISTEN_API: listen_plugin_api = listen_plugin_api {
25        capture_open: None,
26        capture_close: None,
27    };
28
29    const IMPLEMENTS_LISTEN: bool = false;
30}
31
32impl<T> CaptureListenFallbackApi for T {}
33
34#[derive(Debug)]
35pub struct CaptureListenApi<T>(std::marker::PhantomData<T>);
36impl<T: CaptureListenPlugin + 'static> CaptureListenApi<T> {
37    pub const LISTEN_API: listen_plugin_api = listen_plugin_api {
38        capture_open: Some(plugin_capture_open::<T>),
39        capture_close: Some(plugin_capture_close::<T>),
40    };
41
42    pub const IMPLEMENTS_LISTEN: bool = true;
43}
44
45pub unsafe extern "C-unwind" fn plugin_capture_open<T: CaptureListenPlugin>(
46    plugin: *mut ss_plugin_t,
47    listen_input: *const ss_plugin_capture_listen_input,
48) -> ss_plugin_rc {
49    let plugin = unsafe {
50        let Some(plugin) = (plugin as *mut PluginWrapper<T>).as_mut() else {
51            return ss_plugin_rc_SS_PLUGIN_FAILURE;
52        };
53        plugin
54    };
55
56    let Some(actual_plugin) = &mut plugin.plugin else {
57        return ss_plugin_rc_SS_PLUGIN_FAILURE;
58    };
59
60    let listen_input = unsafe {
61        let Ok(listen_input) =
62            CaptureListenInput::try_from(listen_input, actual_plugin.last_error.clone())
63        else {
64            return ss_plugin_rc_SS_PLUGIN_FAILURE;
65        };
66        listen_input
67    };
68
69    if let Err(e) = actual_plugin.plugin.capture_open(&listen_input) {
70        e.set_last_error(&mut plugin.error_buf);
71        return e.status_code();
72    }
73
74    ss_plugin_rc_SS_PLUGIN_SUCCESS
75}
76
77pub unsafe extern "C-unwind" fn plugin_capture_close<T: CaptureListenPlugin>(
78    plugin: *mut ss_plugin_t,
79    listen_input: *const ss_plugin_capture_listen_input,
80) -> ss_plugin_rc {
81    let plugin = unsafe {
82        let Some(plugin) = (plugin as *mut PluginWrapper<T>).as_mut() else {
83            return ss_plugin_rc_SS_PLUGIN_FAILURE;
84        };
85        plugin
86    };
87
88    let Some(actual_plugin) = &mut plugin.plugin else {
89        return ss_plugin_rc_SS_PLUGIN_FAILURE;
90    };
91
92    let listen_input = unsafe {
93        let Ok(listen_input) =
94            CaptureListenInput::try_from(listen_input, actual_plugin.last_error.clone())
95        else {
96            return ss_plugin_rc_SS_PLUGIN_FAILURE;
97        };
98        listen_input
99    };
100
101    if let Err(e) = actual_plugin.plugin.capture_close(&listen_input) {
102        e.set_last_error(&mut plugin.error_buf);
103        return e.status_code();
104    }
105
106    ss_plugin_rc_SS_PLUGIN_SUCCESS
107}
108
109/// # Register an asynchronous event plugin
110///
111/// This macro must be called at most once in a crate (it generates public functions with fixed
112/// `#[unsafe(no_mangle)]` names) with a type implementing [`CaptureListenPlugin`] as the sole
113/// parameter.
114#[macro_export]
115macro_rules! capture_listen_plugin {
116    ($ty:ty) => {
117        unsafe impl $crate::internals::listen::wrappers::CaptureListenPluginExported for $ty {}
118
119        $crate::wrap_ffi! {
120            #[unsafe(no_mangle)]
121            use $crate::internals::listen::wrappers: <$ty>;
122
123            unsafe fn plugin_capture_open(
124                plugin: *mut falco_plugin::api::ss_plugin_t,
125                listen_input: *const falco_plugin::api::ss_plugin_capture_listen_input,
126            ) -> falco_plugin::api::ss_plugin_rc;
127            unsafe fn plugin_capture_close(
128                plugin: *mut falco_plugin::api::ss_plugin_t,
129                listen_input: *const falco_plugin::api::ss_plugin_capture_listen_input,
130            ) -> falco_plugin::api::ss_plugin_rc;
131        }
132
133        #[allow(dead_code)]
134        fn __typecheck_plugin_listen_api() -> falco_plugin::api::plugin_api__bindgen_ty_5 {
135            falco_plugin::api::plugin_api__bindgen_ty_5 {
136                capture_open: Some(plugin_capture_open),
137                capture_close: Some(plugin_capture_close),
138            }
139        }
140    };
141}