use std::io::{Error, ErrorKind, Read, Write};
use std::net::{Ipv4Addr, SocketAddrV4, TcpStream};
use std::str::FromStr;
use byteorder::{ByteOrder, LittleEndian};
use crate::ADBTransport;
use crate::models::{ADBCommand, AdbRequestStatus, SyncCommand};
use crate::{Result, RustADBError};
const DEFAULT_SERVER_IP: Ipv4Addr = Ipv4Addr::LOCALHOST;
const DEFAULT_SERVER_PORT: u16 = 5037;
#[derive(Debug)]
pub struct TCPServerTransport {
socket_addr: SocketAddrV4,
tcp_stream: Option<TcpStream>,
}
impl Default for TCPServerTransport {
fn default() -> Self {
Self::new(SocketAddrV4::new(DEFAULT_SERVER_IP, DEFAULT_SERVER_PORT))
}
}
impl TCPServerTransport {
#[must_use]
pub const fn new(socket_addr: SocketAddrV4) -> Self {
Self {
socket_addr,
tcp_stream: None,
}
}
#[must_use]
pub fn new_or_default(socket_addr: Option<SocketAddrV4>) -> Self {
socket_addr.map_or_else(Self::default, Self::new)
}
#[must_use]
pub const fn get_socketaddr(&self) -> SocketAddrV4 {
self.socket_addr
}
pub(crate) fn proxy_connection(
&self,
adb_command: &ADBCommand,
with_response: bool,
) -> Result<Vec<u8>> {
self.send_adb_request(adb_command)?;
if with_response {
let length = self.get_hex_body_length()?;
let mut body = vec![
0;
length
.try_into()
.map_err(|_| RustADBError::ConversionError)?
];
if length > 0 {
self.get_raw_connection()?.read_exact(&mut body)?;
}
Ok(body)
} else {
Ok(vec![])
}
}
pub(crate) fn get_raw_connection(&self) -> Result<&TcpStream> {
self.tcp_stream
.as_ref()
.ok_or(RustADBError::IOError(Error::new(
ErrorKind::NotConnected,
"not connected",
)))
}
pub(crate) fn get_hex_body_length(&self) -> Result<u32> {
let length_buffer = self.read_body_length()?;
Ok(u32::from_str_radix(
std::str::from_utf8(&length_buffer)?,
16,
)?)
}
pub(crate) fn send_sync_request(&self, command: &SyncCommand) -> Result<()> {
Ok(self
.get_raw_connection()?
.write_all(command.to_string().as_bytes())?)
}
pub(crate) fn get_body_length(&self) -> Result<u32> {
let length_buffer = self.read_body_length()?;
Ok(LittleEndian::read_u32(&length_buffer))
}
fn read_body_length(&self) -> Result<[u8; 4]> {
let mut length_buffer = [0; 4];
self.get_raw_connection()?.read_exact(&mut length_buffer)?;
Ok(length_buffer)
}
pub(crate) fn send_adb_request(&self, command: &ADBCommand) -> Result<()> {
let adb_command_string = command.to_string();
let adb_request = format!("{:04x}{}", adb_command_string.len(), adb_command_string);
self.get_raw_connection()?
.write_all(adb_request.as_bytes())?;
self.read_adb_response()
}
pub(crate) fn read_adb_response(&self) -> Result<()> {
let mut request_status = [0; 4];
self.get_raw_connection()?.read_exact(&mut request_status)?;
match AdbRequestStatus::from_str(std::str::from_utf8(request_status.as_ref())?)? {
AdbRequestStatus::Fail => {
let length = self.get_hex_body_length()?;
let mut body = vec![
0;
length
.try_into()
.map_err(|_| RustADBError::ConversionError)?
];
if length > 0 {
self.get_raw_connection()?.read_exact(&mut body)?;
}
Err(RustADBError::ADBRequestFailed(String::from_utf8(body)?))
}
AdbRequestStatus::Okay => Ok(()),
}
}
}
impl ADBTransport for TCPServerTransport {
fn disconnect(&mut self) -> Result<()> {
if let Some(conn) = &mut self.tcp_stream {
conn.shutdown(std::net::Shutdown::Both)?;
log::trace!("Disconnected from {}", conn.peer_addr()?);
}
Ok(())
}
fn connect(&mut self) -> Result<()> {
if let Some(previous) = &self.tcp_stream {
let _ = previous.shutdown(std::net::Shutdown::Both);
}
let tcp_stream = TcpStream::connect(self.socket_addr)?;
tcp_stream.set_nodelay(true)?;
self.tcp_stream = Some(tcp_stream);
log::trace!("Successfully connected to {}", self.socket_addr);
Ok(())
}
}