From 144f824f17c1f368342ab024c1ac728fac0055a7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 27 May 2026 17:17:22 -0600 Subject: [PATCH] rust/ffi: add thread init callback wrapper Ticket: #8605 --- examples/plugins/rust/src/mod.rs | 12 +++++++ rust/ffi/src/lib.rs | 1 + rust/ffi/src/thread.rs | 55 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 rust/ffi/src/thread.rs diff --git a/examples/plugins/rust/src/mod.rs b/examples/plugins/rust/src/mod.rs index 96ba63ea3f..f41b21ec69 100644 --- a/examples/plugins/rust/src/mod.rs +++ b/examples/plugins/rust/src/mod.rs @@ -3,6 +3,7 @@ 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::{SCLogError, SCLogNotice}; use suricata_sys::sys::{Flow, Packet, SCEveRegisterCallback, SCPlugin, ThreadVars}; @@ -16,6 +17,9 @@ unsafe extern "C" fn init() { if let Err(err) = register_flow_callbacks() { SCLogError!("Failed to register rust example flow callbacks: {}", err); } + if let Err(err) = register_thread_callbacks() { + SCLogError!("Failed to register rust example thread callbacks: {}", err); + } } fn register_eve_callbacks() -> Result<(), &'static str> { @@ -32,6 +36,10 @@ fn register_flow_callbacks() -> Result<(), &'static str> { Ok(()) } +pub fn register_thread_callbacks() -> Result<(), &'static str> { + thread::register_init_callback(on_thread_init) +} + unsafe extern "C" fn log_eve_raw( _tv: *mut ThreadVars, _p: *const Packet, @@ -58,6 +66,10 @@ fn log_eve_wrapped( Ok(()) } +fn on_thread_init(tv: *mut ThreadVars) { + SCLogNotice!("rust example thread init callback: thread={:p}", tv); +} + fn log_flow_init(_tv: *mut ThreadVars, _f: *mut Flow, _p: *const Packet) { SCLogNotice!("rust example flow init callback: flow={:p}", _f); } diff --git a/rust/ffi/src/lib.rs b/rust/ffi/src/lib.rs index 5203abb2ee..b9ca52d328 100644 --- a/rust/ffi/src/lib.rs +++ b/rust/ffi/src/lib.rs @@ -24,6 +24,7 @@ pub mod eve; pub mod flow; pub mod jsonbuilder; pub mod plugin; +pub mod thread; pub const IPPROTO_TCP: u8 = 6; pub const IPPROTO_UDP: u8 = 17; diff --git a/rust/ffi/src/thread.rs b/rust/ffi/src/thread.rs new file mode 100644 index 0000000000..c2ed145c7f --- /dev/null +++ b/rust/ffi/src/thread.rs @@ -0,0 +1,55 @@ +/* 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 suricata_sys::sys::{SCThreadRegisterInitCallback, ThreadVars}; + +/// 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 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(callback: F) -> Result<(), &'static str> +where + 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::), 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(tv: *mut ThreadVars, user: *mut c_void) +where + F: Fn(*mut ThreadVars) + Send + Sync + 'static, +{ + let callback = &*(user as *const F); + callback(tv); +}