use plist::Value;
use std::io::{Cursor, Read};
use tokio::io::{AsyncRead, AsyncReadExt};
use super::errors::DvtError;
use crate::{IdeviceError, pretty_print_plist};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MessageHeader {
magic: u32,
header_len: u32,
fragment_id: u16,
fragment_count: u16,
length: u32,
identifier: u32,
conversation_index: u32,
pub channel: i32,
expects_reply: bool,
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct PayloadHeader {
msg_type: u8,
flags_a: u8,
flags_b: u8,
reserved: u8,
aux_length: u32,
total_length: u32,
flags: u32,
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct AuxHeader {
buffer_size: u32,
unknown: u32,
aux_size: u32,
unknown2: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Aux {
pub header: AuxHeader,
pub values: Vec<AuxValue>,
}
#[derive(Clone, PartialEq)]
pub enum AuxValue {
Null,
String(String),
Array(Vec<u8>),
U32(u32),
I64(i64),
Double(f64),
PrimitiveDictionary(Vec<(AuxValue, Vec<AuxValue>)>),
}
#[derive(Clone, PartialEq)]
pub struct Message {
pub message_header: MessageHeader,
pub payload_header: PayloadHeader,
pub aux: Option<Aux>,
pub data: Option<Value>,
pub raw_data: Option<Vec<u8>>,
}
impl Aux {
fn parse_legacy_bytes(bytes: Vec<u8>) -> Result<Self, IdeviceError> {
if bytes.len() < 16 {
return Err(IdeviceError::NotEnoughBytes(bytes.len(), 16));
}
let mut cursor = Cursor::new(bytes.as_slice());
let header = AuxHeader {
buffer_size: Self::read_u32(&mut cursor)?,
unknown: Self::read_u32(&mut cursor)?,
aux_size: Self::read_u32(&mut cursor)?,
unknown2: Self::read_u32(&mut cursor)?,
};
let mut values = Vec::new();
while cursor.position() + 4 <= bytes.len() as u64 {
let aux_type = Self::read_u32(&mut cursor)?;
match aux_type {
0x0a => {
}
0x0f0 => {
let _flags = Self::read_u32(&mut cursor)?;
let body_len = Self::read_u64(&mut cursor)?;
let pos = cursor.position() as usize;
let end = pos + body_len as usize;
if end > bytes.len() {
return Err(IdeviceError::NotEnoughBytes(bytes.len(), end));
}
cursor.set_position(end as u64);
}
_ => {
let pos = cursor.position() as usize - 4;
let mut sub = Cursor::new(&bytes[pos..]);
values.push(Self::parse_primitive(&mut sub)?);
cursor.set_position(pos as u64 + sub.position());
}
}
}
Ok(Self { header, values })
}
fn read_u32(cursor: &mut Cursor<&[u8]>) -> Result<u32, IdeviceError> {
let mut buf = [0u8; 4];
Read::read_exact(cursor, &mut buf)?;
Ok(u32::from_le_bytes(buf))
}
fn read_u64(cursor: &mut Cursor<&[u8]>) -> Result<u64, IdeviceError> {
let mut buf = [0u8; 8];
Read::read_exact(cursor, &mut buf)?;
Ok(u64::from_le_bytes(buf))
}
fn read_f64(cursor: &mut Cursor<&[u8]>) -> Result<f64, IdeviceError> {
let mut buf = [0u8; 8];
Read::read_exact(cursor, &mut buf)?;
Ok(f64::from_le_bytes(buf))
}
fn read_exact_vec(cursor: &mut Cursor<&[u8]>, len: usize) -> Result<Vec<u8>, IdeviceError> {
let mut buf = vec![0u8; len];
Read::read_exact(cursor, &mut buf)?;
Ok(buf)
}
fn parse_primitive(cursor: &mut Cursor<&[u8]>) -> Result<AuxValue, IdeviceError> {
let raw_type = Self::read_u32(cursor)?;
let type_code = raw_type & 0xFF;
match type_code {
0x01 => {
let len = Self::read_u32(cursor)? as usize;
Ok(AuxValue::String(String::from_utf8(Self::read_exact_vec(
cursor, len,
)?)?))
}
0x02 => {
let len = Self::read_u32(cursor)? as usize;
Ok(AuxValue::Array(Self::read_exact_vec(cursor, len)?))
}
0x03 => Ok(AuxValue::U32(Self::read_u32(cursor)?)),
0x06 => Ok(AuxValue::I64(Self::read_u64(cursor)? as i64)),
0x09 => Ok(AuxValue::Double(Self::read_f64(cursor)?)),
0x0A => Ok(AuxValue::Null),
_ => Err(DvtError::UnknownAuxValueType(raw_type).into()),
}
}
pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, IdeviceError> {
if bytes.is_empty() {
return Ok(Self::from_values(Vec::new()));
}
if (bytes[0] as u32) != 0xF0 {
return Self::parse_legacy_bytes(bytes);
}
if bytes.len() < 16 {
return Err(IdeviceError::NotEnoughBytes(bytes.len(), 16));
}
let mut cursor = Cursor::new(bytes.as_slice());
let _type_and_flags = Self::read_u32(&mut cursor)?;
let _unknown_flags = Self::read_u32(&mut cursor)?;
let body_len = Self::read_u64(&mut cursor)?;
let body_end = 16u64 + body_len;
if body_end > bytes.len() as u64 {
return Err(IdeviceError::NotEnoughBytes(bytes.len(), body_end as usize));
}
let mut values = Vec::new();
while cursor.position() < body_end {
let _key = Self::parse_primitive(&mut cursor)?;
let value = Self::parse_primitive(&mut cursor)?;
values.push(value);
}
Ok(Self {
header: AuxHeader::default(),
values,
})
}
pub fn from_values(values: Vec<AuxValue>) -> Self {
Self {
header: AuxHeader::default(),
values,
}
}
pub fn serialize(&self) -> Vec<u8> {
let mut values_payload = Vec::new();
for v in self.values.iter() {
values_payload.extend_from_slice(&0x0a_u32.to_le_bytes());
match v {
AuxValue::Null => {
}
AuxValue::String(s) => {
values_payload.extend_from_slice(&0x01_u32.to_le_bytes());
values_payload.extend_from_slice(&(s.len() as u32).to_le_bytes());
values_payload.extend_from_slice(s.as_bytes());
}
AuxValue::Array(v) => {
values_payload.extend_from_slice(&0x02_u32.to_le_bytes());
values_payload.extend_from_slice(&(v.len() as u32).to_le_bytes());
values_payload.extend_from_slice(v);
}
AuxValue::U32(u) => {
values_payload.extend_from_slice(&0x03_u32.to_le_bytes());
values_payload.extend_from_slice(&u.to_le_bytes());
}
AuxValue::I64(i) => {
values_payload.extend_from_slice(&0x06_u32.to_le_bytes());
values_payload.extend_from_slice(&i.to_le_bytes());
}
AuxValue::Double(d) => {
values_payload.extend_from_slice(&0x09_u32.to_le_bytes());
values_payload.extend_from_slice(&d.to_le_bytes());
}
AuxValue::PrimitiveDictionary(entries) => {
let mut body_payload = Vec::new();
for (key, values) in entries {
body_payload.extend_from_slice(&0x0a_u32.to_le_bytes());
write_primitive_value(key, &mut body_payload);
for value in values {
write_primitive_value(value, &mut body_payload);
}
}
let body_len = body_payload.len() as u64;
values_payload.extend_from_slice(&0xf0_u32.to_le_bytes());
values_payload.extend_from_slice(&0_u32.to_le_bytes()); values_payload.extend_from_slice(&body_len.to_le_bytes());
values_payload.extend_from_slice(&body_payload);
}
}
}
let mut res = Vec::new();
let buffer_size = 496_u32;
res.extend_from_slice(&buffer_size.to_le_bytes());
res.extend_from_slice(&0_u32.to_le_bytes());
res.extend_from_slice(&(values_payload.len() as u32).to_le_bytes());
res.extend_from_slice(&0_u32.to_le_bytes());
res.extend_from_slice(&values_payload);
res
}
}
fn write_primitive_value(v: &AuxValue, payload: &mut Vec<u8>) {
match v {
AuxValue::Null => {
}
AuxValue::String(s) => {
payload.extend_from_slice(&0x01_u32.to_le_bytes());
payload.extend_from_slice(&(s.len() as u32).to_le_bytes());
payload.extend_from_slice(s.as_bytes());
}
AuxValue::Array(bytes) => {
payload.extend_from_slice(&0x02_u32.to_le_bytes());
payload.extend_from_slice(&(bytes.len() as u32).to_le_bytes());
payload.extend_from_slice(bytes);
}
AuxValue::U32(val) => {
payload.extend_from_slice(&0x03_u32.to_le_bytes());
payload.extend_from_slice(&val.to_le_bytes());
}
AuxValue::I64(val) => {
payload.extend_from_slice(&0x06_u32.to_le_bytes());
payload.extend_from_slice(&val.to_le_bytes());
}
AuxValue::Double(val) => {
payload.extend_from_slice(&0x09_u32.to_le_bytes());
payload.extend_from_slice(&val.to_le_bytes());
}
AuxValue::PrimitiveDictionary(_) => {
payload.extend_from_slice(&0xf0_u32.to_le_bytes());
payload.extend_from_slice(&0_u32.to_le_bytes());
payload.extend_from_slice(&0u64.to_le_bytes());
}
}
}
impl AuxValue {
pub fn archived_value(v: impl Into<plist::Value>) -> Self {
Self::Array(ns_keyed_archive::encode::encode_to_bytes(v.into()).expect("Failed to encode"))
}
pub fn primitive_buffer(bytes: Vec<u8>) -> Self {
Self::Array(bytes)
}
pub fn primitive_dictionary(entries: Vec<(AuxValue, Vec<AuxValue>)>) -> Self {
Self::PrimitiveDictionary(entries)
}
pub fn dtx_method_args(args: Vec<Self>) -> Self {
Self::PrimitiveDictionary(vec![(Self::Null, args)])
}
}
impl MessageHeader {
pub fn new(
fragment_id: u16,
fragment_count: u16,
identifier: u32,
conversation_index: u32,
channel: i32,
expects_reply: bool,
) -> Self {
Self {
magic: 0x1F3D5B79,
header_len: 32,
fragment_id,
fragment_count,
length: 0,
identifier,
conversation_index,
channel,
expects_reply,
}
}
pub(crate) fn identifier(&self) -> u32 {
self.identifier
}
pub(crate) fn conversation_index(&self) -> u32 {
self.conversation_index
}
pub(crate) fn expects_reply(&self) -> bool {
self.expects_reply
}
pub fn serialize(&self) -> Vec<u8> {
let mut res = Vec::new();
res.extend_from_slice(&self.magic.to_le_bytes());
res.extend_from_slice(&self.header_len.to_le_bytes());
res.extend_from_slice(&self.fragment_id.to_le_bytes());
res.extend_from_slice(&self.fragment_count.to_le_bytes());
res.extend_from_slice(&self.length.to_le_bytes());
res.extend_from_slice(&self.identifier.to_le_bytes());
res.extend_from_slice(&self.conversation_index.to_le_bytes());
res.extend_from_slice(&self.channel.to_le_bytes());
res.extend_from_slice(&if self.expects_reply { 1_u32 } else { 0 }.to_le_bytes());
res
}
}
impl PayloadHeader {
pub fn new() -> Self {
Self::default()
}
pub fn serialize(&self) -> Vec<u8> {
let mut res = vec![self.msg_type, self.flags_a, self.flags_b, self.reserved];
res.extend_from_slice(&self.aux_length.to_le_bytes());
res.extend_from_slice(&self.total_length.to_le_bytes());
res.extend_from_slice(&self.flags.to_le_bytes());
res
}
pub fn method_invocation() -> Self {
Self {
msg_type: 2,
..Default::default()
}
}
}
impl Message {
pub async fn from_reader<R: AsyncRead + Unpin>(reader: &mut R) -> Result<Self, IdeviceError> {
let mut packet_data: Vec<u8> = Vec::new();
let mheader = loop {
let mut buf = [0u8; 32];
reader.read_exact(&mut buf).await?;
let header = MessageHeader {
magic: u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]),
header_len: u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]),
fragment_id: u16::from_le_bytes([buf[8], buf[9]]),
fragment_count: u16::from_le_bytes([buf[10], buf[11]]),
length: u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
identifier: u32::from_le_bytes([buf[16], buf[17], buf[18], buf[19]]),
conversation_index: u32::from_le_bytes([buf[20], buf[21], buf[22], buf[23]]),
channel: {
let wire_channel = i32::from_le_bytes([buf[24], buf[25], buf[26], buf[27]]);
let conversation_index =
u32::from_le_bytes([buf[20], buf[21], buf[22], buf[23]]);
if conversation_index.is_multiple_of(2) {
-wire_channel
} else {
wire_channel
}
},
expects_reply: u32::from_le_bytes([buf[28], buf[29], buf[30], buf[31]]) == 1,
};
if header.fragment_count > 1 && header.fragment_id == 0 {
continue;
}
let mut buf = vec![0u8; header.length as usize];
reader.read_exact(&mut buf).await?;
packet_data.extend(buf);
if header.fragment_id == header.fragment_count - 1 {
break header;
}
};
let buf = &packet_data[0..16];
let pheader = PayloadHeader {
msg_type: buf[0],
flags_a: buf[1],
flags_b: buf[2],
reserved: buf[3],
aux_length: u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]),
total_length: u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]),
flags: u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
};
let aux = if pheader.aux_length > 0 {
let buf = packet_data[16..(16 + pheader.aux_length as usize)].to_vec();
Some(Aux::from_bytes(buf)?)
} else {
None
};
let need_len = (pheader.total_length - pheader.aux_length) as usize;
let buf = packet_data
[(pheader.aux_length + 16) as usize..pheader.aux_length as usize + 16 + need_len]
.to_vec();
let raw_data = if buf.is_empty() {
None
} else {
Some(buf.clone())
};
let data = if buf.is_empty() {
None
} else {
Some(
ns_keyed_archive::decode::from_bytes(&buf)
.map_err(super::errors::DvtError::from)?,
)
};
Ok(Message {
message_header: mheader,
payload_header: pheader,
aux,
data,
raw_data,
})
}
pub fn new(
message_header: MessageHeader,
payload_header: PayloadHeader,
aux: Option<Aux>,
data: Option<Value>,
) -> Self {
Self {
message_header,
payload_header,
aux,
data,
raw_data: None,
}
}
pub fn serialize(&self) -> Vec<u8> {
let aux = match &self.aux {
Some(a) => a.serialize(),
None => Vec::new(),
};
let data = match &self.data {
Some(d) => ns_keyed_archive::encode::encode_to_bytes(d.to_owned())
.expect("Failed to encode value"),
None => Vec::new(),
};
let mut payload_header = self.payload_header.to_owned();
payload_header.aux_length = aux.len() as u32;
payload_header.total_length = (aux.len() + data.len()) as u32;
let payload_header = payload_header.serialize();
let mut message_header = self.message_header.to_owned();
message_header.length = (payload_header.len() + aux.len() + data.len()) as u32;
let mut res = Vec::new();
res.extend_from_slice(&message_header.serialize());
res.extend_from_slice(&payload_header);
res.extend_from_slice(&aux);
res.extend_from_slice(&data);
res
}
pub(crate) fn build_raw_reply(
channel: i32,
incoming_msg_id: u32,
incoming_conversation_index: u32,
data_bytes: &[u8],
) -> Vec<u8> {
let msg_type: u8 = if data_bytes.is_empty() { 0 } else { 3 };
let flags_a: u8 = 0;
let flags_b: u8 = 0;
let reserved: u8 = 0;
let aux_len: u32 = 0;
let total_len: u32 = data_bytes.len() as u32;
let payload_total = 16usize + data_bytes.len();
let magic: u32 = 0x1F3D5B79;
let header_len: u32 = 32;
let fragment_id: u16 = 0;
let fragment_count: u16 = 1;
let length: u32 = payload_total as u32;
let conversation_index = incoming_conversation_index + 1;
let expects_reply: u32 = 0;
let wire_channel = if conversation_index.is_multiple_of(2) {
channel
} else {
-channel
};
let mut buf = Vec::with_capacity(32 + 16 + data_bytes.len());
buf.extend_from_slice(&magic.to_le_bytes());
buf.extend_from_slice(&header_len.to_le_bytes());
buf.extend_from_slice(&fragment_id.to_le_bytes());
buf.extend_from_slice(&fragment_count.to_le_bytes());
buf.extend_from_slice(&length.to_le_bytes());
buf.extend_from_slice(&incoming_msg_id.to_le_bytes());
buf.extend_from_slice(&conversation_index.to_le_bytes());
buf.extend_from_slice(&wire_channel.to_le_bytes());
buf.extend_from_slice(&expects_reply.to_le_bytes());
buf.push(msg_type);
buf.push(flags_a);
buf.push(flags_b);
buf.push(reserved);
buf.extend_from_slice(&aux_len.to_le_bytes());
buf.extend_from_slice(&total_len.to_le_bytes());
buf.extend_from_slice(&0_u32.to_le_bytes());
buf.extend_from_slice(data_bytes);
buf
}
}
impl std::fmt::Debug for AuxValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AuxValue::Null => write!(f, "Null"),
AuxValue::String(s) => write!(f, "String({s:?})"),
AuxValue::Array(arr) => write!(
f,
"Array(len={}, first_bytes={:?})",
arr.len(),
&arr[..arr.len().min(10)]
),
AuxValue::U32(n) => write!(f, "U32({n})"),
AuxValue::I64(n) => write!(f, "I64({n})"),
AuxValue::Double(d) => write!(f, "Double({d})"),
AuxValue::PrimitiveDictionary(_) => write!(f, "PrimitiveDictionary"),
}
}
}
impl std::fmt::Debug for Message {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Message")
.field("message_header", &self.message_header)
.field("payload_header", &self.payload_header)
.field("aux", &self.aux)
.field("data", &self.data.as_ref().map(pretty_print_plist))
.finish()
}
}