Package smartcard :: Module ReaderMonitoring
[hide private]
[frames] | no frames]

Source Code for Module smartcard.ReaderMonitoring

  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  # ReaderObserver interface 
43 -class ReaderObserver(Observer):
44 """ 45 ReaderObserver is a base abstract class for objects that are to be notified 46 upon smartcard reader insertion/removal. 47 """ 48
49 - def __init__(self):
50 pass
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
63 -class ReaderMonitor(Observable):
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
79 - def __init__(self, startOnDemand=True, readerProc=smartcard.System.readers, 80 period=1):
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
93 - def addObserver(self, observer):
94 """Add an observer.""" 95 Observable.addObserver(self, observer) 96 97 # If self.startOnDemand is True, the reader monitoring 98 # thread only runs when there are observers. 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 # start reader monitoring thread in another thread to 106 # avoid a deadlock; addObserver and notifyObservers called 107 # in the ReaderMonitoringThread run() method are 108 # synchronized 109 try: 110 # Python 3.x 111 import _thread 112 _thread.start_new_thread(self.rmthread.start, ()) 113 except: 114 # Python 2.x 115 import thread 116 thread.start_new_thread(self.rmthread.start, ()) 117 else: 118 observer.update(self, (self.rmthread.readers, []))
119
120 - def deleteObserver(self, observer):
121 """Remove an observer.""" 122 Observable.deleteObserver(self, observer) 123 # If self.startOnDemand is True, the reader monitoring 124 # thread is stopped when there are no more observers. 125 if self.startOnDemand: 126 if 0 == self.countObservers(): 127 self.rmthread.stop() 128 del self.rmthread 129 self.rmthread = None
130
131 - def __str__(self):
132 return self.__class__.__name__
133 134 synchronize(ReaderMonitor, 135 "addObserver deleteObserver deleteObservers " + 136 "setChanged clearChanged hasChanged " + 137 "countObservers") 138 139
140 -class ReaderMonitoringThread(Thread):
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
160 - def run(self):
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 # no need to monitor if no observers 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 # Notify observers 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 # wait every second on stopEvent 190 self.stopEvent.wait(self.period) 191 192 except Exception: 193 # FIXME Tighten the exceptions caught by this block 194 traceback.print_exc() 195 # Most likely raised during interpreter shutdown due 196 # to unclean exit which failed to remove all observers. 197 # To solve this, we set the stop event and pass the 198 # exception to let the thread finish gracefully. 199 self.stopEvent.set()
200
201 - def stop(self):
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 # a simple reader observer that prints added/removed readers
209 - class printobserver(ReaderObserver):
210
211 - def __init__(self, obsindex):
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
219 - class testthread(Thread):
220
221 - def __init__(self, obsindex):
222 Thread.__init__(self) 223 self.readermonitor = ReaderMonitor() 224 self.obsindex = obsindex 225 self.observer = None
226
227 - def run(self):
228 # create and register observer 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