From 57b9473d206ce60a00a22dd727dd9dea3a806ce0 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:07:40 +0800 Subject: [PATCH] Wintun log rewrite --- src/adapter.rs | 6 ++--- src/log.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/adapter.rs b/src/adapter.rs index 08e2028..e7e1c01 100644 --- a/src/adapter.rs +++ b/src/adapter.rs @@ -84,7 +84,7 @@ impl Adapter { let result = unsafe { wintun.WintunCreateAdapter(name_utf16.as_ptr(), tunnel_type_utf16.as_ptr(), &guid_s) }; if result.is_null() { - return Err("Failed to create adapter".into()); + return crate::log::extract_wintun_log_error("WintunCreateAdapter failed")?; } let mut call = || -> Result, Error> { let luid = crate::ffi::alias_to_luid(name)?; @@ -123,7 +123,7 @@ impl Adapter { let result = unsafe { wintun.WintunOpenAdapter(name_utf16.as_ptr()) }; if result.is_null() { - return Err("WintunOpenAdapter failed".into()); + return crate::log::extract_wintun_log_error("WintunOpenAdapter failed")?; } let call = || -> Result, Error> { let luid = crate::ffi::alias_to_luid(name)?; @@ -177,7 +177,7 @@ impl Adapter { let result = unsafe { self.wintun.WintunStartSession(self.adapter.0, capacity) }; if result.is_null() { - return Err("WintunStartSession failed".into()); + return crate::log::extract_wintun_log_error("WintunStartSession failed")?; } // Manual reset, because we use this event once and it must fire on all threads let shutdown_event = SafeEvent::new(true, false)?; diff --git a/src/log.rs b/src/log.rs index b5aa3ef..f6d26bb 100644 --- a/src/log.rs +++ b/src/log.rs @@ -12,25 +12,72 @@ pub fn reset_logger(wintun: &Wintun) { static SET_LOGGER: AtomicBool = AtomicBool::new(false); +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub(crate) struct LogItem { + pub(crate) level: log::Level, + pub(crate) msg: String, + pub(crate) timestamp: u64, +} + +impl LogItem { + pub(crate) fn new(level: log::Level, msg: String, timestamp: u64) -> Self { + Self { level, msg, timestamp } + } +} + +static LOG_CONTAINER: std::sync::LazyLock>> = + std::sync::LazyLock::new(|| std::sync::Mutex::new(std::collections::VecDeque::new())); + /// The logger that is active by default. Logs messages to the log crate /// /// # Safety /// `message` must be a valid pointer that points to an aligned null terminated UTF-16 string pub unsafe extern "stdcall" fn default_logger( level: wintun_raw::WINTUN_LOGGER_LEVEL, - _timestamp: wintun_raw::DWORD64, + timestamp: wintun_raw::DWORD64, message: windows_sys::core::PCWSTR, ) { //Wintun will always give us a valid UTF16 null termineted string let utf8_msg = util::win_pwstr_to_string(message as *mut u16).unwrap_or_else(|e| e.to_string()); - match level { - wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO => log::info!("WinTun: {}", utf8_msg), - wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN => log::warn!("WinTun: {}", utf8_msg), - wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR => log::error!("WinTun: {}", utf8_msg), - _ => log::debug!("WinTun: {} (with invalid log level {})", utf8_msg, level), + + let l = match level { + wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO => log::Level::Info, + wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN => log::Level::Warn, + wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR => log::Level::Error, + _ => log::Level::Error, + }; + + if let Err(e) = LOG_CONTAINER.lock().map(|mut log| { + log.push_back(LogItem::new(l, utf8_msg, timestamp)); + }) { + log::error!("Failed to log message: {}", e); } } +fn get_log() -> Vec { + LOG_CONTAINER + .lock() + .map(|mut log| log.drain(..).collect()) + .unwrap_or_else(|_e| Vec::new()) +} + +fn get_worst_log_msg(container: &[LogItem]) -> Option<&LogItem> { + container.iter().max_by_key(|item| match item.level { + log::Level::Error => 2, + log::Level::Warn => 1, + log::Level::Info => 0, + _ => 0, + }) +} + +pub(crate) fn extract_wintun_log_error(prifix: &str) -> Result { + let info = get_worst_log_msg(&get_log()) + .map(|item| item.msg.clone()) + .unwrap_or_else(|| "No logs".to_string()); + Err(format!("{} \"{}\"", prifix, info)) +} + pub(crate) fn set_default_logger_if_unset(wintun: &Wintun) { if SET_LOGGER .compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)