8a08f642d436d87bd46c3617e667e7a35a260dac
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8a08f642d4 |
v3.32.2: the Windows card-swap auto-equip loop
release / release (push) Waiting to run
After a card swap (or the first insertion after startup) on Windows the auto-equip looped forever: "card inserted, initializing" / "card gone during initialization", with no "retry 2/3" lines. An equip with the card still present produced no card (app.card None), and that branch reported "card gone" and returned True - a no-op success - so the three retries never ran and the watchdog re-armed every ~5 s. - The card-gone no-op is now only for a real removal (card_present False); a card-present init that produced no card raises a failure. - Any failed attempt marks the transport stale, so the next attempt rebuilds the PC/SC link (a Windows swap can leave the old link unable to connect; _ensure_transport releases the old link before building the new one, so the 2026-09-24 stale-handle bug cannot recur). - The error pySim swallowed (cmd2) is printed as "AUTO-EQUIP: init output:" with its traceback - the failure is diagnosable from the log. - Docs: the READMEs' troubleshooting bullet. - Version strings + the PWA cache bumped together (simple-v460). Tests: a card-present init without a card is a failure, a mid-init removal stays a silent no-op, any failure marks the transport, the stale-handle traceback reaches the log, and an end-to-end retry: a failed init, the old link released, a fresh one built, the retry succeeds. 1012 Python + 953 frontend green. |
||
|
|
bed66c8ff8 |
fix: robust equip-state detection and review follow-ups (v3.5.4)
Code-review follow-ups for v3.5.2/v3.5.1, plus a test flake found while re-running the suites: - F1: a half-initialized equip is no longer reported as success. cmd2 swallows exceptions raised inside the equip command (and prints no traceback by default), while PysimApp.equip() assigns card/rs before it registers the command sets - so app.card alone once let the "CommandSet ... is already installed" abort pass as done while /api/tree stayed broken. The auto-equip attempt now captures the output with cmd2 debug on (a swallowed error prints a traceback), requires the new profile's command-set instances to be installed (_app_equip_complete), and the manual /api/command equip branch applies the post-equip refresh only when that check passes (and reports it in the output when it does not). - F3: SCARD_E_SHARING_VIOLATION is recoverable (a rebuild cannot free another process's claim) instead of transport-fatal. - F4: SPI1 b2b1 = 11 (Digital Signature) is refused instead of building an unsigned packet; help notes RC is CRC-32 only (KID CRC-16 not offered). - F5: _clear_app_card_state removes the muted stdout again when the app object had no stdout attribute. - F7: the watchdog re-arm keeps its rate-limit window when the trigger is busy/disabled instead of consuming it. - F2: stale docstring in _auto_equip_attempt. - tests: equip-state units, half-equip and captured-traceback failures, unequip-on-failure, busy trigger, sharing violation, DS refusal. - bonus: the MCC/MNC random-pick test could fail because a dict keyed by (mcc, mnc) keeps one of two entries (the bundled list carries both a real and an MVNO entry for 234/18 and 234/28); the picker was correct - the assertion now checks the pair against the non-MVNO pairs. 549 frontend / 421 Python green; version 3.5.4; sw cache simple-v256. |
||
|
|
0f8c6dea50 |
fix: recover from a card swap without a server restart (v3.5.2)
Equip was broken after a card swap: auto-equip (and manual Equip) failed with "Failed to transmit with protocol T0. Card was removed. (0x80100069)" until the server was restarted. Chain (v3.1.2 regression): - _handle_card_disconnect() cleared server.card/scc but not pySim's app.card/app.rs/app.lchan, so the removed card - and with it the old PC/SC link and its exclusive card handle - stayed referenced; handlers using app.rs (e.g. the PWA's /api/tree poll) kept transmitting over the dead card. - those errors carry hresult=0x80100069 (SCARD_W_REMOVED_CARD), but _is_pcsc_error() treated any PC/SC error as a dead service and set _TRANSPORT_STALE; the next auto-equip then called _ensure_transport(), which built a second PcscSimLink while the old one was still connected - the new link inherited the removed card's handle and failed on its first APDU. No retry existed, so every later equip repeated the failure. Fixes: - _is_transport_fatal(): only service/context hresults rebuild the transport (E_NO_SERVICE, E_SERVICE_STOPPED, E_NO_READERS_AVAILABLE, E_INVALID_HANDLE, ...); card-level states (W_REMOVED_CARD, E_NO_SMARTCARD, W_RESET_CARD, W_UNRESPONSIVE_CARD, W_UNPOWERED_CARD) reconnect on the existing link. All 8 disconnect call sites pass the new verdict. - _clear_app_card_state(): unequip through pySim's own equip(None, None) before clearing app.card/app.rs/app.lchan. Nulling them alone would make the next equip abort with "CommandSet ... is already installed" (PysimApp.equip() unregisters the previous profile's command sets from self.rs), which left /api/tree broken after a swap. A failed auto-equip attempt unequips the half-initialized shell as well. Handlers now answer "no card" instead of transmitting over the dead card, and the old link becomes collectable. - _ensure_transport(): disconnects the old link before building the new one (restoring it if the factory fails) - the rebuild path is now safe for the real pcscd-restart case. - auto-equip: _auto_equip_attempt()/_auto_equip_attempts() retry up to 3 times, 1 s apart (fatal failures mark the transport so the retry rebuilds); the watchdog re-arms it (_auto_equip_rearm) every 5 s while a card is present and the session is down, with exponential backoff to 60 s for a card that cannot be initialized at all. - fastinit.init_card_fast(): also retries once after a PC/SC link error (CardConnectionException/NoCardException), not only after SW mismatches. Tests: transport-fatal classification, app-state clearing, shell unequip, old-link release, auto-equip retry/backoff/re-arm, fastinit link retry. 547 frontend / 410 Python green; version 3.5.2; sw cache simple-v254. |
||
|
|
b87b3905ee |
fix: recover from a PC/SC service failure without a server restart (v3.1.2)
After pcscd restarted (or the reader re-enumerated) the server stayed permanently cardless: - pyscard's presence-monitor thread stops itself on SCARD_E_NO_SERVICE and pyscard never starts it again, so card insertions were no longer noticed and auto-equip was dead; - PCSCCardConnection.connect() reuses the context handle captured when the reader was opened, so the old connection could not be revived and every APDU kept failing with 'Service not available'. - _start_card_watchdog(): a daemon that every 5 s checks whether CardMonitor().rmthread.instance is alive and recreates the stopped thread (CardMonitoringThread.instance = None + a fresh rmthread); the new thread reports already-present cards as inserted, which triggers auto-equip. start_card_monitor() starts the watchdog. - _is_pcsc_error(): pyscard exceptions carry an hresult, card-level errors do not; the disconnect paths (AUTO-STATUS, status poll, timer expiration, net-sim, tree, event send, OTA send) pass the verdict to _handle_card_disconnect(stale=...), which marks the transport stale. - _ensure_transport(): builds a fresh transport via server.transport_factory (installed by __main__ as mod.init_reader(opts, **tracer_kwargs)) and installs it into app.sl/server.sl; called by the auto-equip worker, the /api/command equip branch and _esim_reinit. - tests: watchdog tick, transport recreation (fresh/stale/failure/no factory), PC/SC classification, stale disconnect flag. - docs: AGENTS card-behavior section, README troubleshooting (EN/RU); version 3.1.2, sw.js simple-v237. |