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