pcsc-lite  2.2.3
eventhandler.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2000-2002
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2002-2023
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in the
17  documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19  derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
39 #include "config.h"
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 
48 #include "misc.h"
49 #include "pcscd.h"
50 #include "debuglog.h"
51 #include "readerfactory.h"
52 #include "eventhandler.h"
53 #include "dyn_generic.h"
54 #include "sys_generic.h"
55 #include "ifdwrapper.h"
56 #include "prothandler.h"
57 #include "utils.h"
58 #include "winscard_svc.h"
59 #include "simclist.h"
60 
62 pthread_mutex_t ClientsWaitingForEvent_lock;
64 static void * EHStatusHandlerThread(READER_CONTEXT *);
65 
66 LONG EHRegisterClientForEvent(int32_t filedes)
67 {
68  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
69 
70  (void)list_append(&ClientsWaitingForEvent, &filedes);
71 
72  (void)MSGSendReaderStates(filedes);
73 
74  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
75 
76  return SCARD_S_SUCCESS;
77 } /* EHRegisterClientForEvent */
78 
83 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
84 {
85  LONG rv = SCARD_S_SUCCESS;
86  int ret;
87 
88  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
89 
90  ret = list_delete(&ClientsWaitingForEvent, &filedes);
91 
92  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
93 
94  if (ret < 0)
96 
97  return rv;
98 } /* EHTryToUnregisterClientForEvent */
99 
103 LONG EHUnregisterClientForEvent(int32_t filedes)
104 {
105  LONG rv = EHTryToUnregisterClientForEvent(filedes);
106 
107  if (rv != SCARD_S_SUCCESS)
108  Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
109 
110  return rv;
111 } /* EHUnregisterClientForEvent */
112 
117 {
118  int32_t filedes;
119 
120  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
121 
122  (void)list_iterator_start(&ClientsWaitingForEvent);
123  while (list_iterator_hasnext(&ClientsWaitingForEvent))
124  {
125  filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
126  MSGSignalClient(filedes, SCARD_S_SUCCESS);
127  }
128  (void)list_iterator_stop(&ClientsWaitingForEvent);
129 
130  (void)list_clear(&ClientsWaitingForEvent);
131 
132  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
133 } /* EHSignalEventToClients */
134 
135 LONG EHInitializeEventStructures(void)
136 {
137  (void)list_init(&ClientsWaitingForEvent);
138 
139  /* request to store copies, and provide the metric function */
140  (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
141 
142  /* setting the comparator, so the list can sort, find the min, max etc */
143  (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
144 
145  (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
146 
147  return SCARD_S_SUCCESS;
148 }
149 
150 LONG EHDeinitializeEventStructures(void)
151 {
152  list_destroy(&ClientsWaitingForEvent);
153  pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
154 
155  return SCARD_S_SUCCESS;
156 }
157 
158 void EHDestroyEventHandler(READER_CONTEXT * rContext)
159 {
160  int rv;
161  DWORD dwGetSize;
162  UCHAR ucGetData[1];
163 
164  if ('\0' == rContext->readerState->readerName[0])
165  {
166  Log1(PCSC_LOG_INFO, "Thread already stomped.");
167  return;
168  }
169 
170  /*
171  * Set the thread to 0 to exit thread
172  */
173  rContext->hLockId = 0xFFFF;
174 
175  Log1(PCSC_LOG_INFO, "Stomping thread.");
176 
177  /* kill the "polling" thread */
178  dwGetSize = sizeof(ucGetData);
180  &dwGetSize, ucGetData);
181 
182  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
183  {
184  Log1(PCSC_LOG_INFO, "Killing polling thread");
185  (void)pthread_cancel(rContext->pthThread);
186  }
187  else
188  {
189  /* ask to stop the "polling" thread */
190  RESPONSECODE (*fct)(DWORD) = NULL;
191 
192  dwGetSize = sizeof(fct);
194  &dwGetSize, (PUCHAR)&fct);
195 
196  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
197  {
198  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
199  fct(rContext->slot);
200  }
201  else
202  Log1(PCSC_LOG_INFO, "Waiting polling thread");
203  }
204 
205  /* wait for the thread to finish */
206  rv = pthread_join(rContext->pthThread, NULL);
207  if (rv)
208  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
209 
210  /* Zero the thread */
211  rContext->pthThread = 0;
212 
213  Log1(PCSC_LOG_INFO, "Thread stomped.");
214 
215  return;
216 }
217 
218 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
219 {
220  LONG rv;
221  DWORD dwStatus = 0;
222 
223  rv = IFDStatusICC(rContext, &dwStatus);
224  if (rv != SCARD_S_SUCCESS)
225  {
226  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
227  rContext->readerState->readerName);
228  return SCARD_F_UNKNOWN_ERROR;
229  }
230 
231  rv = ThreadCreate(&rContext->pthThread, 0,
232  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
233  if (rv)
234  {
235  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
236  return SCARD_E_NO_MEMORY;
237  }
238  else
239  return SCARD_S_SUCCESS;
240 }
241 
242 static void * EHStatusHandlerThread(READER_CONTEXT * rContext)
243 {
244  LONG rv;
245 #ifndef NO_LOG
246  const char *readerName;
247 #endif
248  DWORD dwStatus;
249  uint32_t readerState;
250  int32_t readerSharing;
251  DWORD dwCurrentState;
252 #ifndef DISABLE_AUTO_POWER_ON
253  DWORD dwAtrLen;
254 #endif
255 
256  /*
257  * Zero out everything
258  */
259  dwStatus = 0;
260 
261 #ifndef NO_LOG
262  readerName = rContext->readerState->readerName;
263 #endif
264 
265  rv = IFDStatusICC(rContext, &dwStatus);
266 
267  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
268  {
269 #ifdef DISABLE_AUTO_POWER_ON
270  rContext->readerState->cardAtrLength = 0;
272  readerState = SCARD_PRESENT;
273  Log1(PCSC_LOG_INFO, "Skip card power on");
274 #else
275  dwAtrLen = sizeof(rContext->readerState->cardAtr);
276  rv = IFDPowerICC(rContext, IFD_POWER_UP,
277  rContext->readerState->cardAtr, &dwAtrLen);
278  rContext->readerState->cardAtrLength = dwAtrLen;
279 
280  /* the protocol is unset after a power on */
282 
283  if (rv == IFD_SUCCESS)
284  {
285  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
286  RFSetPowerState(rContext, POWER_STATE_POWERED);
287  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
288 
289  if (rContext->readerState->cardAtrLength > 0)
290  {
291  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
292  rContext->readerState->cardAtr,
293  rContext->readerState->cardAtrLength);
294  }
295  else
296  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
297  }
298  else
299  {
300  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
301  RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
302  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
303  Log2(PCSC_LOG_ERROR, "Error powering up card: %s", rv2text(rv));
304  }
305 #endif
306 
307  dwCurrentState = SCARD_PRESENT;
308  }
309  else
310  {
311  readerState = SCARD_ABSENT;
312  rContext->readerState->cardAtrLength = 0;
314 
315  dwCurrentState = SCARD_ABSENT;
316  }
317 
318  /*
319  * Set all the public attributes to this reader
320  */
321  rContext->readerState->readerState = readerState;
322  rContext->readerState->readerSharing = readerSharing = rContext->contexts;
323 
325 
326  while (1)
327  {
328  dwStatus = 0;
329 
330  rv = IFDStatusICC(rContext, &dwStatus);
331 
332  if (rv != SCARD_S_SUCCESS)
333  {
334  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
335 
336  /*
337  * Set error status on this reader while errors occur
338  */
340  rContext->readerState->cardAtrLength = 0;
342 
343  dwCurrentState = SCARD_UNKNOWN;
344 
346  }
347 
348  if (dwStatus & SCARD_ABSENT)
349  {
350  if (dwCurrentState == SCARD_PRESENT ||
351  dwCurrentState == SCARD_UNKNOWN)
352  {
353  /*
354  * Change the status structure
355  */
356  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
357  /*
358  * Notify the card has been removed
359  */
360  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
361 
362  rContext->readerState->cardAtrLength = 0;
364  rContext->readerState->readerState = SCARD_ABSENT;
365  dwCurrentState = SCARD_ABSENT;
366 
367  rContext->readerState->eventCounter++;
368  if (rContext->readerState->eventCounter > 0xFFFF)
369  rContext->readerState->eventCounter = 0;
370 
372  }
373 
374  }
375  else if (dwStatus & SCARD_PRESENT)
376  {
377  if (dwCurrentState == SCARD_ABSENT ||
378  dwCurrentState == SCARD_UNKNOWN)
379  {
380 #ifdef DISABLE_AUTO_POWER_ON
381  rContext->readerState->cardAtrLength = 0;
384  RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
385  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
386  rv = IFD_SUCCESS;
387  Log1(PCSC_LOG_INFO, "Skip card power on");
388 #else
389  /*
390  * Power and reset the card
391  */
392  dwAtrLen = sizeof(rContext->readerState->cardAtr);
393  rv = IFDPowerICC(rContext, IFD_POWER_UP,
394  rContext->readerState->cardAtr, &dwAtrLen);
395  rContext->readerState->cardAtrLength = dwAtrLen;
396 
397  /* the protocol is unset after a power on */
399 
400  if (rv == IFD_SUCCESS)
401  {
403  RFSetPowerState(rContext, POWER_STATE_POWERED);
404  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
405  }
406  else
407  {
409  RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
410  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
411  rContext->readerState->cardAtrLength = 0;
412  }
413 #endif
414 
415  dwCurrentState = SCARD_PRESENT;
416 
417  rContext->readerState->eventCounter++;
418  if (rContext->readerState->eventCounter > 0xFFFF)
419  rContext->readerState->eventCounter = 0;
420 
421  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
422 
424 
425  if (rv == IFD_SUCCESS)
426  {
427  if (rContext->readerState->cardAtrLength > 0)
428  {
429  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
430  rContext->readerState->cardAtr,
431  rContext->readerState->cardAtrLength);
432  }
433  else
434  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
435  }
436  else
437  Log1(PCSC_LOG_ERROR,"Error powering up card.");
438  }
439  }
440 
441  /*
442  * Sharing may change w/o an event pass it on
443  */
444  if (readerSharing != rContext->contexts)
445  {
446  readerSharing = rContext->contexts;
447  rContext->readerState->readerSharing = readerSharing;
449  }
450 
451  if (rContext->pthCardEvent)
452  {
453  int ret;
454  int timeout;
455 
456 #ifndef DISABLE_ON_DEMAND_POWER_ON
457  if (POWER_STATE_POWERED == RFGetPowerState(rContext))
458  /* The card is powered but not yet used */
459  timeout = PCSCLITE_POWER_OFF_GRACE_PERIOD;
460  else
461  /* The card is already in use or not used at all */
462 #endif
463  timeout = PCSCLITE_STATUS_EVENT_TIMEOUT;
464 
465  ret = rContext->pthCardEvent(rContext->slot, timeout);
466  if (IFD_SUCCESS != ret)
467  (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
468  }
469  else
470  (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
471 
472 #ifndef DISABLE_ON_DEMAND_POWER_ON
473  /* the card is powered but not used */
474  (void)pthread_mutex_lock(&rContext->powerState_lock);
475  if (POWER_STATE_POWERED == rContext->powerState)
476  {
477  /* power down */
478  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
479  rContext->powerState = POWER_STATE_UNPOWERED;
480  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
481 
482  /* the protocol is unset after a power down */
484  }
485 
486  /* the card was in use */
487  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
488  {
489  /* the next state should be UNPOWERED unless the
490  * card is used again */
491  rContext->powerState = POWER_STATE_POWERED;
492  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
493  }
494  (void)pthread_mutex_unlock(&rContext->powerState_lock);
495 #endif
496 
497  if (rContext->hLockId == 0xFFFF)
498  {
499  /*
500  * Exit and notify the caller
501  */
502  Log1(PCSC_LOG_INFO, "Die");
503  rContext->hLockId = 0;
504  (void)pthread_exit(NULL);
505  }
506  }
507 }
508 
EHUnregisterClientForEvent
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:103
pubReaderStatesList::readerState
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:56
IFDStatusICC
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc.
Definition: ifdwrapper.c:339
TAG_IFD_POLLING_THREAD_KILLABLE
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:328
SCARD_POWERED
#define SCARD_POWERED
Card is powered.
Definition: pcsclite.h:262
pubReaderStatesList::cardProtocol
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:61
debuglog.h
This handles debugging.
ReaderContext::slot
int slot
Current Reader Slot.
Definition: readerfactory.h:125
pubReaderStatesList::readerName
char readerName[MAX_READERNAME]
reader name
Definition: eventhandler.h:54
dyn_generic.h
This abstracts dynamic library loading functions.
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
pubReaderStatesList::eventCounter
uint32_t eventCounter
number of card events
Definition: eventhandler.h:55
SCARD_PROTOCOL_UNDEFINED
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:240
SYS_USleep
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:80
SCARD_ABSENT
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:259
IFDGetCapabilities
RESPONSECODE IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Gets capabilities in the reader.
Definition: ifdwrapper.c:240
sys_generic.h
This handles abstract system level calls.
SCARD_UNKNOWN
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:258
readerfactory.h
This keeps track of a list of currently available reader structures.
eventhandler.h
This handles card insertion/removal events, updates ATR, protocol, and status information.
winscard_svc.h
This demarshalls functions over the message queue and keeps track of clients and their handles.
prothandler.h
This handles protocol defaults, PTS, etc.
ReaderContext::readerState
struct pubReaderStatesList * readerState
link to the reader state
Definition: readerfactory.h:135
EHSignalEventToClients
void EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
Definition: eventhandler.c:116
ReaderContext::powerState_lock
pthread_mutex_t powerState_lock
powerState mutex
Definition: readerfactory.h:132
list_t
list object
Definition: simclist.h:181
ReaderContext::contexts
_Atomic int32_t contexts
Number of open contexts.
Definition: readerfactory.h:128
SCARD_SWALLOWED
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:261
ReaderContext
Definition: readerfactory.h:107
ReaderContext::powerState
int powerState
auto power off state
Definition: readerfactory.h:131
ClientsWaitingForEvent
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:61
IFD_SUCCESS
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:351
ClientsWaitingForEvent_lock
pthread_mutex_t ClientsWaitingForEvent_lock
lock for the above list
Definition: eventhandler.c:62
TAG_IFD_STOP_POLLING_THREAD
#define TAG_IFD_STOP_POLLING_THREAD
method used to stop the polling thread (instead of just pthread_kill())
Definition: ifdhandler.h:329
IFDPowerICC
RESPONSECODE IFDPowerICC(READER_CONTEXT *rContext, DWORD dwAction, PUCHAR pucAtr, PDWORD pdwAtrLen)
Power up/down or reset's an ICC located in the IFD.
Definition: ifdwrapper.c:270
IFD_POWER_UP
#define IFD_POWER_UP
power up the card
Definition: ifdhandler.h:343
SCARD_E_NO_MEMORY
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
IFD_POWER_DOWN
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:344
ReaderContext::pthCardEvent
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
Definition: readerfactory.h:111
SCARD_NEGOTIABLE
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition: pcsclite.h:263
SCARD_F_UNKNOWN_ERROR
#define SCARD_F_UNKNOWN_ERROR
An internal error has been detected, but the source is unknown.
Definition: pcsclite.h:147
pubReaderStatesList::cardAtr
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:59
pubReaderStatesList::readerSharing
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:57
ifdwrapper.h
This wraps the dynamic ifdhandler functions.
RFGetPowerState
int RFGetPowerState(READER_CONTEXT *rContext)
Wait until all connected readers have a chance to power up a possibly inserted card.
Definition: readerfactory.c:1582
pubReaderStatesList::cardAtrLength
_Atomic uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:60
SCARD_PRESENT
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:260
ReaderContext::pthThread
pthread_t pthThread
Event polling thread.
Definition: readerfactory.h:110
SCARD_F_INTERNAL_ERROR
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
EHTryToUnregisterClientForEvent
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregister a client If no client is found then do not log an error.
Definition: eventhandler.c:83
ReaderContext::hLockId
_Atomic SCARDHANDLE hLockId
Lock Id.
Definition: readerfactory.h:126