From b8e2b115a595ad025c15af11bc28307f92c37f7a Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Mon, 26 May 2025 16:34:15 -0600 Subject: [PATCH] Use opaque handle for readwrite objects --- ffi/src/adapter.rs | 16 +++++++--- ffi/src/debug_proxy.rs | 46 ++++++++++++++++++++++++++- ffi/src/lib.rs | 7 +++- ffi/src/provider.rs | 2 +- ffi/src/remote_server.rs | 69 ++++++++++++++++++++++++++++++++++------ ffi/src/rsd.rs | 18 +++++++---- 6 files changed, 134 insertions(+), 24 deletions(-) diff --git a/ffi/src/adapter.rs b/ffi/src/adapter.rs index 20fdb88..306237b 100644 --- a/ffi/src/adapter.rs +++ b/ffi/src/adapter.rs @@ -1,11 +1,11 @@ // Jackson Coxson -use std::ffi::{CString, c_char}; +use std::ffi::{CStr, c_char}; use idevice::tcp::stream::AdapterStream; use crate::core_device_proxy::AdapterHandle; -use crate::{IdeviceErrorCode, RUNTIME}; +use crate::{IdeviceErrorCode, RUNTIME, ReadWriteOpaque}; pub struct AdapterStreamHandle<'a>(pub AdapterStream<'a>); @@ -27,7 +27,7 @@ pub struct AdapterStreamHandle<'a>(pub AdapterStream<'a>); pub unsafe extern "C" fn adapter_connect( adapter_handle: *mut AdapterHandle, port: u16, - stream_handle: *mut *mut AdapterStreamHandle, + stream_handle: *mut *mut ReadWriteOpaque, ) -> IdeviceErrorCode { if adapter_handle.is_null() || stream_handle.is_null() { return IdeviceErrorCode::InvalidArg; @@ -37,7 +37,13 @@ pub unsafe extern "C" fn adapter_connect( let res = RUNTIME.block_on(async move { AdapterStream::connect(adapter, port).await }); match res { - Ok(_) => IdeviceErrorCode::IdeviceSuccess, + Ok(r) => { + let boxed = Box::new(ReadWriteOpaque { + inner: Some(Box::new(r)), + }); + unsafe { *stream_handle = Box::into_raw(boxed) }; + IdeviceErrorCode::IdeviceSuccess + } Err(e) => { log::error!("Adapter connect failed: {}", e); IdeviceErrorCode::AdapterIOFailed @@ -67,7 +73,7 @@ pub unsafe extern "C" fn adapter_pcap( } let adapter = unsafe { &mut (*handle).0 }; - let c_str = unsafe { CString::from_raw(path as *mut c_char) }; + let c_str = unsafe { CStr::from_ptr(path) }; let path_str = match c_str.to_str() { Ok(s) => s, Err(_) => return IdeviceErrorCode::InvalidArg, diff --git a/ffi/src/debug_proxy.rs b/ffi/src/debug_proxy.rs index 800c4dd..cb1fc85 100644 --- a/ffi/src/debug_proxy.rs +++ b/ffi/src/debug_proxy.rs @@ -4,9 +4,12 @@ use std::ffi::{CStr, CString, c_char}; use std::os::raw::c_int; use std::ptr; -use idevice::ReadWrite; use idevice::debug_proxy::{DebugProxyClient, DebugserverCommand}; +use idevice::tcp::stream::AdapterStream; +use idevice::{IdeviceError, ReadWrite, RsdService}; +use crate::core_device_proxy::AdapterHandle; +use crate::rsd::RsdHandshakeHandle; use crate::{IdeviceErrorCode, RUNTIME}; /// Opaque handle to a DebugProxyClient @@ -112,6 +115,47 @@ pub unsafe extern "C" fn debugserver_command_free(command: *mut DebugserverComma } } +/// Creates a new DebugProxyClient +/// +/// # Arguments +/// * [`provider`] - An adapter created by this library +/// * [`handshake`] - An RSD handshake from the same provider +/// +/// # Returns +/// An error code indicating success or failure +/// +/// # Safety +/// `provider` must be a valid pointer to a handle allocated by this library +/// `handshake` must be a valid pointer to a location where the handle will be stored +#[unsafe(no_mangle)] +pub unsafe extern "C" fn debug_proxy_connect_rsd( + provider: *mut AdapterHandle, + handshake: *mut RsdHandshakeHandle, + handle: *mut *mut DebugProxyHandle, +) -> IdeviceErrorCode { + if provider.is_null() || handshake.is_null() || handshake.is_null() { + return IdeviceErrorCode::InvalidArg; + } + let res: Result, IdeviceError> = RUNTIME.block_on(async move { + let provider_ref = unsafe { &mut (*provider).0 }; + let handshake_ref = unsafe { &mut (*handshake).0 }; + + // Connect using the reference + DebugProxyClient::connect_rsd(provider_ref, handshake_ref).await + }); + + match res { + Ok(d) => { + let boxed = Box::new(DebugProxyHandle(DebugProxyClient::new(Box::new( + d.into_inner(), + )))); + unsafe { *handle = Box::into_raw(boxed) }; + IdeviceErrorCode::IdeviceSuccess + } + Err(e) => e.into(), + } +} + /// Creates a new DebugProxyClient /// /// # Arguments diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index abb86bb..14cf92f 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -42,7 +42,7 @@ pub mod util; pub use errors::*; pub use pairing_file::*; -use idevice::{Idevice, IdeviceSocket}; +use idevice::{Idevice, IdeviceSocket, ReadWrite}; use once_cell::sync::Lazy; use std::ffi::{CStr, CString, c_char}; use tokio::runtime::{self, Runtime}; @@ -57,6 +57,11 @@ static RUNTIME: Lazy = Lazy::new(|| { pub const LOCKDOWN_PORT: u16 = 62078; +#[repr(C)] +pub struct ReadWriteOpaque { + pub inner: Option>, +} + /// Opaque C-compatible handle to an Idevice connection pub struct IdeviceHandle(pub Idevice); pub struct IdeviceSocketHandle(IdeviceSocket); diff --git a/ffi/src/provider.rs b/ffi/src/provider.rs index 0fe624b..493c567 100644 --- a/ffi/src/provider.rs +++ b/ffi/src/provider.rs @@ -21,7 +21,7 @@ pub struct IdeviceProviderHandle(pub Box); /// /// # Safety /// `ip` must be a valid sockaddr -/// `pairing_file` must never be used again +/// `pairing_file` is consumed must never be used again /// `label` must be a valid Cstr /// `provider` must be a valid, non-null pointer to a location where the handle will be stored #[cfg(feature = "tcp")] diff --git a/ffi/src/remote_server.rs b/ffi/src/remote_server.rs index 1570dd5..f8385b3 100644 --- a/ffi/src/remote_server.rs +++ b/ffi/src/remote_server.rs @@ -1,8 +1,11 @@ // Jackson Coxson -use crate::{IdeviceErrorCode, RUNTIME}; +use crate::core_device_proxy::AdapterHandle; +use crate::rsd::RsdHandshakeHandle; +use crate::{IdeviceErrorCode, RUNTIME, ReadWriteOpaque}; use idevice::dvt::remote_server::RemoteServerClient; -use idevice::{IdeviceError, ReadWrite}; +use idevice::tcp::stream::AdapterStream; +use idevice::{IdeviceError, ReadWrite, RsdService}; /// Opaque handle to a RemoteServerClient pub struct RemoteServerHandle(pub RemoteServerClient>); @@ -17,25 +20,29 @@ pub struct RemoteServerHandle(pub RemoteServerClient>); /// An error code indicating success or failure /// /// # Safety -/// `socket` must be a valid pointer to a handle allocated by this library +/// `socket` must be a valid pointer to a handle allocated by this library. It is consumed and may +/// not be used again. /// `handle` must be a valid pointer to a location where the handle will be stored #[unsafe(no_mangle)] pub unsafe extern "C" fn remote_server_new( - socket: *mut Box, + socket: *mut ReadWriteOpaque, handle: *mut *mut RemoteServerHandle, ) -> IdeviceErrorCode { if socket.is_null() { return IdeviceErrorCode::InvalidArg; } - let connection = unsafe { Box::from_raw(socket) }; + let wrapper = unsafe { &mut *socket }; let res: Result>, IdeviceError> = - RUNTIME.block_on(async move { - let mut client = RemoteServerClient::new(*connection); - client.read_message(0).await?; // Until Message has bindings, we'll do the first read - Ok(client) - }); + match wrapper.inner.take() { + Some(stream) => RUNTIME.block_on(async move { + let mut client = RemoteServerClient::new(stream); + client.read_message(0).await?; + Ok(client) + }), + None => return IdeviceErrorCode::InvalidArg, + }; match res { Ok(client) => { @@ -47,6 +54,48 @@ pub unsafe extern "C" fn remote_server_new( } } +/// Creates a new RemoteServerClient from a handshake and adapter +/// +/// # Arguments +/// * [`provider`] - An adapter created by this library +/// * [`handshake`] - An RSD handshake from the same provider +/// +/// # Returns +/// An error code indicating success or failure +/// +/// # Safety +/// `provider` must be a valid pointer to a handle allocated by this library +/// `handshake` must be a valid pointer to a location where the handle will be stored +#[unsafe(no_mangle)] +pub unsafe extern "C" fn remote_server_connect_rsd( + provider: *mut AdapterHandle, + handshake: *mut RsdHandshakeHandle, + handle: *mut *mut RemoteServerHandle, +) -> IdeviceErrorCode { + if provider.is_null() || handshake.is_null() || handshake.is_null() { + return IdeviceErrorCode::InvalidArg; + } + let res: Result, IdeviceError> = + RUNTIME.block_on(async move { + let provider_ref = unsafe { &mut (*provider).0 }; + let handshake_ref = unsafe { &mut (*handshake).0 }; + + // Connect using the reference + RemoteServerClient::connect_rsd(provider_ref, handshake_ref).await + }); + + match res { + Ok(d) => { + let boxed = Box::new(RemoteServerHandle(RemoteServerClient::new(Box::new( + d.into_inner(), + )))); + unsafe { *handle = Box::into_raw(boxed) }; + IdeviceErrorCode::IdeviceSuccess + } + Err(e) => e.into(), + } +} + /// Frees a RemoteServerClient handle /// /// # Arguments diff --git a/ffi/src/rsd.rs b/ffi/src/rsd.rs index 44c41ec..83d7e5c 100644 --- a/ffi/src/rsd.rs +++ b/ffi/src/rsd.rs @@ -5,9 +5,9 @@ use std::ffi::{CStr, CString}; use std::ptr; -use idevice::{ReadWrite, rsd::RsdHandshake}; +use idevice::rsd::RsdHandshake; -use crate::{IdeviceErrorCode, RUNTIME}; +use crate::{IdeviceErrorCode, RUNTIME, ReadWriteOpaque}; /// Opaque handle to an RsdHandshake pub struct RsdHandshakeHandle(pub RsdHandshake); @@ -50,20 +50,26 @@ pub struct CRsdServiceArray { /// An error code indicating success or failure /// /// # Safety -/// `socket` must be a valid pointer to a ReadWrite handle allocated by this library +/// `socket` must be a valid pointer to a ReadWrite handle allocated by this library. It is +/// consumed and may not be used again. /// `handle` must be a valid pointer to a location where the handle will be stored #[unsafe(no_mangle)] pub unsafe extern "C" fn rsd_handshake_new( - socket: *mut Box, + socket: *mut ReadWriteOpaque, handle: *mut *mut RsdHandshakeHandle, ) -> IdeviceErrorCode { if socket.is_null() || handle.is_null() { return IdeviceErrorCode::InvalidArg; } - let connection = unsafe { Box::from_raw(socket) }; + let wrapper = unsafe { &mut *socket }; - let res = RUNTIME.block_on(async move { RsdHandshake::new(*connection).await }); + let res = match wrapper.inner.take() { + Some(mut w) => RUNTIME.block_on(async move { RsdHandshake::new(w.as_mut()).await }), + None => { + return IdeviceErrorCode::InvalidArg; + } + }; match res { Ok(handshake) => {