@@ -7,13 +7,18 @@ use pcsc::*;
77
88use std:: thread;
99use std:: time:: Duration ;
10+ use std:: ffi:: CString ;
11+
12+ use runloop:: RunLoop ;
13+ use std:: collections:: HashMap ;
1014
1115use u2ftypes:: { APDUDevice } ;
1216
1317pub struct Monitor < F >
1418where
1519 F : Fn ( & mut dyn APDUDevice , & dyn Fn ( ) -> bool ) + Sync ,
1620{
21+ runloops : HashMap < CString , RunLoop > ,
1722 new_device_cb : Arc < F > ,
1823}
1924
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}
0 commit comments