[Pcsclite-muscle] Real time issue for register / unregister to READER_STATE_CHANGE event.

REVILLON Olivier olivier.revillon
Tue Jul 4 05:20:00 PDT 2017


Hello,



We have detected rare real time issue with the SCardGetStatusChange function.

But become more frequent by using SCardGetStatusChange with 0 value as timeout and without using SCARD_STATE_UNAWARE.



The real time issue appends between the timeout of the CMD_WAIT_READER_STATE_CHANGE command and the sending of the CMD_STOP_WAITING_READER_STATE_CHANGE command.

If we consider :

  *   T0 is the time when timeout is detected in the function MessageSendWithHeader for the CMD_WAIT_READER_STATE_CHANGE on the library part.
  *   T1 is the time when the function MessageSendWithHeader is called on the library part.
  *   T2 is the time of the call EHSignalEventToClients on the daemon part.

If in the daemon part ?PCSCD?, a signal is sent between T0 and T1 (T0 < T2 < T1) this signal is considered as the response of the CMD_STOP_WAITING_READER_STATE_CHANGE. But the response is not ?consumed? on the socket. According to the implementation done before SCardGetStatusChange we can have invalid data and / or error.



At this point the next behavior depends to the caller implementation. We remark for our implementation that a new call of SCardGetStatusChange can ?repair? the socket shift but it can result by having an ?event register? in the daemon started without being unregistered (= twice register). So an EHSignalEventToClients event can append at any time if the client is not in the SCardGetStatusChange function.



We have studied this solution for a possible correction :

At daemon side:

We suggest that ?0? is set for timeout if the message is a ?Signal? message (parameter not used for the moment). In order to identify that this message is a signal instead of the response of an unregister request.

LONG MSGSignalClient(uint32_t filedes, LONG rv)
{
                uint32_t ret;
                struct wait_reader_state_change waStr;

                Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);

                waStr.timeOut = 0;  /* To identify message as a signal */
                waStr.rv = rv;
                WRITE_BODY_WITH_COMMAND("SIGNAL", waStr)

                return ret;
} /* MSGSignalClient */



At library side:
When receiving the response of the STOP command verify if the received message is the response. For that, set timeOut to 1. If it is a signal the value is 0 then wait for the response message.

Part of SCardGetStatusChange function :
                /* timeout */
                if (SCARD_E_TIMEOUT == rv)
                {
                               /* ask server to remove us from the event list */
                               waitStatusStruct.timeOut = 1; /* <= ADDED to set a value different as 0 to identify the response. */
                               rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
                                                                                              currentContextMap->dwClientID,
                                                                                              sizeof(waitStatusStruct), &waitStatusStruct);

                               if (rv != SCARD_S_SUCCESS)
                                               goto end;

                               /* Read a message from the server */
                               rv = MessageReceive(&waitStatusStruct,
                                                                                  sizeof(waitStatusStruct),
                                                                                  currentContextMap->dwClientID);

                               if (rv != SCARD_S_SUCCESS)
                                               goto end;
                               /*  ADDED => */
                                if (waitStatusStruct.timeOut == 0)
                               {
                                       rv = MessageReceive(&waitStatusStruct,
                                                                                  sizeof(waitStatusStruct),
                                                                                  currentContextMap->dwClientID);
                                   /* We don?t test rv value, in this case it is for sure an error. */
                            }
                           /* <= ADDED */
                }





The issue shows us that it is possible to be registered twice. Is can better to test it when register :

LONG EHRegisterClientForEvent(int32_t filedes)
{
                (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);

                int pos = list_locate(l, data);
                if (pos < 0)
                {
                               (void)list_append(&ClientsWaitingForEvent, &filedes);
                }

                (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);

                return SCARD_S_SUCCESS;
} /* EHRegisterClientForEvent */



And finally we can add but not necessary an exit condition when timeout is 0. In fact if timeout is 0, the library doesn?t wait so it is not necessary to register. This is in order to optimize the code.



Part of SCardGetStatusChange function :
                /* Break if UNAWARE is set and all readers have been checked */
                if ( (dwBreakFlag == 1) || (0 == dwTime))
                               break;


Best Regards,



Olivier REVILLON
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/pcsclite-muscle/attachments/20170704/b96f8398/attachment.html>



More information about the pcsclite-muscle mailing list