5 changed files with 136 additions and 2 deletions
@ -0,0 +1,87 @@ |
|||||
|
use crate::error::{Error, Result}; |
||||
|
use std::os::raw::c_void; |
||||
|
|
||||
|
/// # Safety
|
||||
|
///
|
||||
|
/// set traffic status callback.
|
||||
|
#[no_mangle] |
||||
|
pub unsafe extern "C" fn tun2proxy_set_traffic_status_callback( |
||||
|
send_interval_secs: u32, |
||||
|
callback: Option<unsafe extern "C" fn(*const TrafficStatus, *mut c_void)>, |
||||
|
ctx: *mut c_void, |
||||
|
) { |
||||
|
if let Ok(mut cb) = TRAFFIC_STATUS_CALLBACK.lock() { |
||||
|
*cb = Some(TrafficStatusCallback(callback, ctx)); |
||||
|
} else { |
||||
|
log::error!("set traffic status callback failed"); |
||||
|
} |
||||
|
if send_interval_secs > 0 { |
||||
|
SEND_INTERVAL_SECS.store(send_interval_secs as u64, std::sync::atomic::Ordering::Relaxed); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#[repr(C)] |
||||
|
#[derive(Debug, Default, Copy, Clone)] |
||||
|
pub struct TrafficStatus { |
||||
|
pub tx: u64, |
||||
|
pub rx: u64, |
||||
|
} |
||||
|
|
||||
|
#[derive(Clone)] |
||||
|
struct TrafficStatusCallback(Option<unsafe extern "C" fn(*const TrafficStatus, *mut c_void)>, *mut c_void); |
||||
|
|
||||
|
impl TrafficStatusCallback { |
||||
|
unsafe fn call(self, info: &TrafficStatus) { |
||||
|
if let Some(cb) = self.0 { |
||||
|
cb(info, self.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
unsafe impl Send for TrafficStatusCallback {} |
||||
|
unsafe impl Sync for TrafficStatusCallback {} |
||||
|
|
||||
|
static TRAFFIC_STATUS_CALLBACK: std::sync::Mutex<Option<TrafficStatusCallback>> = std::sync::Mutex::new(None); |
||||
|
static SEND_INTERVAL_SECS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1); |
||||
|
|
||||
|
lazy_static::lazy_static! { |
||||
|
static ref TRAFFIC_STATUS: std::sync::Mutex<TrafficStatus> = std::sync::Mutex::new(TrafficStatus::default()); |
||||
|
static ref TIME_STAMP: std::sync::Mutex<std::time::Instant> = std::sync::Mutex::new(std::time::Instant::now()); |
||||
|
} |
||||
|
|
||||
|
pub(crate) fn traffic_status_update(delta_tx: usize, delta_rx: usize) -> Result<()> { |
||||
|
{ |
||||
|
let is_none_or_error = TRAFFIC_STATUS_CALLBACK.lock().map(|guard| guard.is_none()).unwrap_or_else(|e| { |
||||
|
log::error!("Failed to acquire lock: {}", e); |
||||
|
true |
||||
|
}); |
||||
|
if is_none_or_error { |
||||
|
return Ok(()); |
||||
|
} |
||||
|
} |
||||
|
let traffic_status = { |
||||
|
let mut traffic_status = TRAFFIC_STATUS.lock().map_err(|e| Error::from(e.to_string()))?; |
||||
|
traffic_status.tx += delta_tx as u64; |
||||
|
traffic_status.rx += delta_rx as u64; |
||||
|
*traffic_status |
||||
|
}; |
||||
|
let old_time = { *TIME_STAMP.lock().map_err(|e| Error::from(e.to_string()))? }; |
||||
|
let interval_secs = SEND_INTERVAL_SECS.load(std::sync::atomic::Ordering::Relaxed); |
||||
|
if std::time::Instant::now().duration_since(old_time).as_secs() >= interval_secs { |
||||
|
send_traffic_stat(&traffic_status)?; |
||||
|
{ |
||||
|
let mut time_stamp = TIME_STAMP.lock().map_err(|e| Error::from(e.to_string()))?; |
||||
|
*time_stamp = std::time::Instant::now(); |
||||
|
} |
||||
|
} |
||||
|
Ok(()) |
||||
|
} |
||||
|
|
||||
|
fn send_traffic_stat(traffic_status: &TrafficStatus) -> Result<()> { |
||||
|
if let Ok(cb) = TRAFFIC_STATUS_CALLBACK.lock() { |
||||
|
if let Some(cb) = cb.clone() { |
||||
|
unsafe { cb.call(traffic_status) }; |
||||
|
} |
||||
|
} |
||||
|
Ok(()) |
||||
|
} |
||||
Loading…
Reference in new issue