pcsc-lite  1.8.8
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 6391 2012-07-26 18:44:54Z 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 EHDestroyEventHandler(READER_CONTEXT * rContext)
132 {
133  int rv;
134  DWORD dwGetSize;
135  UCHAR ucGetData[1];
136 
137  if ('\0' == rContext->readerState->readerName[0])
138  {
139  Log1(PCSC_LOG_INFO, "Thread already stomped.");
140  return SCARD_S_SUCCESS;
141  }
142 
143  /*
144  * Set the thread to 0 to exit thread
145  */
146  rContext->hLockId = 0xFFFF;
147 
148  Log1(PCSC_LOG_INFO, "Stomping thread.");
149 
150  /* kill the "polling" thread */
151  dwGetSize = sizeof(ucGetData);
153  &dwGetSize, ucGetData);
154 
155 #ifdef HAVE_PTHREAD_CANCEL
156  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
157  {
158  Log1(PCSC_LOG_INFO, "Killing polling thread");
159  (void)pthread_cancel(rContext->pthThread);
160  }
161  else
162 #endif
163  {
164  /* ask to stop the "polling" thread */
165  RESPONSECODE (*fct)(DWORD) = NULL;
166 
167  dwGetSize = sizeof(fct);
169  &dwGetSize, (PUCHAR)&fct);
170 
171  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
172  {
173  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
174  fct(rContext->slot);
175  }
176  else
177  Log1(PCSC_LOG_INFO, "Waiting polling thread");
178  }
179 
180  /* wait for the thread to finish */
181  rv = pthread_join(rContext->pthThread, NULL);
182  if (rv)
183  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
184 
185  /* Zero the thread */
186  rContext->pthThread = 0;
187 
188  Log1(PCSC_LOG_INFO, "Thread stomped.");
189 
190  return SCARD_S_SUCCESS;
191 }
192 
193 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
194 {
195  LONG rv;
196  DWORD dwStatus = 0;
197 
198  rv = IFDStatusICC(rContext, &dwStatus);
199  if (rv != SCARD_S_SUCCESS)
200  {
201  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
202  rContext->readerState->readerName);
203  return SCARD_F_UNKNOWN_ERROR;
204  }
205 
206  rv = ThreadCreate(&rContext->pthThread, 0,
207  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
208  if (rv)
209  {
210  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
211  return SCARD_E_NO_MEMORY;
212  }
213  else
214  return SCARD_S_SUCCESS;
215 }
216 
217 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
218 {
219  LONG rv;
220  const char *readerName;
221  DWORD dwStatus;
222  uint32_t readerState;
223  int32_t readerSharing;
224  DWORD dwCurrentState;
225  DWORD dwAtrLen;
226 
227  /*
228  * Zero out everything
229  */
230  dwStatus = 0;
231 
232  readerName = rContext->readerState->readerName;
233 
234  rv = IFDStatusICC(rContext, &dwStatus);
235 
236  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
237  {
238 #ifdef DISABLE_AUTO_POWER_ON
239  rContext->readerState->cardAtrLength = 0;
241  readerState = SCARD_PRESENT;
242  Log1(PCSC_LOG_INFO, "Skip card power on");
243 #else
244  dwAtrLen = sizeof(rContext->readerState->cardAtr);
245  rv = IFDPowerICC(rContext, IFD_POWER_UP,
246  rContext->readerState->cardAtr, &dwAtrLen);
247  rContext->readerState->cardAtrLength = dwAtrLen;
248 
249  /* the protocol is unset after a power on */
251 
252  if (rv == IFD_SUCCESS)
253  {
254  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
255  rContext->powerState = POWER_STATE_POWERED;
256  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
257 
258  if (rContext->readerState->cardAtrLength > 0)
259  {
260  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
261  rContext->readerState->cardAtr,
262  rContext->readerState->cardAtrLength);
263  }
264  else
265  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
266  }
267  else
268  {
269  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
270  rContext->powerState = POWER_STATE_UNPOWERED;
271  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
272  Log3(PCSC_LOG_ERROR, "Error powering up card: %ld 0x%04lX", rv, rv);
273  }
274 #endif
275 
276  dwCurrentState = SCARD_PRESENT;
277  }
278  else
279  {
280  readerState = SCARD_ABSENT;
281  rContext->readerState->cardAtrLength = 0;
283 
284  dwCurrentState = SCARD_ABSENT;
285  }
286 
287  /*
288  * Set all the public attributes to this reader
289  */
290  rContext->readerState->readerState = readerState;
291  rContext->readerState->readerSharing = readerSharing = rContext->contexts;
292 
293  (void)EHSignalEventToClients();
294 
295  while (1)
296  {
297  dwStatus = 0;
298 
299  rv = IFDStatusICC(rContext, &dwStatus);
300 
301  if (rv != SCARD_S_SUCCESS)
302  {
303  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
304 
305  /*
306  * Set error status on this reader while errors occur
307  */
309  rContext->readerState->cardAtrLength = 0;
311 
312  dwCurrentState = SCARD_UNKNOWN;
313 
314  (void)EHSignalEventToClients();
315  }
316 
317  if (dwStatus & SCARD_ABSENT)
318  {
319  if (dwCurrentState == SCARD_PRESENT ||
320  dwCurrentState == SCARD_UNKNOWN)
321  {
322  /*
323  * Change the status structure
324  */
325  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
326  /*
327  * Notify the card has been removed
328  */
329  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
330 
331  rContext->readerState->cardAtrLength = 0;
333  rContext->readerState->readerState = SCARD_ABSENT;
334  dwCurrentState = SCARD_ABSENT;
335 
336  rContext->readerState->eventCounter++;
337 
338  (void)EHSignalEventToClients();
339  }
340 
341  }
342  else if (dwStatus & SCARD_PRESENT)
343  {
344  if (dwCurrentState == SCARD_ABSENT ||
345  dwCurrentState == SCARD_UNKNOWN)
346  {
347 #ifdef DISABLE_AUTO_POWER_ON
348  rContext->readerState->cardAtrLength = 0;
351  rContext->powerState = POWER_STATE_UNPOWERED;
352  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
353  readerState = SCARD_PRESENT;
354  rv = IFD_SUCCESS;
355  Log1(PCSC_LOG_INFO, "Skip card power on");
356 #else
357  /*
358  * Power and reset the card
359  */
360  dwAtrLen = sizeof(rContext->readerState->cardAtr);
361  rv = IFDPowerICC(rContext, IFD_POWER_UP,
362  rContext->readerState->cardAtr, &dwAtrLen);
363  rContext->readerState->cardAtrLength = dwAtrLen;
364 
365  /* the protocol is unset after a power on */
367 
368  if (rv == IFD_SUCCESS)
369  {
370  rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
371  rContext->powerState = POWER_STATE_POWERED;
372  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
373  }
374  else
375  {
376  rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
377  rContext->powerState = POWER_STATE_UNPOWERED;
378  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
379  rContext->readerState->cardAtrLength = 0;
380  }
381 #endif
382 
383  dwCurrentState = SCARD_PRESENT;
384 
385  rContext->readerState->eventCounter++;
386 
387  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
388 
389  (void)EHSignalEventToClients();
390 
391  if (rv == IFD_SUCCESS)
392  {
393  if (rContext->readerState->cardAtrLength > 0)
394  {
395  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
396  rContext->readerState->cardAtr,
397  rContext->readerState->cardAtrLength);
398  }
399  else
400  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
401  }
402  else
403  Log1(PCSC_LOG_ERROR,"Error powering up card.");
404  }
405  }
406 
407  /*
408  * Sharing may change w/o an event pass it on
409  */
410  if (readerSharing != rContext->contexts)
411  {
412  readerSharing = rContext->contexts;
413  rContext->readerState->readerSharing = readerSharing;
414  (void)EHSignalEventToClients();
415  }
416 
417  if (rContext->pthCardEvent)
418  {
419  int ret;
420  int timeout;
421 
422 #ifndef DISABLE_ON_DEMAND_POWER_ON
423  if (POWER_STATE_POWERED == rContext->powerState)
424  /* The card is powered but not yet used */
426  else
427  /* The card is already in use or not used at all */
428 #endif
430 
431  ret = rContext->pthCardEvent(rContext->slot, timeout);
432  if (IFD_SUCCESS != ret)
434  }
435  else
437 
438 #ifndef DISABLE_ON_DEMAND_POWER_ON
439  /* the card is powered but not used */
440  (void)pthread_mutex_lock(&rContext->powerState_lock);
441  if (POWER_STATE_POWERED == rContext->powerState)
442  {
443  /* power down */
444  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
445  rContext->powerState = POWER_STATE_UNPOWERED;
446  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
447 
448  /* the protocol is unset after a power down */
450  }
451 
452  /* the card was in use */
453  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
454  {
455  /* the next state should be UNPOWERED unless the
456  * card is used again */
457  rContext->powerState = POWER_STATE_POWERED;
458  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
459  }
460  (void)pthread_mutex_unlock(&rContext->powerState_lock);
461 #endif
462 
463  if (rContext->hLockId == 0xFFFF)
464  {
465  /*
466  * Exit and notify the caller
467  */
468  (void)EHSignalEventToClients();
469  Log1(PCSC_LOG_INFO, "Die");
470  rContext->hLockId = 0;
471  (void)pthread_exit(NULL);
472  }
473  }
474 }
475 
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