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