pcsc-lite  1.8.14
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$
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 "utils.h"
60 #include "winscard_svc.h"
61 #include "simclist.h"
62 
64 pthread_mutex_t ClientsWaitingForEvent_lock;
66 static void EHStatusHandlerThread(READER_CONTEXT *);
67 
68 LONG EHRegisterClientForEvent(int32_t filedes)
69 {
70  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
71 
72  (void)list_append(&ClientsWaitingForEvent, &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  LONG rv = SCARD_S_SUCCESS;
119  int32_t filedes;
120 
121  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
122 
123  (void)list_iterator_start(&ClientsWaitingForEvent);
124  while (list_iterator_hasnext(&ClientsWaitingForEvent))
125  {
126  filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
127  rv = MSGSignalClient(filedes, SCARD_S_SUCCESS);
128  }
129  (void)list_iterator_stop(&ClientsWaitingForEvent);
130 
131  (void)list_clear(&ClientsWaitingForEvent);
132 
133  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
134 
135  return rv;
136 } /* EHSignalEventToClients */
137 
138 LONG EHInitializeEventStructures(void)
139 {
140  (void)list_init(&ClientsWaitingForEvent);
141 
142  /* request to store copies, and provide the metric function */
143  (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
144 
145  /* setting the comparator, so the list can sort, find the min, max etc */
146  (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
147 
148  (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
149 
150  return SCARD_S_SUCCESS;
151 }
152 
153 LONG EHDeinitializeEventStructures(void)
154 {
155  list_destroy(&ClientsWaitingForEvent);
156  pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
157 
158  return SCARD_S_SUCCESS;
159 }
160 
161 LONG EHDestroyEventHandler(READER_CONTEXT * rContext)
162 {
163  int rv;
164  DWORD dwGetSize;
165  UCHAR ucGetData[1];
166 
167  if ('\0' == rContext->readerState->readerName[0])
168  {
169  Log1(PCSC_LOG_INFO, "Thread already stomped.");
170  return SCARD_S_SUCCESS;
171  }
172 
173  /*
174  * Set the thread to 0 to exit thread
175  */
176  rContext->hLockId = 0xFFFF;
177 
178  Log1(PCSC_LOG_INFO, "Stomping thread.");
179 
180  /* kill the "polling" thread */
181  dwGetSize = sizeof(ucGetData);
183  &dwGetSize, ucGetData);
184 
185 #ifdef HAVE_PTHREAD_CANCEL
186  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
187  {
188  Log1(PCSC_LOG_INFO, "Killing polling thread");
189  (void)pthread_cancel(rContext->pthThread);
190  }
191  else
192 #endif
193  {
194  /* ask to stop the "polling" thread */
195  RESPONSECODE (*fct)(DWORD) = NULL;
196 
197  dwGetSize = sizeof(fct);
199  &dwGetSize, (PUCHAR)&fct);
200 
201  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
202  {
203  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
204  fct(rContext->slot);
205  }
206  else
207  Log1(PCSC_LOG_INFO, "Waiting polling thread");
208  }
209 
210  /* wait for the thread to finish */
211  rv = pthread_join(rContext->pthThread, NULL);
212  if (rv)
213  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
214 
215  /* Zero the thread */
216  rContext->pthThread = 0;
217 
218  Log1(PCSC_LOG_INFO, "Thread stomped.");
219 
220  return SCARD_S_SUCCESS;
221 }
222 
223 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
224 {
225  LONG rv;
226  DWORD dwStatus = 0;
227 
228  rv = IFDStatusICC(rContext, &dwStatus);
229  if (rv != SCARD_S_SUCCESS)
230  {
231  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
232  rContext->readerState->readerName);
233  return SCARD_F_UNKNOWN_ERROR;
234  }
235 
236  rv = ThreadCreate(&rContext->pthThread, 0,
237  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
238  if (rv)
239  {
240  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
241  return SCARD_E_NO_MEMORY;
242  }
243  else
244  return SCARD_S_SUCCESS;
245 }
246 
247 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
248 {
249  LONG rv;
250  const char *readerName;
251  DWORD dwStatus;
252  uint32_t readerState;
253  int32_t readerSharing;
254  DWORD dwCurrentState;
255 #ifndef DISABLE_AUTO_POWER_ON
256  DWORD dwAtrLen;
257 #endif
258 
259  /*
260  * Zero out everything
261  */
262  dwStatus = 0;
263 
264  readerName = rContext->readerState->readerName;
265 
266  rv = IFDStatusICC(rContext, &dwStatus);
267 
268  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
269  {
270 #ifdef DISABLE_AUTO_POWER_ON
271  rContext->readerState->cardAtrLength = 0;
273  readerState = SCARD_PRESENT;
274  Log1(PCSC_LOG_INFO, "Skip card power on");
275 #else
276  dwAtrLen = sizeof(rContext->readerState->cardAtr);
277  rv = IFDPowerICC(rContext, IFD_POWER_UP,
278  rContext->readerState->cardAtr, &dwAtrLen);
279  rContext->readerState->cardAtrLength = dwAtrLen;
280 
281  /* the protocol is unset after a power on */
283 
284  if (rv == IFD_SUCCESS)
285  {
286  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
287  rContext->powerState = POWER_STATE_POWERED;
288  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
289 
290  if (rContext->readerState->cardAtrLength > 0)
291  {
292  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
293  rContext->readerState->cardAtr,
294  rContext->readerState->cardAtrLength);
295  }
296  else
297  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
298  }
299  else
300  {
301  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
302  rContext->powerState = POWER_STATE_UNPOWERED;
303  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
304  Log3(PCSC_LOG_ERROR, "Error powering up card: %ld 0x%04lX", rv, rv);
305  }
306 #endif
307 
308  dwCurrentState = SCARD_PRESENT;
309  }
310  else
311  {
312  readerState = SCARD_ABSENT;
313  rContext->readerState->cardAtrLength = 0;
315 
316  dwCurrentState = SCARD_ABSENT;
317  }
318 
319  /*
320  * Set all the public attributes to this reader
321  */
322  rContext->readerState->readerState = readerState;
323  rContext->readerState->readerSharing = readerSharing = rContext->contexts;
324 
325  (void)EHSignalEventToClients();
326 
327  while (1)
328  {
329  dwStatus = 0;
330 
331  rv = IFDStatusICC(rContext, &dwStatus);
332 
333  if (rv != SCARD_S_SUCCESS)
334  {
335  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
336 
337  /*
338  * Set error status on this reader while errors occur
339  */
341  rContext->readerState->cardAtrLength = 0;
343 
344  dwCurrentState = SCARD_UNKNOWN;
345 
346  (void)EHSignalEventToClients();
347  }
348 
349  if (dwStatus & SCARD_ABSENT)
350  {
351  if (dwCurrentState == SCARD_PRESENT ||
352  dwCurrentState == SCARD_UNKNOWN)
353  {
354  /*
355  * Change the status structure
356  */
357  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
358  /*
359  * Notify the card has been removed
360  */
361  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
362 
363  rContext->readerState->cardAtrLength = 0;
365  rContext->readerState->readerState = SCARD_ABSENT;
366  dwCurrentState = SCARD_ABSENT;
367 
368  rContext->readerState->eventCounter++;
369  if (rContext->readerState->eventCounter > 0xFFFF)
370  rContext->readerState->eventCounter = 0;
371 
372  (void)EHSignalEventToClients();
373  }
374 
375  }
376  else if (dwStatus & SCARD_PRESENT)
377  {
378  if (dwCurrentState == SCARD_ABSENT ||
379  dwCurrentState == SCARD_UNKNOWN)
380  {
381 #ifdef DISABLE_AUTO_POWER_ON
382  rContext->readerState->cardAtrLength = 0;
385  rContext->powerState = POWER_STATE_UNPOWERED;
386  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
387  rv = IFD_SUCCESS;
388  Log1(PCSC_LOG_INFO, "Skip card power on");
389 #else
390  /*
391  * Power and reset the card
392  */
393  dwAtrLen = sizeof(rContext->readerState->cardAtr);
394  rv = IFDPowerICC(rContext, IFD_POWER_UP,
395  rContext->readerState->cardAtr, &dwAtrLen);
396  rContext->readerState->cardAtrLength = dwAtrLen;
397 
398  /* the protocol is unset after a power on */
400 
401  if (rv == IFD_SUCCESS)
402  {
403  rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
404  rContext->powerState = POWER_STATE_POWERED;
405  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
406  }
407  else
408  {
409  rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
410  rContext->powerState = POWER_STATE_UNPOWERED;
411  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
412  rContext->readerState->cardAtrLength = 0;
413  }
414 #endif
415 
416  dwCurrentState = SCARD_PRESENT;
417 
418  rContext->readerState->eventCounter++;
419  if (rContext->readerState->eventCounter > 0xFFFF)
420  rContext->readerState->eventCounter = 0;
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: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: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:332
pthread_t pthThread
Event polling thread.
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
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
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:116
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
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:346
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:63
#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:83
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:64
#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:345
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:331
This handles debugging.
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:353
#define SCARD_REMOVED
Card was removed.
Definition: pcscd.h:47
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:104