Skip to content

Commit

Permalink
Wintun log rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
ssrlive committed Dec 27, 2024
1 parent f45b32a commit 57b9473
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 9 deletions.
6 changes: 3 additions & 3 deletions src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Arc<Adapter>, Error> {
let luid = crate::ffi::alias_to_luid(name)?;
Expand Down Expand Up @@ -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<Arc<Adapter>, Error> {
let luid = crate::ffi::alias_to_luid(name)?;
Expand Down Expand Up @@ -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)?;
Expand Down
59 changes: 53 additions & 6 deletions src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::Mutex<std::collections::VecDeque<LogItem>>> =
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<LogItem> {
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<T>(prifix: &str) -> Result<T, String> {
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)
Expand Down

0 comments on commit 57b9473

Please sign in to comment.