using PCSC; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.ServiceProcess; using System.Text; using System.Threading; using Interfaces; namespace CardReaderService { public partial class CardReaderService : ServiceBase { private Thread _mainWorkThread; private bool _stopMainWorkerThread; private string _readerName = ""; private SCardMonitor _cardMonitor; private bool _initialised = false; private AutoResetEvent _mainWorkerTerminationSignal; private ILogger _logger; public CardReaderService() { InitializeComponent(); } public void Start() { OnStart(new string[] {}); } protected override void OnStart(string[] args) { _logger = NinjectHelper.GetInstance().Get(); StartWorkerThread(); } public void StopService() { OnStop(); } protected override void OnStop() { _stopMainWorkerThread = true; _mainWorkerTerminationSignal.Set(); if (_mainWorkThread!= null && _mainWorkThread.IsAlive) { _mainWorkThread.Join(3000); if (_mainWorkThread.IsAlive) { _mainWorkThread.Interrupt(); } } if (_cardMonitor == null) return; _cardMonitor.Cancel(); _cardMonitor.Dispose(); _cardMonitor = null; } private void StartWorkerThread() { _stopMainWorkerThread = false; _mainWorkThread = new Thread(MainWorkerThread) { Name = "CardServiceMainThread", IsBackground = false }; _mainWorkerTerminationSignal = new AutoResetEvent(false); _mainWorkThread.Start(); } private void _cardMonitor_CardInserted(object sender, CardStatusEventArgs e) { var ctxFac = ContextFactory.Instance; using (var ctx = ctxFac.Establish(SCardScope.System)) { var reader = new SCardReader(ctx); var pioSendPci = new IntPtr(); var rcvBuffer = new byte[256]; if (_readerName == string.Empty) { _logger.Fatal("Reader name is somehow empty...exiting"); _stopMainWorkerThread = true; return; } var err = reader.Connect(_readerName, SCardShareMode.Shared, SCardProtocol.T0 | SCardProtocol.T1); if (err == SCardError.Success) { var uIdcmd = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; err = reader.Transmit(pioSendPci, uIdcmd, ref rcvBuffer); if (err != SCardError.Success) return; var uid = ConvertByteUIDToString(rcvBuffer); var atrString = ConvertByteUIDToString(e.Atr); _logger.Trace("Card Inserted, ATR: " + atrString + ", and UID is: " + uid); var postObj = new CardDataPost {CardUId = uid}; DataCenterHelper.PostAsync(_logger, postObj, "/api/swipedata"); _logger.Trace("Posted to Server"); } else { _logger.Trace("Reader failed to connect, error: " + Enum.GetName(typeof(SCardError), err)); } reader.Dispose(); } } private void MainWorkerThread() { while (!_stopMainWorkerThread) { //dont actually need to do anything.. but cannot exit right away? if (!WeHaveValidCardReader()) { if (_initialised) { //card reader no longer available, tidy up. _cardMonitor.Cancel(); _cardMonitor.CardInserted -= _cardMonitor_CardInserted; _cardMonitor.Dispose(); _cardMonitor = null; _initialised = false; } var ctxFactory = ContextFactory.Instance; using (var context = ctxFactory.Establish(SCardScope.System)) { var readerNames = context.GetReaders(); if (NoReaderAvailable(readerNames)) { _logger.Trace("No Card Reader is available.."); } else { foreach (var reader in readerNames) { _logger.Trace("Found reader: {0}", reader); } var readerNameConfig = ConfigurationHandler.ConfigurationHandler.GetConfiguration("ReaderName"); if (string.IsNullOrEmpty(readerNameConfig) || (!readerNames.Contains(readerNameConfig))) { _logger.Warn("No reader found with the name: {0}, defaulting to first available reader {1}", readerNameConfig, readerNames.First()); readerNameConfig = readerNames.First(); } _logger.Trace("Choosing reader: {0}", readerNameConfig); _readerName = readerNameConfig; _cardMonitor = new SCardMonitor(ctxFactory, SCardScope.System); _cardMonitor.CardInserted += _cardMonitor_CardInserted; _cardMonitor.Start(_readerName); _initialised = true; } } } _mainWorkerTerminationSignal.WaitOne(3000); } } private string ConvertByteUIDToString(byte[] uid) { var sb = new StringBuilder(); foreach(var b in uid) { sb.AppendFormat("{0:X2}", b); } return sb.ToString(); } private bool NoReaderAvailable(ICollection readerNames) { return readerNames == null || readerNames.Count < 1; } private bool WeHaveValidCardReader() { if (_cardMonitor == null) { return false; } _logger.Trace(_cardMonitor.GetCurrentState(0).ToString()); if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown || _cardMonitor.GetCurrentState(0) == SCRState.Unavailable || _cardMonitor.GetCurrentState(0) == (SCRState.Ignore | SCRState.Unavailable) //|| _cardMonitor.GetCurrentState(0) == SCRState.Unaware //if we say this is an invalid state, we cause a memory leak where we create a duplicate card monitor, subscribe and overwrite. ) { return false; } return true; } } }