diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e0229fd1..bda21e9d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -399,6 +399,7 @@ jobs: build-android: name: Build library (Android) needs: [checks] + # NB: RUST_VERSION must be <1.68 here to support NDK 17 env: RUST_VERSION: "1.67" diff --git a/src/ffi/error.rs b/src/ffi/error.rs index cf20bc8e..15a55c81 100644 --- a/src/ffi/error.rs +++ b/src/ffi/error.rs @@ -1,13 +1,37 @@ use crate::error::{Error, ErrorKind}; +use std::collections::BTreeMap; use std::os::raw::c_char; -use std::sync::RwLock; +use std::sync::atomic::{AtomicI64, Ordering}; +use std::sync::Mutex; +use std::time::{Duration, Instant}; use ffi_support::rust_string_to_c; - use once_cell::sync::Lazy; -static LAST_ERROR: Lazy>> = Lazy::new(|| RwLock::new(None)); +struct StoredError { + error: Error, + time: Instant, +} + +static ERRORS: Lazy>> = + Lazy::new(|| Mutex::new(BTreeMap::new())); + +static ERROR_INDEX: AtomicI64 = AtomicI64::new(1); + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ErrorHandle(i64); + +impl ErrorHandle { + pub const OK: Self = Self(0); + + pub fn next() -> Self { + Self(ERROR_INDEX.fetch_add(1, Ordering::Relaxed)) + } +} + +pub const ERROR_EXPIRY: Duration = Duration::from_secs(30); #[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] #[repr(i64)] @@ -50,37 +74,45 @@ impl From> for ErrorCode { } #[no_mangle] -pub extern "C" fn askar_get_current_error(error_json_p: *mut *const c_char) -> ErrorCode { - trace!("askar_get_current_error"); +pub extern "C" fn askar_fetch_error( + handle: ErrorHandle, + error_json_p: *mut *const c_char, +) -> ErrorCode { + trace!("askar_fetch_error"); - let error = rust_string_to_c(get_current_error_json()); + let error = rust_string_to_c(fetch_error_json(handle)); unsafe { *error_json_p = error }; ErrorCode::Success } -pub fn get_current_error_json() -> String { +pub fn fetch_error_json(handle: ErrorHandle) -> String { #[derive(Serialize)] struct ErrorJson { code: usize, message: String, } - if let Some(err) = Option::take(&mut *LAST_ERROR.write().unwrap()) { - let message = err.to_string(); - let code = ErrorCode::from(err.kind()) as usize; + let mut errors = ERRORS.lock().unwrap(); + if let Some(err) = errors.remove(&handle) { + let message = err.error.to_string(); + let code = ErrorCode::from(err.error.kind()) as usize; serde_json::json!(&ErrorJson { code, message }).to_string() } else { r#"{"code":0,"message":null}"#.to_owned() } } -pub fn set_last_error(error: Option) -> ErrorCode { - trace!("askar_set_last_error"); - let code = match error.as_ref() { - Some(err) => err.kind.into(), - None => ErrorCode::Success, - }; - *LAST_ERROR.write().unwrap() = error; - code +pub fn store_error(error: Error) -> ErrorHandle { + trace!("askar_store_error"); + let mut errors = ERRORS.lock().unwrap(); + let time = Instant::now(); + while let Some(entry) = errors.first_entry() { + if entry.get().time + ERROR_EXPIRY < time { + entry.remove(); + } + } + let handle = ErrorHandle::next(); + errors.insert(handle, StoredError { error, time }); + handle } diff --git a/src/ffi/key.rs b/src/ffi/key.rs index 099570de..1305534d 100644 --- a/src/ffi/key.rs +++ b/src/ffi/key.rs @@ -3,9 +3,9 @@ use std::{os::raw::c_char, str::FromStr}; use ffi_support::{rust_string_to_c, ByteBuffer, FfiStr}; use super::{ + error::ErrorHandle, handle::ArcHandle, secret::{EncryptedBuffer, SecretBuffer}, - ErrorCode, }; use crate::kms::{ crypto_box, crypto_box_open, crypto_box_random_nonce, crypto_box_seal, crypto_box_seal_open, @@ -25,7 +25,7 @@ pub extern "C" fn askar_key_generate( alg: FfiStr<'_>, ephemeral: i8, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Generate key: {}", alg); @@ -33,7 +33,7 @@ pub extern "C" fn askar_key_generate( let alg = KeyAlg::from_str(alg)?; let key = LocalKey::generate(alg, ephemeral != 0)?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -43,7 +43,7 @@ pub extern "C" fn askar_key_from_seed( seed: ByteBuffer, method: FfiStr<'_>, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Create key from seed: {}", alg); @@ -51,18 +51,18 @@ pub extern "C" fn askar_key_from_seed( let alg = KeyAlg::from_str(alg)?; let key = LocalKey::from_seed(alg, seed.as_slice(), method.as_opt_str())?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] -pub extern "C" fn askar_key_from_jwk(jwk: ByteBuffer, out: *mut LocalKeyHandle) -> ErrorCode { +pub extern "C" fn askar_key_from_jwk(jwk: ByteBuffer, out: *mut LocalKeyHandle) -> ErrorHandle { catch_err! { trace!("Load key from JWK"); check_useful_c_ptr!(out); let key = LocalKey::from_jwk_slice(jwk.as_slice())?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -71,7 +71,7 @@ pub extern "C" fn askar_key_from_public_bytes( alg: FfiStr<'_>, public: ByteBuffer, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Load key from public: {}", alg); @@ -79,7 +79,7 @@ pub extern "C" fn askar_key_from_public_bytes( let alg = KeyAlg::from_str(alg)?; let key = LocalKey::from_public_bytes(alg, public.as_slice())?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -87,14 +87,14 @@ pub extern "C" fn askar_key_from_public_bytes( pub extern "C" fn askar_key_get_public_bytes( handle: LocalKeyHandle, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get key public bytes: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let public = key.to_public_bytes()?; unsafe { *out = SecretBuffer::from_secret(public) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -103,7 +103,7 @@ pub extern "C" fn askar_key_from_secret_bytes( alg: FfiStr<'_>, secret: ByteBuffer, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Load key from secret: {}", alg); @@ -111,7 +111,7 @@ pub extern "C" fn askar_key_from_secret_bytes( let alg = KeyAlg::from_str(alg)?; let key = LocalKey::from_secret_bytes(alg, secret.as_slice())?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -119,14 +119,14 @@ pub extern "C" fn askar_key_from_secret_bytes( pub extern "C" fn askar_key_get_secret_bytes( handle: LocalKeyHandle, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get key secret bytes: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let public = key.to_secret_bytes()?; unsafe { *out = SecretBuffer::from_secret(public) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -135,7 +135,7 @@ pub extern "C" fn askar_key_convert( handle: LocalKeyHandle, alg: FfiStr<'_>, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Convert key: {} to {}", handle, alg); @@ -143,7 +143,7 @@ pub extern "C" fn askar_key_convert( let alg = KeyAlg::from_str(alg)?; let key = handle.load()?.convert_key(alg)?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -153,7 +153,7 @@ pub extern "C" fn askar_key_from_key_exchange( sk_handle: LocalKeyHandle, pk_handle: LocalKeyHandle, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Key exchange: {}, {}, {}", alg, sk_handle, pk_handle); @@ -163,7 +163,7 @@ pub extern "C" fn askar_key_from_key_exchange( let pk = pk_handle.load()?; let key = sk.to_key_exchange(alg, &pk)?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -176,24 +176,24 @@ pub extern "C" fn askar_key_free(handle: LocalKeyHandle) { pub extern "C" fn askar_key_get_algorithm( handle: LocalKeyHandle, out: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get key algorithm: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; unsafe { *out = rust_string_to_c(key.algorithm().as_str()) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] -pub extern "C" fn askar_key_get_ephemeral(handle: LocalKeyHandle, out: *mut i8) -> ErrorCode { +pub extern "C" fn askar_key_get_ephemeral(handle: LocalKeyHandle, out: *mut i8) -> ErrorHandle { catch_err! { trace!("Get key ephemeral: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; unsafe { *out = key.ephemeral as i8 }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -202,7 +202,7 @@ pub extern "C" fn askar_key_get_jwk_public( handle: LocalKeyHandle, alg: FfiStr<'_>, out: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get key JWK public: {}", handle); check_useful_c_ptr!(out); @@ -210,7 +210,7 @@ pub extern "C" fn askar_key_get_jwk_public( let alg = alg.as_opt_str().map(KeyAlg::from_str).transpose()?; let jwk = key.to_jwk_public(alg)?; unsafe { *out = rust_string_to_c(jwk) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -218,14 +218,14 @@ pub extern "C" fn askar_key_get_jwk_public( pub extern "C" fn askar_key_get_jwk_secret( handle: LocalKeyHandle, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get key JWK secret: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let jwk = key.to_jwk_secret()?; unsafe { *out = SecretBuffer::from_secret(jwk) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -234,7 +234,7 @@ pub extern "C" fn askar_key_get_jwk_thumbprint( handle: LocalKeyHandle, alg: FfiStr<'_>, out: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get key JWK thumbprint: {}", handle); check_useful_c_ptr!(out); @@ -242,7 +242,7 @@ pub extern "C" fn askar_key_get_jwk_thumbprint( let alg = alg.as_opt_str().map(KeyAlg::from_str).transpose()?; let thumb = key.to_jwk_thumbprint(alg)?; unsafe { *out = rust_string_to_c(thumb) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -250,14 +250,14 @@ pub extern "C" fn askar_key_get_jwk_thumbprint( pub extern "C" fn askar_key_aead_random_nonce( handle: LocalKeyHandle, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("AEAD create nonce: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let nonce = key.aead_random_nonce()?; unsafe { *out = SecretBuffer::from_secret(nonce) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -265,7 +265,7 @@ pub extern "C" fn askar_key_aead_random_nonce( pub extern "C" fn askar_key_aead_get_params( handle: LocalKeyHandle, out: *mut AeadParams, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("AEAD get params: {}", handle); check_useful_c_ptr!(out); @@ -275,7 +275,7 @@ pub extern "C" fn askar_key_aead_get_params( nonce_length: params.nonce_length as i32, tag_length: params.tag_length as i32 } }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -284,7 +284,7 @@ pub extern "C" fn askar_key_aead_get_padding( handle: LocalKeyHandle, msg_len: i64, out: *mut i32, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("AEAD get padding: {}", handle); check_useful_c_ptr!(out); @@ -294,7 +294,7 @@ pub extern "C" fn askar_key_aead_get_padding( let key = handle.load()?; let padding = key.aead_padding(msg_len as usize); unsafe { *out = padding as i32 }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -305,7 +305,7 @@ pub extern "C" fn askar_key_aead_encrypt( nonce: ByteBuffer, aad: ByteBuffer, out: *mut EncryptedBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("AEAD encrypt: {}", handle); check_useful_c_ptr!(out); @@ -313,7 +313,7 @@ pub extern "C" fn askar_key_aead_encrypt( let enc = key.aead_encrypt(message.as_slice(), nonce.as_slice(), aad.as_slice())?; let result = EncryptedBuffer::from_encrypted(enc); unsafe { *out = result }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -325,14 +325,14 @@ pub extern "C" fn askar_key_aead_decrypt( tag: ByteBuffer, aad: ByteBuffer, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("AEAD decrypt: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let dec = key.aead_decrypt((ciphertext.as_slice(), tag.as_slice()), nonce.as_slice(), aad.as_slice())?; unsafe { *out = SecretBuffer::from_secret(dec) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -342,14 +342,14 @@ pub extern "C" fn askar_key_sign_message( message: ByteBuffer, sig_type: FfiStr<'_>, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Sign message: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let sig = key.sign_message(message.as_slice(), sig_type.as_opt_str())?; unsafe { *out = SecretBuffer::from_secret(sig) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -360,14 +360,14 @@ pub extern "C" fn askar_key_verify_signature( signature: ByteBuffer, sig_type: FfiStr<'_>, out: *mut i8, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Verify signature: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let verify = key.verify_signature(message.as_slice(), signature.as_slice(), sig_type.as_opt_str())?; unsafe { *out = verify as i8 }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -377,7 +377,7 @@ pub extern "C" fn askar_key_wrap_key( other: LocalKeyHandle, nonce: ByteBuffer, out: *mut EncryptedBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Wrap key: {}", handle); check_useful_c_ptr!(out); @@ -385,7 +385,7 @@ pub extern "C" fn askar_key_wrap_key( let other = other.load()?; let result = key.wrap_key(&other, nonce.as_slice())?; unsafe { *out = EncryptedBuffer::from_encrypted(result) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -397,7 +397,7 @@ pub extern "C" fn askar_key_unwrap_key( nonce: ByteBuffer, tag: ByteBuffer, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("Unwrap key: {}", handle); @@ -406,18 +406,18 @@ pub extern "C" fn askar_key_unwrap_key( let alg = KeyAlg::from_str(alg)?; let result = key.unwrap_key(alg, (ciphertext.as_slice(), tag.as_slice()), nonce.as_slice())?; unsafe { *out = LocalKeyHandle::create(result) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] -pub extern "C" fn askar_key_crypto_box_random_nonce(out: *mut SecretBuffer) -> ErrorCode { +pub extern "C" fn askar_key_crypto_box_random_nonce(out: *mut SecretBuffer) -> ErrorHandle { catch_err! { trace!("crypto box random nonce"); check_useful_c_ptr!(out); let nonce = crypto_box_random_nonce()?; unsafe { *out = SecretBuffer::from_secret(&nonce[..]) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -428,7 +428,7 @@ pub extern "C" fn askar_key_crypto_box( message: ByteBuffer, nonce: ByteBuffer, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("crypto box: {}, {}", recip_key, sender_key); check_useful_c_ptr!(out); @@ -441,7 +441,7 @@ pub extern "C" fn askar_key_crypto_box( nonce.as_slice() )?; unsafe { *out = SecretBuffer::from_secret(message) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -452,7 +452,7 @@ pub extern "C" fn askar_key_crypto_box_open( message: ByteBuffer, nonce: ByteBuffer, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("crypto box open: {}, {}", recip_key, sender_key); check_useful_c_ptr!(out); @@ -465,7 +465,7 @@ pub extern "C" fn askar_key_crypto_box_open( nonce.as_slice() )?; unsafe { *out = SecretBuffer::from_secret(message) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -474,14 +474,14 @@ pub extern "C" fn askar_key_crypto_box_seal( handle: LocalKeyHandle, message: ByteBuffer, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("crypto box seal: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let enc = crypto_box_seal(&key, message.as_slice())?; unsafe { *out = SecretBuffer::from_secret(enc) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -490,14 +490,14 @@ pub extern "C" fn askar_key_crypto_box_seal_open( handle: LocalKeyHandle, ciphertext: ByteBuffer, out: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("crypto box seal open: {}", handle); check_useful_c_ptr!(out); let key = handle.load()?; let enc = crypto_box_seal_open(&key, ciphertext.as_slice())?; unsafe { *out = SecretBuffer::from_secret(enc) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -511,7 +511,7 @@ pub extern "C" fn askar_key_derive_ecdh_es( apv: ByteBuffer, receive: i8, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("ECDH-ES: {}", alg); @@ -529,7 +529,7 @@ pub extern "C" fn askar_key_derive_ecdh_es( receive == 1 )?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -545,7 +545,7 @@ pub extern "C" fn askar_key_derive_ecdh_1pu( cc_tag: ByteBuffer, receive: i8, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let alg = alg.as_opt_str().unwrap_or_default(); trace!("ECDH-1PU: {}", alg); @@ -566,6 +566,6 @@ pub extern "C" fn askar_key_derive_ecdh_1pu( receive == 1 )?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } diff --git a/src/ffi/log.rs b/src/ffi/log.rs index abcc7c8e..17884bf8 100644 --- a/src/ffi/log.rs +++ b/src/ffi/log.rs @@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use log::{LevelFilter, Metadata, Record}; use once_cell::sync::OnceCell; -use super::error::ErrorCode; +use super::error::ErrorHandle; use crate::error::Error; static LOGGER: OnceCell = OnceCell::new(); @@ -111,7 +111,7 @@ pub extern "C" fn askar_set_custom_logger( enabled: Option, flush: Option, max_level: i32, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { let max_level = get_level_filter(max_level)?; if LOGGER.set(CustomLogger::new(context, enabled, log, flush)).is_err() { @@ -121,7 +121,7 @@ pub extern "C" fn askar_set_custom_logger( |_| err_msg!(Input, "Repeated logger initialization"))?; log::set_max_level(max_level); debug!("Initialized custom logger"); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -134,20 +134,20 @@ pub extern "C" fn askar_clear_custom_logger() { } #[no_mangle] -pub extern "C" fn askar_set_default_logger() -> ErrorCode { +pub extern "C" fn askar_set_default_logger() -> ErrorHandle { catch_err! { env_logger::try_init().map_err( |_| err_msg!(Input, "Repeated logger initialization"))?; debug!("Initialized default logger"); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] -pub extern "C" fn askar_set_max_log_level(max_level: i32) -> ErrorCode { +pub extern "C" fn askar_set_max_log_level(max_level: i32) -> ErrorHandle { catch_err! { log::set_max_level(get_level_filter(max_level)?); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } diff --git a/src/ffi/macros.rs b/src/ffi/macros.rs index 0f0410e7..8d92eb79 100644 --- a/src/ffi/macros.rs +++ b/src/ffi/macros.rs @@ -3,11 +3,11 @@ macro_rules! catch_err { match std::panic::catch_unwind(move || -> Result<_, $crate::error::Error> {$($e)*}) { Ok(Ok(a)) => a, Ok(Err(err)) => { // lib error - $crate::ffi::error::set_last_error(Some(err)) + $crate::ffi::error::store_error(err) } Err(_) => { // panic error let err: $crate::error::Error = err_msg!(Unexpected, "Panic during execution"); - $crate::ffi::error::set_last_error(Some(err)) + $crate::ffi::error::store_error(err) } } } diff --git a/src/ffi/migration.rs b/src/ffi/migration.rs index c397aa84..e540b1d8 100644 --- a/src/ffi/migration.rs +++ b/src/ffi/migration.rs @@ -4,7 +4,7 @@ use crate::storage::future::spawn_ok; use crate::storage::migration::IndySdkToAriesAskarMigration; use super::{ - error::{set_last_error, ErrorCode}, + error::{store_error, ErrorHandle}, CallbackId, EnsureCallback, }; @@ -24,9 +24,9 @@ pub extern "C" fn askar_migrate_indy_sdk( wallet_name: FfiStr<'_>, wallet_key: FfiStr<'_>, kdf_level: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err!( trace!("Migrate sqlite wallet from indy-sdk structure to aries-askar"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -37,8 +37,8 @@ pub extern "C" fn askar_migrate_indy_sdk( let cb = EnsureCallback::new(move |result| match result { - Ok(_) => cb(cb_id, ErrorCode::Success), - Err(err) => cb(cb_id, set_last_error(Some(err))), + Ok(_) => cb(cb_id, ErrorHandle::OK), + Err(err) => cb(cb_id, store_error(err)), }); spawn_ok(async move { @@ -49,6 +49,6 @@ pub extern "C" fn askar_migrate_indy_sdk( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) ) } diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index baa78d32..fdd9f054 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -28,7 +28,6 @@ mod tags; #[cfg(all(feature = "migration", feature = "sqlite"))] mod migration; -use self::error::ErrorCode; use crate::error::Error; pub type CallbackId = i64; diff --git a/src/ffi/result_list.rs b/src/ffi/result_list.rs index a4edd0f1..1e466064 100644 --- a/src/ffi/result_list.rs +++ b/src/ffi/result_list.rs @@ -1,7 +1,8 @@ use std::{ffi::CString, os::raw::c_char, ptr}; use super::{ - handle::ArcHandle, key::LocalKeyHandle, secret::SecretBuffer, tags::EntryTagSet, ErrorCode, + error::ErrorHandle, handle::ArcHandle, key::LocalKeyHandle, secret::SecretBuffer, + tags::EntryTagSet, }; use crate::{entry::Entry, error::Error, kms::KeyEntry}; @@ -54,12 +55,12 @@ pub type EntryListHandle = ArcHandle; pub type FfiEntryList = FfiResultList; #[no_mangle] -pub extern "C" fn askar_entry_list_count(handle: EntryListHandle, count: *mut i32) -> ErrorCode { +pub extern "C" fn askar_entry_list_count(handle: EntryListHandle, count: *mut i32) -> ErrorHandle { catch_err! { check_useful_c_ptr!(count); let results = handle.load()?; unsafe { *count = results.len() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -68,13 +69,13 @@ pub extern "C" fn askar_entry_list_get_category( handle: EntryListHandle, index: i32, category: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(category); let results = handle.load()?; let entry = results.get_row(index)?; unsafe { *category = CString::new(entry.category.as_str()).unwrap().into_raw() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -83,13 +84,13 @@ pub extern "C" fn askar_entry_list_get_name( handle: EntryListHandle, index: i32, name: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(name); let results = handle.load()?; let entry = results.get_row(index)?; unsafe { *name = CString::new(entry.name.as_str()).unwrap().into_raw() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -98,13 +99,13 @@ pub extern "C" fn askar_entry_list_get_value( handle: EntryListHandle, index: i32, value: *mut SecretBuffer, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(value); let results = handle.load()?; let entry = results.get_row(index)?; unsafe { *value = SecretBuffer::from_secret(entry.value.as_ref()); } - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -113,7 +114,7 @@ pub extern "C" fn askar_entry_list_get_tags( handle: EntryListHandle, index: i32, tags: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(tags); let results = handle.load()?; @@ -124,7 +125,7 @@ pub extern "C" fn askar_entry_list_get_tags( let tag_json = serde_json::to_vec(&EntryTagSet::from(entry.tags.as_slice())).unwrap(); unsafe { *tags = CString::new(tag_json).unwrap().into_raw() }; } - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -141,12 +142,12 @@ pub type FfiKeyEntryList = FfiResultList; pub extern "C" fn askar_key_entry_list_count( handle: KeyEntryListHandle, count: *mut i32, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(count); let results = handle.load()?; unsafe { *count = results.len() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -160,7 +161,7 @@ pub extern "C" fn askar_key_entry_list_get_algorithm( handle: KeyEntryListHandle, index: i32, alg: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(alg); let results = handle.load()?; @@ -170,7 +171,7 @@ pub extern "C" fn askar_key_entry_list_get_algorithm( } else { unsafe { *alg = ptr::null() }; } - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -179,13 +180,13 @@ pub extern "C" fn askar_key_entry_list_get_name( handle: KeyEntryListHandle, index: i32, name: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(name); let results = handle.load()?; let entry = results.get_row(index)?; unsafe { *name = CString::new(entry.name.as_str()).unwrap().into_raw() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -194,7 +195,7 @@ pub extern "C" fn askar_key_entry_list_get_metadata( handle: KeyEntryListHandle, index: i32, metadata: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(metadata); let results = handle.load()?; @@ -204,7 +205,7 @@ pub extern "C" fn askar_key_entry_list_get_metadata( } else { unsafe { *metadata = ptr::null(); } } - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -213,7 +214,7 @@ pub extern "C" fn askar_key_entry_list_get_tags( handle: KeyEntryListHandle, index: i32, tags: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(tags); let results = handle.load()?; @@ -224,7 +225,7 @@ pub extern "C" fn askar_key_entry_list_get_tags( let tag_json = serde_json::to_vec(&EntryTagSet::from(entry.tags.as_slice())).unwrap(); unsafe { *tags = CString::new(tag_json).unwrap().into_raw() }; } - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -233,7 +234,7 @@ pub extern "C" fn askar_key_entry_list_load_local( handle: KeyEntryListHandle, index: i32, out: *mut LocalKeyHandle, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Load key"); check_useful_c_ptr!(out); @@ -241,7 +242,7 @@ pub extern "C" fn askar_key_entry_list_load_local( let entry = results.get_row(index)?; let key = entry.load_local_key()?; unsafe { *out = LocalKeyHandle::create(key) }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -250,12 +251,15 @@ pub type StringListHandle = ArcHandle; pub type FfiStringList = FfiResultList; #[no_mangle] -pub extern "C" fn askar_string_list_count(handle: StringListHandle, count: *mut i32) -> ErrorCode { +pub extern "C" fn askar_string_list_count( + handle: StringListHandle, + count: *mut i32, +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(count); let results = handle.load()?; unsafe { *count = results.len() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -264,13 +268,13 @@ pub extern "C" fn askar_string_list_get_item( handle: StringListHandle, index: i32, item: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { check_useful_c_ptr!(item); let results = handle.load()?; let entry = results.get_row(index)?; unsafe { *item = CString::new(entry.clone()).unwrap().into_raw() }; - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } diff --git a/src/ffi/store.rs b/src/ffi/store.rs index 95e7f0c7..b62c0a71 100644 --- a/src/ffi/store.rs +++ b/src/ffi/store.rs @@ -5,13 +5,13 @@ use ffi_support::{rust_string_to_c, ByteBuffer, FfiStr}; use once_cell::sync::Lazy; use super::{ - error::set_last_error, + error::{store_error, ErrorHandle}, key::LocalKeyHandle, result_list::{ EntryListHandle, FfiEntryList, FfiKeyEntryList, KeyEntryListHandle, StringListHandle, }, tags::EntryTagSet, - CallbackId, EnsureCallback, ErrorCode, ResourceHandle, + CallbackId, EnsureCallback, ResourceHandle, }; use crate::{ entry::{Entry, EntryOperation, Scan, TagFilter}, @@ -131,7 +131,7 @@ where pub extern "C" fn askar_store_generate_raw_key( seed: ByteBuffer, out: *mut *const c_char, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Create raw store key"); let seed = match seed.as_slice() { @@ -140,7 +140,7 @@ pub extern "C" fn askar_store_generate_raw_key( }; let key = Store::new_raw_key(seed)?; unsafe { *out = rust_string_to_c(key.to_string()); } - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -151,9 +151,9 @@ pub extern "C" fn askar_store_provision( pass_key: FfiStr<'_>, profile: FfiStr<'_>, recreate: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Provision store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -168,9 +168,9 @@ pub extern "C" fn askar_store_provision( match result { Ok(sid) => { debug!("Provisioned store {}", sid); - cb(cb_id, ErrorCode::Success, sid) + cb(cb_id, ErrorHandle::OK, sid) } - Err(err) => cb(cb_id, set_last_error(Some(err)), StoreHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), StoreHandle::invalid()), } ); spawn_ok(async move { @@ -186,7 +186,7 @@ pub extern "C" fn askar_store_provision( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -196,9 +196,9 @@ pub extern "C" fn askar_store_open( key_method: FfiStr<'_>, pass_key: FfiStr<'_>, profile: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Open store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -213,9 +213,9 @@ pub extern "C" fn askar_store_open( match result { Ok(sid) => { debug!("Opened store {}", sid); - cb(cb_id, ErrorCode::Success, sid) + cb(cb_id, ErrorHandle::OK, sid) } - Err(err) => cb(cb_id, set_last_error(Some(err)), StoreHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), StoreHandle::invalid()), } ); spawn_ok(async move { @@ -230,31 +230,31 @@ pub extern "C" fn askar_store_open( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] pub extern "C" fn askar_store_remove( spec_uri: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Remove store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; let spec_uri = spec_uri.into_opt_string().ok_or_else(|| err_msg!("No store URI provided"))?; let cb = EnsureCallback::new(move |result: Result| match result { - Ok(removed) => cb(cb_id, ErrorCode::Success, removed as i8), - Err(err) => cb(cb_id, set_last_error(Some(err)), 0), + Ok(removed) => cb(cb_id, ErrorHandle::OK, removed as i8), + Err(err) => cb(cb_id, store_error(err), 0), } ); spawn_ok(async move { let result = Store::remove(spec_uri.as_str()).await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -262,17 +262,17 @@ pub extern "C" fn askar_store_remove( pub extern "C" fn askar_store_create_profile( handle: StoreHandle, profile: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Create profile"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; let profile = profile.into_opt_string(); let cb = EnsureCallback::new(move |result| match result { - Ok(name) => cb(cb_id, ErrorCode::Success, rust_string_to_c(name)), - Err(err) => cb(cb_id, set_last_error(Some(err)), ptr::null()), + Ok(name) => cb(cb_id, ErrorHandle::OK, rust_string_to_c(name)), + Err(err) => cb(cb_id, store_error(err), ptr::null()), } ); spawn_ok(async move { @@ -283,23 +283,23 @@ pub extern "C" fn askar_store_create_profile( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] pub extern "C" fn askar_store_get_profile_name( handle: StoreHandle, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get profile name"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; let cb = EnsureCallback::new(move |result| match result { - Ok(name) => cb(cb_id, ErrorCode::Success, rust_string_to_c(name)), - Err(err) => cb(cb_id, set_last_error(Some(err)), ptr::null_mut()), + Ok(name) => cb(cb_id, ErrorHandle::OK, rust_string_to_c(name)), + Err(err) => cb(cb_id, store_error(err), ptr::null_mut()), } ); spawn_ok(async move { @@ -309,16 +309,16 @@ pub extern "C" fn askar_store_get_profile_name( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] pub extern "C" fn askar_store_list_profiles( handle: StoreHandle, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("List profiles"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -326,9 +326,9 @@ pub extern "C" fn askar_store_list_profiles( match result { Ok(rows) => { let res = StringListHandle::create(FfiStringList::from(rows)); - cb(cb_id, ErrorCode::Success, res) + cb(cb_id, ErrorHandle::OK, res) }, - Err(err) => cb(cb_id, set_last_error(Some(err)), StringListHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), StringListHandle::invalid()), } ); spawn_ok(async move { @@ -339,7 +339,7 @@ pub extern "C" fn askar_store_list_profiles( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -347,17 +347,17 @@ pub extern "C" fn askar_store_list_profiles( pub extern "C" fn askar_store_remove_profile( handle: StoreHandle, profile: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Remove profile"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; let profile = profile.into_opt_string().ok_or_else(|| err_msg!("Profile name not provided"))?; let cb = EnsureCallback::new(move |result| match result { - Ok(removed) => cb(cb_id, ErrorCode::Success, removed as i8), - Err(err) => cb(cb_id, set_last_error(Some(err)), 0), + Ok(removed) => cb(cb_id, ErrorHandle::OK, removed as i8), + Err(err) => cb(cb_id, store_error(err), 0), } ); spawn_ok(async move { @@ -367,24 +367,24 @@ pub extern "C" fn askar_store_remove_profile( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] pub extern "C" fn askar_store_get_default_profile( handle: StoreHandle, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Get default profile"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; let cb = EnsureCallback::new(move |result: Result| match result { - Ok(name) => cb(cb_id, ErrorCode::Success, + Ok(name) => cb(cb_id, ErrorHandle::OK, CString::new(name.as_str()).unwrap().into_raw() as *const c_char), - Err(err) => cb(cb_id, set_last_error(Some(err)), ptr::null()), + Err(err) => cb(cb_id, store_error(err), ptr::null()), } ); spawn_ok(async move { @@ -394,7 +394,7 @@ pub extern "C" fn askar_store_get_default_profile( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -402,17 +402,17 @@ pub extern "C" fn askar_store_get_default_profile( pub extern "C" fn askar_store_set_default_profile( handle: StoreHandle, profile: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Set default profile"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; let profile = profile.into_opt_string().ok_or_else(|| err_msg!("Profile name not provided"))?; let cb = EnsureCallback::new(move |result| match result { - Ok(_) => cb(cb_id, ErrorCode::Success), - Err(err) => cb(cb_id, set_last_error(Some(err))), + Ok(_) => cb(cb_id, ErrorHandle::OK), + Err(err) => cb(cb_id, store_error(err)), } ); spawn_ok(async move { @@ -422,7 +422,7 @@ pub extern "C" fn askar_store_set_default_profile( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -431,9 +431,9 @@ pub extern "C" fn askar_store_rekey( handle: StoreHandle, key_method: FfiStr<'_>, pass_key: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Re-key store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -444,8 +444,8 @@ pub extern "C" fn askar_store_rekey( let pass_key = PassKey::from(pass_key.as_opt_str()).into_owned(); let cb = EnsureCallback::new(move |result| match result { - Ok(_) => cb(cb_id, ErrorCode::Success), - Err(err) => cb(cb_id, set_last_error(Some(err))), + Ok(_) => cb(cb_id, ErrorHandle::OK), + Err(err) => cb(cb_id, store_error(err)), } ); spawn_ok(async move { @@ -457,7 +457,7 @@ pub extern "C" fn askar_store_rekey( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -468,9 +468,9 @@ pub extern "C" fn askar_store_copy( key_method: FfiStr<'_>, pass_key: FfiStr<'_>, recreate: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Copy store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -482,8 +482,8 @@ pub extern "C" fn askar_store_copy( let pass_key = PassKey::from(pass_key.as_opt_str()).into_owned(); let cb = EnsureCallback::new(move |result| match result { - Ok(handle) => cb(cb_id, ErrorCode::Success, handle), - Err(err) => cb(cb_id, set_last_error(Some(err)), StoreHandle::invalid()), + Ok(handle) => cb(cb_id, ErrorHandle::OK, handle), + Err(err) => cb(cb_id, store_error(err), StoreHandle::invalid()), } ); spawn_ok(async move { @@ -495,23 +495,23 @@ pub extern "C" fn askar_store_copy( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] pub extern "C" fn askar_store_close( handle: StoreHandle, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Close store"); let cb = cb.map(|cb| { EnsureCallback::new(move |result| match result { - Ok(_) => cb(cb_id, ErrorCode::Success), - Err(err) => cb(cb_id, set_last_error(Some(err))), + Ok(_) => cb(cb_id, ErrorHandle::OK), + Err(err) => cb(cb_id, store_error(err)), } ) }); @@ -534,7 +534,7 @@ pub extern "C" fn askar_store_close( error!("{}", err); } }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -546,9 +546,9 @@ pub extern "C" fn askar_scan_start( tag_filter: FfiStr<'_>, offset: i64, limit: i64, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Scan store start"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -559,9 +559,9 @@ pub extern "C" fn askar_scan_start( match result { Ok(scan_handle) => { debug!("Started scan {} on store {}", scan_handle, handle); - cb(cb_id, ErrorCode::Success, scan_handle) + cb(cb_id, ErrorHandle::OK, scan_handle) } - Err(err) => cb(cb_id, set_last_error(Some(err)), ScanHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), ScanHandle::invalid()), } ); spawn_ok(async move { @@ -572,16 +572,16 @@ pub extern "C" fn askar_scan_start( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] pub extern "C" fn askar_scan_next( handle: ScanHandle, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Scan store next"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -589,10 +589,10 @@ pub extern "C" fn askar_scan_next( match result { Ok(Some(entries)) => { let results = EntryListHandle::create(FfiEntryList::from(entries)); - cb(cb_id, ErrorCode::Success, results) + cb(cb_id, ErrorHandle::OK, results) }, - Ok(None) => cb(cb_id, ErrorCode::Success, EntryListHandle::invalid()), - Err(err) => cb(cb_id, set_last_error(Some(err)), EntryListHandle::invalid()), + Ok(None) => cb(cb_id, ErrorHandle::OK, EntryListHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), EntryListHandle::invalid()), } ); spawn_ok(async move { @@ -603,12 +603,12 @@ pub extern "C" fn askar_scan_next( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } #[no_mangle] -pub extern "C" fn askar_scan_free(handle: ScanHandle) -> ErrorCode { +pub extern "C" fn askar_scan_free(handle: ScanHandle) -> ErrorHandle { catch_err! { trace!("Close scan"); spawn_ok(async move { @@ -620,7 +620,7 @@ pub extern "C" fn askar_scan_free(handle: ScanHandle) -> ErrorCode { debug!("Scan not found for closing: {}", handle); } }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -629,9 +629,9 @@ pub extern "C" fn askar_session_start( handle: StoreHandle, profile: FfiStr<'_>, as_transaction: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Session start"); let profile = profile.into_opt_string(); @@ -640,9 +640,9 @@ pub extern "C" fn askar_session_start( match result { Ok(sess_handle) => { debug!("Started session {} on store {} (txn: {})", sess_handle, handle, as_transaction != 0); - cb(cb_id, ErrorCode::Success, sess_handle) + cb(cb_id, ErrorHandle::OK, sess_handle) } - Err(err) => cb(cb_id, set_last_error(Some(err)), SessionHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), SessionHandle::invalid()), } ); spawn_ok(async move { @@ -657,7 +657,7 @@ pub extern "C" fn askar_session_start( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -666,9 +666,9 @@ pub extern "C" fn askar_session_count( handle: SessionHandle, category: FfiStr<'_>, tag_filter: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Count from store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -676,8 +676,8 @@ pub extern "C" fn askar_session_count( let tag_filter = tag_filter.as_opt_str().map(TagFilter::from_str).transpose()?; let cb = EnsureCallback::new(move |result: Result| match result { - Ok(count) => cb(cb_id, ErrorCode::Success, count), - Err(err) => cb(cb_id, set_last_error(Some(err)), 0), + Ok(count) => cb(cb_id, ErrorHandle::OK, count), + Err(err) => cb(cb_id, store_error(err), 0), } ); spawn_ok(async move { @@ -687,7 +687,7 @@ pub extern "C" fn askar_session_count( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -697,9 +697,9 @@ pub extern "C" fn askar_session_fetch( category: FfiStr<'_>, name: FfiStr<'_>, for_update: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Fetch from store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -709,10 +709,10 @@ pub extern "C" fn askar_session_fetch( match result { Ok(Some(entry)) => { let results = EntryListHandle::create(FfiEntryList::from(entry)); - cb(cb_id, ErrorCode::Success, results) + cb(cb_id, ErrorHandle::OK, results) }, - Ok(None) => cb(cb_id, ErrorCode::Success, EntryListHandle::invalid()), - Err(err) => cb(cb_id, set_last_error(Some(err)), EntryListHandle::invalid()), + Ok(None) => cb(cb_id, ErrorHandle::OK, EntryListHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), EntryListHandle::invalid()), } ); spawn_ok(async move { @@ -722,7 +722,7 @@ pub extern "C" fn askar_session_fetch( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -733,9 +733,9 @@ pub extern "C" fn askar_session_fetch_all( tag_filter: FfiStr<'_>, limit: i64, for_update: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Count from store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -746,9 +746,9 @@ pub extern "C" fn askar_session_fetch_all( match result { Ok(rows) => { let results = EntryListHandle::create(FfiEntryList::from(rows)); - cb(cb_id, ErrorCode::Success, results) + cb(cb_id, ErrorHandle::OK, results) } - Err(err) => cb(cb_id, set_last_error(Some(err)), EntryListHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), EntryListHandle::invalid()), } ); spawn_ok(async move { @@ -758,7 +758,7 @@ pub extern "C" fn askar_session_fetch_all( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -767,9 +767,9 @@ pub extern "C" fn askar_session_remove_all( handle: SessionHandle, category: FfiStr<'_>, tag_filter: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Count from store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -778,9 +778,9 @@ pub extern "C" fn askar_session_remove_all( let cb = EnsureCallback::new(move |result| match result { Ok(removed) => { - cb(cb_id, ErrorCode::Success, removed) + cb(cb_id, ErrorHandle::OK, removed) } - Err(err) => cb(cb_id, set_last_error(Some(err)), 0), + Err(err) => cb(cb_id, store_error(err), 0), } ); spawn_ok(async move { @@ -790,7 +790,7 @@ pub extern "C" fn askar_session_remove_all( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -803,9 +803,9 @@ pub extern "C" fn askar_session_update( value: ByteBuffer, tags: FfiStr<'_>, expiry_ms: i64, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Update store"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -834,8 +834,8 @@ pub extern "C" fn askar_session_update( }; let cb = EnsureCallback::new(move |result| match result { - Ok(_) => cb(cb_id, ErrorCode::Success), - Err(err) => cb(cb_id, set_last_error(Some(err))), + Ok(_) => cb(cb_id, ErrorHandle::OK), + Err(err) => cb(cb_id, store_error(err)), } ); spawn_ok(async move { @@ -845,7 +845,7 @@ pub extern "C" fn askar_session_update( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -857,9 +857,9 @@ pub extern "C" fn askar_session_insert_key( metadata: FfiStr<'_>, tags: FfiStr<'_>, expiry_ms: i64, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Insert key"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -883,9 +883,9 @@ pub extern "C" fn askar_session_insert_key( let cb = EnsureCallback::new(move |result| match result { Ok(_) => { - cb(cb_id, ErrorCode::Success) + cb(cb_id, ErrorHandle::OK) } - Err(err) => cb(cb_id, set_last_error(Some(err))), + Err(err) => cb(cb_id, store_error(err)), } ); @@ -902,7 +902,7 @@ pub extern "C" fn askar_session_insert_key( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -911,9 +911,9 @@ pub extern "C" fn askar_session_fetch_key( handle: SessionHandle, name: FfiStr<'_>, for_update: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Fetch key"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -923,12 +923,12 @@ pub extern "C" fn askar_session_fetch_key( match result { Ok(Some(entry)) => { let results = KeyEntryListHandle::create(FfiKeyEntryList::from(entry)); - cb(cb_id, ErrorCode::Success, results) + cb(cb_id, ErrorHandle::OK, results) } Ok(None) => { - cb(cb_id, ErrorCode::Success, KeyEntryListHandle::invalid()) + cb(cb_id, ErrorHandle::OK, KeyEntryListHandle::invalid()) } - Err(err) => cb(cb_id, set_last_error(Some(err)), KeyEntryListHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), KeyEntryListHandle::invalid()), } ); @@ -942,7 +942,7 @@ pub extern "C" fn askar_session_fetch_key( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -954,9 +954,9 @@ pub extern "C" fn askar_session_fetch_all_keys( tag_filter: FfiStr<'_>, limit: i64, for_update: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Fetch all keys"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -969,9 +969,9 @@ pub extern "C" fn askar_session_fetch_all_keys( match result { Ok(entries) => { let results = KeyEntryListHandle::create(FfiKeyEntryList::from(entries)); - cb(cb_id, ErrorCode::Success, results) + cb(cb_id, ErrorHandle::OK, results) } - Err(err) => cb(cb_id, set_last_error(Some(err)), KeyEntryListHandle::invalid()), + Err(err) => cb(cb_id, store_error(err), KeyEntryListHandle::invalid()), } ); @@ -988,7 +988,7 @@ pub extern "C" fn askar_session_fetch_all_keys( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -999,9 +999,9 @@ pub extern "C" fn askar_session_update_key( metadata: FfiStr<'_>, tags: FfiStr<'_>, expiry_ms: i64, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Update key"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -1024,9 +1024,9 @@ pub extern "C" fn askar_session_update_key( let cb = EnsureCallback::new(move |result| match result { Ok(_) => { - cb(cb_id, ErrorCode::Success) + cb(cb_id, ErrorHandle::OK) } - Err(err) => cb(cb_id, set_last_error(Some(err))), + Err(err) => cb(cb_id, store_error(err)), } ); @@ -1043,7 +1043,7 @@ pub extern "C" fn askar_session_update_key( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -1051,9 +1051,9 @@ pub extern "C" fn askar_session_update_key( pub extern "C" fn askar_session_remove_key( handle: SessionHandle, name: FfiStr<'_>, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Remove key"); let cb = cb.ok_or_else(|| err_msg!("No callback provided"))?; @@ -1061,9 +1061,9 @@ pub extern "C" fn askar_session_remove_key( let cb = EnsureCallback::new(move |result| match result { Ok(_) => { - cb(cb_id, ErrorCode::Success) + cb(cb_id, ErrorHandle::OK) } - Err(err) => cb(cb_id, set_last_error(Some(err))), + Err(err) => cb(cb_id, store_error(err)), } ); @@ -1076,7 +1076,7 @@ pub extern "C" fn askar_session_remove_key( }.await; cb.resolve(result); }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } @@ -1084,17 +1084,17 @@ pub extern "C" fn askar_session_remove_key( pub extern "C" fn askar_session_close( handle: SessionHandle, commit: i8, - cb: Option, + cb: Option, cb_id: CallbackId, -) -> ErrorCode { +) -> ErrorHandle { catch_err! { trace!("Close session"); let cb = cb.map(|cb| { EnsureCallback::new(move |result| match result { - Ok(_) => cb(cb_id, ErrorCode::Success), + Ok(_) => cb(cb_id, ErrorHandle::OK), Err(err) => { - cb(cb_id, set_last_error(Some(err))) + cb(cb_id, store_error(err)) } } ) @@ -1124,6 +1124,6 @@ pub extern "C" fn askar_session_close( error!("{}", err); } }); - Ok(ErrorCode::Success) + Ok(ErrorHandle::OK) } } diff --git a/wrappers/python/aries_askar/bindings/lib.py b/wrappers/python/aries_askar/bindings/lib.py index 6c13cfb7..f5030539 100644 --- a/wrappers/python/aries_askar/bindings/lib.py +++ b/wrappers/python/aries_askar/bindings/lib.py @@ -44,6 +44,15 @@ } +class ErrorHandle(Structure): + _fields_ = [ + ("value", c_int64), + ] + + def __bool__(self) -> bool: + return self.value != 0 + + def _convert_log_level(level: Union[str, int, None]): if level is None or level == "-1": return -1 @@ -187,14 +196,15 @@ def _enabled_cb(_context, level: int) -> bool: (c_void_p, c_void_p, c_void_p, c_void_p, c_int32), restype=c_int64, ) - if set_logger( + err = set_logger( None, # context self._log_cb, self._log_enabled_cb, None, # flush level, - ): - raise self.get_current_error(True) + ) + if err: + raise self.fetch_error(err) try: finalize(self, self.method("askar_clear_custom_logger", None, restype=None)) @@ -204,19 +214,19 @@ def _enabled_cb(_context, level: int) -> bool: def invoke(self, name, argtypes, *args): """Perform a synchronous library function call.""" - method = self.method(name, argtypes, restype=c_int64) + method = self.method(name, argtypes, restype=ErrorHandle) if not method: raise ValueError(f"FFI method not found: {name}") args = _load_method_arguments(name, argtypes, args) - result = method(*args) - if result: - raise self.get_current_error(True) + err = method(*args) + if err: + raise self.fetch_error(err) def invoke_async( self, name: str, argtypes, *args, return_type=None ) -> asyncio.Future: """Perform an asynchronous library function call.""" - method = self.method(name, (*argtypes, c_void_p, c_int64), restype=c_int64) + method = self.method(name, (*argtypes, c_void_p, c_int64), restype=ErrorHandle) if not method: raise ValueError(f"FFI method not found: {name}") loop = asyncio.get_event_loop() @@ -225,7 +235,7 @@ def invoke_async( if cb_info: cb = cb_info[1] else: - cb_args = [c_int64, c_int64] + cb_args = [c_int64, ErrorHandle] if return_type: cb_args.append(return_type) cb_type = CFUNCTYPE(None, *cb_args) @@ -236,10 +246,10 @@ def invoke_async( args = _load_method_arguments(name, argtypes, args) cb_id = next(self._cb_id) self._callbacks[cb_id] = (loop, fut, name) - result = method(*args, cb, cb_id) - if result: + err = method(*args, cb, cb_id) + if err: # FFI must not execute the callback if an error is returned - err = self.get_current_error(True) + err = self.fetch_error(err) if self._callbacks.pop(cb_id, None): self._fulfill_future(fut, None, err) return fut @@ -249,8 +259,8 @@ def invoke_dtor(self, name: str, *values, argtypes=None, restype=None): if method: method(*values) - def _handle_callback(self, cb_id: int, err: int, result=None): - exc = self.get_current_error(True) if err else None + def _handle_callback(self, cb_id: int, err: ErrorHandle, result=None): + exc = self.fetch_error(err) if err else None cb = self._callbacks.pop(cb_id, None) if not cb: LOGGER.info("Callback already fulfilled: %s", cb_id) @@ -267,7 +277,7 @@ def _fulfill_future(self, fut: asyncio.Future, result, err: Exception = None): else: fut.set_result(result) - def get_current_error(self, expect: bool = False) -> Optional[AskarError]: + def fetch_error(self, handle: ErrorHandle) -> Optional[AskarError]: """ Get the error result from the previous failed API method. @@ -276,20 +286,23 @@ def get_current_error(self, expect: bool = False) -> Optional[AskarError]: """ err_json = StrBuffer() method = self.method( - "askar_get_current_error", (POINTER(StrBuffer),), restype=c_int64 + "askar_fetch_error", + ( + ErrorHandle, + POINTER(StrBuffer), + ), + restype=c_int64, ) - if not method(byref(err_json)): + if not method(handle, byref(err_json)): try: msg = json.loads(err_json.value) except json.JSONDecodeError: - LOGGER.warning("JSON decode error for askar_get_current_error") + LOGGER.warning("JSON decode error for askar_fetch_error") msg = None if msg and "message" in msg and "code" in msg: return AskarError( AskarErrorCode(msg["code"]), msg["message"], msg.get("extra") ) - if not expect: - return None return AskarError(AskarErrorCode.WRAPPER, "Unknown error") def method(self, name, argtypes, *, restype=None):