ockam_ffi/
error.rs

1use ockam_core::{
2    errcode::{Kind, Origin},
3    Error,
4};
5use std::ffi::CString;
6use std::os::raw::c_char;
7
8#[repr(C)]
9#[derive(Debug, PartialEq, Eq)]
10/// Error type relating to FFI specific failures.
11pub struct FfiOckamError {
12    code: i32,
13    domain: *const c_char,
14}
15
16impl FfiOckamError {
17    /// Create a new error.
18    pub fn new(code: i32, domain: &str) -> Self {
19        Self {
20            code,
21            // TODO: Should this graciously fail?
22            domain: CString::new(domain.as_bytes()).unwrap().into_raw(),
23        }
24    }
25
26    /// No error.
27    pub fn none() -> Self {
28        Self {
29            code: 0,
30            domain: std::ptr::null(),
31        }
32    }
33}
34
35/// Represents the failures that can occur in an Ockam FFI Vault.
36#[derive(Clone, Copy, Debug)]
37pub enum FfiError {
38    /// Persistence is not supported for this Vault implementation.
39    VaultDoesNotSupportPersistence = 1,
40
41    /// An underlying filesystem error prevented Vault creation.
42    ErrorCreatingFilesystemVault,
43
44    /// Invalid parameter.
45    InvalidParam,
46
47    /// Entry not found.
48    EntryNotFound,
49
50    /// Unknown public key type.
51    UnknownPublicKeyType,
52
53    /// Invalid string.
54    InvalidString,
55
56    /// Buffer is too small.
57    BufferTooSmall,
58
59    /// A public key is invalid.
60    InvalidPublicKey,
61
62    /// No such Vault.
63    VaultNotFound,
64
65    /// Ownership error.
66    OwnershipError,
67
68    /// Caught a panic (which would be UB if we let it unwind across the FFI).
69    UnexpectedPanic,
70}
71impl ockam_core::compat::error::Error for FfiError {}
72impl From<FfiError> for Error {
73    #[track_caller]
74    fn from(err: FfiError) -> Self {
75        Error::new(Origin::Other, Kind::Other, err)
76    }
77}
78impl core::fmt::Display for FfiError {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        match self {
81            Self::VaultDoesNotSupportPersistence => write!(
82                f,
83                "persistence is not supported for this Vault implementation."
84            ),
85            Self::ErrorCreatingFilesystemVault => write!(
86                f,
87                "an underlying filesystem error prevented Vault creation."
88            ),
89            Self::InvalidParam => write!(f, "invalid parameter."),
90            Self::EntryNotFound => write!(f, "entry not found."),
91            Self::UnknownPublicKeyType => write!(f, "unknown public key type."),
92            Self::InvalidString => write!(f, "invalid string."),
93            Self::BufferTooSmall => write!(f, "buffer is too small."),
94            Self::InvalidPublicKey => write!(f, "a public key is invalid."),
95            Self::VaultNotFound => write!(f, "no such Vault."),
96            Self::OwnershipError => write!(f, "ownership error."),
97            Self::UnexpectedPanic => write!(
98                f,
99                "caught a panic (which would be UB if we let it unwind across the FFI)."
100            ),
101        }
102    }
103}
104
105impl From<Error> for FfiOckamError {
106    fn from(err: Error) -> Self {
107        Self::new(
108            err.code().origin as i32 * 10_000 + err.code().kind as i32,
109            "unknown",
110        )
111    }
112}
113
114impl From<FfiError> for FfiOckamError {
115    fn from(err: FfiError) -> Self {
116        let err2: Error = err.into();
117        Self::from(err2)
118    }
119}
120
121/// # Safety
122/// frees `FfiOckamError::domain` if it's non-null
123#[no_mangle]
124pub unsafe extern "C" fn ockam_vault_free_error(context: &mut FfiOckamError) {
125    if !context.domain.is_null() {
126        let _ = CString::from_raw(context.domain as *mut _);
127        context.domain = core::ptr::null();
128    }
129}