pcsc-lite  1.8.10
eventhandler.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 2000-2002
5  * David Corcoran <corcoran@linuxnet.com>
6  * Copyright (C) 2002-2011
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9  * $Id: eventhandler.c 6711 2013-08-05 18:59:56Z rousseau $
10  */
11 
18 #include "config.h"
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <pthread.h>
26 
27 #include "misc.h"
28 #include "pcscd.h"
29 #include "debuglog.h"
30 #include "readerfactory.h"
31 #include "eventhandler.h"
32 #include "dyn_generic.h"
33 #include "sys_generic.h"
34 #include "ifdwrapper.h"
35 #include "prothandler.h"
36 #include "strlcpycat.h"
37 #include "utils.h"
38 #include "winscard_svc.h"
39 #include "simclist.h"
40 
42 pthread_mutex_t ClientsWaitingForEvent_lock;
44 static void EHStatusHandlerThread(READER_CONTEXT *);
45 
46 LONG EHRegisterClientForEvent(int32_t filedes)
47 {
48  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
49 
50  (void)list_append(&ClientsWaitingForEvent, &filedes);
51 
52  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
53 
54  return SCARD_S_SUCCESS;
55 } /* EHRegisterClientForEvent */
56 
61 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
62 {
63  LONG rv = SCARD_S_SUCCESS;
64  int ret;
65 
66  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
67 
68  ret = list_delete(&ClientsWaitingForEvent, &filedes);
69 
70  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
71 
72  if (ret < 0)
74 
75  return rv;
76 } /* EHTryToUnregisterClientForEvent */
77 
81 LONG EHUnregisterClientForEvent(int32_t filedes)
82 {
83  LONG rv = EHTryToUnregisterClientForEvent(filedes);
84 
85  if (rv < 0)
86  Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
87 
88  return rv;
89 } /* EHUnregisterClientForEvent */
90 
95 {
96  LONG rv = SCARD_S_SUCCESS;
97  int32_t filedes;
98 
99  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
100 
101  (void)list_iterator_start(&ClientsWaitingForEvent);
102  while (list_iterator_hasnext(&ClientsWaitingForEvent))
103  {
104  filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
105  rv = MSGSignalClient(filedes, SCARD_S_SUCCESS);
106  }
107  (void)list_iterator_stop(&ClientsWaitingForEvent);
108 
109  (void)list_clear(&ClientsWaitingForEvent);
110 
111  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
112 
113  return rv;
114 } /* EHSignalEventToClients */
115 
116 LONG EHInitializeEventStructures(void)
117 {
118  (void)list_init(&ClientsWaitingForEvent);
119 
120  /* request to store copies, and provide the metric function */
121  (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
122 
123  /* setting the comparator, so the list can sort, find the min, max etc */
124  (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
125 
126  (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
127 
128  return SCARD_S_SUCCESS;
129 }
130 
131 LONG EHDeinitializeEventStructures(void)
132 {
133  list_destroy(&ClientsWaitingForEvent);
134  pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
135 
136  return SCARD_S_SUCCESS;
137 }
138 
139 LONG EHDestroyEventHandler(READER_CONTEXT * rContext)
140 {
141  int rv;
142  DWORD dwGetSize;
143  UCHAR ucGetData[1];
144 
145  if ('\0' == rContext->readerState->readerName[0])
146  {
147  Log1(PCSC_LOG_INFO, "Thread already stomped.");
148  return SCARD_S_SUCCESS;
149  }
150 
151  /*
152  * Set the thread to 0 to exit thread
153  */
154  rContext->hLockId = 0xFFFF;
155 
156  Log1(PCSC_LOG_INFO, "Stomping thread.");
157 
158  /* kill the "polling" thread */
159  dwGetSize = sizeof(ucGetData);
161  &dwGetSize, ucGetData);
162 
163 #ifdef HAVE_PTHREAD_CANCEL
164  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
165  {
166  Log1(PCSC_LOG_INFO, "Killing polling thread");
167  (void)pthread_cancel(rContext->pthThread);
168  }
169  else
170 #endif
171  {
172  /* ask to stop the "polling" thread */
173  RESPONSECODE (*fct)(DWORD) = NULL;
174 
175  dwGetSize = sizeof(fct);
177  &dwGetSize, (PUCHAR)&fct);
178 
179  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
180  {
181  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
182  fct(rContext->slot);
183  }
184  else
185  Log1(PCSC_LOG_INFO, "Waiting polling thread");
186  }
187 
188  /* wait for the thread to finish */
189  rv = pthread_join(rContext->pthThread, NULL);
190  if (rv)
191  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
192 
193  /* Zero the thread */
194  rContext->pthThread = 0;
195 
196  Log1(PCSC_LOG_INFO, "Thread stomped.");
197 
198  return SCARD_S_SUCCESS;
199 }
200 
201 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
202 {
203  LONG rv;
204  DWORD dwStatus = 0;
205 
206  rv = IFDStatusICC(rContext, &dwStatus);
207  if (rv != SCARD_S_SUCCESS)
208  {
209  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
210  rContext->readerState->readerName);
211  return SCARD_F_UNKNOWN_ERROR;
212  }
213 
214  rv = ThreadCreate(&rContext->pthThread, 0,
215  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
216  if (rv)
217  {
218  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
219  return SCARD_E_NO_MEMORY;
220  }
221  else
222  return SCARD_S_SUCCESS;
223 }
224 
225 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
226 {
227  LONG rv;
228  const char *readerName;
229  DWORD dwStatus;
230  uint32_t readerState;
231  int32_t readerSharing;
232  DWORD dwCurrentState;
233 #ifndef DISABLE_AUTO_POWER_ON
234  DWORD dwAtrLen;
235 #endif
236 
237  /*
238  * Zero out everything
239  */
240  dwStatus = 0;
241 
242  readerName = rContext->readerState->readerName;
243 
244  rv = IFDStatusICC(rContext, &dwStatus);
245 
246  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
247  {
248 #ifdef DISABLE_AUTO_POWER_ON
249  rContext->readerState->cardAtrLength = 0;
251  readerState = SCARD_PRESENT;
252  Log1(PCSC_LOG_INFO, "Skip card power on");
253 #else
254  dwAtrLen = sizeof(rContext->readerState->cardAtr);
255  rv = IFDPowerICC(rContext, IFD_POWER_UP,
256  rContext->readerState->cardAtr, &dwAtrLen);
257  rContext->readerState->cardAtrLength = dwAtrLen;
258 
259  /* the protocol is unset after a power on */
261 
262  if (rv == IFD_SUCCESS)
263  {
264  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
265  rContext->powerState = POWER_STATE_POWERED;
266  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
267 
268  if (rContext->readerState->cardAtrLength > 0)
269  {
270  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
271  rContext->readerState->cardAtr,
272  rContext->readerState->cardAtrLength);
273  }
274  else
275  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
276  }
277  else
278  {
279  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
280  rContext->powerState = POWER_STATE_UNPOWERED;
281  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
282  Log3(PCSC_LOG_ERROR, "Error powering up card: %ld 0x%04lX", rv, rv);
283  }
284 #endif
285 
286  dwCurrentState = SCARD_PRESENT;
287  }
288  else
289  {
290  readerState = SCARD_ABSENT;
291  rContext->readerState->cardAtrLength = 0;
293 
294  dwCurrentState = SCARD_ABSENT;
295  }
296 
297  /*
298  * Set all the public attributes to this reader
299  */
300  rContext->readerState->readerState = readerState;
301  rContext->readerState->readerSharing = readerSharing = rContext->contexts;
302 
303  (void)EHSignalEventToClients();
304 
305  while (1)
306  {
307  dwStatus = 0;
308 
309  rv = IFDStatusICC(rContext, &dwStatus);
310 
311  if (rv != SCARD_S_SUCCESS)
312  {
313  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
314 
315  /*
316  * Set error status on this reader while errors occur
317  */
319  rContext->readerState->cardAtrLength = 0;
321 
322  dwCurrentState = SCARD_UNKNOWN;
323 
324  (void)EHSignalEventToClients();
325  }
326 
327  if (dwStatus & SCARD_ABSENT)
328  {
329  if (dwCurrentState == SCARD_PRESENT ||
330  dwCurrentState == SCARD_UNKNOWN)
331  {
332  /*
333  * Change the status structure
334  */
335  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
336  /*
337  * Notify the card has been removed
338  */
339  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
340 
341  rContext->readerState->cardAtrLength = 0;
343  rContext->readerState->readerState = SCARD_ABSENT;
344  dwCurrentState = SCARD_ABSENT;
345 
346  rContext->readerState->eventCounter++;
347 
348  (void)EHSignalEventToClients();
349  }
350 
351  }
352  else if (dwStatus & SCARD_PRESENT)
353  {
354  if (dwCurrentState == SCARD_ABSENT ||
355  dwCurrentState == SCARD_UNKNOWN)
356  {
357 #ifdef DISABLE_AUTO_POWER_ON
358  rContext->readerState->cardAtrLength = 0;
361  rContext->powerState = POWER_STATE_UNPOWERED;
362  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
363  rv = IFD_SUCCESS;
364  Log1(PCSC_LOG_INFO, "Skip card power on");
365 #else
366  /*
367  * Power and reset the card
368  */
369  dwAtrLen = sizeof(rContext->readerState->cardAtr);
370  rv = IFDPowerICC(rContext, IFD_POWER_UP,
371  rContext->readerState->cardAtr, &dwAtrLen);
372  rContext->readerState->cardAtrLength = dwAtrLen;
373 
374  /* the protocol is unset after a power on */
376 
377  if (rv == IFD_SUCCESS)
378  {
379  rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
380  rContext->powerState = POWER_STATE_POWERED;
381  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
382  }
383  else
384  {
385  rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
386  rContext->powerState = POWER_STATE_UNPOWERED;
387  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
388  rContext->readerState->cardAtrLength = 0;
389  }
390 #endif
391 
392  dwCurrentState = SCARD_PRESENT;
393 
394  rContext->readerState->eventCounter++;
395 
396  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
397 
398  (void)EHSignalEventToClients();
399 
400  if (rv == IFD_SUCCESS)
401  {
402  if (rContext->readerState->cardAtrLength > 0)
403  {
404  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
405  rContext->readerState->cardAtr,
406  rContext->readerState->cardAtrLength);
407  }
408  else
409  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
410  }
411  else
412  Log1(PCSC_LOG_ERROR,"Error powering up card.");
413  }
414  }
415 
416  /*
417  * Sharing may change w/o an event pass it on
418  */
419  if (readerSharing != rContext->contexts)
420  {
421  readerSharing = rContext->contexts;
422  rContext->readerState->readerSharing = readerSharing;
423  (void)EHSignalEventToClients();
424  }
425 
426  if (rContext->pthCardEvent)
427  {
428  int ret;
429  int timeout;
430 
431 #ifndef DISABLE_ON_DEMAND_POWER_ON
432  if (POWER_STATE_POWERED == rContext->powerState)
433  /* The card is powered but not yet used */
435  else
436  /* The card is already in use or not used at all */
437 #endif
439 
440  ret = rContext->pthCardEvent(rContext->slot, timeout);
441  if (IFD_SUCCESS != ret)
443  }
444  else
446 
447 #ifndef DISABLE_ON_DEMAND_POWER_ON
448  /* the card is powered but not used */
449  (void)pthread_mutex_lock(&rContext->powerState_lock);
450  if (POWER_STATE_POWERED == rContext->powerState)
451  {
452  /* power down */
453  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
454  rContext->powerState = POWER_STATE_UNPOWERED;
455  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
456 
457  /* the protocol is unset after a power down */
459  }
460 
461  /* the card was in use */
462  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
463  {
464  /* the next state should be UNPOWERED unless the
465  * card is used again */
466  rContext->powerState = POWER_STATE_POWERED;
467  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
468  }
469  (void)pthread_mutex_unlock(&rContext->powerState_lock);
470 #endif
471 
472  if (rContext->hLockId == 0xFFFF)
473  {
474  /*
475  * Exit and notify the caller
476  */
477  (void)EHSignalEventToClients();
478  Log1(PCSC_LOG_INFO, "Die");
479  rContext->hLockId = 0;
480  (void)pthread_exit(NULL);
481  }
482  }
483 }
484 
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:81
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc...
Definition: ifdwrapper.c:318
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:35
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:307
pthread_t pthThread
Event polling thread.
Definition: readerfactory.h:89
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
Definition: readerfactory.h:90
LONG IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Get&#39;s capabilities in the reader.
Definition: ifdwrapper.c:214
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:168
char readerName[MAX_READERNAME]
reader name
Definition: eventhandler.h:29
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:32
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:30
LONG EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
Definition: eventhandler.c:94
This wraps the dynamic ifdhandler functions.
This demarshalls functions over the message queue and keeps track of clients and their handles...
#define SCARD_F_UNKNOWN_ERROR
An internal error has been detected, but the source is unknown.
Definition: pcsclite.h:100
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:170
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:62
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition: pcsclite.h:173
prototypes of strlcpy()/strlcat() imported from OpenBSD
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:321
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:41
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:34
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
Definition: eventhandler.c:61
This handles card insertion/removal events, updates ATR, protocol, and status information.
powered
Definition: pcscd.h:48
pthread_mutex_t ClientsWaitingForEvent_lock
lock for the above list
Definition: eventhandler.c:42
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:171
int powerState
auto power off state
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:150
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:34
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:244
#define PCSCLITE_STATUS_EVENT_TIMEOUT
normal timeout for pthCardEvent driver function when no card or card in use
Definition: pcscd.h:58
#define SCARD_POWERED
Card is powered.
Definition: pcsclite.h:172
card was in use
Definition: pcscd.h:49
#define PCSCLITE_POWER_OFF_GRACE_PERIOD
time to wait before powering down an unused card
Definition: pcscd.h:54
This keeps a list of defines for pcsc-lite.
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:169
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:36
auto power off
Definition: pcscd.h:47
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:86
This keeps track of a list of currently available reader structures.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:31
pthread_mutex_t powerState_lock
powerState mutex
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:80
#define IFD_POWER_UP
power up the card
Definition: ifdhandler.h:320
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:306
This handles debugging.
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:328
#define SCARD_REMOVED
Card was removed.
Definition: pcscd.h:24
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:81