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, Exchange, Transport,
16};
17
18#[derive(Default)]
20pub struct TcpTransport {}
21
22pub struct TcpDevice {
24 s: TcpStream,
25 pub info: TcpInfo,
26}
27
28#[derive(Clone, PartialEq, Debug)]
30pub struct TcpInfo {
31 pub addr: SocketAddr,
32}
33
34impl Default for TcpInfo {
35 fn default() -> Self {
36 Self {
37 addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1237)),
38 }
39 }
40}
41
42impl Display for TcpInfo {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "{}", self.addr)
45 }
46}
47
48impl TcpTransport {
49 pub fn new() -> Result<Self, Error> {
51 Ok(Self {})
52 }
53}
54
55impl Transport for TcpTransport {
56 type Filters = ();
57 type Info = TcpInfo;
58 type Device = TcpDevice;
59
60 async fn list(&mut self, _filters: Self::Filters) -> Result<Vec<LedgerInfo>, Error> {
65 let mut devices = vec![];
66
67 let addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 1237);
69
70 match TcpListener::bind(addr).await {
73 Ok(_) => (),
74 Err(_) => {
76 devices.push(LedgerInfo {
77 conn: TcpInfo { addr }.into(),
78 model: Model::Unknown { usb_pid: None },
79 });
80 }
81 }
82
83 Ok(devices)
84 }
85
86 async fn connect(&mut self, info: TcpInfo) -> Result<TcpDevice, Error> {
88 debug!("Connecting to: {:?}", info);
89
90 let s = match TcpStream::connect(info.addr).await {
92 Ok(v) => v,
93 Err(e) => {
94 error!("TCP connection failed: {:?}", e);
95 return Err(e.into());
96 }
97 };
98
99 Ok(TcpDevice { s, info })
101 }
102}
103
104impl TcpDevice {
105 async fn write_command(&mut self, req: &[u8]) -> Result<(), Error> {
107 let mut buff = vec![0; 4 + req.len()];
109
110 buff[0..4].copy_from_slice(&(req.len() as u32).to_be_bytes());
112
113 buff[4..].copy_from_slice(req);
115
116 debug!("TX: {:02x?}", buff);
117
118 if let Err(e) = self.s.write_all(&buff).await {
120 error!("Failed to write request APDU: {:?}", e);
121 return Err(e.into());
122 }
123
124 Ok(())
125 }
126
127 async fn read_data(&mut self) -> Result<Vec<u8>, Error> {
129 let mut buff = vec![0u8; 4];
130
131 let n = match self.s.read_exact(&mut buff[..4]).await {
133 Ok(_) => u32::from_be_bytes(buff[..4].try_into().unwrap()) as usize + 2,
134 Err(e) => {
135 error!("Failed to read response APDU length: {:?}", e);
136 return Err(e.into());
137 }
138 };
139
140 buff.resize(n + 4, 0);
142 if let Err(e) = self.s.read_exact(&mut buff[4..][..n]).await {
143 error!("Failed to read response APDU data: {:?}", e);
144 return Err(e.into());
145 }
146
147 debug!("RX: {:02x?}", buff);
148
149 Ok(buff[4..].to_vec())
151 }
152
153 pub(crate) async fn is_connected(&self) -> Result<bool, Error> {
154 let r = self.s.ready(Interest::WRITABLE).await?;
155 Ok(!r.is_read_closed() || !r.is_write_closed())
156 }
157}
158
159impl Exchange for TcpDevice {
161 async fn exchange(&mut self, req: &[u8], timeout: Duration) -> Result<Vec<u8>, Error> {
162 self.write_command(req).await?;
164
165 let d = match tokio::time::timeout(timeout, self.read_data()).await {
167 Ok(Ok(d)) => d,
168 Ok(Err(e)) => return Err(e),
169 Err(e) => return Err(e.into()),
170 };
171
172 Ok(d)
174 }
175}