devices/usb/backend/fido_backend/
transfer.rs1use std::sync::Weak;
6use std::time::Instant;
7
8use base::error;
9use base::Clock;
10use sync::Mutex;
11use usb_util::TransferBuffer;
12use usb_util::TransferStatus;
13
14use crate::usb::backend::error::Error as BackendError;
15use crate::usb::backend::error::Result as BackendResult;
16use crate::usb::backend::fido_backend::constants::USB_TRANSFER_TIMEOUT_MILLIS;
17use crate::usb::backend::transfer::BackendTransfer;
18use crate::usb::backend::transfer::BackendTransferType;
19use crate::usb::backend::transfer::GenericTransferHandle;
20
21pub struct FidoTransfer {
25 pub buffer: TransferBuffer,
27 status: TransferStatus,
29 pub actual_length: usize,
31 pub endpoint: u8,
33 submission_time: Instant,
35 pub callback: Option<Box<dyn Fn(FidoTransfer) + Send + Sync>>,
37}
38
39impl FidoTransfer {
40 pub fn new(endpoint: u8, buffer: TransferBuffer) -> FidoTransfer {
41 let clock = Clock::new();
42 FidoTransfer {
43 buffer,
44 status: TransferStatus::Error, actual_length: 0,
46 endpoint,
47 submission_time: clock.now(),
48 callback: None,
49 }
50 }
51
52 pub fn signal_device_lost(&mut self) {
55 self.status = TransferStatus::NoDevice;
56 }
57
58 pub fn timeout_expired(&self) -> bool {
60 self.submission_time.elapsed().as_millis() >= USB_TRANSFER_TIMEOUT_MILLIS.into()
61 }
62
63 pub fn complete_transfer(mut self) {
66 if self.status == TransferStatus::Error {
69 self.status = TransferStatus::Completed;
70 }
71
72 if let Some(cb) = self.callback.take() {
73 cb(self);
74 }
75 }
76}
77
78impl BackendTransfer for FidoTransfer {
79 fn status(&self) -> TransferStatus {
80 self.status
81 }
82
83 fn actual_length(&self) -> usize {
84 self.actual_length
85 }
86
87 fn buffer(&self) -> &TransferBuffer {
88 &self.buffer
89 }
90
91 fn set_callback<C: 'static + Fn(BackendTransferType) + Send + Sync>(&mut self, cb: C) {
92 let callback = move |t: FidoTransfer| cb(BackendTransferType::FidoDevice(t));
93 self.callback = Some(Box::new(callback));
94 }
95}
96
97pub struct FidoTransferHandle {
99 pub weak_transfer: Weak<Mutex<Option<FidoTransfer>>>,
100}
101
102impl GenericTransferHandle for FidoTransferHandle {
103 fn cancel(&self) -> BackendResult<()> {
104 let rc_transfer = match self.weak_transfer.upgrade() {
105 None => {
106 return Err(BackendError::TransferHandleAlreadyComplete);
107 }
108 Some(rc_transfer) => rc_transfer,
109 };
110
111 let mut lock = rc_transfer.lock();
112
113 let mut transfer = match lock.take() {
114 Some(t) => t,
115 None => {
116 error!("Transfer has already been lost while being cancelled. Ignore");
117 return Err(BackendError::TransferHandleAlreadyComplete);
118 }
119 };
120 transfer.status = TransferStatus::Cancelled;
121 *lock = Some(transfer);
122 Ok(())
123 }
124}