pcsc-lite  1.8.11
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 Changes to this license can be made only by the copyright author with
22 explicit written consent.
23 
24 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  * $Id: eventhandler.c 6851 2014-02-14 15:43:32Z rousseau $
36  */
37 
44 #include "config.h"
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <pthread.h>
52 
53 #include "misc.h"
54 #include "pcscd.h"
55 #include "debuglog.h"
56 #include "readerfactory.h"
57 #include "eventhandler.h"
58 #include "dyn_generic.h"
59 #include "sys_generic.h"
60 #include "ifdwrapper.h"
61 #include "prothandler.h"
62 #include "strlcpycat.h"
63 #include "utils.h"
64 #include "winscard_svc.h"
65 #include "simclist.h"
66 
68 pthread_mutex_t ClientsWaitingForEvent_lock;
70 static void EHStatusHandlerThread(READER_CONTEXT *);
71 
72 LONG EHRegisterClientForEvent(int32_t filedes)
73 {
74  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
75 
76  (void)list_append(&ClientsWaitingForEvent, &filedes);
77 
78  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
79 
80  return SCARD_S_SUCCESS;
81 } /* EHRegisterClientForEvent */
82 
87 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
88 {
89  LONG rv = SCARD_S_SUCCESS;
90  int ret;
91 
92  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
93 
94  ret = list_delete(&ClientsWaitingForEvent, &filedes);
95 
96  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
97 
98  if (ret < 0)
100 
101  return rv;
102 } /* EHTryToUnregisterClientForEvent */
103 
107 LONG EHUnregisterClientForEvent(int32_t filedes)
108 {
109  LONG rv = EHTryToUnregisterClientForEvent(filedes);
110 
111  if (rv < 0)
112  Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
113 
114  return rv;
115 } /* EHUnregisterClientForEvent */
116 
121 {
122  LONG rv = SCARD_S_SUCCESS;
123  int32_t filedes;
124 
125  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
126 
127  (void)list_iterator_start(&ClientsWaitingForEvent);
128  while (list_iterator_hasnext(&ClientsWaitingForEvent))
129  {
130  filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
131  rv = MSGSignalClient(filedes, SCARD_S_SUCCESS);
132  }
133  (void)list_iterator_stop(&ClientsWaitingForEvent);
134 
135  (void)list_clear(&ClientsWaitingForEvent);
136 
137  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
138 
139  return rv;
140 } /* EHSignalEventToClients */
141 
142 LONG EHInitializeEventStructures(void)
143 {
144  (void)list_init(&ClientsWaitingForEvent);
145 
146  /* request to store copies, and provide the metric function */
147  (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
148 
149  /* setting the comparator, so the list can sort, find the min, max etc */
150  (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
151 
152  (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
153 
154  return SCARD_S_SUCCESS;
155 }
156 
157 LONG EHDeinitializeEventStructures(void)
158 {
159  list_destroy(&ClientsWaitingForEvent);
160  pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
161 
162  return SCARD_S_SUCCESS;
163 }
164 
165 LONG EHDestroyEventHandler(READER_CONTEXT * rContext)
166 {
167  int rv;
168  DWORD dwGetSize;
169  UCHAR ucGetData[1];
170 
171  if ('\0' == rContext->readerState->readerName[0])
172  {
173  Log1(PCSC_LOG_INFO, "Thread already stomped.");
174  return SCARD_S_SUCCESS;
175  }
176 
177  /*
178  * Set the thread to 0 to exit thread
179  */
180  rContext->hLockId = 0xFFFF;
181 
182  Log1(PCSC_LOG_INFO, "Stomping thread.");
183 
184  /* kill the "polling" thread */
185  dwGetSize = sizeof(ucGetData);
187  &dwGetSize, ucGetData);
188 
189 #ifdef HAVE_PTHREAD_CANCEL
190  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
191  {
192  Log1(PCSC_LOG_INFO, "Killing polling thread");
193  (void)pthread_cancel(rContext->pthThread);
194  }
195  else
196 #endif
197  {
198  /* ask to stop the "polling" thread */
199  RESPONSECODE (*fct)(DWORD) = NULL;
200 
201  dwGetSize = sizeof(fct);
203  &dwGetSize, (PUCHAR)&fct);
204 
205  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
206  {
207  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
208  fct(rContext->slot);
209  }
210  else
211  Log1(PCSC_LOG_INFO, "Waiting polling thread");
212  }
213 
214  /* wait for the thread to finish */
215  rv = pthread_join(rContext->pthThread, NULL);
216  if (rv)
217  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
218 
219  /* Zero the thread */
220  rContext->pthThread = 0;
221 
222  Log1(PCSC_LOG_INFO, "Thread stomped.");
223 
224  return SCARD_S_SUCCESS;
225 }
226 
227 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
228 {
229  LONG rv;
230  DWORD dwStatus = 0;
231 
232  rv = IFDStatusICC(rContext, &dwStatus);
233  if (rv != SCARD_S_SUCCESS)
234  {
235  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
236  rContext->readerState->readerName);
237  return SCARD_F_UNKNOWN_ERROR;
238  }
239 
240  rv = ThreadCreate(&rContext->pthThread, 0,
241  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
242  if (rv)
243  {
244  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
245  return SCARD_E_NO_MEMORY;
246  }
247  else
248  return SCARD_S_SUCCESS;
249 }
250 
251 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
252 {
253  LONG rv;
254  const char *readerName;
255  DWORD dwStatus;
256  uint32_t readerState;
257  int32_t readerSharing;
258  DWORD dwCurrentState;
259 #ifndef DISABLE_AUTO_POWER_ON
260  DWORD dwAtrLen;
261 #endif
262 
263  /*
264  * Zero out everything
265  */
266  dwStatus = 0;
267 
268  readerName = rContext->readerState->readerName;
269 
270  rv = IFDStatusICC(rContext, &dwStatus);
271 
272  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
273  {
274 #ifdef DISABLE_AUTO_POWER_ON
275  rContext->readerState->cardAtrLength = 0;
277  readerState = SCARD_PRESENT;
278  Log1(PCSC_LOG_INFO, "Skip card power on");
279 #else
280  dwAtrLen = sizeof(rContext->readerState->cardAtr);
281  rv = IFDPowerICC(rContext, IFD_POWER_UP,
282  rContext->readerState->cardAtr, &dwAtrLen);
283  rContext->readerState->cardAtrLength = dwAtrLen;
284 
285  /* the protocol is unset after a power on */
287 
288  if (rv == IFD_SUCCESS)
289  {
290  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
291  rContext->powerState = POWER_STATE_POWERED;
292  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
293 
294  if (rContext->readerState->cardAtrLength > 0)
295  {
296  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
297  rContext->readerState->cardAtr,
298  rContext->readerState->cardAtrLength);
299  }
300  else
301  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
302  }
303  else
304  {
305  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
306  rContext->powerState = POWER_STATE_UNPOWERED;
307  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
308  Log3(PCSC_LOG_ERROR, "Error powering up card: %ld 0x%04lX", rv, rv);
309  }
310 #endif
311 
312  dwCurrentState = SCARD_PRESENT;
313  }
314  else
315  {
316  readerState = SCARD_ABSENT;
317  rContext->readerState->cardAtrLength = 0;
319 
320  dwCurrentState = SCARD_ABSENT;
321  }
322 
323  /*
324  * Set all the public attributes to this reader
325  */
326  rContext->readerState->readerState = readerState;
327  rContext->readerState->readerSharing = readerSharing = rContext->contexts;
328 
329  (void)EHSignalEventToClients();
330 
331  while (1)
332  {
333  dwStatus = 0;
334 
335  rv = IFDStatusICC(rContext, &dwStatus);
336 
337  if (rv != SCARD_S_SUCCESS)
338  {
339  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
340 
341  /*
342  * Set error status on this reader while errors occur
343  */
345  rContext->readerState->cardAtrLength = 0;
347 
348  dwCurrentState = SCARD_UNKNOWN;
349 
350  (void)EHSignalEventToClients();
351  }
352 
353  if (dwStatus & SCARD_ABSENT)
354  {
355  if (dwCurrentState == SCARD_PRESENT ||
356  dwCurrentState == SCARD_UNKNOWN)
357  {
358  /*
359  * Change the status structure
360  */
361  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
362  /*
363  * Notify the card has been removed
364  */
365  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
366 
367  rContext->readerState->cardAtrLength = 0;
369  rContext->readerState->readerState = SCARD_ABSENT;
370  dwCurrentState = SCARD_ABSENT;
371 
372  rContext->readerState->eventCounter++;
373 
374  (void)EHSignalEventToClients();
375  }
376 
377  }
378  else if (dwStatus & SCARD_PRESENT)
379  {
380  if (dwCurrentState == SCARD_ABSENT ||
381  dwCurrentState == SCARD_UNKNOWN)
382  {
383 #ifdef DISABLE_AUTO_POWER_ON
384  rContext->readerState->cardAtrLength = 0;
387  rContext->powerState = POWER_STATE_UNPOWERED;
388  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
389  rv = IFD_SUCCESS;
390  Log1(PCSC_LOG_INFO, "Skip card power on");
391 #else
392  /*
393  * Power and reset the card
394  */
395  dwAtrLen = sizeof(rContext->readerState->cardAtr);
396  rv = IFDPowerICC(rContext, IFD_POWER_UP,
397  rContext->readerState->cardAtr, &dwAtrLen);
398  rContext->readerState->cardAtrLength = dwAtrLen;
399 
400  /* the protocol is unset after a power on */
402 
403  if (rv == IFD_SUCCESS)
404  {
405  rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
406  rContext->powerState = POWER_STATE_POWERED;
407  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
408  }
409  else
410  {
411  rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
412  rContext->powerState = POWER_STATE_UNPOWERED;
413  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
414  rContext->readerState->cardAtrLength = 0;
415  }
416 #endif
417 
418  dwCurrentState = SCARD_PRESENT;
419 
420  rContext->readerState->eventCounter++;
421 
422  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
423 
424  (void)EHSignalEventToClients();
425 
426  if (rv == IFD_SUCCESS)
427  {
428  if (rContext->readerState->cardAtrLength > 0)
429  {
430  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
431  rContext->readerState->cardAtr,
432  rContext->readerState->cardAtrLength);
433  }
434  else
435  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
436  }
437  else
438  Log1(PCSC_LOG_ERROR,"Error powering up card.");
439  }
440  }
441 
442  /*
443  * Sharing may change w/o an event pass it on
444  */
445  if (readerSharing != rContext->contexts)
446  {
447  readerSharing = rContext->contexts;
448  rContext->readerState->readerSharing = readerSharing;
449  (void)EHSignalEventToClients();
450  }
451 
452  if (rContext->pthCardEvent)
453  {
454  int ret;
455  int timeout;
456 
457 #ifndef DISABLE_ON_DEMAND_POWER_ON
458  if (POWER_STATE_POWERED == rContext->powerState)
459  /* The card is powered but not yet used */
461  else
462  /* The card is already in use or not used at all */
463 #endif
465 
466  ret = rContext->pthCardEvent(rContext->slot, timeout);
467  if (IFD_SUCCESS != ret)
469  }
470  else
472 
473 #ifndef DISABLE_ON_DEMAND_POWER_ON
474  /* the card is powered but not used */
475  (void)pthread_mutex_lock(&rContext->powerState_lock);
476  if (POWER_STATE_POWERED == rContext->powerState)
477  {
478  /* power down */
479  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
480  rContext->powerState = POWER_STATE_UNPOWERED;
481  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
482 
483  /* the protocol is unset after a power down */
485  }
486 
487  /* the card was in use */
488  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
489  {
490  /* the next state should be UNPOWERED unless the
491  * card is used again */
492  rContext->powerState = POWER_STATE_POWERED;
493  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
494  }
495  (void)pthread_mutex_unlock(&rContext->powerState_lock);
496 #endif
497 
498  if (rContext->hLockId == 0xFFFF)
499  {
500  /*
501  * Exit and notify the caller
502  */
503  (void)EHSignalEventToClients();
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:107
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc...
Definition: ifdwrapper.c:344
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:61
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:333
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:240
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:194
char readerName[MAX_READERNAME]
reader name
Definition: eventhandler.h:55
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:58
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:56
LONG EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
Definition: eventhandler.c:120
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:126
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:196
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:88
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition: pcsclite.h:199
prototypes of strlcpy()/strlcat() imported from OpenBSD
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:347
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:67
#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:87
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:68
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:197
int powerState
auto power off state
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:176
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:60
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:270
#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:198
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:195
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:62
auto power off
Definition: pcscd.h:47
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:112
This keeps track of a list of currently available reader structures.
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:57
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:106
#define IFD_POWER_UP
power up the card
Definition: ifdhandler.h:346
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:332
This handles debugging.
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:354
#define SCARD_REMOVED
Card was removed.
Definition: pcscd.h:24
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:107