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-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  # 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, (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
62 -class ReaderMonitor(Observable):
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
78 - def __init__(self, startOnDemand=True, readerProc=smartcard.System.readers, 79 period=1):
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
92 - def addObserver(self, observer):
93 """Add an observer.""" 94 Observable.addObserver(self, observer) 95 96 # If self.startOnDemand is True, the reader monitoring 97 # thread only runs when there are observers. 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 # start reader monitoring thread in another thread to 105 # avoid a deadlock; addObserver and notifyObservers called 106 # in the ReaderMonitoringThread run() method are 107 # synchronized 108 import thread 109 thread.start_new_thread(self.rmthread.start, ()) 110 else: 111 observer.update(self, (self.rmthread.readers, []))
112
113 - def deleteObserver(self, observer):
114 """Remove an observer.""" 115 Observable.deleteObserver(self, observer) 116 # If self.startOnDemand is True, the reader monitoring 117 # thread is stopped when there are no more observers. 118 if self.startOnDemand: 119 if 0 == self.countObservers(): 120 self.rmthread.stop() 121 del self.rmthread 122 self.rmthread = None
123
124 - def __str__(self):
125 return self.__class__.__name__
126 127 synchronize(ReaderMonitor, 128 "addObserver deleteObserver deleteObservers " + 129 "setChanged clearChanged hasChanged " + 130 "countObservers") 131 132
133 -class ReaderMonitoringThread(Thread):
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
153 - def run(self):
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 # no need to monitor if no observers 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 # Notify observers 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 # wait every second on stopEvent 183 self.stopEvent.wait(self.period) 184 185 except Exception, e: 186 # Most likely raised during interpreter shutdown due 187 # to unclean exit which failed to remove all observers. 188 # To solve this, we set the stop event and pass the 189 # exception to let the thread finish gracefully. 190 self.stopEvent.set()
191
192 - def stop(self):
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 # a simple reader observer that prints added/removed readers
201 - class printobserver(ReaderObserver):
202
203 - def __init__(self, obsindex):
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
210 - class testthread(Thread):
211
212 - def __init__(self, obsindex):
213 Thread.__init__(self) 214 self.readermonitor = ReaderMonitor() 215 self.obsindex = obsindex 216 self.observer = None
217
218 - def run(self):
219 # create and register observer 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