pcsc-lite  1.8.13
eventhandler.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
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  * $Id: eventhandler.c 7004 2014-10-02 09:26:36Z rousseau $
33  */
34 
41 #include "config.h"
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <pthread.h>
49 
50 #include "misc.h"
51 #include "pcscd.h"
52 #include "debuglog.h"
53 #include "readerfactory.h"
54 #include "eventhandler.h"
55 #include "dyn_generic.h"
56 #include "sys_generic.h"
57 #include "ifdwrapper.h"
58 #include "prothandler.h"
59 #include "strlcpycat.h"
60 #include "utils.h"
61 #include "winscard_svc.h"
62 #include "simclist.h"
63 
65 pthread_mutex_t ClientsWaitingForEvent_lock;
67 static void EHStatusHandlerThread(READER_CONTEXT *);
68 
69 LONG EHRegisterClientForEvent(int32_t filedes)
70 {
71  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
72 
73  (void)list_append(&ClientsWaitingForEvent, &filedes);
74 
75  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
76 
77  return SCARD_S_SUCCESS;
78 } /* EHRegisterClientForEvent */
79 
84 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
85 {
86  LONG rv = SCARD_S_SUCCESS;
87  int ret;
88 
89  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
90 
91  ret = list_delete(&ClientsWaitingForEvent, &filedes);
92 
93  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
94 
95  if (ret < 0)
97 
98  return rv;
99 } /* EHTryToUnregisterClientForEvent */
100 
104 LONG EHUnregisterClientForEvent(int32_t filedes)
105 {
106  LONG rv = EHTryToUnregisterClientForEvent(filedes);
107 
108  if (rv < 0)
109  Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
110 
111  return rv;
112 } /* EHUnregisterClientForEvent */
113 
118 {
119  LONG rv = SCARD_S_SUCCESS;
120  int32_t filedes;
121 
122  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
123 
124  (void)list_iterator_start(&ClientsWaitingForEvent);
125  while (list_iterator_hasnext(&ClientsWaitingForEvent))
126  {
127  filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
128  rv = MSGSignalClient(filedes, SCARD_S_SUCCESS);
129  }
130  (void)list_iterator_stop(&ClientsWaitingForEvent);
131 
132  (void)list_clear(&ClientsWaitingForEvent);
133 
134  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
135 
136  return rv;
137 } /* EHSignalEventToClients */
138 
139 LONG EHInitializeEventStructures(void)
140 {
141  (void)list_init(&ClientsWaitingForEvent);
142 
143  /* request to store copies, and provide the metric function */
144  (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
145 
146  /* setting the comparator, so the list can sort, find the min, max etc */
147  (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
148 
149  (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
150 
151  return SCARD_S_SUCCESS;
152 }
153 
154 LONG EHDeinitializeEventStructures(void)
155 {
156  list_destroy(&ClientsWaitingForEvent);
157  pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
158 
159  return SCARD_S_SUCCESS;
160 }
161 
162 LONG EHDestroyEventHandler(READER_CONTEXT * rContext)
163 {
164  int rv;
165  DWORD dwGetSize;
166  UCHAR ucGetData[1];
167 
168  if ('\0' == rContext->readerState->readerName[0])
169  {
170  Log1(PCSC_LOG_INFO, "Thread already stomped.");
171  return SCARD_S_SUCCESS;
172  }
173 
174  /*
175  * Set the thread to 0 to exit thread
176  */
177  rContext->hLockId = 0xFFFF;
178 
179  Log1(PCSC_LOG_INFO, "Stomping thread.");
180 
181  /* kill the "polling" thread */
182  dwGetSize = sizeof(ucGetData);
184  &dwGetSize, ucGetData);
185 
186 #ifdef HAVE_PTHREAD_CANCEL
187  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
188  {
189  Log1(PCSC_LOG_INFO, "Killing polling thread");
190  (void)pthread_cancel(rContext->pthThread);
191  }
192  else
193 #endif
194  {
195  /* ask to stop the "polling" thread */
196  RESPONSECODE (*fct)(DWORD) = NULL;
197 
198  dwGetSize = sizeof(fct);
200  &dwGetSize, (PUCHAR)&fct);
201 
202  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
203  {
204  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
205  fct(rContext->slot);
206  }
207  else
208  Log1(PCSC_LOG_INFO, "Waiting polling thread");
209  }
210 
211  /* wait for the thread to finish */
212  rv = pthread_join(rContext->pthThread, NULL);
213  if (rv)
214  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
215 
216  /* Zero the thread */
217  rContext->pthThread = 0;
218 
219  Log1(PCSC_LOG_INFO, "Thread stomped.");
220 
221  return SCARD_S_SUCCESS;
222 }
223 
224 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
225 {
226  LONG rv;
227  DWORD dwStatus = 0;
228 
229  rv = IFDStatusICC(rContext, &dwStatus);
230  if (rv != SCARD_S_SUCCESS)
231  {
232  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
233  rContext->readerState->readerName);
234  return SCARD_F_UNKNOWN_ERROR;
235  }
236 
237  rv = ThreadCreate(&rContext->pthThread, 0,
238  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
239  if (rv)
240  {
241  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
242  return SCARD_E_NO_MEMORY;
243  }
244  else
245  return SCARD_S_SUCCESS;
246 }
247 
248 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
249 {
250  LONG rv;
251  const char *readerName;
252  DWORD dwStatus;
253  uint32_t readerState;
254  int32_t readerSharing;
255  DWORD dwCurrentState;
256 #ifndef DISABLE_AUTO_POWER_ON
257  DWORD dwAtrLen;
258 #endif
259 
260  /*
261  * Zero out everything
262  */
263  dwStatus = 0;
264 
265  readerName = rContext->readerState->readerName;
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 
326  (void)EHSignalEventToClients();
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 
347  (void)EHSignalEventToClients();
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 
371  (void)EHSignalEventToClients();
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  rContext->powerState = 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  {
402  rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
403  rContext->powerState = POWER_STATE_POWERED;
404  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
405  }
406  else
407  {
408  rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
409  rContext->powerState = 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 
419  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
420 
421  (void)EHSignalEventToClients();
422 
423  if (rv == IFD_SUCCESS)
424  {
425  if (rContext->readerState->cardAtrLength > 0)
426  {
427  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
428  rContext->readerState->cardAtr,
429  rContext->readerState->cardAtrLength);
430  }
431  else
432  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
433  }
434  else
435  Log1(PCSC_LOG_ERROR,"Error powering up card.");
436  }
437  }
438 
439  /*
440  * Sharing may change w/o an event pass it on
441  */
442  if (readerSharing != rContext->contexts)
443  {
444  readerSharing = rContext->contexts;
445  rContext->readerState->readerSharing = readerSharing;
446  (void)EHSignalEventToClients();
447  }
448 
449  if (rContext->pthCardEvent)
450  {
451  int ret;
452  int timeout;
453 
454 #ifndef DISABLE_ON_DEMAND_POWER_ON
455  if (POWER_STATE_POWERED == rContext->powerState)
456  /* The card is powered but not yet used */
458  else
459  /* The card is already in use or not used at all */
460 #endif
462 
463  ret = rContext->pthCardEvent(rContext->slot, timeout);
464  if (IFD_SUCCESS != ret)
466  }
467  else
469 
470 #ifndef DISABLE_ON_DEMAND_POWER_ON
471  /* the card is powered but not used */
472  (void)pthread_mutex_lock(&rContext->powerState_lock);
473  if (POWER_STATE_POWERED == rContext->powerState)
474  {
475  /* power down */
476  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
477  rContext->powerState = POWER_STATE_UNPOWERED;
478  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
479 
480  /* the protocol is unset after a power down */
482  }
483 
484  /* the card was in use */
485  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
486  {
487  /* the next state should be UNPOWERED unless the
488  * card is used again */
489  rContext->powerState = POWER_STATE_POWERED;
490  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
491  }
492  (void)pthread_mutex_unlock(&rContext->powerState_lock);
493 #endif
494 
495  if (rContext->hLockId == 0xFFFF)
496  {
497  /*
498  * Exit and notify the caller
499  */
500  (void)EHSignalEventToClients();
501  Log1(PCSC_LOG_INFO, "Die");
502  rContext->hLockId = 0;
503  (void)pthread_exit(NULL);
504  }
505  }
506 }
507 
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:104
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc...
Definition: ifdwrapper.c:341
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:58
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:330
pthread_t pthThread
Event polling thread.
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
LONG IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Get's capabilities in the reader.
Definition: ifdwrapper.c:237
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:191
char readerName[MAX_READERNAME]
reader name
Definition: eventhandler.h:52
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:55
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:53
LONG EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
Definition: eventhandler.c:117
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:123
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:193
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:85
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition: pcsclite.h:196
prototypes of strlcpy()/strlcat() imported from OpenBSD
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:344
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:64
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:57
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
Definition: eventhandler.c:84
This handles card insertion/removal events, updates ATR, protocol, and status information.
powered
Definition: pcscd.h:71
pthread_mutex_t ClientsWaitingForEvent_lock
lock for the above list
Definition: eventhandler.c:65
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:194
int powerState
auto power off state
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:173
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:57
LONG 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:267
#define PCSCLITE_STATUS_EVENT_TIMEOUT
normal timeout for pthCardEvent driver function when no card or card in use
Definition: pcscd.h:81
#define SCARD_POWERED
Card is powered.
Definition: pcsclite.h:195
card was in use
Definition: pcscd.h:72
#define PCSCLITE_POWER_OFF_GRACE_PERIOD
time to wait before powering down an unused card
Definition: pcscd.h:77
This keeps a list of defines for pcsc-lite.
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:192
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:59
auto power off
Definition: pcscd.h:70
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:109
This keeps track of a list of currently available reader structures.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:54
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:103
#define IFD_POWER_UP
power up the card
Definition: ifdhandler.h:343
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:329
This handles debugging.
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:351
#define SCARD_REMOVED
Card was removed.
Definition: pcscd.h:47
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:104