Skip to content

Commit 5912fc9

Browse files
committed
clean up Monitor code, improve debugging
1 parent 9caad1b commit 5912fc9

File tree

5 files changed

+109
-32
lines changed

5 files changed

+109
-32
lines changed

src/consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,5 @@ pub const SW_WRONG_LENGTH: [u8; 2] = [0x67, 0x00];
8181
pub const U2F_AID: [u8; 8] = [0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01];
8282
pub const U2F_SELECT_FILE: u8 = 0xA4;
8383
pub const U2F_SELECT_DIRECT: u8 = 0x04;
84-
pub const U2F_CONTINUE: u8 = 0xC0;
84+
pub const U2F_GET_RESPONSE: u8 = 0xC0;
8585
pub const U2F_MORE_DATA: u8 = 0x61;

src/nfc/device.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use pcsc::*;
66
use std::io;
7-
use log;
87

98
use u2ftypes::*;
109
use u2fprotocol::status_word_to_result;
@@ -21,9 +20,7 @@ fn sendrecv(card: &mut Card, send: &[u8]) -> io::Result<Vec<u8>>
2120
Ok(rapdu.to_vec())
2221
},
2322
Err(err) => {
24-
if log_enabled!(log::Level::Trace) {
25-
trace!("NFC error: {}", err);
26-
}
23+
trace!("NFC error: {}", err);
2724
let s = format!("{}", err);
2825
Err(io_err(&s))
2926
}
@@ -55,7 +52,7 @@ impl APDUDevice for Card {
5552
}
5653

