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-2011 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 sys import exc_info
32 from threading import Thread, Event, enumerate
33 from time import sleep
34
35 import smartcard.System
36 from smartcard.Exceptions import ListReadersException
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, (addedreaders, removedreaders)):
53 """Called upon reader insertion/removal.
54
55 observable:
56 addedreaders: list of added readers causing notification
57 removedreaders: list of removed readers causing notification
58 """
59 pass
60
61
63 """Class that monitors reader insertion/removal.
64 and notify observers
65
66 note: a reader monitoring thread will be running
67 as long as the reader monitor has observers, or ReaderMonitor.stop()
68 is called.
69
70 It implements the shared state design pattern, where objects
71 of the same type all share the same state, in our case essentially
72 the ReaderMonitoring Thread. Thanks to Frank Aune for implementing
73 the shared state pattern logics.
74 """
75
76 __shared_state = {}
77
80 self.__dict__ = self.__shared_state
81 Observable.__init__(self)
82 self.startOnDemand = startOnDemand
83 self.readerProc = readerProc
84 self.period = period
85 if self.startOnDemand:
86 self.rmthread = None
87 else:
88 self.rmthread = ReaderMonitoringThread(self, self.readerProc,
89 self.period)
90 self.rmthread.start()
91
93 """Add an observer."""
94 Observable.addObserver(self, observer)
95
96
97
98 if self.startOnDemand:
99 if 0 < self.countObservers():
100 if not self.rmthread:
101 self.rmthread = ReaderMonitoringThread(self,
102 self.readerProc, self.period)
103
104
105
106
107
108 import thread
109 thread.start_new_thread(self.rmthread.start, ())
110 else:
111 observer.update(self, (self.rmthread.readers, []))
112
114 """Remove an observer."""
115 Observable.deleteObserver(self, observer)
116
117
118 if self.startOnDemand:
119 if 0 == self.countObservers():
120 self.rmthread.stop()
121 del self.rmthread
122 self.rmthread = None
123
125 return self.__class__.__name__
126
127 synchronize(ReaderMonitor,
128 "addObserver deleteObserver deleteObservers " +
129 "setChanged clearChanged hasChanged " +
130 "countObservers")
131
132
134 """Reader insertion thread.
135 This thread polls for pcsc reader insertion, since no
136 reader insertion event is available in pcsc.
137 """
138
139 __shared_state = {}
140
141 - def __init__(self, observable, readerProc, period):
142 self.__dict__ = self.__shared_state
143 Thread.__init__(self)
144 self.observable = observable
145 self.stopEvent = Event()
146 self.stopEvent.clear()
147 self.readers = []
148 self.setDaemon(True)
149 self.setName('smartcard.ReaderMonitoringThread')
150 self.readerProc = readerProc
151 self.period = period
152
154 """Runs until stopEvent is notified, and notify
155 observers of all reader insertion/removal.
156 """
157 while not self.stopEvent.isSet():
158 try:
159
160 if 0 < self.observable.countObservers():
161 currentReaders = self.readerProc()
162 addedReaders = []
163 removedReaders = []
164
165 if currentReaders != self.readers:
166 for reader in currentReaders:
167 if not reader in self.readers:
168 addedReaders.append(reader)
169 for reader in self.readers:
170 if not reader in currentReaders:
171 removedReaders.append(reader)
172
173 if addedReaders or removedReaders:
174
175 self.readers = []
176 for r in currentReaders:
177 self.readers.append(r)
178 self.observable.setChanged()
179 self.observable.notifyObservers((addedReaders,
180 removedReaders))
181
182
183 self.stopEvent.wait(self.period)
184
185 except Exception, e:
186
187
188
189
190 self.stopEvent.set()
191
193 self.stopEvent.set()
194 self.join()
195
196 if __name__ == "__main__":
197 from smartcard.ReaderMonitoring import ReaderMonitor
198 print 'insert or remove readers in the next 20 seconds'
199
200
202
204 self.obsindex = obsindex
205
206 - def update(self, observable, (addedreaders, removedreaders)):
207 print "%d - added: " % self.obsindex, addedreaders
208 print "%d - removed: " % self.obsindex, removedreaders
209
211
213 Thread.__init__(self)
214 self.readermonitor = ReaderMonitor()
215 self.obsindex = obsindex
216 self.observer = None
217
219
220 self.observer = printobserver(self.obsindex)
221 self.readermonitor.addObserver(self.observer)
222 sleep(20)
223 self.readermonitor.deleteObserver(self.observer)
224
225 t1 = testthread(1)
226 t2 = testthread(2)
227 t1.start()
228 t2.start()
229 t1.join()
230 t2.join()
231