summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2017-04-08 18:21:57 -0700
committerDaniel Mueller <deso@posteo.net>2017-04-08 18:21:57 -0700
commitf571751d203cfcf2456dc0d85b724cbab3d4075a (patch)
treede97e894262aaa78873f84c3cc8ed47cd4fa2eda
parent02d31ed3dc89528f5b46201abb0c03b6ef29cc16 (diff)
downloadnitrocli-f571751d203cfcf2456dc0d85b724cbab3d4075a.tar.gz
nitrocli-f571751d203cfcf2456dc0d85b724cbab3d4075a.tar.bz2
Retry send/receive on failure
It is possible that sending or receiving a feature report fails. Such failures can have multiple reasons, including transient problems. In the case of such a transient failure we should retry the operation. This change accomplishes this feat by retrying a send in case of a failure up to a maximum of three times, with a small wait in between. It also introduces the logic or receiving a response (which is not yet evaluated fully).
-rw-r--r--nitrocli/src/main.rs64
1 files changed, 59 insertions, 5 deletions
diff --git a/nitrocli/src/main.rs b/nitrocli/src/main.rs
index a1f026e..6b39ad2 100644
--- a/nitrocli/src/main.rs
+++ b/nitrocli/src/main.rs
@@ -32,6 +32,7 @@ mod nitrokey;
mod pinentry;
use error::Error;
+use std::mem;
use std::process;
use std::result;
use std::thread;
@@ -41,6 +42,8 @@ type Result<T> = result::Result<T, Error>;
type NitroFunc = Fn(&mut libhid::Handle) -> Result<()>;
+const SEND_TRY_COUNT: i8 = 3;
+const RECV_TRY_COUNT: i8 = 40;
const SEND_RECV_DELAY_MS: u64 = 200;
@@ -48,8 +51,25 @@ const SEND_RECV_DELAY_MS: u64 = 200;
fn send<P>(handle: &mut libhid::Handle, report: &nitrokey::Report<P>) -> Result<()>
where P: AsRef<[u8]>,
{
- handle.feature().send_to(0, report.as_ref())?;
- return Ok(());
+ let mut retry = SEND_TRY_COUNT;
+ loop {
+ let result = handle.feature().send_to(0, report.as_ref());
+ retry -= 1;
+
+ match result {
+ Ok(_) => {
+ return Ok(());
+ },
+ Err(err) => {
+ if retry > 0 {
+ thread::sleep(time::Duration::from_millis(SEND_RECV_DELAY_MS));
+ continue;
+ } else {
+ return Err(Error::HidError(err));
+ }
+ },
+ }
+ }
}
@@ -57,9 +77,43 @@ fn send<P>(handle: &mut libhid::Handle, report: &nitrokey::Report<P>) -> Result<
fn receive<P>(handle: &mut libhid::Handle) -> Result<nitrokey::Report<P>>
where P: AsRef<[u8]> + Default,
{
- let mut report = nitrokey::Report::<P>::new();
- handle.feature().get_from(0, report.as_mut())?;
- return Ok(report);
+ let mut retry = RECV_TRY_COUNT;
+ loop {
+ let mut report = nitrokey::Report::<P>::new();
+ let result = handle.feature().get_from(0, report.as_mut());
+
+ retry -= 1;
+
+ match result {
+ Ok(size) => {
+ if size < mem::size_of_val(&report) {
+ if retry > 0 {
+ continue;
+ } else {
+ return Err(Error::Error("Failed to receive complete report".to_string()));
+ }
+ }
+
+ if !report.is_valid() {
+ if retry > 0 {
+ continue;
+ } else {
+ return Err(Error::Error("Failed to receive report: CRC mismatch".to_string()));
+ }
+ }
+ return Ok(report);
+ },
+
+ Err(err) => {
+ if retry > 0 {
+ thread::sleep(time::Duration::from_millis(SEND_RECV_DELAY_MS));
+ continue;
+ } else {
+ return Err(Error::HidError(err));
+ }
+ },
+ }
+ }
}