mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Create new RSD service trait
This commit is contained in:
@@ -25,7 +25,7 @@ pub use services::*;
|
||||
pub use xpc::RemoteXpcClient;
|
||||
|
||||
use log::{debug, error, trace};
|
||||
use provider::IdeviceProvider;
|
||||
use provider::{IdeviceProvider, RsdProvider};
|
||||
use rustls::{crypto::CryptoProvider, pki_types::ServerName};
|
||||
use std::{
|
||||
io::{self, BufWriter},
|
||||
@@ -65,6 +65,25 @@ pub trait IdeviceService: Sized {
|
||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
|
||||
}
|
||||
|
||||
pub trait RsdService: Sized {
|
||||
fn rsd_service_name() -> &'static str;
|
||||
fn from_stream(
|
||||
stream: Self::Stream,
|
||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
|
||||
fn connect_rsd<'a, S>(
|
||||
provider: &'a mut impl RsdProvider<'a, Stream = S>,
|
||||
handshake: &mut rsd::RsdHandshake,
|
||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>>
|
||||
where
|
||||
Self: crate::RsdService<Stream = S>,
|
||||
S: ReadWrite,
|
||||
{
|
||||
handshake.connect(provider)
|
||||
}
|
||||
|
||||
type Stream: ReadWrite;
|
||||
}
|
||||
|
||||
/// Type alias for boxed device connection sockets
|
||||
///
|
||||
/// Used to enable dynamic dispatch of different connection types while maintaining
|
||||
@@ -424,6 +443,8 @@ pub enum IdeviceError {
|
||||
HeartbeatTimeout,
|
||||
#[error("not found")]
|
||||
NotFound,
|
||||
#[error("service not found")]
|
||||
ServiceNotFound,
|
||||
#[error("CDTunnel packet too short")]
|
||||
CdtunnelPacketTooShort,
|
||||
#[error("CDTunnel packet invalid magic")]
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::{future::Future, pin::Pin};
|
||||
#[cfg(feature = "tcp")]
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use crate::{pairing_file::PairingFile, Idevice, IdeviceError};
|
||||
use crate::{pairing_file::PairingFile, Idevice, IdeviceError, ReadWrite};
|
||||
|
||||
#[cfg(feature = "usbmuxd")]
|
||||
use crate::usbmuxd::UsbmuxdAddr;
|
||||
@@ -42,6 +42,14 @@ pub trait IdeviceProvider: Unpin + Send + Sync + std::fmt::Debug {
|
||||
) -> Pin<Box<dyn Future<Output = Result<PairingFile, IdeviceError>> + Send>>;
|
||||
}
|
||||
|
||||
pub trait RsdProvider<'a>: Unpin + Send + Sync + std::fmt::Debug {
|
||||
fn connect_to_service_port(
|
||||
&'a mut self,
|
||||
port: u16,
|
||||
) -> impl std::future::Future<Output = Result<Self::Stream, IdeviceError>> + Send;
|
||||
type Stream: ReadWrite;
|
||||
}
|
||||
|
||||
/// TCP-based device connection provider
|
||||
#[cfg(feature = "tcp")]
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -8,10 +8,22 @@ use log::debug;
|
||||
use std::fmt::Write;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
use crate::{IdeviceError, ReadWrite};
|
||||
use crate::{IdeviceError, ReadWrite, RsdService};
|
||||
|
||||
/// The service name for the debug proxy as registered with lockdownd
|
||||
pub const SERVICE_NAME: &str = "com.apple.internal.dt.remote.debugproxy";
|
||||
impl<R: ReadWrite> RsdService for DebugProxyClient<R> {
|
||||
fn rsd_service_name() -> &'static str {
|
||||
"com.apple.internal.dt.remote.debugproxy"
|
||||
}
|
||||
|
||||
async fn from_stream(stream: R) -> Result<Self, IdeviceError> {
|
||||
Ok(Self {
|
||||
socket: stream,
|
||||
noack_mode: false,
|
||||
})
|
||||
}
|
||||
|
||||
type Stream = R;
|
||||
}
|
||||
|
||||
/// Client for interacting with the iOS debug proxy service
|
||||
///
|
||||
@@ -300,4 +312,3 @@ impl From<&str> for DebugserverCommand {
|
||||
s.to_string().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
// Jackson Coxson
|
||||
|
||||
use crate::{IdeviceError, ReadWrite, RsdService};
|
||||
|
||||
#[cfg(feature = "location_simulation")]
|
||||
pub mod location_simulation;
|
||||
pub mod message;
|
||||
pub mod process_control;
|
||||
pub mod remote_server;
|
||||
|
||||
pub const SERVICE_NAME: &str = "com.apple.instruments.dtservicehub";
|
||||
impl<R: ReadWrite> RsdService for remote_server::RemoteServerClient<R> {
|
||||
fn rsd_service_name() -> &'static str {
|
||||
"com.apple.instruments.dtservicehub"
|
||||
}
|
||||
|
||||
async fn from_stream(stream: R) -> Result<Self, IdeviceError> {
|
||||
Ok(Self::new(stream))
|
||||
}
|
||||
|
||||
type Stream = R;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::collections::HashMap;
|
||||
use log::warn;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{IdeviceError, ReadWrite, RemoteXpcClient};
|
||||
use crate::{provider::RsdProvider, IdeviceError, ReadWrite, RemoteXpcClient};
|
||||
|
||||
/// Describes an available XPC service
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -23,21 +23,19 @@ pub struct RsdService {
|
||||
pub service_version: Option<i64>,
|
||||
}
|
||||
|
||||
pub struct RsdClient<R: ReadWrite> {
|
||||
inner: RemoteXpcClient<R>,
|
||||
pub struct RsdHandshake {
|
||||
pub services: HashMap<String, RsdService>,
|
||||
pub protocol_version: usize,
|
||||
pub properties: HashMap<String, plist::Value>,
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
impl<R: ReadWrite> RsdClient<R> {
|
||||
pub async fn new(socket: R) -> Result<Self, IdeviceError> {
|
||||
Ok(Self {
|
||||
inner: RemoteXpcClient::new(socket).await?,
|
||||
})
|
||||
}
|
||||
impl RsdHandshake {
|
||||
pub async fn new(socket: impl ReadWrite) -> Result<Self, IdeviceError> {
|
||||
let mut xpc_client = RemoteXpcClient::new(socket).await?;
|
||||
let data = xpc_client.do_handshake().await?;
|
||||
|
||||
pub async fn get_services(&mut self) -> Result<HashMap<String, RsdService>, IdeviceError> {
|
||||
let data = self.inner.do_handshake().await?;
|
||||
|
||||
let data = match data
|
||||
let services_dict = match data
|
||||
.as_dictionary()
|
||||
.and_then(|x| x.get("Services"))
|
||||
.and_then(|x| x.as_dictionary())
|
||||
@@ -47,8 +45,8 @@ impl<R: ReadWrite> RsdClient<R> {
|
||||
};
|
||||
|
||||
// Parse available services
|
||||
let mut services = HashMap::new();
|
||||
for (name, service) in data.into_iter() {
|
||||
let mut services: HashMap<String, RsdService> = HashMap::new();
|
||||
for (name, service) in services_dict.into_iter() {
|
||||
match service.as_dictionary() {
|
||||
Some(service) => {
|
||||
let entitlement = match service.get("Entitlement").and_then(|x| x.as_string()) {
|
||||
@@ -116,6 +114,64 @@ impl<R: ReadWrite> RsdClient<R> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(services)
|
||||
let protocol_version = match data.as_dictionary().and_then(|x| {
|
||||
x.get("MessagingProtocolVersion")
|
||||
.and_then(|x| x.as_signed_integer())
|
||||
}) {
|
||||
Some(p) => p as usize,
|
||||
None => {
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
let uuid = match data
|
||||
.as_dictionary()
|
||||
.and_then(|x| x.get("UUID").and_then(|x| x.as_string()))
|
||||
{
|
||||
Some(u) => u.to_string(),
|
||||
None => {
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
let properties = match data
|
||||
.as_dictionary()
|
||||
.and_then(|x| x.get("Properties").and_then(|x| x.as_dictionary()))
|
||||
{
|
||||
Some(d) => d
|
||||
.into_iter()
|
||||
.map(|(name, prop)| (name.to_owned(), prop.to_owned()))
|
||||
.collect::<HashMap<String, plist::Value>>(),
|
||||
None => {
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
services,
|
||||
protocol_version,
|
||||
properties,
|
||||
uuid,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn connect<'a, T, S>(
|
||||
&mut self,
|
||||
provider: &'a mut impl RsdProvider<'a, Stream = S>,
|
||||
) -> Result<T, IdeviceError>
|
||||
where
|
||||
T: crate::RsdService<Stream = S>,
|
||||
S: ReadWrite,
|
||||
{
|
||||
let service_name = T::rsd_service_name();
|
||||
let service = match self.services.get(service_name) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return Err(IdeviceError::ServiceNotFound);
|
||||
}
|
||||
};
|
||||
|
||||
let stream = provider.connect_to_service_port(service.port).await?;
|
||||
T::from_stream(stream).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@ use std::{
|
||||
};
|
||||
|
||||
use log::debug;
|
||||
use stream::AdapterStream;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::provider::RsdProvider;
|
||||
|
||||
pub mod adapter;
|
||||
pub mod packets;
|
||||
pub mod stream;
|
||||
@@ -36,6 +39,18 @@ pub(crate) fn log_packet(file: &Arc<tokio::sync::Mutex<tokio::fs::File>>, packet
|
||||
});
|
||||
}
|
||||
|
||||
impl<'a> RsdProvider<'a> for adapter::Adapter {
|
||||
async fn connect_to_service_port(
|
||||
&'a mut self,
|
||||
port: u16,
|
||||
) -> Result<stream::AdapterStream<'a>, crate::IdeviceError> {
|
||||
let s = stream::AdapterStream::connect(self, port).await?;
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
type Stream = AdapterStream<'a>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{
|
||||
|
||||
Reference in New Issue
Block a user