rust/ffi: use ThreadVars wrapper in thread init callback

Update the thread init callback registration to pass the safe ThreadVars
wrapper instead of a raw pointer.

Ticket: #8598
pull/15499/head
Jason Ish 1 month ago committed by Victor Julien
parent 5fe88212c3
commit 45762aa644

@ -11,20 +11,19 @@ Thread Init Callback
====================
Register a callback with ``thread::register_init_callback`` to run code for
each Suricata thread as it is initialized. The callback receives a raw
``ThreadVars`` pointer for the thread that has just been initialized.
each Suricata thread as it is initialized. The callback receives a
``ThreadVars`` wrapper for the thread that has just been initialized.
The current Rust thread lifecycle API exposes an init callback only; there is
no Rust thread deinit callback.
.. code-block:: rust
use suricata_ffi::thread;
use suricata_ffi::thread::{self, ThreadVars};
use suricata_ffi::SCLogNotice;
use suricata_sys::sys::ThreadVars;
fn on_thread_init(tv: *mut ThreadVars) {
SCLogNotice!("thread initialized: {:p}", tv);
fn on_thread_init(tv: &mut ThreadVars) {
SCLogNotice!("thread initialized: {:p}", tv.as_ptr());
}
fn register_thread_callbacks() -> Result<(), &'static str> {
@ -32,9 +31,10 @@ no Rust thread deinit callback.
}
The wrapper accepts function items or closures that implement
``Fn(*mut ThreadVars) + Send + Sync + 'static`` and returns
``Fn(&mut ThreadVars) + Send + Sync + 'static`` and returns
``Result<(), &'static str>``. An error means the callback could not be
registered. Registered callbacks are kept for the Suricata process lifetime.
The ``ThreadVars`` pointer is only valid for the duration of the callback
invocation and must not be stored. Rust callbacks must not panic.
``ThreadVars`` carries a lifetime tied to the callback invocation, so the
borrow checker prevents it from being stored beyond the call. Rust callbacks
must not panic, as they are invoked across an FFI boundary.

@ -3,9 +3,9 @@ use std::ptr::null_mut;
use suricata_ffi::eve::{self, SCJsonBuilder};
use suricata_ffi::flow;
use suricata_ffi::jsonbuilder::JsonBuilder;
use suricata_ffi::thread;
use suricata_ffi::thread::{self, ThreadVars};
use suricata_ffi::{SCLogError, SCLogNotice};
use suricata_sys::sys::{Flow, Packet, SCEveRegisterCallback, SCPlugin, ThreadVars};
use suricata_sys::sys::{self, Flow, Packet, SCEveRegisterCallback, SCPlugin};
unsafe extern "C" fn init() {
suricata_ffi::plugin::init();
@ -41,7 +41,7 @@ pub fn register_thread_callbacks() -> Result<(), &'static str> {
}
unsafe extern "C" fn log_eve_raw(
_tv: *mut ThreadVars,
_tv: *mut sys::ThreadVars,
_p: *const Packet,
_f: *mut Flow,
jb: *mut SCJsonBuilder,
@ -54,7 +54,7 @@ unsafe extern "C" fn log_eve_raw(
}
fn log_eve_wrapped(
_tv: *mut ThreadVars,
_tv: *mut sys::ThreadVars,
_p: *const Packet,
f: *mut Flow,
jb: &mut JsonBuilder,
@ -66,15 +66,18 @@ fn log_eve_wrapped(
Ok(())
}
fn on_thread_init(tv: *mut ThreadVars) {
SCLogNotice!("rust example thread init callback: thread={:p}", tv);
fn on_thread_init(tv: &mut ThreadVars) {
SCLogNotice!(
"rust example thread init callback: thread={:p}",
tv.as_ptr()
);
}
fn log_flow_init(_tv: *mut ThreadVars, _f: *mut Flow, _p: *const Packet) {
fn log_flow_init(_tv: *mut sys::ThreadVars, _f: *mut Flow, _p: *const Packet) {
SCLogNotice!("rust example flow init callback: flow={:p}", _f);
}
fn log_flow_update(_tv: *mut ThreadVars, _f: *mut Flow, _p: *mut Packet) {
fn log_flow_update(_tv: *mut sys::ThreadVars, _f: *mut Flow, _p: *mut Packet) {
SCLogNotice!(
"rust example flow update callback: flow={:p}, packet={:p}",
_f,
@ -82,7 +85,7 @@ fn log_flow_update(_tv: *mut ThreadVars, _f: *mut Flow, _p: *mut Packet) {
);
}
fn log_flow_finish(_tv: *mut ThreadVars, _f: *mut Flow) {
fn log_flow_finish(_tv: *mut sys::ThreadVars, _f: *mut Flow) {
SCLogNotice!("rust example flow finish callback: flow={:p}", _f);
}

@ -52,16 +52,9 @@ impl<'a> ThreadVars<'a> {
/// The callback is invoked for every thread being initialized during Suricata
/// startup. It receives the `ThreadVars` for the thread that has just been
/// initialized.
///
/// # Safety
///
/// The callback receives a raw pointer from Suricata. This pointer is only
/// valid for the duration of the callback invocation and must not be stored.
///
/// The callback must not panic.
pub fn register_init_callback<F>(callback: F) -> Result<(), &'static str>
where
F: Fn(*mut sys::ThreadVars) + Send + Sync + 'static,
F: Fn(&mut ThreadVars) + Send + Sync + 'static,
{
let user = Box::into_raw(Box::new(callback)) as *mut c_void;
if unsafe { SCThreadRegisterInitCallback(Some(init_callback_wrapper::<F>), user) } {
@ -76,8 +69,9 @@ where
unsafe extern "C" fn init_callback_wrapper<F>(tv: *mut sys::ThreadVars, user: *mut c_void)
where
F: Fn(*mut sys::ThreadVars) + Send + Sync + 'static,
F: Fn(&mut ThreadVars) + Send + Sync + 'static,
{
let callback = &*(user as *const F);
callback(tv);
let mut tv = ThreadVars::from_ptr(tv);
callback(&mut tv);
}

Loading…
Cancel
Save