// SPDX-FileCopyrightText: 2023 Foundation Devices Inc. // SPDX-FileCopyrightText: 2024 Foundation Devices Inc. // // SPDX-License-Identifier: MIT use log::{error, warn}; use std::cell::RefCell; use std::error::Error; use std::ffi::{c_char, CString}; //pub(crate) use crate::unwrap_or_return; thread_local! { static LAST_ERROR: RefCell>> = RefCell::new(None); } #[no_mangle] pub unsafe extern "C" fn tor_last_error_message() -> *const c_char { let last_error = match crate::error::take_last_error() { Some(err) => err, None => return CString::new("").unwrap().into_raw(), }; let error_message = last_error.to_string(); CString::new(error_message).unwrap().into_raw() } macro_rules! unwrap_or_return { ($a:expr,$b:expr) => { match $a { Ok(x) => x, Err(e) => { update_last_error(e); return $b; } } }; } /// Update the most recent error, clearing whatever may have been there before. pub fn update_last_error(err: E) { error!("Setting LAST_ERROR: {}", err); { // Print a pseudo-backtrace for this error, following back each error's // cause until we reach the root error. let mut cause = err.source(); while let Some(parent_err) = cause { warn!("Caused by: {}", parent_err); cause = parent_err.source(); } } LAST_ERROR.with(|prev| { *prev.borrow_mut() = Some(Box::new(err)); }); } /// Retrieve the most recent error, clearing it in the process. pub fn take_last_error() -> Option> { LAST_ERROR.with(|prev| prev.borrow_mut().take()) }