Skip to main content

adb_client/server_device/commands/
recv.rs

1use crate::{
2    Result,
3    models::{ADBCommand, ADBLocalCommand, SyncCommand},
4    server_device::ADBServerDevice,
5};
6use byteorder::{LittleEndian, ReadBytesExt};
7use std::io::{BufReader, BufWriter, Read, Write};
8
9/// Internal structure wrapping a [`std::io::Read`] and hiding underlying protocol logic.
10struct ADBRecvCommandReader<R: Read> {
11    inner: R,
12    remaining_data_bytes_to_read: usize,
13}
14
15impl<R: Read> ADBRecvCommandReader<R> {
16    pub const fn new(inner: R) -> Self {
17        Self {
18            inner,
19            remaining_data_bytes_to_read: 0,
20        }
21    }
22}
23
24impl<R: Read> Read for ADBRecvCommandReader<R> {
25    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
26        // In case of a "DATA" header, we may not have enough space in `buf` to fill it with "length" bytes coming from device.
27        // `remaining_data_bytes_to_read` represents how many bytes are still left to read before receiving another header.
28        if self.remaining_data_bytes_to_read == 0 {
29            let mut header = [0_u8; 4];
30            self.inner.read_exact(&mut header)?;
31
32            match &header[..] {
33                b"DATA" => {
34                    let length = self.inner.read_u32::<LittleEndian>()? as usize;
35                    // ensuring read data is at most the buffer length
36                    let min_data_to_read = std::cmp::min(length, buf.len());
37                    let effective_read = self.inner.read(&mut buf[0..min_data_to_read])?;
38                    self.remaining_data_bytes_to_read = length - effective_read;
39
40                    Ok(effective_read)
41                }
42                b"DONE" => Ok(0),
43                b"FAIL" => {
44                    let length = self.inner.read_u32::<LittleEndian>()? as usize;
45                    let mut error_msg = vec![0; length];
46                    self.inner.read_exact(&mut error_msg)?;
47
48                    Err(std::io::Error::other(format!(
49                        "ADB request failed: {}",
50                        String::from_utf8_lossy(&error_msg)
51                    )))
52                }
53                _ => Err(std::io::Error::other(format!(
54                    "Unknown response from device {header:#?}"
55                ))),
56            }
57        } else {
58            // Computing minimum to ensure to stop reading before next header...
59            let data_to_read = std::cmp::min(self.remaining_data_bytes_to_read, buf.len());
60            self.inner.read_exact(&mut buf[..data_to_read])?;
61
62            self.remaining_data_bytes_to_read -= data_to_read;
63
64            Ok(data_to_read)
65        }
66    }
67}
68
69const BUFFER_SIZE: usize = 65535;
70
71impl ADBServerDevice {
72    /// Receives path to stream from the device.
73    pub fn pull(&mut self, path: &dyn AsRef<str>, stream: &mut dyn Write) -> Result<()> {
74        self.set_serial_transport()?;
75
76        // Set device in SYNC mode
77        self.transport
78            .send_adb_request(&ADBCommand::Local(ADBLocalCommand::Sync))?;
79
80        // Send a recv command
81        self.transport.send_sync_request(&SyncCommand::Recv)?;
82
83        self.handle_recv_command(path, stream)
84    }
85
86    fn handle_recv_command<S: AsRef<str>>(&self, from: S, output: &mut dyn Write) -> Result<()> {
87        let mut raw_connection = self.transport.get_raw_connection()?;
88
89        let from_as_bytes = from.as_ref().as_bytes();
90        let mut buffer = Vec::with_capacity(4 + from_as_bytes.len());
91        buffer.extend_from_slice(&(u32::try_from(from.as_ref().len())?).to_le_bytes());
92        buffer.extend_from_slice(from_as_bytes);
93        raw_connection.write_all(&buffer)?;
94
95        let reader = ADBRecvCommandReader::new(raw_connection);
96        std::io::copy(
97            &mut BufReader::with_capacity(BUFFER_SIZE, reader),
98            &mut BufWriter::with_capacity(BUFFER_SIZE, output),
99        )?;
100
101        // Connection should've been left in SYNC mode by now
102        Ok(())
103    }
104}