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 Some(plugin) = (plugin as *mut PluginWrapper<T>).as_mut() else {
50        return ss_plugin_rc_SS_PLUGIN_FAILURE;
51    };
52
53    let Some(ref mut actual_plugin) = &mut plugin.plugin else {
54        return ss_plugin_rc_SS_PLUGIN_FAILURE;
55    };
56
57    let Ok(listen_input) =
58        CaptureListenInput::try_from(listen_input, actual_plugin.last_error.clone())
59    else {
60        return ss_plugin_rc_SS_PLUGIN_FAILURE;
61    };
62
63    if let Err(e) = actual_plugin.plugin.capture_open(&listen_input) {
64        e.set_last_error(&mut plugin.error_buf);
65        return e.status_code();
66    }
67
68    ss_plugin_rc_SS_PLUGIN_SUCCESS
69}
70
71pub unsafe extern "C-unwind" fn plugin_capture_close<T: CaptureListenPlugin>(
72    plugin: *mut ss_plugin_t,
73    listen_input: *const ss_plugin_capture_listen_input,
74) -> ss_plugin_rc {
75    let Some(plugin) = (plugin as *mut PluginWrapper<T>).as_mut() else {
76        return ss_plugin_rc_SS_PLUGIN_FAILURE;
77    };
78
79    let Some(ref mut actual_plugin) = &mut plugin.plugin else {
80        return ss_plugin_rc_SS_PLUGIN_FAILURE;
81    };
82
83    let Ok(listen_input) =
84        CaptureListenInput::try_from(listen_input, actual_plugin.last_error.clone())
85    else {
86        return ss_plugin_rc_SS_PLUGIN_FAILURE;
87    };
88
89    if let Err(e) = actual_plugin.plugin.capture_close(&listen_input) {
90        e.set_last_error(&mut plugin.error_buf);
91        return e.status_code();
92    }
93
94    ss_plugin_rc_SS_PLUGIN_SUCCESS
95}
96
97/// # Register an asynchronous event plugin
98///
99/// This macro must be called at most once in a crate (it generates public functions with fixed
100/// `#[no_mangle]` names) with a type implementing [`CaptureListenPlugin`] as the sole
101/// parameter.
102#[macro_export]
103macro_rules! capture_listen_plugin {
104    ($ty:ty) => {
105        unsafe impl $crate::internals::listen::wrappers::CaptureListenPluginExported for $ty {}
106
107        $crate::wrap_ffi! {
108            #[no_mangle]
109            use $crate::internals::listen::wrappers: <$ty>;
110
111            unsafe fn plugin_capture_open(
112                plugin: *mut falco_plugin::api::ss_plugin_t,
113                listen_input: *const falco_plugin::api::ss_plugin_capture_listen_input,
114            ) -> falco_plugin::api::ss_plugin_rc;
115            unsafe fn plugin_capture_close(
116                plugin: *mut falco_plugin::api::ss_plugin_t,
117                listen_input: *const falco_plugin::api::ss_plugin_capture_listen_input,
118            ) -> falco_plugin::api::ss_plugin_rc;
119        }
120
121        #[allow(dead_code)]
122        fn __typecheck_plugin_listen_api() -> falco_plugin::api::plugin_api__bindgen_ty_5 {
123            falco_plugin::api::plugin_api__bindgen_ty_5 {
124                capture_open: Some(plugin_capture_open),
125                capture_close: Some(plugin_capture_close),
126            }
127        }
128    };
129}