From 7ec0db9ebbb792f6b142c882323598d1865d6119 Mon Sep 17 00:00:00 2001 From: "Chris.Watts90@outlook.com" Date: Tue, 6 Mar 2018 14:31:31 +0000 Subject: [PATCH 1/4] Set service so that it will always start, not exit early if there is no card reader attached. WIP #90 --- .../CardReaderService/Service1.cs | 88 +++++++++++-------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/CardReaderService/CardReaderService/Service1.cs b/CardReaderService/CardReaderService/Service1.cs index 971ea0b..2254187 100644 --- a/CardReaderService/CardReaderService/Service1.cs +++ b/CardReaderService/CardReaderService/Service1.cs @@ -12,9 +12,8 @@ namespace CardReaderService { private Thread _mainWorkThread; private bool _stopMainWorkerThread; - + private AutoResetEvent _mainWorkerTerminationSignal; private string _readerName = ""; - //private SCardReader _reader; private SCardMonitor _cardMonitor; public Service1() @@ -24,29 +23,27 @@ namespace CardReaderService public void Start() { - OnStart(new string[] {}); + OnStart(new string[] { }); } -// + protected override void OnStart(string[] args) { - Console.WriteLine("Starting.. Getting available readers"); - var ctxFactory = ContextFactory.Instance; - using(var context = ctxFactory.Establish(SCardScope.System)) - { - var readerNames = context.GetReaders(); - if (NoReaderAvailable(readerNames)) - { - Console.WriteLine("No Card Reader is available, Exiting.."); - return; - } - Console.WriteLine("Choosing first available reader: " + readerNames.First()); - _readerName = readerNames.First(); - _cardMonitor = new SCardMonitor(ctxFactory, SCardScope.System); - _cardMonitor.CardInserted += _cardMonitor_CardInserted; - _cardMonitor.Start(_readerName); + StartWorkerThread(); + } - StartWorkerThread(); + private bool WeHaveValidCardReader() + { + if (_cardMonitor == null) + { + return false; } + if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown || + _cardMonitor.GetCurrentState(0) == SCRState.Unavailable || + _cardMonitor.GetCurrentState(0) == SCRState.Unaware) + { + return false; + } + return true; } public void Stop() @@ -57,19 +54,16 @@ namespace CardReaderService protected override void OnStop() { _stopMainWorkerThread = true; - if (_mainWorkThread!= null && _mainWorkThread.IsAlive) + _mainWorkerTerminationSignal.Set(); + if (_mainWorkThread != null && _mainWorkThread.IsAlive) { - _mainWorkThread.Join(3000); - if (_mainWorkThread.IsAlive) - { - _mainWorkThread.Interrupt(); - } + _mainWorkThread.Interrupt(); } if (_cardMonitor != null) { _cardMonitor.Cancel(); _cardMonitor.Dispose(); - _cardMonitor = null; + _cardMonitor = null; } } @@ -81,6 +75,7 @@ namespace CardReaderService Name = "CardServiceMainThread", IsBackground = false }; + _mainWorkerTerminationSignal = new AutoResetEvent(false); _mainWorkThread.Start(); } @@ -99,7 +94,7 @@ namespace CardReaderService _stopMainWorkerThread = true; return; } - + var err = reader.Connect(_readerName, SCardShareMode.Shared, SCardProtocol.T0 | SCardProtocol.T1); if (err == SCardError.Success) @@ -113,10 +108,10 @@ namespace CardReaderService var atrString = ConvertByteUIDToString(e.Atr); Console.WriteLine("Card Inserted, ATR: " + atrString + ", and UID is: " + uid); - CardDataPost postObj = new CardDataPost {CardUId = uid}; + CardDataPost postObj = new CardDataPost { CardUId = uid }; DataCenterHelper.PostAsync(postObj, "/api/swipedata"); Console.WriteLine("Posted to Server"); - } + } } else { @@ -125,21 +120,44 @@ namespace CardReaderService } } - + private void MainWorkerThread() { while (!_stopMainWorkerThread) { - //dont actually need to do anything.. but cannot exit right away? - Thread.Sleep(3000); + if (!WeHaveValidCardReader()) + { //only do this if we don't have a valid card reader + Console.WriteLine("Starting.. Getting available readers"); + var ctxFactory = ContextFactory.Instance; + using (var context = ctxFactory.Establish(SCardScope.System)) + { + var readerNames = context.GetReaders(); + if (!NoReaderAvailable(readerNames)) + { + //we have a reader available, so initialise! + Console.WriteLine("Choosing first available reader: " + readerNames.First()); + _readerName = readerNames.First(); + _cardMonitor = new SCardMonitor(ctxFactory, SCardScope.System); + _cardMonitor.CardInserted += _cardMonitor_CardInserted; + _cardMonitor.Start(_readerName); + + StartWorkerThread(); + } + else + { + Console.WriteLine("No Card Reader is available.."); + } + } + } + _mainWorkerTerminationSignal.WaitOne(3000); } } private string ConvertByteUIDToString(byte[] uid) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); - foreach(var b in uid) + foreach (var b in uid) { sb.AppendFormat("{0:X2}", b); } From 3eef3017a08a53052f240b20d1435e417be699e5 Mon Sep 17 00:00:00 2001 From: "Chris.Watts90@outlook.com" Date: Tue, 6 Mar 2018 14:45:27 +0000 Subject: [PATCH 2/4] Fix memory leak issue, where we would create a duplicate cardmonitor for an "unaware" card reader state. --- CardReaderService/CardReaderService/Service1.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CardReaderService/CardReaderService/Service1.cs b/CardReaderService/CardReaderService/Service1.cs index 2254187..9cd3413 100644 --- a/CardReaderService/CardReaderService/Service1.cs +++ b/CardReaderService/CardReaderService/Service1.cs @@ -37,9 +37,11 @@ namespace CardReaderService { return false; } - if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown || - _cardMonitor.GetCurrentState(0) == SCRState.Unavailable || - _cardMonitor.GetCurrentState(0) == SCRState.Unaware) + Console.WriteLine(_cardMonitor.GetCurrentState(0)); + if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown + || _cardMonitor.GetCurrentState(0) == 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; } From d443ecb24c233d433cf3c555ba2abc1e568a386c Mon Sep 17 00:00:00 2001 From: "Chris.Watts90@outlook.com" Date: Tue, 6 Mar 2018 14:45:27 +0000 Subject: [PATCH 3/4] fixup! Fix memory leak issue, where we would create a duplicate cardmonitor for an "unaware" card reader state. #90 --- CardReaderService/CardReaderService/Service1.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CardReaderService/CardReaderService/Service1.cs b/CardReaderService/CardReaderService/Service1.cs index 2254187..9cd3413 100644 --- a/CardReaderService/CardReaderService/Service1.cs +++ b/CardReaderService/CardReaderService/Service1.cs @@ -37,9 +37,11 @@ namespace CardReaderService { return false; } - if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown || - _cardMonitor.GetCurrentState(0) == SCRState.Unavailable || - _cardMonitor.GetCurrentState(0) == SCRState.Unaware) + Console.WriteLine(_cardMonitor.GetCurrentState(0)); + if (_cardMonitor.GetCurrentState(0) == SCRState.Unknown + || _cardMonitor.GetCurrentState(0) == 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; } From 901e9190a4cba08e0100504ece01b0e22add3c3b Mon Sep 17 00:00:00 2001 From: "Chris.Watts90@outlook.com" Date: Tue, 6 Mar 2018 15:10:10 +0000 Subject: [PATCH 4/4] Improve code to handle disconnected card reader during runtime. Correct thread/memory leak issue where two main threads were created/running. (bad juju!) #90 --- CardReaderService/CardReaderService/Service1.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CardReaderService/CardReaderService/Service1.cs b/CardReaderService/CardReaderService/Service1.cs index 9cd3413..7039de9 100644 --- a/CardReaderService/CardReaderService/Service1.cs +++ b/CardReaderService/CardReaderService/Service1.cs @@ -15,6 +15,7 @@ namespace CardReaderService private AutoResetEvent _mainWorkerTerminationSignal; private string _readerName = ""; private SCardMonitor _cardMonitor; + private bool _initialised=false; public Service1() { @@ -40,6 +41,7 @@ namespace CardReaderService Console.WriteLine(_cardMonitor.GetCurrentState(0)); 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. ) { @@ -129,6 +131,15 @@ namespace CardReaderService { if (!WeHaveValidCardReader()) { //only do this if we don't have a valid card reader + if (_initialised) + { + //card reader no longer available, tidy up. + _cardMonitor.Cancel(); + _cardMonitor.CardInserted -= _cardMonitor_CardInserted; + _cardMonitor.Dispose(); + _cardMonitor = null; + _initialised = false; + } Console.WriteLine("Starting.. Getting available readers"); var ctxFactory = ContextFactory.Instance; using (var context = ctxFactory.Establish(SCardScope.System)) @@ -142,8 +153,8 @@ namespace CardReaderService _cardMonitor = new SCardMonitor(ctxFactory, SCardScope.System); _cardMonitor.CardInserted += _cardMonitor_CardInserted; _cardMonitor.Start(_readerName); - - StartWorkerThread(); + + _initialised = true; } else {