falco_plugin/async_event/
wrappers.rs1use crate::async_event::async_handler::AsyncHandler;
2use crate::async_event::AsyncEventPlugin;
3use crate::base::wrappers::PluginWrapper;
4use crate::error::ffi_result::FfiResult;
5use crate::error::panic::catch_panic;
6use falco_plugin_api::plugin_api__bindgen_ty_4 as async_plugin_api;
7use falco_plugin_api::{
8 ss_plugin_async_event_handler_t, ss_plugin_owner_t, ss_plugin_rc,
9 ss_plugin_rc_SS_PLUGIN_FAILURE, ss_plugin_rc_SS_PLUGIN_SUCCESS, ss_plugin_t,
10};
11use std::any::TypeId;
12use std::collections::BTreeMap;
13use std::ffi::{c_char, CString};
14use std::panic::AssertUnwindSafe;
15use std::sync::Mutex;
16
17#[diagnostic::on_unimplemented(
25 message = "Async plugin is not exported",
26 note = "use either `async_plugin!` or `static_plugin!`"
27)]
28pub unsafe trait AsyncPluginExported {}
29
30pub trait AsyncPluginFallbackApi {
31 const ASYNC_API: async_plugin_api = async_plugin_api {
32 get_async_event_sources: None,
33 get_async_events: None,
34 set_async_event_handler: None,
35 dump_state: None,
36 };
37
38 const IMPLEMENTS_ASYNC: bool = false;
39}
40impl<T> AsyncPluginFallbackApi for T {}
41
42#[derive(Debug)]
43pub struct AsyncPluginApi<T>(std::marker::PhantomData<T>);
44impl<T: AsyncEventPlugin + 'static> AsyncPluginApi<T> {
45 pub const ASYNC_API: async_plugin_api = async_plugin_api {
46 get_async_event_sources: Some(plugin_get_async_event_sources::<T>),
47 get_async_events: Some(plugin_get_async_events::<T>),
48 set_async_event_handler: Some(plugin_set_async_event_handler::<T>),
49 dump_state: Some(plugin_dump_state::<T>),
50 };
51
52 pub const IMPLEMENTS_ASYNC: bool = true;
53}
54
55pub extern "C" fn plugin_get_async_event_sources<T: AsyncEventPlugin + 'static>() -> *const c_char {
56 static SOURCES: Mutex<BTreeMap<TypeId, CString>> = Mutex::new(BTreeMap::new());
57
58 let ty = TypeId::of::<T>();
59 let mut sources_map = SOURCES.lock().unwrap();
60 sources_map
63 .entry(ty)
64 .or_insert_with(|| {
65 let sources = serde_json::to_string(T::EVENT_SOURCES)
66 .expect("failed to serialize event source array");
67 CString::new(sources.into_bytes()).expect("failed to add NUL to event source array")
68 })
69 .as_ptr()
70}
71
72pub extern "C" fn plugin_get_async_events<T: AsyncEventPlugin + 'static>() -> *const c_char {
73 static EVENTS: Mutex<BTreeMap<TypeId, CString>> = Mutex::new(BTreeMap::new());
74
75 let ty = TypeId::of::<T>();
76 let mut event_map = EVENTS.lock().unwrap();
77 event_map
80 .entry(ty)
81 .or_insert_with(|| {
82 let sources = serde_json::to_string(T::ASYNC_EVENTS)
83 .expect("failed to serialize event name array");
84 CString::new(sources.into_bytes()).expect("failed to add NUL to event name array")
85 })
86 .as_ptr()
87}
88
89pub unsafe extern "C" fn plugin_set_async_event_handler<T: AsyncEventPlugin>(
93 plugin: *mut ss_plugin_t,
94 owner: *mut ss_plugin_owner_t,
95 handler: ss_plugin_async_event_handler_t,
96) -> ss_plugin_rc {
97 unsafe {
98 let Some(plugin) = (plugin as *mut PluginWrapper<T>).as_mut() else {
99 return ss_plugin_rc_SS_PLUGIN_FAILURE;
100 };
101
102 let Some(actual_plugin) = &mut plugin.plugin else {
103 return ss_plugin_rc_SS_PLUGIN_FAILURE;
104 };
105
106 if let Err(e) = catch_panic(AssertUnwindSafe(|| actual_plugin.plugin.stop_async())) {
107 e.set_last_error(&mut plugin.error_buf);
108 return e.status_code();
109 }
110
111 let Some(raw_handler) = handler.as_ref() else {
112 return ss_plugin_rc_SS_PLUGIN_SUCCESS;
113 };
114
115 let handler = AsyncHandler {
116 owner,
117 raw_handler: *raw_handler,
118 };
119 if let Err(e) = catch_panic(AssertUnwindSafe(|| {
120 actual_plugin.plugin.start_async(handler)
121 })) {
122 e.set_last_error(&mut plugin.error_buf);
123 return e.status_code();
124 }
125
126 ss_plugin_rc_SS_PLUGIN_SUCCESS
127 }
128}
129
130pub unsafe extern "C" fn plugin_dump_state<T: AsyncEventPlugin>(
134 plugin: *mut ss_plugin_t,
135 owner: *mut ss_plugin_owner_t,
136 handler: ss_plugin_async_event_handler_t,
137) -> ss_plugin_rc {
138 unsafe {
139 let Some(plugin) = (plugin as *mut PluginWrapper<T>).as_mut() else {
140 return ss_plugin_rc_SS_PLUGIN_FAILURE;
141 };
142
143 let Some(actual_plugin) = &mut plugin.plugin else {
144 return ss_plugin_rc_SS_PLUGIN_FAILURE;
145 };
146
147 let Some(raw_handler) = handler.as_ref() else {
148 return ss_plugin_rc_SS_PLUGIN_SUCCESS;
149 };
150
151 let handler = AsyncHandler {
152 owner,
153 raw_handler: *raw_handler,
154 };
155 if let Err(e) = catch_panic(AssertUnwindSafe(|| {
156 actual_plugin.plugin.dump_state(handler)
157 })) {
158 e.set_last_error(&mut plugin.error_buf);
159 return e.status_code();
160 }
161
162 ss_plugin_rc_SS_PLUGIN_SUCCESS
163 }
164}
165
166#[macro_export]
172macro_rules! async_event_plugin {
173 ($ty:ty) => {
174 unsafe impl $crate::async_event::wrappers::AsyncPluginExported for $ty {}
175
176 $crate::wrap_ffi! {
177 #[unsafe(no_mangle)]
178 use $crate::async_event::wrappers: <$ty>;
179
180 unsafe fn plugin_get_async_events() -> *const ::std::ffi::c_char;
181 unsafe fn plugin_get_async_event_sources() -> *const ::std::ffi::c_char;
182 unsafe fn plugin_set_async_event_handler(
183 plugin: *mut falco_plugin::api::ss_plugin_t,
184 owner: *mut falco_plugin::api::ss_plugin_owner_t,
185 handler: falco_plugin::api::ss_plugin_async_event_handler_t,
186 ) -> falco_plugin::api::ss_plugin_rc;
187 unsafe fn plugin_dump_state(
188 plugin: *mut falco_plugin::api::ss_plugin_t,
189 owner: *mut falco_plugin::api::ss_plugin_owner_t,
190 handler: falco_plugin::api::ss_plugin_async_event_handler_t,
191 ) -> falco_plugin::api::ss_plugin_rc;
192 }
193
194 #[allow(dead_code)]
195 fn __typecheck_plugin_async_api() -> falco_plugin::api::plugin_api__bindgen_ty_4 {
196 falco_plugin::api::plugin_api__bindgen_ty_4 {
197 get_async_event_sources: Some(plugin_get_async_event_sources),
198 get_async_events: Some(plugin_get_async_events),
199 set_async_event_handler: Some(plugin_set_async_event_handler),
200 dump_state: Some(plugin_dump_state),
201 }
202 }
203 };
204}