Tuesday, April 3, 2012

monitor_smartcard_readers usage

Building a loop to monitor smart cards on windows turns out to be tricky. I have written a function to do this and allow code to be inserted in the necessary places.

template<
  typename SetContext, 
  typename ClearContext,
  typename Wait,
  typename Report
>
unique_winerror monitor_smartcard_readers(
  SetContext && setContext,
  ClearContext && clearContext,
  Wait && wait,
  Report &&  report
);

By itself the data produced by this function isn't too interesting, but I have a project in mind that I hope will use it to advantage.

To use monitor_smartcard_readers you call the function passing in lambdas for the code to insert.

  • setContext when the function establishes a context it calls this lambda to allow the caller to store the context and use it later to call SCardCancel
  • clearContext when the function closes the context it calls this function to inform the caller that it is no longer valid.
  • wait when the function needs to wait for the service to become available or check to see if it should exit it calls this lambda. this lambda must return a bool, true for continue and false for exit.
  • report when the function has an update to the status it calls this lambda with a range of reader states.

A quick example should show how this all stitches together.

void monitor()
{

First need to get the win32 event handle that is set when the smart card service is running.

  HANDLE waitfor[1] = {SCardAccessStartedEvent()};
  ON_UNWIND_AUTO([] {SCardReleaseStartedEvent();});

  unique_winerror winerror;
  SCARDCONTEXT context = NULL;

  while (!winerror) {
    winerror = monitor_smartcard_readers(

when setContext is called, store the context in the local stack variable.

    [&](SCARDCONTEXT context) {
      context = context;
    },

when clearContext is called, set the local stack variable to NULL

    [&]() {
      context = NULL;
    },

when wait is called, wait for the smart card service to start. If additional threads were in play this might include other events to signal that monitor_smartcard_readers should exit.

    [&]() -> bool {
      if (WAIT_OBJECT_0 != WaitForMultipleObjects(
          lib::rng::size(waitfor), 
          waitfor, 
          FALSE, 
          INFINITE
        )
      ) {
        // monitor_smardcard_readers will 
        // return SCARD_E_CANCELLED
        return false;
      }
      return true;
    },

when report is called, print out the state changes.

    [&](
      lib::rng::range<SCARD_READERSTATE*> readersrange
    ) {
      std::wcout << L"---status update---" << std::endl;
      for (auto & state : readersrange) {
        auto stateChanges = (
          state.dwCurrentState ^ state.dwEventState
        ) & std::numeric_limits<unsigned short>::max();
        
        std::wcout << L"reader: " << state.szReader 
        << L" changes: " << 
           std::hex << std::showbase << stateChanges
        << L" state: "
        << ((state.dwEventState == SCARD_STATE_UNAWARE) ? 
           L" SCARD_STATE_UNAWARE" : L"")
        << ((state.dwEventState & SCARD_STATE_PRESENT) ? 
           L" SCARD_STATE_PRESENT" : L"")
        << ((state.dwEventState & SCARD_STATE_ATRMATCH) ? 
           L" SCARD_STATE_ATRMATCH" : L"")
        << ((state.dwEventState & SCARD_STATE_CHANGED) ? 
           L" SCARD_STATE_CHANGED" : L"")
        << ((state.dwEventState & SCARD_STATE_EMPTY) ? 
           L" SCARD_STATE_EMPTY" : L"")
        << ((state.dwEventState & SCARD_STATE_EXCLUSIVE) ? 
           L" SCARD_STATE_EXCLUSIVE" : L"")
        << ((state.dwEventState & SCARD_STATE_IGNORE) ? 
           L" SCARD_STATE_IGNORE" : L"")
        << ((state.dwEventState & SCARD_STATE_INUSE) ? 
           L" SCARD_STATE_INUSE" : L"")
        << ((state.dwEventState & SCARD_STATE_MUTE) ? 
           L" SCARD_STATE_MUTE" : L"")
        << ((state.dwEventState & SCARD_STATE_UNAVAILABLE) ? 
           L" SCARD_STATE_UNAVAILABLE" : L"")
        << ((state.dwEventState & SCARD_STATE_UNKNOWN) ? 
           L" SCARD_STATE_UNKNOWN" : L"")
        << ((state.dwEventState & SCARD_STATE_UNPOWERED) ? 
           L" SCARD_STATE_UNPOWERED" : L"")
        << std::endl; 
      }
      std::wcout << L"--status update end--" << std::endl;
    }
    );
  }
}

Next post will explore the implementation of monitor_smartcard_readers..

No comments:

Post a Comment