ledger_lib/transport/
tcp.rs1use std::{
2 fmt::Display,
3 net::{Ipv4Addr, SocketAddr, SocketAddrV4},
4 time::Duration,
5};
6
7use tokio::{
8 io::{AsyncReadExt, AsyncWriteExt, Interest},
9 net::{TcpListener, TcpStream},
10};
11use tracing::{debug, error};
12
13use crate::{
14 info::{LedgerInfo, Model},
15 Error,
16};
17
18use super::{Exchange, Transport};
19
20#[derive(Default)]
22pub struct TcpTransport {}
23
24pub struct TcpDevice {
26 s: TcpStream,
27 pub info: TcpInfo,
28}
29
30#[derive(Clone, PartialEq, Debug)]
32pub struct TcpInfo {
33 pub addr: SocketAddr,
34}
35
36impl Default for TcpInfo {
37 fn default() -> Self {
38 Self {
39 addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1237)),
40 }
41 }
42}
43
44impl Display for TcpInfo {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(f, "{}", self.addr)
47 }
48}
49
50impl TcpTransport {
51 pub fn new() -> Result<Self, Error> {
53 Ok(Self {})
54 }
55}
56
57#[cfg_attr(not(feature = "unstable_async_trait"), async_trait::async_trait)]
58impl Transport for TcpTransport {
59 type Filters = ();
60 type Info = TcpInfo;
61 type Device = TcpDevice;
62
63 async fn list(&mut self, _filters: Self::Filters) -> Result<Vec<LedgerInfo>, Error> {
68 let mut devices = vec![];
69
70 let addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 1237);
72
73 match TcpListener::bind(addr).await {
76 Ok(_) => (),
77 Err(_) => {
79 devices.push(LedgerInfo {
80 conn: TcpInfo { addr }.into(),
81 model: Model::Unknown(0),
82 });
83 }
84 }
85
86 Ok(devices)
87 }
88
89 async fn connect(&mut self, info: TcpInfo) -> Result<TcpDevice, Error> {
91 debug!("Connecting to: {:?}", info);
92
93 let s = match TcpStream::connect(info.addr).await {
95 Ok(v) => v,
96 Err(e) => {
97 error!("TCP connection failed: {:?}", e);
98 return Err(e.into());
99 }
100 };
101
102 Ok(TcpDevice { s, info })
104 }
105}
106
107impl TcpDevice {
108 async fn write_command(&mut self, req: &[u8]) -> Result<(), Error> {
110 let mut buff = vec![0; 4 + req.len()];
112
113 buff[0..4].copy_from_slice(&(req.len() as u32).to_be_bytes());
115
116 buff[4..].copy_from_slice(req);
118
119 debug!("TX: {:02x?}", buff);
120
121 if let Err(e) = self.s.write_all(&buff).await {
123 error!("Failed to write request APDU: {:?}", e);
124 return Err(e.into());
125 }
126
127 Ok(())
128 }
129
130 async fn read_data(&mut self) -> Result<Vec<u8>, Error> {
132 let mut buff = vec![0u8; 4];
133
134 let n = match self.s.read_exact(&mut buff[..4]).await {
136 Ok(_) => u32::from_be_bytes(buff[..4].try_into().unwrap()) as usize + 2,
137 Err(e) => {
138 error!("Failed to read response APDU length: {:?}", e);
139 return Err(e.into());
140 }
141 };
142
143 buff.resize(n + 4, 0);
145 if let Err(e) = self.s.read_exact(&mut buff[4..][..n]).await {
146 error!("Failed to read response APDU data: {:?}", e);
147 return Err(e.into());
148 }
149
150 debug!("RX: {:02x?}", buff);
151
152 Ok(buff[4..].to_vec())
154 }
155
156 pub(crate) async fn is_connected(&self) -> Result<bool, Error> {
157 let r = self.s.ready(Interest::WRITABLE).await?;
158 Ok(!r.is_read_closed() || !r.is_write_closed())
159 }
160}
161
162#[cfg_attr(not(feature = "unstable_async_trait"), async_trait::async_trait)]
164impl Exchange for TcpDevice {
165 async fn exchange(&mut self, req: &[u8], timeout: Duration) -> Result<Vec<u8>, Error> {
166 self.write_command(req).await?;
168
169 let d = match tokio::time::timeout(timeout, self.read_data()).await {
171 Ok(Ok(d)) => d,
172 Ok(Err(e)) => return Err(e),
173 Err(e) => return Err(e.into()),
174 };
175
176 Ok(d)
178 }
179}