add diag relay c++ bindings, screenshotr ffi (#58)

This commit is contained in:
uncor3
2026-01-14 13:46:47 -08:00
committed by GitHub
parent ead5fbf3d3
commit 5bb9330cf6
8 changed files with 412 additions and 3 deletions

View File

@@ -50,6 +50,7 @@ tss = ["idevice/tss"]
tunneld = ["idevice/tunneld"]
usbmuxd = ["idevice/usbmuxd"]
xpc = ["idevice/xpc"]
screenshotr = ["idevice/screenshotr"]
full = [
"afc",
"amfi",
@@ -75,6 +76,7 @@ full = [
"tunneld",
"springboardservices",
"syslog_relay",
"screenshotr",
]
default = ["full", "aws-lc"]

View File

@@ -620,10 +620,10 @@ pub unsafe extern "C" fn afc_file_read(
let fd = unsafe { &mut *(handle as *mut FileDescriptor) };
let res: Result<Vec<u8>, IdeviceError> = run_sync({
let mut buf = Vec::with_capacity(len);
let mut buf = vec![0u8; len];
async move {
let r = fd.read(&mut buf).await?;
buf.resize(r, 0);
buf.truncate(r);
Ok(buf)
}
});

View File

@@ -190,7 +190,7 @@ pub unsafe extern "C" fn diagnostics_relay_client_mobilegestalt(
return ffi_err!(IdeviceError::FfiInvalidArg);
}
let keys = if keys.is_null() {
let keys = if !keys.is_null() {
let keys = unsafe { std::slice::from_raw_parts(keys, keys_len) };
Some(
keys.iter()

View File

@@ -35,6 +35,8 @@ mod pairing_file;
pub mod provider;
#[cfg(feature = "xpc")]
pub mod rsd;
#[cfg(feature = "screenshotr")]
pub mod screenshotr;
#[cfg(feature = "springboardservices")]
pub mod springboardservices;
#[cfg(feature = "syslog_relay")]

View File

@@ -250,6 +250,60 @@ pub unsafe extern "C" fn lockdownd_enter_recovery(
}
}
/// Sets a value in lockdownd
///
/// # Arguments
/// * `client` - A valid LockdowndClient handle
/// * `key` - The key to set (null-terminated string)
/// * `value` - The value to set as a plist
/// * `domain` - The domain to set in (null-terminated string, optional)
///
/// # Returns
/// An IdeviceFfiError on error, null on success
///
/// # Safety
/// `client` must be a valid pointer to a handle allocated by this library
/// `key` must be a valid null-terminated string
/// `value` must be a valid plist
/// `domain` must be a valid null-terminated string or NULL
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lockdownd_set_value(
client: *mut LockdowndClientHandle,
key: *const libc::c_char,
value: plist_t,
domain: *const libc::c_char,
) -> *mut IdeviceFfiError {
if client.is_null() || key.is_null() || value.is_null() {
return ffi_err!(IdeviceError::FfiInvalidArg);
}
let key = match unsafe { std::ffi::CStr::from_ptr(key) }.to_str() {
Ok(k) => k,
Err(_) => return ffi_err!(IdeviceError::InvalidCString),
};
let domain = if domain.is_null() {
None
} else {
Some(match unsafe { std::ffi::CStr::from_ptr(domain) }.to_str() {
Ok(d) => d,
Err(_) => return ffi_err!(IdeviceError::InvalidCString),
})
};
let value = unsafe { &mut *value }.borrow_self().clone();
let res: Result<(), IdeviceError> = run_sync_local(async move {
let client_ref = unsafe { &mut (*client).0 };
client_ref.set_value(key, value, domain).await
});
match res {
Ok(_) => null_mut(),
Err(e) => ffi_err!(e),
}
}
/// Frees a LockdowndClient handle
///
/// # Arguments

132
ffi/src/screenshotr.rs Normal file
View File

@@ -0,0 +1,132 @@
// Jackson Coxson
use std::ptr::null_mut;
use idevice::{
IdeviceError, IdeviceService, provider::IdeviceProvider,
services::screenshotr::ScreenshotService,
};
use crate::{IdeviceFfiError, ffi_err, provider::IdeviceProviderHandle, run_sync_local};
pub struct ScreenshotrClientHandle(pub ScreenshotService);
/// Represents a screenshot data buffer
#[repr(C)]
pub struct ScreenshotData {
pub data: *mut u8,
pub length: usize,
}
/// Connects to screenshotr service using provider
///
/// # Arguments
/// * [`provider`] - An IdeviceProvider
/// * [`client`] - On success, will be set to point to a newly allocated ScreenshotrClient handle
///
/// # Returns
/// An IdeviceFfiError on error, null on success
///
/// # 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 screenshotr_connect(
provider: *mut IdeviceProviderHandle,
client: *mut *mut ScreenshotrClientHandle,
) -> *mut IdeviceFfiError {
if provider.is_null() || client.is_null() {
tracing::error!("Null pointer provided");
return ffi_err!(IdeviceError::FfiInvalidArg);
}
let res: Result<ScreenshotService, IdeviceError> = run_sync_local(async move {
let provider_ref: &dyn IdeviceProvider = unsafe { &*(*provider).0 };
ScreenshotService::connect(provider_ref).await
});
match res {
Ok(r) => {
let boxed = Box::new(ScreenshotrClientHandle(r));
unsafe { *client = Box::into_raw(boxed) };
null_mut()
}
Err(e) => ffi_err!(e),
}
}
/// Takes a screenshot from the device
///
/// # Arguments
/// * `client` - A valid ScreenshotrClient handle
/// * `screenshot` - Pointer to store the screenshot data
///
/// # Returns
/// An IdeviceFfiError on error, null on success
///
/// # Safety
/// `client` must be a valid pointer to a handle allocated by this library
/// `screenshot` must be a valid pointer to store the screenshot data
/// The caller is responsible for freeing the screenshot data using screenshotr_screenshot_free
#[unsafe(no_mangle)]
pub unsafe extern "C" fn screenshotr_take_screenshot(
client: *mut ScreenshotrClientHandle,
screenshot: *mut ScreenshotData,
) -> *mut IdeviceFfiError {
if client.is_null() || screenshot.is_null() {
return ffi_err!(IdeviceError::FfiInvalidArg);
}
let res: Result<Vec<u8>, IdeviceError> = run_sync_local(async move {
let client_ref = unsafe { &mut (*client).0 };
client_ref.take_screenshot().await
});
match res {
Ok(data) => {
let len = data.len();
let boxed = data.into_boxed_slice();
let ptr = Box::into_raw(boxed) as *mut u8;
unsafe {
(*screenshot).data = ptr;
(*screenshot).length = len;
}
null_mut()
}
Err(e) => ffi_err!(e),
}
}
/// Frees screenshot data
///
/// # Arguments
/// * `screenshot` - The screenshot data to free
///
/// # Safety
/// `screenshot` must be a valid ScreenshotData that was allocated by screenshotr_take_screenshot
/// or NULL (in which case this function does nothing)
#[unsafe(no_mangle)]
pub unsafe extern "C" fn screenshotr_screenshot_free(screenshot: ScreenshotData) {
if !screenshot.data.is_null() && screenshot.length > 0 {
tracing::debug!("Freeing screenshot data");
let _ =
unsafe { Vec::from_raw_parts(screenshot.data, screenshot.length, screenshot.length) };
}
}
/// Frees a ScreenshotrClient 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 screenshotr_client_free(handle: *mut ScreenshotrClientHandle) {
if !handle.is_null() {
tracing::debug!("Freeing screenshotr_client");
let _ = unsafe { Box::from_raw(handle) };
}
}