-
-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deadlock with multiple readers and quick reads #220
Comments
By "hold on / off" you mean insert and remove?
You mean the card is no more inserted in the reader but PySCard has not generated a removedcards event? Can you also run |
I use NFC Reader. So i only hold on a Desfire Card and Remote the Card ready quick. |
"You mean the card is no more inserted in the reader but PySCard has not generated a removedcards event?" |
Running |
Tell me if I am. correct in my understanding:
|
Thanks a lot for your quick response. If I could provide you any further information, let me know |
About point 3, from your second screen capture the "status unavailable" is for reader "NXP PN7462AU CCID (1.00) 01 00". Is that reader a or reader b? |
We have 2 issues:
For 1 I will have a look. For 2 the problem is not in PySCard.
Are you able to reproduce issue 1 or 2 with only one reader? |
Hey, i total agree that there are 2 issues. |
From pcsc-lite source code, To continue the investigation I will need pcscd logs as described in https://ccid.apdu.fr/#support |
|
From your logs:
The driver sends a PC_to_RDR_IccPowerOff command (63h) After that the reader is "confused" and refuses to work correctly:
It is not a problem in PySCard or pcsc-lite or the CCID driver. |
Thanks a lot for this deep analysis. I will provide this information to the Vendor. So this is Issue 2. Do you see a chance that pyscard can get the events in the scenario on other readers (Issue 1)? This would help a lot. |
Maybe the firmware of your NXP reader is old. |
An easy way to reproduce the missing event problem is to use this patch: diff --git a/src/smartcard/CardMonitoring.py b/src/smartcard/CardMonitoring.py
index bb7f3f7..d9bad74 100644
--- a/src/smartcard/CardMonitoring.py
+++ b/src/smartcard/CardMonitoring.py
@@ -177,6 +177,8 @@ class CardMonitoringThread:
self.observable.setChanged()
self.observable.notifyObservers((addedcards, removedcards))
+ sleep(5)
+
except CardRequestTimeoutException:
pass I know what need to be fixed. |
We now use the states returned by the previous SCardGetStatusChange() call as initial state for the next call. Since pcsc-lite includes and use the number of card events in the high word of dwEventState the function SCardGetStatusChange() returns if an event was missed. Thanks to Lars Lengersdorf for the bug report " Deadlock with multiple readers and quick reads #220 " LudovicRousseau/pyscard#220
The missing event problem should be fixed in https://github.com/LudovicRousseau/pyscard-devel |
Hey Sorry for the late response, do i need to compile it in a way? In the installed pyscard i have smartcard/scard/scard.py file witch is missing in https://github.com/LudovicRousseau/pyscard-devel/tree/master/src/smartcard/scard. So i try to copy the last 2 commit in my installed pyscard but the bug ist not fixed then. |
The easiest way to test is to download the file PCSCCardRequest.py and replace the one from your local installation. You should add something like:
at the beginning of the method The only Ubuntu version that provides python3-pyscard version 2.2.0 is plucky (the not yet released Ubuntu 25.04) https://packages.ubuntu.com/search?keywords=python3-pyscard |
Here is a fixed version of your sample code. import time
from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.util import toHexString
class NFCObserver(CardObserver):
def update(self, observable, actions):
# callback method from observer
addedcards, removedcards = actions
print("------ update", actions)
try:
for card in addedcards:
print(f"Add Card from reader {card.reader}- ATR: {toHexString(card.atr)}")
connection = card.createConnection()
connection.connect()
connection.disconnect()
for card in removedcards:
print("Removed Card from reader %s- Removed card: %s" % (card.reader, toHexString(card.atr)))
except Exception as e:
print(e.__class__.__name__, e, actions)
print("Unexpected %s during NFCObserver callback: %s action=%s" % (e.__class__.__name__, e, actions))
def main():
card_observer = NFCObserver()
card_monitor = CardMonitor()
card_monitor.addObserver(card_observer)
while True:
time.sleep(10)
card_monitor.deleteObserver(card_observer)
if __name__ == "__main__":
main() Use Questions:
Since you have a firmware issue (reader reports "CmdGetSlotStatus Slot busy") I don't think it is a good idea to continue your tests with these readers. You will always get problems. Do you have readers from another manufacturer? |
I don't understand why a problem on one reader would create problems on the second reader. I propose you to generate debug traces so I can analyze in detail what is happening.
Start the 2 logs capture and reproduce the problem. |
Sorry for the late response, Chrismath and end of year hits in, but now I am back in Focus with Smartcards. From your screen capture, I understand that you add/remove the card only on the reader named "NXP PN7462AU CCID (1.00) 01 00". Exact? --> Yes If you use 1 reader only, do you also get the missing event problem? -> Yes, but only one missing remove Card. When I hold the card again to this reader, everything works fine. This is due to the fact that the reader did not fully comply (guess from your analysis) I don't understand why a problem on one reader would create problems on the second reader. |
A missing event is a card event reported by pcsc_scan but not by PySCard. If the problem is the firmware issue then the reader will fail to report a card removed but pcsc_scan and PySCard will have the same status. So when you use only 1 reader do you see a event that is reported by pcsc_scan but not by PySCard (with my patch applied)? Can you detail what you can reproduce exactly when you use a NXP reader and your internal laptop reader? |
first on ubuntu 22.04 the latest pcsc-lite version is 1.9.5 and install_spy.sh is available in 1.9.8 So when you use only 1 reader do you see an event that is reported by pcsc_scan but not by PySCard (with my patch applied)? Can you detail what you can reproduce exactly when you use a NXP reader and your internal laptop reader? Here you find the pcsc-spy log of pcsc_scan and the pcscd log. Some Times pcsc-spy crashed
log_pcscd_multi_nxp_and_internal.txt I Relay hope this will help you. If you need any further information, do not hesitate to ask. |
Thanks.
The pcsc-spy crash trace is not complete. I guess Python reported an exception name. But it is not present in what you provide. |
How do I log pcsc_scan an python with pcsc_spy in multiple Files? |
Ah yes, you can't (easily) spy 2 applications at the same time. I see you have in fact 2 Broadcom readers (or interfaces) and 4 readers in total:
One question: are you able to see card events on each reader with your Python program (when you do not try to generate a problem)? |
I think I found the problem thanks to the pcscd logs.
The If you do not want to lose card events, your The problem is NOT in PySCard. |
My patch is now included in a released version Closing this issue. |
Yes, you are totally right. This is exactly the Problem. So just for everyone running in this Problem. The wrapt_timeout_decorator can handle multithreading timeouts. So when the problem occurs, the import datetime
import time
from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.scard import (
SCardEstablishContext,
SCardListReaders,
SCARD_SCOPE_USER,
)
from smartcard.util import toHexString
from wrapt_timeout_decorator import timeout
class NFCObserver(CardObserver):
def update(self, observable, actions):
# callback method from observer
print("------ update", actions, datetime.datetime.now().isoformat())
try:
self.long_function_call(actions)
except TimeoutError as e:
print("Timed out!")
@timeout(10, use_signals=False, timeout_exception=TimeoutError, dec_poll_subprocess=1)
def long_function_call(self, actions):
addedcards, removedcards = actions
try:
for card in addedcards:
print(f"ADD Card from reader {card.reader}- ATR: {toHexString(card.atr)}")
connection = card.createConnection()
connection.connect()
connection.disconnect()
print("------ After connection")
for card in removedcards:
print("REMOVED Card from reader %s- Removed card: %s" % (card.reader, toHexString(card.atr)))
except Exception as e:
print(e.__class__.__name__, e, actions)
print("Unexpected %s during NFCObserver callback: %s action=%s" % (e.__class__.__name__, e, actions))
def main():
hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
hresult, readers = SCardListReaders(hcontext, [])
print(readers)
card_observer = NFCObserver()
card_monitor = CardMonitor()
card_monitor.addObserver(card_observer)
while True:
time.sleep(10)
card_monitor.deleteObserver(card_observer)
if __name__ == "__main__":
main()
Thank you so much for your Support, the really quick response time and the fix. |
Your system information
Please describe your issue in as much detail as possible:
Describe what you expected should happen.
I have a setup where I have 2 Readers (call them a and b). If I hold on / off a card really quickly for about 40 times to reader a. the CardObserver miss one removedcards.
When I hold on any card to the other reader (b), no card will be detected on this reader.
To heal this state, I need to hold a card to reader a (this will not be detected throw the observer as well) and remove the card (will be detected). Then both reader works as intended. Sometimes holding a card to reader b will call update with one card add and one removed (his did not trigger the deadlock).
I could not reproduce this with pcscd in debug mode.
Here is ne minimum script to reproduce.
Describe what did happen.
Steps for reproducing this issue:
It is sometiimes a bit tricky to reproduce it. Just try for a few times.
If you need further information please let me know.
Thank you in advance
The text was updated successfully, but these errors were encountered: