Fix insertion/removal detection pcsc now errors out of the SCardGetStatusChange call with SCARD_E_UNKNOWN_READER if any of the passed readers aren't known. This includes readers that were very recently forgotton about because a user just disconnected them. (See http://anonscm.debian.org/viewvc/pcsclite/trunk/PCSC/src/winscard_clnt.c?r1=5858&r2=5881 for the change to pcsc) Unfortunately, this means SECMOD_WaitForAnyTokenEvent will fail with a SC_NO_EVENT error if a user removes their smartcard at the wrong time. This patch changes coolkey to detect removed readers before calling SCardGetStatusChange, so that it can handle the removal itself. diff -up coolkey-1.1.0/src/coolkey/slot.cpp.fix coolkey-1.1.0/src/coolkey/slot.cpp --- coolkey-1.1.0/src/coolkey/slot.cpp.fix 2013-05-22 16:23:41.728846957 -0400 +++ coolkey-1.1.0/src/coolkey/slot.cpp 2013-05-22 17:09:59.813958927 -0400 @@ -279,24 +279,22 @@ SlotList::updateReaderList() * don't recognize. */ - /* first though, let's check to see if any previously removed readers have - * come back from the dead. If the ignored bit has been set, we do not need - * it any more. - */ + /* Iterate through all the readers to see if we need to make unavailable any + * freshly removed readers. Also, see if any previously removed + * readers have come back from the dead and don't need to be ignored. + */ const char *curReaderName = NULL; unsigned long knownState = 0; for(int ri = 0 ; ri < numReaders; ri ++) { - knownState = CKYReader_GetKnownState(&readerStates[ri]); - if( !(knownState & SCARD_STATE_IGNORE)) { - continue; - } - + curReaderName = CKYReader_GetReaderName(&readerStates[ri]); if(readerNameExistsInList(curReaderName,&readerNames)) { CKYReader_SetKnownState(&readerStates[ri], knownState & ~SCARD_STATE_IGNORE); - + } else { + if (!(knownState & SCARD_STATE_UNAVAILABLE)) + CKYReader_SetKnownState(&readerStates[ri], knownState | SCARD_STATE_UNAVAILABLE | SCARD_STATE_CHANGED); } } @@ -1238,6 +1236,32 @@ SlotList::waitForSlotEvent(CK_FLAGS flag throw; } + /* Before round-tripping to the daemon for the duration of the + * timeout, first see if we lost any readers, and pick a slot + * from that set to return + */ + for (i=0; i < numReaders; i++) { + unsigned long knownState = CKYReader_GetKnownState(&readerStates[i]); + + if ((knownState & SCARD_STATE_UNAVAILABLE) && + (knownState & SCARD_STATE_CHANGED)) { + CKYReader_SetKnownState(&readerStates[i], knownState & ~SCARD_STATE_CHANGED); + readerListLock.releaseLock(); + *slotp = slotIndexToID(i); + found = TRUE; + break; + } + } + + if (found) { + break; + } + + if (shuttingDown) { + readerListLock.releaseLock(); + break; + } + if (myNumReaders != numReaders) { if (myReaderStates) { delete [] myReaderStates;