5754
loop {
58-
let out = APDU::serialize_short(U2F_CONTINUE, 0x00, &[])?;
55+
let out = APDU::serialize_short(U2F_GET_RESPONSE, 0x00, &[])?;
5956
let ret = sendrecv(self, &out)?;
6057
let (mut more, [s1, s2]) = APDU::deserialize(ret)?;
6158
data.append(&mut more);

src/nfc/monitor.rs

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ use pcsc::*;
77

88
use std::thread;
99
use std::time::Duration;
10+
use std::ffi::CString;
11+
12+
use runloop::RunLoop;
13+
use std::collections::HashMap;
1014

1115
use u2ftypes::{APDUDevice};
1216

1317
pub struct Monitor<F>
1418
where
1519
F: Fn(&mut dyn APDUDevice, &dyn Fn() -> bool) + Sync,
1620
{
21+
runloops: HashMap<CString, RunLoop>,
1722
new_device_cb: Arc<F>,
1823
}
1924

@@ -23,6 +28,7 @@ where
2328
{
2429
pub fn new(new_device_cb: F) -> Self {
2530
Self {
31+
runloops: HashMap::new(),
2632
new_device_cb: Arc::new(new_device_cb),
2733
}
2834
}
@@ -31,40 +37,108 @@ where
3137
let ctx = Context::establish(Scope::User)?;
3238

3339
let mut readers_buf = [0; 2048];
34-
let mut reader_states: Vec<ReaderState> = vec![
35-
// Listen for reader insertions/removals, if supported.
36-
//ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE),
37-
];
40+
// We _could_ insert `ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE)`
41+
// to be reminded of reader insertion/removal,
42+
// but this is not guaranteed to be supported
43+
// and we need to poll anyways.
44+
let mut reader_states: Vec<ReaderState> = Vec::new();
3845

3946
while alive() {
40-
// Remove dead readers.
41-
reader_states.retain(|rs| !rs.event_state().intersects(State::UNKNOWN | State::IGNORE));
42-
4347
// Add new readers.
4448
let names = ctx.list_readers(&mut readers_buf)?;
4549
for name in names {
46-
if !reader_states.iter().any(|rs| rs.name() == name) {
50+
if !reader_states.iter().any(|reader| reader.name() == name) {
51+
debug!("Adding reader {:?}", name);
4752
reader_states.push(ReaderState::new(name, State::UNAWARE));
4853
}
4954
}
5055

51-
// TODO:
52-
// This REALLY spams the reader, perhaps check whether a card is present first??
56+
// Remove dead readers.
57+
fn is_dead(reader: &ReaderState) -> bool {
58+
reader.event_state().intersects(State::UNKNOWN | State::IGNORE)
59+
}
5360
for reader in &reader_states {
54-
let mut card = match ctx.connect(reader.name(), ShareMode::Shared, Protocols::ANY) {
55-
Ok(card) => card,
56-
_ => continue
57-
};
58-
59-
let f = self.new_device_cb.clone();
60-
if alive() {
61-
f(&mut card, alive);
61+
if is_dead(reader) {
62+
debug!("Removing reader {:?}", reader.name());
63+
}
64+
}
65+
reader_states.retain(|reader| !is_dead(reader));
66+
67+
// Let backend know that we know about the reader state.
68+
// Otherwise it will keep trying to update us.
69+
for rs in &mut reader_states {
70+
rs.sync_current_state();
71+
}
72+
73+
if reader_states.len() == 0 {
74+
// No readers available. This means that `get_status_change` will return
75+
// immediately without any work, causing a busy-loop.
76+
// Let's wait for a bit and look for a new reader.
77+
thread::sleep(Duration::from_millis(500));
78+
continue;
79+
}
80+
81+
// This call is blocking, so we must give it _some_ timeout in order for
82+
// the `alive()` check to work.
83+
let timeout = Duration::from_millis(100);
84+
if let Err(e) = ctx.get_status_change(timeout, &mut reader_states) {
85+
if e == Error::Timeout {
86+
continue;
6287
}
88+
return Err(e);
6389
}
6490

65-
// TODO: sleep here to prevent infinite loop?
66-
//thread::sleep(Duration::from_millis(1000));
91+
for reader in &mut reader_states {
92+
let state = reader.event_state();
93+
let name = reader.name();
94+
95+
trace!("Reader {:?}: state {:?}", name, state);
96+
97+
if state.contains(State::PRESENT) && !state.contains(State::EXCLUSIVE) {
98+
self.add_card(&ctx, CString::from(name));
99+
} else {
100+
self.remove_card(CString::from(name));
101+
}
102+
}
67103
}
104+
105+
self.remove_all_cards();
106+
68107
Ok(())
69108
}
109+
110+
fn add_card(&mut self, ctx: &Context, reader: CString) {
111+
let key = reader.clone();
112+
let f = self.new_device_cb.clone();
113+
114+
let mut card = match ctx.connect(&reader, ShareMode::Shared, Protocols::ANY) {
115+
Ok(card) => card,
116+
_ => return
117+
};
118+
119+
let runloop = RunLoop::new(move |alive| {
120+
if alive() {
121+
debug!("Connected to card on reader {:?}", reader);
122+
f(&mut card, alive);
123+
}
124+
});
125+
126+
if let Ok(runloop) = runloop {
127+
self.runloops.insert(key, runloop);
128+
}
129+
}
130+
131+
fn remove_card(&mut self, reader: CString) {
132+
if let Some(runloop) = self.runloops.remove(&reader) {
133+
runloop.cancel();
134+
debug!("Disconnected from card on reader {:?}", reader);
135+
}
136+
}
137+
138+
fn remove_all_cards(&mut self) {
139+
while !self.runloops.is_empty() {
140+
let reader = self.runloops.keys().next().unwrap().clone();
141+
self.remove_card(reader);
142+
}
143+
}
70144
}

src/u2fprotocol.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@ use util::io_err;
2020
pub fn u2f_init_device(dev: &mut dyn APDUDevice) -> bool
2121
{
2222
// Initialize the device and check its version.
23-
dev.init_apdu().is_ok() && is_v2_device(dev).unwrap_or(false)
23+
if let Err(_) = dev.init_apdu() {
24+
debug!("Device could not be initialized");
25+
return false;
26+
}
27+
if !is_v2_device(dev).unwrap_or(false) {
28+
debug!("Device is not v2");
29+
return false;
30+
}
31+
true
2432
}
2533

2634
pub fn u2f_register(dev: &mut dyn APDUDevice, challenge: &[u8], application: &[u8]) -> io::Result<Vec<u8>>

src/util.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,7 @@ impl<T> Clone for OnceCallback<T> {
103103
}
104104

105105
pub fn trace_hex(label: &str, data: &[u8]) {
106-
if log_enabled!(log::Level::Trace) {
107-
let parts: Vec<String> = data.iter().map(|byte| format!("{:02x} ", byte)).collect();
108-
let s = parts.join("");
109-
trace!("{} ({}): {}", label, data.len(), s);
110-
}
106+
let parts: Vec<String> = data.iter().map(|byte| format!("{:02x} ", byte)).collect();
107+
let s = parts.join("");
108+
trace!("{} ({}): {}", label, data.len(), s);
111109
}

0 commit comments

Comments
 (0)