ledger_lib/transport/
tcp.rsuse std::{
fmt::Display,
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
time::Duration,
};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt, Interest},
net::{TcpListener, TcpStream},
};
use tracing::{debug, error};
use crate::{
info::{LedgerInfo, Model},
Error,
};
use super::{Exchange, Transport};
#[derive(Default)]
pub struct TcpTransport {}
pub struct TcpDevice {
s: TcpStream,
pub info: TcpInfo,
}
#[derive(Clone, PartialEq, Debug)]
pub struct TcpInfo {
pub addr: SocketAddr,
}
impl Default for TcpInfo {
fn default() -> Self {
Self {
addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1237)),
}
}
}
impl Display for TcpInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.addr)
}
}
impl TcpTransport {
pub fn new() -> Result<Self, Error> {
Ok(Self {})
}
}
#[cfg_attr(not(feature = "unstable_async_trait"), async_trait::async_trait)]
impl Transport for TcpTransport {
type Filters = ();
type Info = TcpInfo;
type Device = TcpDevice;
async fn list(&mut self, _filters: Self::Filters) -> Result<Vec<LedgerInfo>, Error> {
let mut devices = vec![];
let addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 1237);
match TcpListener::bind(addr).await {
Ok(_) => (),
Err(_) => {
devices.push(LedgerInfo {
conn: TcpInfo { addr }.into(),
model: Model::Unknown(0),
});
}
}
Ok(devices)
}
async fn connect(&mut self, info: TcpInfo) -> Result<TcpDevice, Error> {
debug!("Connecting to: {:?}", info);
let s = match TcpStream::connect(info.addr).await {
Ok(v) => v,
Err(e) => {
error!("TCP connection failed: {:?}", e);
return Err(e.into());
}
};
Ok(TcpDevice { s, info })
}
}
impl TcpDevice {
async fn write_command(&mut self, req: &[u8]) -> Result<(), Error> {
let mut buff = vec![0; 4 + req.len()];
buff[0..4].copy_from_slice(&(req.len() as u32).to_be_bytes());
buff[4..].copy_from_slice(req);
debug!("TX: {:02x?}", buff);
if let Err(e) = self.s.write_all(&buff).await {
error!("Failed to write request APDU: {:?}", e);
return Err(e.into());
}
Ok(())
}
async fn read_data(&mut self) -> Result<Vec<u8>, Error> {
let mut buff = vec![0u8; 4];
let n = match self.s.read_exact(&mut buff[..4]).await {
Ok(_) => u32::from_be_bytes(buff[..4].try_into().unwrap()) as usize + 2,
Err(e) => {
error!("Failed to read response APDU length: {:?}", e);
return Err(e.into());
}
};
buff.resize(n + 4, 0);
if let Err(e) = self.s.read_exact(&mut buff[4..][..n]).await {
error!("Failed to read response APDU data: {:?}", e);
return Err(e.into());
}
debug!("RX: {:02x?}", buff);
Ok(buff[4..].to_vec())
}
pub(crate) async fn is_connected(&self) -> Result<bool, Error> {
let r = self.s.ready(Interest::WRITABLE).await?;
Ok(!r.is_read_closed() || !r.is_write_closed())
}
}
#[cfg_attr(not(feature = "unstable_async_trait"), async_trait::async_trait)]
impl Exchange for TcpDevice {
async fn exchange(&mut self, req: &[u8], timeout: Duration) -> Result<Vec<u8>, Error> {
self.write_command(req).await?;
let d = match tokio::time::timeout(timeout, self.read_data()).await {
Ok(Ok(d)) => d,
Ok(Err(e)) => return Err(e),
Err(e) => return Err(e.into()),
};
Ok(d)
}
}