pcsc-lite 1.9.9
eventhandler.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
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 *
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions
11are met:
12
131. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
152. 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.
183. 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
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30THIS 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
64static void * EHStatusHandlerThread(READER_CONTEXT *);
65
66LONG EHRegisterClientForEvent(int32_t filedes)
67{
68 (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
69
70 (void)list_append(&ClientsWaitingForEvent, &filedes);
71
72 (void)MSGSendReaderStates(filedes);
73
74 (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
75
76 return SCARD_S_SUCCESS;
77} /* EHRegisterClientForEvent */
78
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
103LONG EHUnregisterClientForEvent(int32_t filedes)
104{
105 LONG rv = EHTryToUnregisterClientForEvent(filedes);
106
107 if (rv != SCARD_S_SUCCESS)
108 Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
109
110 return rv;
111} /* EHUnregisterClientForEvent */
112
117{
118 int32_t filedes;
119
120 (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
121
122 (void)list_iterator_start(&ClientsWaitingForEvent);
123 while (list_iterator_hasnext(&ClientsWaitingForEvent))
124 {
125 filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
126 MSGSignalClient(filedes, SCARD_S_SUCCESS);
127 }
128 (void)list_iterator_stop(&ClientsWaitingForEvent);
129
130 (void)list_clear(&ClientsWaitingForEvent);
131
132 (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
133} /* EHSignalEventToClients */
134
135LONG EHInitializeEventStructures(void)
136{
137 (void)list_init(&ClientsWaitingForEvent);
138
139 /* request to store copies, and provide the metric function */
140 (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
141
142 /* setting the comparator, so the list can sort, find the min, max etc */
143 (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
144
145 (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
146
147 return SCARD_S_SUCCESS;
148}
149
150LONG EHDeinitializeEventStructures(void)
151{
152 list_destroy(&ClientsWaitingForEvent);
153 pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
154
155 return SCARD_S_SUCCESS;
156}
157
158void EHDestroyEventHandler(READER_CONTEXT * rContext)
159{
160 int rv;
161 DWORD dwGetSize;
162 UCHAR ucGetData[1];
163
164 if ('\0' == rContext->readerState->readerName[0])
165 {
166 Log1(PCSC_LOG_INFO, "Thread already stomped.");
167 return;
168 }
169
170 /*
171 * Set the thread to 0 to exit thread
172 */
173 rContext->hLockId = 0xFFFF;
174
175 Log1(PCSC_LOG_INFO, "Stomping thread.");
176
177 /* kill the "polling" thread */
178 dwGetSize = sizeof(ucGetData);
180 &dwGetSize, ucGetData);
181
182#ifdef HAVE_PTHREAD_CANCEL
183 if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
184 {
185 Log1(PCSC_LOG_INFO, "Killing polling thread");
186 (void)pthread_cancel(rContext->pthThread);
187 }
188 else
189#endif
190 {
191 /* ask to stop the "polling" thread */
192 RESPONSECODE (*fct)(DWORD) = NULL;
193
194 dwGetSize = sizeof(fct);
196 &dwGetSize, (PUCHAR)&fct);
197
198 if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
199 {
200 Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
201 fct(rContext->slot);
202 }
203 else
204 Log1(PCSC_LOG_INFO, "Waiting polling thread");
205 }
206
207 /* wait for the thread to finish */
208 rv = pthread_join(rContext->pthThread, NULL);
209 if (rv)
210 Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
211
212 /* Zero the thread */
213 rContext->pthThread = 0;
214
215 Log1(PCSC_LOG_INFO, "Thread stomped.");
216
217 return;
218}
219
220LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
221{
222 LONG rv;
223 DWORD dwStatus = 0;
224
225 rv = IFDStatusICC(rContext, &dwStatus);
226 if (rv != SCARD_S_SUCCESS)
227 {
228 Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
229 rContext->readerState->readerName);
231 }
232
233 rv = ThreadCreate(&rContext->pthThread, 0,
234 (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
235 if (rv)
236 {
237 Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
238 return SCARD_E_NO_MEMORY;
239 }
240 else
241 return SCARD_S_SUCCESS;
242}
243
244static void * EHStatusHandlerThread(READER_CONTEXT * rContext)
245{
246 LONG rv;
247#ifndef NO_LOG
248 const char *readerName;
249#endif
250 DWORD dwStatus;
251 uint32_t readerState;
252 int32_t readerSharing;
253 DWORD dwCurrentState;
254#ifndef DISABLE_AUTO_POWER_ON
255 DWORD dwAtrLen;
256#endif
257
258 /*
259 * Zero out everything
260 */
261 dwStatus = 0;
262
263#ifndef NO_LOG
264 readerName = rContext->readerState->readerName;
265#endif
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 {
288 RFSetPowerState(rContext, 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 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
304 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
305 Log2(PCSC_LOG_ERROR, "Error powering up card: %s", rv2text(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
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
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;
367 dwCurrentState = SCARD_ABSENT;
368
369 rContext->readerState->eventCounter++;
370 if (rContext->readerState->eventCounter > 0xFFFF)
371 rContext->readerState->eventCounter = 0;
372
374 }
375
376 }
377 else if (dwStatus & SCARD_PRESENT)
378 {
379 if (dwCurrentState == SCARD_ABSENT ||
380 dwCurrentState == SCARD_UNKNOWN)
381 {
382#ifdef DISABLE_AUTO_POWER_ON
383 rContext->readerState->cardAtrLength = 0;
386 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
387 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
388 rv = IFD_SUCCESS;
389 Log1(PCSC_LOG_INFO, "Skip card power on");
390#else
391 /*
392 * Power and reset the card
393 */
394 dwAtrLen = sizeof(rContext->readerState->cardAtr);
395 rv = IFDPowerICC(rContext, IFD_POWER_UP,
396 rContext->readerState->cardAtr, &dwAtrLen);
397 rContext->readerState->cardAtrLength = dwAtrLen;
398
399 /* the protocol is unset after a power on */
401
402 if (rv == IFD_SUCCESS)
403 {
405 RFSetPowerState(rContext, POWER_STATE_POWERED);
406 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
407 }
408 else
409 {
411 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
412 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
413 rContext->readerState->cardAtrLength = 0;
414 }
415#endif
416
417 dwCurrentState = SCARD_PRESENT;
418
419 rContext->readerState->eventCounter++;
420 if (rContext->readerState->eventCounter > 0xFFFF)
421 rContext->readerState->eventCounter = 0;
422
423 Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
424
426
427 if (rv == IFD_SUCCESS)
428 {
429 if (rContext->readerState->cardAtrLength > 0)
430 {
431 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
432 rContext->readerState->cardAtr,
433 rContext->readerState->cardAtrLength);
434 }
435 else
436 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
437 }
438 else
439 Log1(PCSC_LOG_ERROR,"Error powering up card.");
440 }
441 }
442
443 /*
444 * Sharing may change w/o an event pass it on
445 */
446 if (readerSharing != rContext->contexts)
447 {
448 readerSharing = rContext->contexts;
449 rContext->readerState->readerSharing = readerSharing;
451 }
452
453 if (rContext->pthCardEvent)
454 {
455 int ret;
456 int timeout;
457
458#ifndef DISABLE_ON_DEMAND_POWER_ON
459 if (POWER_STATE_POWERED == RFGetPowerState(rContext))
460 /* The card is powered but not yet used */
462 else
463 /* The card is already in use or not used at all */
464#endif
466
467 ret = rContext->pthCardEvent(rContext->slot, timeout);
468 if (IFD_SUCCESS != ret)
470 }
471 else
473
474#ifndef DISABLE_ON_DEMAND_POWER_ON
475 /* the card is powered but not used */
476 (void)pthread_mutex_lock(&rContext->powerState_lock);
477 if (POWER_STATE_POWERED == rContext->powerState)
478 {
479 /* power down */
480 IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
482 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
483
484 /* the protocol is unset after a power down */
486 }
487
488 /* the card was in use */
489 if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
490 {
491 /* the next state should be UNPOWERED unless the
492 * card is used again */
494 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
495 }
496 (void)pthread_mutex_unlock(&rContext->powerState_lock);
497#endif
498
499 if (rContext->hLockId == 0xFFFF)
500 {
501 /*
502 * Exit and notify the caller
503 */
504 Log1(PCSC_LOG_INFO, "Die");
505 rContext->hLockId = 0;
506 (void)pthread_exit(NULL);
507 }
508 }
509}
510
This handles debugging.
This abstracts dynamic library loading functions.
static list_t ClientsWaitingForEvent
list of client file descriptors
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregister a client If no client is found then do not log an error.
void EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
pthread_mutex_t ClientsWaitingForEvent_lock
lock for the above list
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition pcsclite.h:109
#define SCARD_F_UNKNOWN_ERROR
An internal error has been detected, but the source is unknown.
Definition pcsclite.h:147
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define IFD_POWER_UP
power up the card
Definition ifdhandler.h:343
#define TAG_IFD_STOP_POLLING_THREAD
method used to stop the polling thread (instead of just pthread_kill())
Definition ifdhandler.h:329
#define IFD_POWER_DOWN
power down the card
Definition ifdhandler.h:344
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition ifdhandler.h:328
#define IFD_SUCCESS
no error
Definition ifdhandler.h:351
RESPONSECODE IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Gets capabilities in the reader.
Definition ifdwrapper.c:235
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc.
Definition ifdwrapper.c:334
RESPONSECODE 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:265
This wraps the dynamic ifdhandler functions.
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_STATUS_EVENT_TIMEOUT
normal timeout for pthCardEvent driver function when no card or card in use
Definition pcscd.h:74
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition pcscd.h:53
#define PCSCLITE_POWER_OFF_GRACE_PERIOD
time to wait before powering down an unused card
Definition pcscd.h:70
@ POWER_STATE_UNPOWERED
auto power off
Definition pcscd.h:63
@ POWER_STATE_POWERED
powered
Definition pcscd.h:64
@ POWER_STATE_GRACE_PERIOD
card was in use
Definition pcscd.h:65
#define SCARD_REMOVED
Card was removed.
Definition pcscd.h:43
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:260
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition pcsclite.h:239
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:259
#define SCARD_POWERED
Card is powered.
Definition pcsclite.h:261
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:258
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:257
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition pcsclite.h:262
This handles protocol defaults, PTS, etc.
int RFGetPowerState(READER_CONTEXT *rContext)
Wait until all connected readers have a chance to power up a possibly inserted card.
This keeps track of a list of currently available reader structures.
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
pthread_mutex_t powerState_lock
powerState mutex
pthread_t pthThread
Event polling thread.
_Atomic int32_t contexts
Number of open contexts.
int slot
Current Reader Slot.
_Atomic SCARDHANDLE hLockId
Lock Id.
struct pubReaderStatesList * readerState
link to the reader state
int powerState
auto power off state
list object
Definition simclist.h:181
char readerName[MAX_READERNAME]
reader name
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
uint32_t eventCounter
number of card events
uint32_t readerState
SCARD_* bit field.
uint32_t cardAtrLength
ATR length.
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition sys_unix.c:80
This demarshalls functions over the message queue and keeps track of clients and their handles.