1 """Smart card reader monitoring classes.
2
3 ReaderObserver is a base class for objects that are to be notified
4 upon smartcard reader insertion/removal.
5
6 ReaderMonitor is a singleton object notifying registered ReaderObservers
7 upon reader insertion/removal.
8
9 __author__ = "http://www.gemalto.com"
10
11 Copyright 2001-2012 gemalto
12 Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
13
14 This file is part of pyscard.
15
16 pyscard is free software; you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation; either version 2.1 of the License, or
19 (at your option) any later version.
20
21 pyscard is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with pyscard; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 """
30
31 from __future__ import print_function
32 from threading import Thread, Event
33 from time import sleep
34 import traceback
35
36 import smartcard.System
37 from smartcard.Observer import Observer
38 from smartcard.Observer import Observable
39 from smartcard.Synchronization import *
40
41
42
44 """
45 ReaderObserver is a base abstract class for objects that are to be notified
46 upon smartcard reader insertion/removal.
47 """
48
51
52 - def update(self, observable, handlers):
53 """Called upon reader insertion/removal.
54
55 @param observable:
56 @param handlers:
57 - addedreaders: list of added readers causing notification
58 - removedreaders: list of removed readers causing notification
59 """
60 pass
61
62
64 """Class that monitors reader insertion/removal.
65 and notify observers
66
67 note: a reader monitoring thread will be running
68 as long as the reader monitor has observers, or ReaderMonitor.stop()
69 is called.
70
71 It implements the shared state design pattern, where objects
72 of the same type all share the same state, in our case essentially
73 the ReaderMonitoring Thread. Thanks to Frank Aune for implementing
74 the shared state pattern logics.
75 """
76
77 __shared_state = {}
78
81 self.__dict__ = self.__shared_state
82 Observable.__init__(self)
83 self.startOnDemand = startOnDemand
84 self.readerProc = readerProc
85 self.period = period
86 if self.startOnDemand:
87 self.rmthread = None
88 else:
89 self.rmthread = ReaderMonitoringThread(self, self.readerProc,
90 self.period)
91 self.rmthread.start()
92
94 """Add an observer."""
95 Observable.addObserver(self, observer)
96
97
98
99 if self.startOnDemand:
100 if 0 < self.countObservers():
101 if not self.rmthread:
102 self.rmthread = ReaderMonitoringThread(self,
103 self.readerProc, self.period)
104
105
106
107
108
109 try:
110
111 import _thread
112 _thread.start_new_thread(self.rmthread.start, ())
113 except:
114
115 import thread
116 thread.start_new_thread(self.rmthread.start, ())
117 else:
118 observer.update(self, (self.rmthread.readers, []))
119
121 """Remove an observer."""
122 Observable.deleteObserver(self, observer)
123
124
125 if self.startOnDemand:
126 if 0 == self.countObservers():
127 self.rmthread.stop()
128 del self.rmthread
129 self.rmthread = None
130
132 return self.__class__.__name__
133
134 synchronize(ReaderMonitor,
135 "addObserver deleteObserver deleteObservers " +
136 "setChanged clearChanged hasChanged " +
137 "countObservers")
138
139
141 """Reader insertion thread.
142 This thread polls for pcsc reader insertion, since no
143 reader insertion event is available in pcsc.
144 """
145
146 __shared_state = {}
147
148 - def __init__(self, observable, readerProc, period):
149 self.__dict__ = self.__shared_state
150 Thread.__init__(self)
151 self.observable = observable
152 self.stopEvent = Event()
153 self.stopEvent.clear()
154 self.readers = []
155 self.setDaemon(True)
156 self.setName('smartcard.ReaderMonitoringThread')
157 self.readerProc = readerProc
158 self.period = period
159
161 """Runs until stopEvent is notified, and notify
162 observers of all reader insertion/removal.
163 """
164 while not self.stopEvent.isSet():
165 try:
166
167 if 0 < self.observable.countObservers():
168 currentReaders = self.readerProc()
169 addedReaders = []
170 removedReaders = []
171
172 if currentReaders != self.readers:
173 for reader in currentReaders:
174 if not reader in self.readers:
175 addedReaders.append(reader)
176 for reader in self.readers:
177 if not reader in currentReaders:
178 removedReaders.append(reader)
179
180 if addedReaders or removedReaders:
181
182 self.readers = []
183 for r in currentReaders:
184 self.readers.append(r)
185 self.observable.setChanged()
186 self.observable.notifyObservers((addedReaders,
187 removedReaders))
188
189
190 self.stopEvent.wait(self.period)
191
192 except Exception:
193
194 traceback.print_exc()
195
196
197
198
199 self.stopEvent.set()
200
202 self.stopEvent.set()
203 self.join()
204
205 if __name__ == "__main__":
206 print('insert or remove readers in the next 20 seconds')
207
208
210
212 self.obsindex = obsindex
213
214 - def update(self, observable, handlers):
215 addedreaders, removedreaders = handlers
216 print("%d - added: " % self.obsindex, addedreaders)
217 print("%d - removed: " % self.obsindex, removedreaders)
218
220
222 Thread.__init__(self)
223 self.readermonitor = ReaderMonitor()
224 self.obsindex = obsindex
225 self.observer = None
226
228
229 self.observer = printobserver(self.obsindex)
230 self.readermonitor.addObserver(self.observer)
231 sleep(20)
232 self.readermonitor.deleteObserver(self.observer)
233
234 t1 = testthread(1)
235 t2 = testthread(2)
236 t1.start()
237 t2.start()
238 t1.join()
239 t2.join()
240