pcsc-lite 2.5.0
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-2023
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
38
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
63
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)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
73
74 return SCARD_S_SUCCESS;
75} /* EHRegisterClientForEvent */
76
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
101LONG EHUnregisterClientForEvent(int32_t filedes)
102{
103 LONG rv = EHTryToUnregisterClientForEvent(filedes);
104
105 if (rv != SCARD_S_SUCCESS)
106 Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
107
108 return rv;
109} /* EHUnregisterClientForEvent */
110
115{
116 int32_t filedes;
117
118 (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
119
120 (void)list_iterator_start(&ClientsWaitingForEvent);
121 while (list_iterator_hasnext(&ClientsWaitingForEvent))
122 {
123 filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
124 MSGSignalClient(filedes, SCARD_S_SUCCESS);
125 }
126 (void)list_iterator_stop(&ClientsWaitingForEvent);
127
128 (void)list_clear(&ClientsWaitingForEvent);
129
130 (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
131} /* EHSignalEventToClients */
132
133LONG EHInitializeEventStructures(void)
134{
135 (void)list_init(&ClientsWaitingForEvent);
136
137 /* request to store copies, and provide the metric function */
138 (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
139
140 /* setting the comparator, so the list can sort, find the min, max etc */
141 (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
142
143 (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
144
145 return SCARD_S_SUCCESS;
146}
147
148LONG EHDeinitializeEventStructures(void)
149{
150 list_destroy(&ClientsWaitingForEvent);
151 pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
152
153 return SCARD_S_SUCCESS;
154}
155
156void EHDestroyEventHandler(READER_CONTEXT * rContext)
157{
158 int rv;
159 DWORD dwGetSize;
160 UCHAR ucGetData[1];
161
162 if ('\0' == rContext->readerState.readerName[0])
163 {
164 Log1(PCSC_LOG_INFO, "Thread already stomped.");
165 return;
166 }
167
168 /*
169 * Set the thread to 0 to exit thread
170 */
171 rContext->hLockId = 0xFFFF;
172
173 Log1(PCSC_LOG_INFO, "Stomping thread.");
174
175 /* kill the "polling" thread */
176 dwGetSize = sizeof(ucGetData);
178 &dwGetSize, ucGetData);
179
180 if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
181 {
182 Log1(PCSC_LOG_INFO, "Killing polling thread");
183 (void)pthread_cancel(rContext->pthThread);
184 }
185 else
186 {
187 /* ask to stop the "polling" thread */
188 RESPONSECODE (*fct)(DWORD) = NULL;
189
190 dwGetSize = sizeof(fct);
192 &dwGetSize, (PUCHAR)&fct);
193
194 if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
195 {
196 Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
197 fct(rContext->slot);
198 }
199 else
200 Log1(PCSC_LOG_INFO, "Waiting polling thread");
201 }
202
203 /* wait for the thread to finish */
204 rv = pthread_join(rContext->pthThread, NULL);
205 if (rv)
206 Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
207
208 /* Zero the thread */
209 rContext->pthThread = 0;
210
211 Log1(PCSC_LOG_INFO, "Thread stomped.");
212
213 return;
214}
215
216LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
217{
218 LONG rv;
219 DWORD dwStatus = 0;
220
221 rv = IFDStatusICC(rContext, &dwStatus);
222 if (rv != SCARD_S_SUCCESS)
223 {
224 Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
225 rContext->readerState.readerName);
227 }
228
229 rv = ThreadCreate(&rContext->pthThread, 0,
230 (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
231 if (rv)
232 {
233 Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
234 return SCARD_E_NO_MEMORY;
235 }
236 else
237 return SCARD_S_SUCCESS;
238}
239
240static void * EHStatusHandlerThread(READER_CONTEXT * rContext)
241{
242 LONG rv;
243#ifndef NO_LOG
244 const char *readerName;
245#endif
246 DWORD dwStatus;
247 uint32_t readerState;
248 int32_t readerSharing;
249 DWORD dwCurrentState;
250#ifndef DISABLE_AUTO_POWER_ON
251 DWORD dwAtrLen;
252#endif
253
254 /*
255 * Zero out everything
256 */
257 dwStatus = 0;
258
259#ifndef NO_LOG
260 readerName = rContext->readerState.readerName;
261#endif
262
263 rv = IFDStatusICC(rContext, &dwStatus);
264
265 if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
266 {
267#ifdef DISABLE_AUTO_POWER_ON
268 rContext->readerState.cardAtrLength = 0;
270 readerState = SCARD_PRESENT;
271 Log1(PCSC_LOG_INFO, "Skip card power on");
272#else
273 dwAtrLen = sizeof(rContext->readerState.cardAtr);
274 rv = IFDPowerICC(rContext, IFD_POWER_UP,
275 rContext->readerState.cardAtr, &dwAtrLen);
276 rContext->readerState.cardAtrLength = dwAtrLen;
277
278 /* the protocol is unset after a power on */
280
281 if (rv == IFD_SUCCESS)
282 {
284 RFSetPowerState(rContext, POWER_STATE_POWERED);
285 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
286
287 if (rContext->readerState.cardAtrLength > 0)
288 {
289 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
290 rContext->readerState.cardAtr,
291 rContext->readerState.cardAtrLength);
292 }
293 else
294 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
295 }
296 else
297 {
298 readerState = SCARD_PRESENT | SCARD_SWALLOWED;
299 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
300 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
301 Log2(PCSC_LOG_ERROR, "Error powering up card: %s", rv2text(rv));
302 }
303#endif
304
305 dwCurrentState = SCARD_PRESENT;
306 }
307 else
308 {
309 readerState = SCARD_ABSENT;
310 rContext->readerState.cardAtrLength = 0;
312
313 dwCurrentState = SCARD_ABSENT;
314 }
315
316 /*
317 * Set all the public attributes to this reader
318 */
319 rContext->readerState.readerState = readerState;
320 rContext->readerState.readerSharing = readerSharing = rContext->contexts;
321
323
324 while (1)
325 {
326 dwStatus = 0;
327
328 rv = IFDStatusICC(rContext, &dwStatus);
329
330 if (rv != SCARD_S_SUCCESS)
331 {
332 Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
333
334 /*
335 * Set error status on this reader while errors occur
336 */
338 rContext->readerState.cardAtrLength = 0;
340
341 dwCurrentState = SCARD_UNKNOWN;
342
344 }
345
346 if (dwStatus & SCARD_ABSENT)
347 {
348 if (dwCurrentState == SCARD_PRESENT ||
349 dwCurrentState == SCARD_UNKNOWN)
350 {
351 /*
352 * Change the status structure
353 */
354 Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
355 /*
356 * Notify the card has been removed
357 */
358 (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
359
360 rContext->readerState.cardAtrLength = 0;
363 dwCurrentState = SCARD_ABSENT;
364
365 rContext->readerState.eventCounter++;
366 if (rContext->readerState.eventCounter > 0xFFFF)
367 rContext->readerState.eventCounter = 0;
368
370 }
371
372 }
373 else if (dwStatus & SCARD_PRESENT)
374 {
375 if (dwCurrentState == SCARD_ABSENT ||
376 dwCurrentState == SCARD_UNKNOWN)
377 {
378#ifdef DISABLE_AUTO_POWER_ON
379 rContext->readerState.cardAtrLength = 0;
382 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
383 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
384 rv = IFD_SUCCESS;
385 Log1(PCSC_LOG_INFO, "Skip card power on");
386#else
387 /*
388 * Power and reset the card
389 */
390 dwAtrLen = sizeof(rContext->readerState.cardAtr);
391 rv = IFDPowerICC(rContext, IFD_POWER_UP,
392 rContext->readerState.cardAtr, &dwAtrLen);
393 rContext->readerState.cardAtrLength = dwAtrLen;
394
395 /* the protocol is unset after a power on */
397
398 if (rv == IFD_SUCCESS)
399 {
401 RFSetPowerState(rContext, POWER_STATE_POWERED);
402 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
403 }
404 else
405 {
407 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
408 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
409 rContext->readerState.cardAtrLength = 0;
410 }
411#endif
412
413 dwCurrentState = SCARD_PRESENT;
414
415 rContext->readerState.eventCounter++;
416 if (rContext->readerState.eventCounter > 0xFFFF)
417 rContext->readerState.eventCounter = 0;
418
419 Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
420
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;
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 == RFGetPowerState(rContext))
456 /* The card is powered but not yet used */
457 timeout = PCSCLITE_POWER_OFF_GRACE_PERIOD;
458 else
459 /* The card is already in use or not used at all */
460#endif
461 timeout = PCSCLITE_STATUS_EVENT_TIMEOUT;
462
463 ret = rContext->pthCardEvent(rContext->slot, timeout);
464 if (IFD_SUCCESS != ret)
465 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
466 }
467 else
468 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
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 Log1(PCSC_LOG_INFO, "Die");
501 rContext->hLockId = 0;
502 (void)pthread_exit(NULL);
503 }
504 }
505}
506
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:238
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc.
Definition ifdwrapper.c:337
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:268
This wraps the dynamic ifdhandler functions.
#define SCARD_SWALLOWED
Card not powered.
Definition pcsclite.h:261
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition pcsclite.h:240
#define SCARD_PRESENT
Card is present.
Definition pcsclite.h:260
#define SCARD_POWERED
Card is powered.
Definition pcsclite.h:262
#define SCARD_ABSENT
Card is absent.
Definition pcsclite.h:259
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:258
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition pcsclite.h:263
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.
READER_STATE readerState
reader state
Definition readers.h:133
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
Definition readers.h:109
pthread_mutex_t powerState_lock
powerState mutex
Definition readers.h:130
pthread_t pthThread
Event polling thread.
Definition readers.h:108
_Atomic int32_t contexts
Number of open contexts.
Definition readers.h:126
int slot
Current Reader Slot.
Definition readers.h:123
_Atomic SCARDHANDLE hLockId
Lock Id.
Definition readers.h:124
int powerState
auto power off state
Definition readers.h:129
list object
Definition simclist.h:181
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition readers.h:54
char readerName[MAX_READERNAME]
reader name
Definition readers.h:51
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition readers.h:58
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition readers.h:56
uint32_t eventCounter
number of card events
Definition readers.h:52
_Atomic uint32_t cardAtrLength
ATR length.
Definition readers.h:57
uint32_t readerState
SCARD_* bit field.
Definition readers.h:53
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.