Skip to content

Commit

Permalink
usb: use bincode for conversions between message header struct and ra…
Browse files Browse the repository at this point in the history
…w bytes (#33)

* refactor: use bincode to serialize message headers

---------

Co-authored-by: LIAUD Corentin <corentinliaud26@gmail.com>
  • Loading branch information
lavafroth and cocool97 authored Oct 18, 2024
1 parent 5634679 commit fc1fe74
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 93 deletions.
3 changes: 3 additions & 0 deletions adb_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ version.workspace = true

[dependencies]
base64 = "0.22.1"
bincode = "1.3.3"
byteorder = { version = "1.5.0" }
chrono = { version = "0.4.38" }
homedir = { version = "0.3.4" }
Expand All @@ -21,4 +22,6 @@ rand = "0.7.0"
regex = { version = "1.11.0", features = ["perf", "std", "unicode"] }
rsa = { version = "0.3.0" }
rusb = { version = "0.9.4", features = ["vendored"] }
serde = { version = "1.0.210", features = ["derive"] }
serde_repr = "0.1.19"
thiserror = { version = "1.0.64" }
4 changes: 3 additions & 1 deletion adb_client/src/models/device_short.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ impl TryFrom<Vec<u8>> for DeviceShort {

fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
// Optional final '\n' is used to match TrackDevices inputs
let groups = DEVICES_REGEX.captures(&value).unwrap();
let groups = DEVICES_REGEX
.captures(&value)
.ok_or(RustADBError::RegexParsingError)?;
Ok(DeviceShort {
identifier: String::from_utf8(
groups
Expand Down
4 changes: 2 additions & 2 deletions adb_client/src/transports/usb_transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ impl USBTransport {
Self::configure_endpoint(handle, &endpoint)?;

// TODO: loop
let message_bytes = &message.to_bytes();
let written = handle.write_bulk(endpoint.address, message_bytes, timeout)?;
let message_bytes = message.to_bytes()?;
let written = handle.write_bulk(endpoint.address, &message_bytes, timeout)?;

// TODO: loop
let payload = message.into_payload();
Expand Down
82 changes: 31 additions & 51 deletions adb_client/src/usb/adb_usb_message.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use serde::{Deserialize, Serialize};

use super::usb_commands::USBCommand;
use crate::RustADBError;

Expand All @@ -7,77 +9,55 @@ pub const AUTH_RSAPUBLICKEY: u32 = 3;

#[derive(Debug)]
pub struct ADBUsbMessage {
header: ADBUsbMessageHeader,
payload: Vec<u8>,
}

#[derive(Debug, Serialize, Deserialize)]
#[repr(C)]
pub struct ADBUsbMessageHeader {
command: USBCommand, /* command identifier constant */
arg0: u32, /* first argument */
arg1: u32, /* second argument */
data_length: u32, /* length of payload (0 is allowed) */
data_crc32: u32, /* crc32 of data payload */
magic: u32, /* command ^ 0xffffffff */
payload: Vec<u8>,
}

impl ADBUsbMessage {
pub fn new(command: USBCommand, arg0: u32, arg1: u32, data: Vec<u8>) -> Self {
let command_u32 = command.u32_value();
let command_u32 = command as u32;
Self {
command,
arg0,
arg1,
data_length: data.len() as u32,
data_crc32: data.iter().map(|&x| x as u32).sum(),
magic: command_u32 ^ 0xFFFFFFFF,
header: ADBUsbMessageHeader {
command,
arg0,
arg1,
data_length: data.len() as u32,
data_crc32: data.iter().map(|&x| x as u32).sum(),
magic: command_u32 ^ 0xFFFFFFFF,
},
payload: data,
}
}

pub fn compute_checksum(&self) -> u32 {
self.command.u32_value() ^ 0xFFFFFFFF
self.header.command as u32 ^ 0xFFFFFFFF
}

pub fn check_message_integrity(&self) -> bool {
self.compute_checksum() == self.magic
}

pub fn to_bytes(&self) -> [u8; 24] {
let mut result = [0u8; 24];
let mut offset = 0;

let command_bytes = self.command.u32_value().to_le_bytes();
result[offset..offset + 4].copy_from_slice(&command_bytes);
offset += 4;

let arg0_bytes = self.arg0.to_le_bytes();
result[offset..offset + 4].copy_from_slice(&arg0_bytes);
offset += 4;

let arg1_bytes = self.arg1.to_le_bytes();
result[offset..offset + 4].copy_from_slice(&arg1_bytes);
offset += 4;

let data_length_bytes = self.data_length.to_le_bytes();
result[offset..offset + 4].copy_from_slice(&data_length_bytes);
offset += 4;

let data_crc32_bytes = self.data_crc32.to_le_bytes();
result[offset..offset + 4].copy_from_slice(&data_crc32_bytes);
offset += 4;

let magic_bytes = self.magic.to_le_bytes();
result[offset..offset + 4].copy_from_slice(&magic_bytes);

result
self.compute_checksum() == self.header.magic
}

pub fn command(&self) -> USBCommand {
self.command
self.header.command
}

pub fn arg0(&self) -> u32 {
self.arg0
self.header.arg0
}

pub fn data_length(&self) -> u32 {
self.data_length
self.header.data_length
}

pub fn into_payload(self) -> Vec<u8> {
Expand All @@ -87,27 +67,27 @@ impl ADBUsbMessage {
pub fn with_payload(&mut self, payload: Vec<u8>) {
self.payload = payload;
}

pub fn to_bytes(&self) -> Result<Vec<u8>, RustADBError> {
bincode::serialize(&self.header).map_err(|_e| RustADBError::ConversionError)
}
}

impl TryFrom<[u8; 24]> for ADBUsbMessage {
type Error = RustADBError;

fn try_from(value: [u8; 24]) -> Result<Self, Self::Error> {
let message = Self {
command: USBCommand::try_from(&value[0..4])?,
arg0: u32::from_le_bytes(value[4..8].try_into()?),
arg1: u32::from_le_bytes(value[8..12].try_into()?),
data_length: u32::from_le_bytes(value[12..16].try_into()?),
data_crc32: u32::from_le_bytes(value[16..20].try_into()?),
magic: u32::from_le_bytes(value[20..24].try_into()?),
let header = bincode::deserialize(&value).map_err(|_e| RustADBError::ConversionError)?;
let message = ADBUsbMessage {
header,
payload: vec![],
};

// Check checksum
if !message.check_message_integrity() {
return Err(RustADBError::InvalidCRC32(
message.compute_checksum(),
message.magic,
message.header.magic,
));
}

Expand Down
49 changes: 10 additions & 39 deletions adb_client/src/usb/usb_commands.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::fmt::Display;

use crate::RustADBError;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
#[repr(u32)]
pub enum USBCommand {
/// Connect to a device
Cnxn,
Cnxn = 0x4e584e43,
/// Close connection to a device
Clse,
Clse = 0x45534c43,
/// Device ask for authentication
Auth,
Auth = 0x48545541,
/// Open a data connection
Open,
/// Server understood the message
Okay,
Open = 0x4e45504f,
/// Write data to connection
Write,
Write = 0x45545257,
/// Server understood the message
Okay = 0x59414b4f,
// Sync 0x434e5953
// Stls 0x534C5453
}

impl USBCommand {
pub fn u32_value(&self) -> u32 {
match self {
Self::Cnxn => 0x4e584e43,
Self::Clse => 0x45534c43,
Self::Auth => 0x48545541,
Self::Open => 0x4e45504f,
Self::Write => 0x45545257,
Self::Okay => 0x59414b4f,
}
}
}

impl Display for USBCommand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand All @@ -45,19 +32,3 @@ impl Display for USBCommand {
}
}
}

impl TryFrom<&[u8]> for USBCommand {
type Error = RustADBError;

fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
match u32::from_le_bytes(value.try_into()?) {
0x4e584e43 => Ok(Self::Cnxn),
0x45534c43 => Ok(Self::Clse),
0x48545541 => Ok(Self::Auth),
0x4e45504f => Ok(Self::Open),
0x45545257 => Ok(Self::Write),
0x59414b4f => Ok(Self::Okay),
_ => Err(RustADBError::ConversionError),
}
}
}

0 comments on commit fc1fe74

Please sign in to comment.