rust/ffi: add thread lifecycle callback wrappers

Ticket: #8605
This commit is contained in:
Jason Ish 2026-05-27 14:40:58 -06:00
parent cca2eb2b82
commit ea3a4e4eaf
3 changed files with 73 additions and 0 deletions

View file

@ -4,6 +4,7 @@ use suricata_ffi::eve::{self, SCJsonBuilder};
use suricata_ffi::flow::{self, Flow, FlowStorage};
use suricata_ffi::jsonbuilder::JsonBuilder;
use suricata_ffi::packet::Packet;
use suricata_ffi::thread;
use suricata_ffi::threadvars::ThreadVars;
use suricata_ffi::{SCLogError, SCLogNotice};
use suricata_sys::sys::{
@ -23,6 +24,7 @@ unsafe extern "C" fn init() {
pub fn register() -> Result<(), &'static str> {
register_eve_callbacks()?;
register_flow_callbacks()?;
register_thread_callbacks()?;
Ok(())
}
@ -33,6 +35,13 @@ pub fn register_eve_callbacks() -> Result<(), &'static str> {
eve::register_callback(log_eve_wrapped)
}
pub fn register_thread_callbacks() -> Result<(), &'static str> {
// This thread init callback registration shows how we can use a closure to
// pass "user" data.
let user_data = "foo";
thread::register_init_callback(|tv| on_thread_init(tv, user_data))
}
#[derive(Default)]
struct ExampleFlowState {
packets: u64,
@ -74,6 +83,13 @@ fn log_eve_wrapped(
Ok(())
}
fn on_thread_init(tv: ThreadVars<'_>, _foo: &str) {
SCLogNotice!(
"rust example thread init callback: thread={:p}",
tv.as_ptr()
);
}
fn log_flow_init(
_tv: ThreadVars<'_>,
mut f: Flow<'_>,

View file

@ -25,6 +25,7 @@ pub mod flow;
pub mod jsonbuilder;
pub mod packet;
pub mod plugin;
pub mod thread;
pub mod threadvars;
pub const IPPROTO_TCP: u8 = 6;

56
rust/ffi/src/thread.rs Normal file
View file

@ -0,0 +1,56 @@
/* Copyright (C) 2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use std::os::raw::c_void;
use crate::threadvars::ThreadVars;
use suricata_sys::sys;
/// Register a thread initialization callback.
///
/// 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 raw pointers from Suricata. These pointers are 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: for<'a> Fn(ThreadVars<'a>) + Send + Sync + 'static,
{
let user = Box::into_raw(Box::new(callback)) as *mut c_void;
if unsafe { sys::SCThreadRegisterInitCallback(Some(init_callback_wrapper::<F>), user) } {
Ok(())
} else {
unsafe {
drop(Box::from_raw(user as *mut F));
}
Err("Failed to register thread init callback")
}
}
unsafe extern "C" fn init_callback_wrapper<F>(tv: *mut sys::ThreadVars, user: *mut c_void)
where
F: for<'a> Fn(ThreadVars<'a>) + Send + Sync + 'static,
{
let callback = &*(user as *const F);
callback(ThreadVars::from_ptr(tv));
}