use std::{os::raw::c_char, ptr::null_mut}; use idevice::{ IdeviceError, IdeviceService, provider::IdeviceProvider, syslog_relay::SyslogRelayClient, }; use crate::{IdeviceFfiError, ffi_err, provider::IdeviceProviderHandle, run_sync_local}; pub struct SyslogRelayClientHandle(pub SyslogRelayClient); /// Automatically creates and connects to syslog relay, returning a client handle /// /// # Arguments /// * [`provider`] - An IdeviceProvider /// * [`client`] - On success, will be set to point to a newly allocated SyslogRelayClient handle /// /// # Safety /// `provider` must be a valid pointer to a handle allocated by this library /// `client` must be a valid, non-null pointer to a location where the handle will be stored #[unsafe(no_mangle)] pub unsafe extern "C" fn syslog_relay_connect_tcp( provider: *mut IdeviceProviderHandle, client: *mut *mut SyslogRelayClientHandle, ) -> *mut IdeviceFfiError { if provider.is_null() { tracing::error!("Null pointer provided"); return ffi_err!(IdeviceError::FfiInvalidArg); } let res: Result = run_sync_local(async move { let provider_ref: &dyn IdeviceProvider = unsafe { &*(*provider).0 }; SyslogRelayClient::connect(provider_ref).await }); match res { Ok(c) => { let boxed = Box::new(SyslogRelayClientHandle(c)); unsafe { *client = Box::into_raw(boxed) }; null_mut() } Err(e) => { let _ = unsafe { Box::from_raw(provider) }; ffi_err!(e) } } } /// Frees a handle /// /// # Arguments /// * [`handle`] - The handle to free /// /// # Safety /// `handle` must be a valid pointer to the handle that was allocated by this library, /// or NULL (in which case this function does nothing) #[unsafe(no_mangle)] pub unsafe extern "C" fn syslog_relay_client_free(handle: *mut SyslogRelayClientHandle) { if !handle.is_null() { tracing::debug!("Freeing syslog relay client"); let _ = unsafe { Box::from_raw(handle) }; } } /// Gets the next log message from the relay /// /// # Arguments /// * [`client`] - The SyslogRelayClient handle /// * [`log_message`] - On success a newly allocated cstring will be set to point to the log message /// /// # Safety /// `client` must be a valid pointer to a handle allocated by this library /// `log_message` must be a valid, non-null pointer to a location where the log message will be stored #[unsafe(no_mangle)] pub unsafe extern "C" fn syslog_relay_next( client: *mut SyslogRelayClientHandle, log_message: *mut *mut c_char, ) -> *mut IdeviceFfiError { if client.is_null() || log_message.is_null() { return ffi_err!(IdeviceError::FfiInvalidArg); } let res = run_sync_local(async { unsafe { &mut *client }.0.next().await }); match res { Ok(log) => { use std::ffi::CString; // null bytes are a curse in C, so just use spaces let safe_log = log.replace('\0', " "); match CString::new(safe_log) { Ok(c_string) => { unsafe { *log_message = c_string.into_raw() }; null_mut() } Err(_) => { tracing::error!("Failed to convert log message to C string"); ffi_err!(IdeviceError::FfiInvalidString) } } } Err(e) => ffi_err!(e), } }