pcsc-lite  1.8.25
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-2011
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 < 0)
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 #ifdef HAVE_PTHREAD_CANCEL
183  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
184  {
185  Log1(PCSC_LOG_INFO, "Killing polling thread");
186  (void)pthread_cancel(rContext->pthThread);
187  }
188  else
189 #endif
190  {
191  /* ask to stop the "polling" thread */
192  RESPONSECODE (*fct)(DWORD) = NULL;
193 
194  dwGetSize = sizeof(fct);
196  &dwGetSize, (PUCHAR)&fct);
197 
198  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
199  {
200  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
201  fct(rContext->slot);
202  }
203  else
204  Log1(PCSC_LOG_INFO, "Waiting polling thread");
205  }
206 
207  /* wait for the thread to finish */
208  rv = pthread_join(rContext->pthThread, NULL);
209  if (rv)
210  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
211 
212  /* Zero the thread */
213  rContext->pthThread = 0;
214 
215  Log1(PCSC_LOG_INFO, "Thread stomped.");
216 
217  return;
218 }
219 
220 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
221 {
222  LONG rv;
223  DWORD dwStatus = 0;
224 
225  rv = IFDStatusICC(rContext, &dwStatus);
226  if (rv != SCARD_S_SUCCESS)
227  {
228  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
229  rContext->readerState->readerName);
230  return SCARD_F_UNKNOWN_ERROR;
231  }
232 
233  rv = ThreadCreate(&rContext->pthThread, 0,
234  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
235  if (rv)
236  {
237  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
238  return SCARD_E_NO_MEMORY;
239  }
240  else
241  return SCARD_S_SUCCESS;
242 }
243 
244 static void * EHStatusHandlerThread(READER_CONTEXT * rContext)
245 {
246  LONG rv;
247 #ifndef NO_LOG
248  const char *readerName;
249 #endif
250  DWORD dwStatus;
251  uint32_t readerState;
252  int32_t readerSharing;
253  DWORD dwCurrentState;
254 #ifndef DISABLE_AUTO_POWER_ON
255  DWORD dwAtrLen;
256 #endif
257 
258  /*
259  * Zero out everything
260  */
261  dwStatus = 0;
262 
263 #ifndef NO_LOG
264  readerName = rContext->readerState->readerName;
265 #endif
266 
267  rv = IFDStatusICC(rContext, &dwStatus);
268 
269  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
270  {
271 #ifdef DISABLE_AUTO_POWER_ON
272  rContext->readerState->cardAtrLength = 0;
274  readerState = SCARD_PRESENT;
275  Log1(PCSC_LOG_INFO, "Skip card power on");
276 #else
277  dwAtrLen = sizeof(rContext->readerState->cardAtr);
278  rv = IFDPowerICC(rContext, IFD_POWER_UP,
279  rContext->readerState->cardAtr, &dwAtrLen);
280  rContext->readerState->cardAtrLength = dwAtrLen;
281 
282  /* the protocol is unset after a power on */
284 
285  if (rv == IFD_SUCCESS)
286  {
287  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
288  rContext->powerState = POWER_STATE_POWERED;
289  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
290 
291  if (rContext->readerState->cardAtrLength > 0)
292  {
293  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
294  rContext->readerState->cardAtr,
295  rContext->readerState->cardAtrLength);
296  }
297  else
298  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
299  }
300  else
301  {
302  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
303  rContext->powerState = POWER_STATE_UNPOWERED;
304  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
305  Log3(PCSC_LOG_ERROR, "Error powering up card: %ld 0x%04lX", rv, rv);
306  }
307 #endif
308 
309  dwCurrentState = SCARD_PRESENT;
310  }
311  else
312  {
313  readerState = SCARD_ABSENT;
314  rContext->readerState->cardAtrLength = 0;
316 
317  dwCurrentState = SCARD_ABSENT;
318  }
319 
320  /*
321  * Set all the public attributes to this reader
322  */
323  rContext->readerState->readerState = readerState;
324  rContext->readerState->readerSharing = readerSharing = rContext->contexts;
325 
327 
328  while (1)
329  {
330  dwStatus = 0;
331 
332  rv = IFDStatusICC(rContext, &dwStatus);
333 
334  if (rv != SCARD_S_SUCCESS)
335  {
336  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
337 
338  /*
339  * Set error status on this reader while errors occur
340  */
342  rContext->readerState->cardAtrLength = 0;
344 
345  dwCurrentState = SCARD_UNKNOWN;
346 
348  }
349 
350  if (dwStatus & SCARD_ABSENT)
351  {
352  if (dwCurrentState == SCARD_PRESENT ||
353  dwCurrentState == SCARD_UNKNOWN)
354  {
355  /*
356  * Change the status structure
357  */
358  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
359  /*
360  * Notify the card has been removed
361  */
362  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
363 
364  rContext->readerState->cardAtrLength = 0;
366  rContext->readerState->readerState = SCARD_ABSENT;
367  dwCurrentState = SCARD_ABSENT;
368 
369  rContext->readerState->eventCounter++;
370  if (rContext->readerState->eventCounter > 0xFFFF)
371  rContext->readerState->eventCounter = 0;
372 
374  }
375 
376  }
377  else if (dwStatus & SCARD_PRESENT)
378  {
379  if (dwCurrentState == SCARD_ABSENT ||
380  dwCurrentState == SCARD_UNKNOWN)
381  {
382 #ifdef DISABLE_AUTO_POWER_ON
383  rContext->readerState->cardAtrLength = 0;
386  rContext->powerState = POWER_STATE_UNPOWERED;
387  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
388  rv = IFD_SUCCESS;
389  Log1(PCSC_LOG_INFO, "Skip card power on");
390 #else
391  /*
392  * Power and reset the card
393  */
394  dwAtrLen = sizeof(rContext->readerState->cardAtr);
395  rv = IFDPowerICC(rContext, IFD_POWER_UP,
396  rContext->readerState->cardAtr, &dwAtrLen);
397  rContext->readerState->cardAtrLength = dwAtrLen;
398 
399  /* the protocol is unset after a power on */
401 
402  if (rv == IFD_SUCCESS)
403  {
405  rContext->powerState = POWER_STATE_POWERED;
406  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
407  }
408  else
409  {
411  rContext->powerState = POWER_STATE_UNPOWERED;
412  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
413  rContext->readerState->cardAtrLength = 0;
414  }
415 #endif
416 
417  dwCurrentState = SCARD_PRESENT;
418 
419  rContext->readerState->eventCounter++;
420  if (rContext->readerState->eventCounter > 0xFFFF)
421  rContext->readerState->eventCounter = 0;
422 
423  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
424 
426 
427  if (rv == IFD_SUCCESS)
428  {
429  if (rContext->readerState->cardAtrLength > 0)
430  {
431  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
432  rContext->readerState->cardAtr,
433  rContext->readerState->cardAtrLength);
434  }
435  else
436  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
437  }
438  else
439  Log1(PCSC_LOG_ERROR,"Error powering up card.");
440  }
441  }
442 
443  /*
444  * Sharing may change w/o an event pass it on
445  */
446  if (readerSharing != rContext->contexts)
447  {
448  readerSharing = rContext->contexts;
449  rContext->readerState->readerSharing = readerSharing;
451  }
452 
453  if (rContext->pthCardEvent)
454  {
455  int ret;
456  int timeout;
457 
458 #ifndef DISABLE_ON_DEMAND_POWER_ON
459  if (POWER_STATE_POWERED == rContext->powerState)
460  /* The card is powered but not yet used */
462  else
463  /* The card is already in use or not used at all */
464 #endif
466 
467  ret = rContext->pthCardEvent(rContext->slot, timeout);
468  if (IFD_SUCCESS != ret)
470  }
471  else
473 
474 #ifndef DISABLE_ON_DEMAND_POWER_ON
475  /* the card is powered but not used */
476  (void)pthread_mutex_lock(&rContext->powerState_lock);
477  if (POWER_STATE_POWERED == rContext->powerState)
478  {
479  /* power down */
480  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
481  rContext->powerState = POWER_STATE_UNPOWERED;
482  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
483 
484  /* the protocol is unset after a power down */
486  }
487 
488  /* the card was in use */
489  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
490  {
491  /* the next state should be UNPOWERED unless the
492  * card is used again */
493  rContext->powerState = POWER_STATE_POWERED;
494  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
495  }
496  (void)pthread_mutex_unlock(&rContext->powerState_lock);
497 #endif
498 
499  if (rContext->hLockId == 0xFFFF)
500  {
501  /*
502  * Exit and notify the caller
503  */
504  Log1(PCSC_LOG_INFO, "Die");
505  rContext->hLockId = 0;
506  (void)pthread_exit(NULL);
507  }
508  }
509 }
510 
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:103
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc...
Definition: ifdwrapper.c:334
This abstracts dynamic library loading functions.
struct pubReaderStatesList * readerState
link to the reader state
list object
Definition: simclist.h:181
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:56
int32_t contexts
Number of open contexts.
volatile SCARDHANDLE hLockId
Lock Id.
#define TAG_IFD_STOP_POLLING_THREAD
method used to stop the polling thread (instead of just pthread_kill())
Definition: ifdhandler.h:329
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
void EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
Definition: eventhandler.c:116
pthread_t pthThread
Event polling thread.
LONG IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Get&#39;s capabilities in the reader.
Definition: ifdwrapper.c:235
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
char readerName[MAX_READERNAME]
reader name
Definition: eventhandler.h:50
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:53
This handles protocol defaults, PTS, etc.
This handles abstract system level calls.
int slot
Current Reader Slot.
uint32_t eventCounter
number of card events
Definition: eventhandler.h:51
This wraps the dynamic ifdhandler functions.
This demarshalls functions over the message queue and keeps track of clients and their handles...
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition: pcsclite.h:262
#define SCARD_F_UNKNOWN_ERROR
An internal error has been detected, but the source is unknown.
Definition: pcsclite.h:147
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:343
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:61
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
Definition: eventhandler.c:83
This handles card insertion/removal events, updates ATR, protocol, and status information.
powered
Definition: pcscd.h:67
pthread_mutex_t ClientsWaitingForEvent_lock
lock for the above list
Definition: eventhandler.c:62
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
int powerState
auto power off state
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:239
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:55
LONG IFDPowerICC(READER_CONTEXT *rContext, DWORD dwAction, PUCHAR pucAtr, PDWORD pdwAtrLen)
Power up/down or reset&#39;s an ICC located in the IFD.
Definition: ifdwrapper.c:265
#define PCSCLITE_STATUS_EVENT_TIMEOUT
normal timeout for pthCardEvent driver function when no card or card in use
Definition: pcscd.h:77
#define SCARD_POWERED
Card is powered.
Definition: pcsclite.h:261
card was in use
Definition: pcscd.h:68
#define PCSCLITE_POWER_OFF_GRACE_PERIOD
time to wait before powering down an unused card
Definition: pcscd.h:73
This keeps a list of defines for pcsc-lite.
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:258
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:57
auto power off
Definition: pcscd.h:66
This keeps track of a list of currently available reader structures.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:52
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
pthread_mutex_t powerState_lock
powerState mutex
#define IFD_POWER_UP
power up the card
Definition: ifdhandler.h:342
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:328
This handles debugging.
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:350
#define SCARD_REMOVED
Card was removed.
Definition: pcscd.h:43