Skip to content

Commit bbea8e3

Browse files
committed
rust/ffi: add thread lifecycle callback wrappers
Ticket: OISF#8605
1 parent 5b69d8c commit bbea8e3

5 files changed

Lines changed: 68 additions & 2 deletions

File tree

examples/plugins/rust/src/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use suricata_ffi::eve::{self, SCJsonBuilder};
44
use suricata_ffi::flow::{self, Flow, FlowStorage};
55
use suricata_ffi::jsonbuilder::JsonBuilder;
66
use suricata_ffi::packet::Packet;
7-
use suricata_ffi::threadvars::ThreadVars;
7+
use suricata_ffi::threadvars::{self, ThreadVars};
88
use suricata_ffi::{SCLogError, SCLogNotice};
99
use suricata_sys::sys::{
1010
Flow as RawFlow, Packet as RawPacket, SCEveRegisterCallback, SCPlugin,
@@ -23,6 +23,7 @@ unsafe extern "C" fn init() {
2323
pub fn register() -> Result<(), &'static str> {
2424
register_eve_callbacks()?;
2525
register_flow_callbacks()?;
26+
register_thread_callbacks()?;
2627
Ok(())
2728
}
2829

@@ -33,6 +34,10 @@ pub fn register_eve_callbacks() -> Result<(), &'static str> {
3334
eve::register_callback(log_eve_wrapped)
3435
}
3536

37+
pub fn register_thread_callbacks() -> Result<(), &'static str> {
38+
threadvars::register_init_callback(on_thread_init)
39+
}
40+
3641
#[derive(Default)]
3742
struct ExampleFlowState {
3843
packets: u64,
@@ -74,6 +79,13 @@ fn log_eve_wrapped(
7479
Ok(())
7580
}
7681

82+
fn on_thread_init(tv: ThreadVars<'_>) {
83+
SCLogNotice!(
84+
"rust example thread init callback: thread={:p}",
85+
tv.as_ptr()
86+
);
87+
}
88+
7789
fn log_flow_init(
7890
_tv: ThreadVars<'_>,
7991
mut f: Flow<'_>,

rust/ffi/src/threadvars.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
*/
1717

1818
use std::marker::PhantomData;
19+
use std::os::raw::c_void;
1920

2021
use suricata_sys::sys;
22+
use suricata_sys::sys::{SCThreadRegisterInitCallback, ThreadVars as RawThreadVars};
2123

2224
pub struct ThreadVars<'a> {
2325
ptr: *const sys::ThreadVars,
@@ -36,3 +38,38 @@ impl<'a> ThreadVars<'a> {
3638
self.ptr
3739
}
3840
}
41+
42+
/// Register a thread initialization callback.
43+
///
44+
/// The callback is invoked for every thread being initialized during Suricata
45+
/// startup. It receives the `ThreadVars` for the thread that has just been
46+
/// initialized.
47+
///
48+
/// # Safety
49+
///
50+
/// The callback receives raw pointers from Suricata. These pointers are only
51+
/// valid for the duration of the callback invocation and must not be stored.
52+
///
53+
/// The callback must not panic.
54+
pub fn register_init_callback<F>(callback: F) -> Result<(), &'static str>
55+
where
56+
F: for<'a> Fn(ThreadVars<'a>) + Send + Sync + 'static,
57+
{
58+
let user = Box::into_raw(Box::new(callback)) as *mut c_void;
59+
if unsafe { SCThreadRegisterInitCallback(Some(init_callback_wrapper::<F>), user) } {
60+
Ok(())
61+
} else {
62+
unsafe {
63+
drop(Box::from_raw(user as *mut F));
64+
}
65+
Err("Failed to register thread init callback")
66+
}
67+
}
68+
69+
unsafe extern "C" fn init_callback_wrapper<F>(tv: *mut RawThreadVars, user: *mut c_void)
70+
where
71+
F: for<'a> Fn(ThreadVars<'a>) + Send + Sync + 'static,
72+
{
73+
let callback = &*(user as *const F);
74+
callback(ThreadVars::from_ptr(tv));
75+
}

rust/sys/src/sys.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,20 @@ extern "C" {
18781878
Free: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
18791879
) -> SCFlowStorageId;
18801880
}
1881+
#[doc = " \\brief Function type for thread intialization callbacks.\n\n Once registered by SCThreadRegisterInitCallback, this function will\n be called for every thread being initialized during Suricata\n startup.\n\n \\param tv The ThreadVars struct that has just been initialized.\n \\param user The user data provided when registering the callback."]
1882+
pub type SCThreadInitCallbackFn = ::std::option::Option<
1883+
unsafe extern "C" fn(tv: *mut ThreadVars, user: *mut ::std::os::raw::c_void),
1884+
>;
1885+
extern "C" {
1886+
#[doc = " \\brief Register a thread init callback.\n\n Register a user provided function to be called every time a thread is\n initialized for use.\n\n \\param fn Pointer to function to be called\n \\param user Additional user data to be passed to callback\n\n \\returns true if callback was registered, otherwise false if the\n callback could not be registered due to memory allocation error."]
1887+
pub fn SCThreadRegisterInitCallback(
1888+
fn_: SCThreadInitCallbackFn, user: *mut ::std::os::raw::c_void,
1889+
) -> bool;
1890+
}
1891+
extern "C" {
1892+
#[doc = " \\internal\n\n Run all registered flow init callbacks."]
1893+
pub fn SCThreadRunInitCallbacks(tv: *mut ThreadVars);
1894+
}
18811895
extern "C" {
18821896
pub fn SCSRepCatGetByShortname(shortname: *const ::std::os::raw::c_char) -> u8;
18831897
}

src/bindgen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
#include "flow-callbacks.h"
6666
#include "flow-storage.h"
6767

68+
#include "thread-callbacks.h"
69+
6870
#include "reputation.h"
6971
#include "feature.h"
7072
#include "datasets.h"

src/thread-callbacks.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
#ifndef SURICATA_THREAD_CALLBACKS_H
1919
#define SURICATA_THREAD_CALLBACKS_H
2020

21-
#include "suricata-common.h"
21+
#ifndef SURICATA_BINDGEN_H
2222
#include "threadvars.h"
23+
#endif
2324

2425
/** \brief Function type for thread intialization callbacks.
2526
*

0 commit comments

Comments
 (0)