use crate::crypto::xmlsec::wrapper::bindings;
use lazy_static::lazy_static;
use super::backend;
use super::error::XmlSecError;
use super::XmlSecResult;
use std::convert::TryInto;
use std::ptr::null;
use std::sync::Mutex;
lazy_static! {
static ref XMLSEC: Mutex<Option<XmlSecContext>> = Mutex::new(None);
}
pub fn guarantee_xmlsec_init() -> XmlSecResult<()> {
let mut inner = XMLSEC
.lock()
.expect("Unable to lock global wrapper initalization wrapper");
if inner.is_none() {
*inner = Some(XmlSecContext::new()?);
}
Ok(())
}
pub struct XmlSecContext {}
impl XmlSecContext {
pub fn new() -> XmlSecResult<Self> {
unsafe {
libxml::bindings::xmlInitParser();
}
init_xmlsec()?;
init_crypto_app()?;
init_crypto()?;
Ok(Self {})
}
}
impl Drop for XmlSecContext {
fn drop(&mut self) {
cleanup_crypto();
cleanup_crypto_app();
cleanup_xmlsec();
}
}
fn init_xmlsec() -> XmlSecResult<()> {
let rc = unsafe {
bindings::xmlSecCheckVersionExt(
bindings::XMLSEC_VERSION_MAJOR.try_into().unwrap(),
bindings::XMLSEC_VERSION_MINOR.try_into().unwrap(),
bindings::XMLSEC_VERSION_SUBMINOR.try_into().unwrap(),
bindings::xmlSecCheckVersionMode_xmlSecCheckVersionABICompatible,
)
};
if rc < 0 {
return Err(XmlSecError::XmlSecAbiMismatch);
}
let rc = unsafe { bindings::xmlSecInit() };
if rc < 0 {
Err(XmlSecError::XmlSecInitError)
} else {
Ok(())
}
}
fn init_crypto_app() -> XmlSecResult<()> {
#[cfg(xmlsec_dynamic)]
{
let rc = unsafe { backend::xmlSecCryptoDLLoadLibrary(null()) };
if rc < 0 {
return Err(XmlSecError::CryptoLoadLibraryError);
}
}
let rc = unsafe { backend::xmlSecCryptoAppInit(null()) };
if rc < 0 {
Err(XmlSecError::CryptoInitOpenSSLAppError)
} else {
Ok(())
}
}
fn init_crypto() -> XmlSecResult<()> {
let rc = unsafe { backend::xmlSecCryptoInit() };
if rc < 0 {
Err(XmlSecError::CryptoInitOpenSSLError)
} else {
Ok(())
}
}
fn cleanup_crypto() {
unsafe { backend::xmlSecCryptoShutdown() };
}
fn cleanup_crypto_app() {
unsafe { backend::xmlSecCryptoAppShutdown() };
}
fn cleanup_xmlsec() {
unsafe { bindings::xmlSecShutdown() };
}