Implement proper message channeling

This commit is contained in:
Jackson Coxson
2025-03-11 22:12:57 -06:00
parent dca957ccee
commit 6d80201e35
5 changed files with 107 additions and 36 deletions

View File

@@ -21,7 +21,7 @@ pub struct MessageHeader {
length: u32, // Length of of the payload length: u32, // Length of of the payload
identifier: u32, identifier: u32,
conversation_index: u32, conversation_index: u32,
channel: u32, pub channel: u32,
expects_reply: bool, expects_reply: bool,
} }
@@ -194,7 +194,7 @@ impl MessageHeader {
expects_reply: bool, expects_reply: bool,
) -> Self { ) -> Self {
Self { Self {
magic: 0x795b3d1f, magic: 0x1F3D5B79,
header_len: 32, header_len: 32,
fragment_id, fragment_id,
fragment_count, fragment_count,
@@ -236,8 +236,7 @@ impl PayloadHeader {
res res
} }
// from pymobiledevice3 pub fn method_invocation() -> Self {
pub fn instruments_message_type() -> Self {
Self { Self {
flags: 2, flags: 2,
..Default::default() ..Default::default()
@@ -369,7 +368,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn t1() { async fn t1() {
let test = "/Users/jacksoncoxson/Desktop/try1"; let test = "/Users/jacksoncoxson/Desktop/try2";
let mut bytes = tokio::fs::File::open(test).await.unwrap(); let mut bytes = tokio::fs::File::open(test).await.unwrap();
let message = Message::from_reader(&mut bytes).await.unwrap(); let message = Message::from_reader(&mut bytes).await.unwrap();

View File

@@ -1,5 +1,19 @@
// Jackson Coxson // Jackson Coxson
pub struct ProcessControlClient { use crate::IdeviceError;
client: super::remote_server::RemoteServerClient,
use super::remote_server::{Channel, RemoteServerClient};
const IDENTIFIER: &str = "com.apple.instruments.server.services.processcontrol";
pub struct ProcessControlClient<'a> {
channel: Channel<'a>,
}
impl<'a> ProcessControlClient<'a> {
pub async fn new(client: &'a mut RemoteServerClient) -> Result<Self, IdeviceError> {
let channel = client.make_channel(IDENTIFIER).await?; // Drop `&mut client` before continuing
Ok(Self { channel })
}
} }

View File

@@ -1,7 +1,8 @@
// Jackson Coxson // Jackson Coxson
use std::collections::HashMap; use std::collections::{HashMap, VecDeque};
use log::{debug, warn};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use crate::{ use crate::{
@@ -17,7 +18,12 @@ pub struct RemoteServerClient {
idevice: Box<dyn ReadWrite>, idevice: Box<dyn ReadWrite>,
current_message: u32, current_message: u32,
new_channel: u32, new_channel: u32,
channels: HashMap<u8, Vec<Message>>, channels: HashMap<u32, VecDeque<Message>>,
}
pub struct Channel<'a> {
client: &'a mut RemoteServerClient,
channel: u32,
} }
impl RemoteServerClient { impl RemoteServerClient {
@@ -33,9 +39,17 @@ impl RemoteServerClient {
pub async fn make_channel( pub async fn make_channel(
&mut self, &mut self,
identifier: impl Into<String>, identifier: impl Into<String>,
) -> Result<(), IdeviceError> { ) -> Result<Channel, IdeviceError> {
let code = self.new_channel; let code = self.new_channel;
let args = vec![AuxValue::U32(code), AuxValue::String(identifier.into())]; self.new_channel += 1;
let args = vec![
AuxValue::U32(code),
AuxValue::Array(
ns_keyed_archive::encode::encode_to_bytes(plist::Value::String(identifier.into()))
.expect("Failed to encode"),
),
];
self.send_message( self.send_message(
0, 0,
Some("_requestChannelWithCode:identifier:"), Some("_requestChannelWithCode:identifier:"),
@@ -44,12 +58,19 @@ impl RemoteServerClient {
) )
.await?; .await?;
let res = self.read_message().await?; let res = self.read_message(0).await?;
if res.data.is_some() { if res.data.is_some() {
return Err(IdeviceError::UnexpectedResponse); return Err(IdeviceError::UnexpectedResponse);
} }
Ok(()) self.build_channel(code)
}
fn build_channel(&mut self, code: u32) -> Result<Channel, IdeviceError> {
Ok(Channel {
client: self,
channel: code,
})
} }
pub async fn send_message( pub async fn send_message(
@@ -62,35 +83,64 @@ impl RemoteServerClient {
self.current_message += 1; self.current_message += 1;
let mheader = MessageHeader::new(0, 1, self.current_message, 0, channel, expect_reply); let mheader = MessageHeader::new(0, 1, self.current_message, 0, channel, expect_reply);
let mut pheader = PayloadHeader::instruments_message_type(); let pheader = PayloadHeader::method_invocation();
if expect_reply {
pheader.apply_expects_reply_map();
}
let aux = args.map(Aux::from_values); let aux = args.map(Aux::from_values);
let data: Option<plist::Value> = data.map(Into::into); let data: Option<plist::Value> = data.map(Into::into);
let message = Message::new(mheader, pheader, aux, data); let message = Message::new(mheader, pheader, aux, data);
debug!("Sending message: {message:#?}");
let bytes = message.serialize();
debug!(
"Re serde: {:#?}",
Message::from_reader(&mut std::io::Cursor::new(bytes)).await
);
self.idevice.write_all(&message.serialize()).await?; self.idevice.write_all(&message.serialize()).await?;
Ok(()) Ok(())
} }
pub async fn read_message(&mut self, channel: u32) -> Result<Message, IdeviceError> {
// Determine if we already have a message cached
let cache = match self.channels.get_mut(&channel) {
Some(c) => c,
None => return Err(IdeviceError::UnknownChannel(channel)),
};
if let Some(msg) = cache.pop_front() {
return Ok(msg);
}
loop {
let msg = Message::from_reader(&mut self.idevice).await?;
debug!("Read message: {msg:#?}");
if msg.message_header.channel == channel {
return Ok(msg);
} else if let Some(cache) = self.channels.get_mut(&msg.message_header.channel) {
cache.push_back(msg);
} else {
warn!(
"Received message for unknown channel: {}",
msg.message_header.channel
);
}
}
}
}
impl Channel<'_> {
pub async fn read_message(&mut self) -> Result<Message, IdeviceError> { pub async fn read_message(&mut self) -> Result<Message, IdeviceError> {
Message::from_reader(&mut self.idevice).await self.client.read_message(self.channel).await
} }
}
pub async fn send_message(
pub struct Channel {} &mut self,
data: Option<impl Into<plist::Value>>,
#[cfg(test)] args: Option<Vec<AuxValue>>,
mod tests { expect_reply: bool,
use crate::util::plist_to_archived_bytes; ) -> Result<(), IdeviceError> {
self.client
#[test] .send_message(self.channel, data, args, expect_reply)
fn t1() { .await
let selector: plist::Value = "asdf".into();
let selector = plist_to_archived_bytes(selector);
std::fs::write("/Users/jacksoncoxson/code/test/test-rs.plist", selector).unwrap();
} }
} }

View File

@@ -308,6 +308,10 @@ pub enum IdeviceError {
#[error("Unknown aux value type")] #[error("Unknown aux value type")]
UnknownAuxValueType(u32), UnknownAuxValueType(u32),
#[cfg(feature = "dvt")]
#[error("unknown channel")]
UnknownChannel(u32),
#[error("not enough bytes, expected {1}, got {0}")] #[error("not enough bytes, expected {1}, got {0}")]
NotEnoughBytes(usize, usize), NotEnoughBytes(usize, usize),

View File

@@ -1,13 +1,12 @@
// Jackson Coxson // Jackson Coxson
use std::{ use std::{
io::Write,
net::{IpAddr, SocketAddr}, net::{IpAddr, SocketAddr},
str::FromStr, str::FromStr,
}; };
use clap::{Arg, Command}; use clap::{Arg, Command};
use idevice::{debug_proxy::DebugProxyClient, tunneld::get_tunneld_devices, xpc::XPCDevice}; use idevice::{tunneld::get_tunneld_devices, xpc::XPCDevice};
use tokio::net::TcpStream; use tokio::net::TcpStream;
mod common; mod common;
@@ -78,5 +77,10 @@ async fn main() {
.await .await
.expect("Failed to connect"); .expect("Failed to connect");
let rs_client = idevice::dvt::remote_server::RemoteServerClient::new(Box::new(stream)); let mut rs_client =
idevice::dvt::remote_server::RemoteServerClient::new(Box::new(stream)).unwrap();
rs_client.read_message(0).await.expect("no read??");
let pc_client = idevice::dvt::process_control::ProcessControlClient::new(&mut rs_client)
.await
.unwrap();
} }