/// <summary> /// Create an unknown state list for a named reader /// </summary> /// <remarks> /// Sets the currentState and eventState to 'Unaware' for the reader /// </remarks> /// <param name="readerName">Reader name for which to create initial state</param> /// <returns>List of unknown reader states</returns> private SmartcardInterop.ScardReaderState CreatePendingReaderState(string readerName) { var state = new SmartcardInterop.ScardReaderState { reader = readerName, currentState = SmartcardInterop.State.Unaware, eventState = 0, atrLength = 0 }; return(state); }
/// <summary> /// Call the card removed delegate for each changed reader /// </summary> /// <param name="state">State class containing the smartcard reader name</param> private void FireCardRemovedEvent(SmartcardInterop.ScardReaderState state) { if (this.DebounceState(state.reader, CardEvent.Remove)) { return; } var args = new SmartcardEventArgs(null, state.reader); this.logger.DebugFormat("Firing card removed event for reader {0}", state.reader); this.OnCardRemoved?.Invoke(this, args); }
/// <summary> /// Call the card detected delegate for each changed reader /// </summary> /// <param name="state">State class containing the smartcard reader name</param> private void FireCardPresentEvent(SmartcardInterop.ScardReaderState state) { if (this.DebounceState(state.reader, CardEvent.Insert)) { return; } var cardname = this.FindCardWithAtr(state.atr); var scard = new Smartcard(state.reader, cardname); var args = new SmartcardEventArgs(scard, state.reader); this.logger.DebugFormat("Firing card insert event for reader {0}, card {1}", state.reader, cardname); this.OnCardInserted?.Invoke(this, args); }
/// <summary> /// Monitor for smartcard change events and fire events on detected changes /// </summary> private void WaitForReaderStateChange() { var awaitNewReader = new SmartcardInterop.ScardReaderState { reader = NotificationReader, currentState = 0, eventState = 0, atrLength = 0 }; this.currentState.Add(awaitNewReader); var i = 0; var result = 0; while (!this.cancelToken.IsCancellationRequested) { try { i++; var scardstate = this.currentState.ToArray(); this.logger.DebugFormat("StateChange - start: {0}; last status = 0x{1}; statecount = {2}", i, result.ToString("X"), scardstate.Length); // We have a 30 second timeout rather than infinite. As of Windows 8, the smartcard // service shuts down if no readers attached and more than a couple of minutes have // elapsed since the last SCard API call. So a 30 second timeout will keep the service // alive and mean we're not reseting context (and thus restarting smartcard service) // every couple of minutes. result = SmartcardInterop.SCardGetStatusChange(this.readerContext, 30000, scardstate, scardstate.Length); if (this.cancelToken.IsCancellationRequested || result == SmartcardException.SCardECancelled) { this.logger.Debug("Cancellation requested"); break; } if (result == SmartcardException.SCardETimeout) { continue; } this.logger.Debug("StateChange - result: 0x" + result.ToString("X")); var scardstatelist = scardstate.ToList(); // If the service has stopped, then we need to flag all existing cards as removed if (this.HandleStoppedService(scardstatelist, result)) { // Need to reset the smartcard context this.ResetContext(); this.currentState.Add(awaitNewReader); continue; } // All other errors, throw an exception if (result != SmartcardException.SCardSuccess) { this.logger.DebugFormat("Failed to get smartcard state: error 0x{0}", result); throw new SmartcardException(result); } // Now deal with the actual smartcard changes var scardChanges = scardstatelist.Where(x => (x.eventState & SmartcardInterop.State.Changed) != 0).ToList(); if (scardChanges.Count == 0) { continue; } this.DumpState(scardChanges); this.HandleRemovedReaders(scardChanges, result); this.HandleRemovedCards(scardChanges, result); this.HandleInsertedCards(ref scardChanges, result); this.SaveState(scardChanges); } catch (SmartcardException ex) { if (ex.Status == SmartcardException.SCardEServiceStopped || ex.Status == SmartcardException.SCardENoService) { this.logger.Debug("Smartcard service stopped; resetting context"); this.ResetContext(); this.currentState.Add(awaitNewReader); } else { throw; } } } this.logger.Debug("Monitoring stopped."); }