Skip to main content

ios_core/mux/
client.rs

1use crate::mux::connection::{usbmuxd_socket_address, UsbmuxStream};
2use crate::mux::protocol::*;
3use crate::mux::{MuxDevice, MuxError};
4
5/// usbmuxd client for device discovery and connection.
6pub struct MuxClient {
7    stream: UsbmuxStream,
8    tag: u32,
9}
10
11impl MuxClient {
12    /// Connect to the local usbmuxd daemon.
13    pub async fn connect() -> Result<Self, MuxError> {
14        let addr = usbmuxd_socket_address();
15        let stream = UsbmuxStream::connect(&addr).await?;
16        Ok(Self { stream, tag: 1 })
17    }
18
19    /// List all currently connected devices.
20    pub async fn list_devices(&mut self) -> Result<Vec<MuxDevice>, MuxError> {
21        let req = ListDevicesRequest {
22            message_type: "ListDevices",
23            prog_name: "ios-rs",
24            client_version_string: "ios-rs-0.1",
25        };
26        let tag = self.next_tag();
27        send_plist(&mut self.stream, &req, tag).await?;
28        let resp: DeviceList = recv_plist(&mut self.stream).await?;
29        Ok(resp
30            .device_list
31            .into_iter()
32            .map(MuxDevice::from_raw)
33            .collect())
34    }
35
36    /// Read the system BUID from usbmuxd.
37    pub async fn read_buid(&mut self) -> Result<String, MuxError> {
38        let req = ReadBuidRequest {
39            message_type: "ReadBUID",
40            prog_name: "ios-rs",
41            client_version_string: "ios-rs-0.1",
42            bundle_id: "rs.ios",
43            lib_usbmux_version: 3,
44        };
45        let tag = self.next_tag();
46        send_plist(&mut self.stream, &req, tag).await?;
47        let resp: ReadBuidResponse = recv_plist(&mut self.stream).await?;
48        Ok(resp.buid)
49    }
50
51    /// Send ReadPairRecord to usbmuxd (acknowledgment only; pair record is loaded from filesystem).
52    pub async fn read_pair_record(&mut self, udid: &str) -> Result<(), MuxError> {
53        let req = ReadPairRecordRequest {
54            message_type: "ReadPairRecord",
55            prog_name: "ios-rs",
56            client_version_string: "ios-rs-0.1",
57            bundle_id: "rs.ios",
58            lib_usbmux_version: 3,
59            pair_record_id: udid.to_string(),
60        };
61        let tag = self.next_tag();
62        send_plist(&mut self.stream, &req, tag).await?;
63        let _: plist::Value = recv_plist(&mut self.stream).await?;
64        Ok(())
65    }
66
67    /// Connect the stream to a device port. Consumes self; returns the raw stream.
68    pub async fn connect_to_port(
69        mut self,
70        device_id: u32,
71        port: u16,
72    ) -> Result<UsbmuxStream, MuxError> {
73        let be_port = port.to_be();
74        let req = ConnectRequest {
75            message_type: "Connect",
76            prog_name: "ios-rs",
77            client_version_string: "ios-rs-0.1",
78            bundle_id: "rs.ios",
79            lib_usbmux_version: 3,
80            device_id,
81            port_number: be_port,
82        };
83        let tag = self.next_tag();
84        send_plist(&mut self.stream, &req, tag).await?;
85        let resp: ConnectResponse = recv_plist(&mut self.stream).await?;
86        if resp.number != 0 {
87            return Err(MuxError::Protocol(format!(
88                "usbmuxd connect failed: code {}",
89                resp.number
90            )));
91        }
92        Ok(self.stream)
93    }
94
95    fn next_tag(&mut self) -> u32 {
96        let t = self.tag;
97        self.tag += 1;
98        t
99    }
100}