pcsc-lite 2.5.2
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 LONG rv = SCARD_S_SUCCESS;
69 int lrv;
70
71 (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
72
73 if (list_locate(&ClientsWaitingForEvent, &filedes) < 0)
74 {
75 lrv = list_append(&ClientsWaitingForEvent, &filedes);
76 if (lrv < 0)
78 }
79 else
80 {
81 Log2(PCSC_LOG_ERROR, "Client %d already in list", filedes);
83 }
84
85 (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
86
87 return rv;
88} /* EHRegisterClientForEvent */
89
95{
96 LONG rv = SCARD_S_SUCCESS;
97 int ret;
98
99 (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
100
101 ret = list_delete(&ClientsWaitingForEvent, &filedes);
102
103 (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
104
105 if (ret < 0)
107
108 return rv;
109} /* EHTryToUnregisterClientForEvent */
110
114LONG EHUnregisterClientForEvent(int32_t filedes)
115{
116 LONG rv = EHTryToUnregisterClientForEvent(filedes);
117
118 if (rv != SCARD_S_SUCCESS)
119 Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
120
121 return rv;
122} /* EHUnregisterClientForEvent */
123
128{
129 int32_t filedes;
130
131 (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
132
133 (void)list_iterator_start(&ClientsWaitingForEvent);
134 while (list_iterator_hasnext(&ClientsWaitingForEvent))
135 {
136 filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
137 MSGSignalClient(filedes, SCARD_S_SUCCESS);
138 }
139 (void)list_iterator_stop(&ClientsWaitingForEvent);
140
141 (void)list_clear(&ClientsWaitingForEvent);
142
143 (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
144} /* EHSignalEventToClients */
145
146LONG EHInitializeEventStructures(void)
147{
148 (void)list_init(&ClientsWaitingForEvent);
149
150 /* request to store copies, and provide the metric function */
151 (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
152
153 /* setting the comparator, so the list can sort, find the min, max etc */
154 (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
155
156 (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
157
158 return SCARD_S_SUCCESS;
159}
160
161LONG EHDeinitializeEventStructures(void)
162{
163 list_destroy(&ClientsWaitingForEvent);
164 pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
165
166 return SCARD_S_SUCCESS;
167}
168
169void EHDestroyEventHandler(READER_CONTEXT * rContext)
170{
171 int rv;
172 DWORD dwGetSize;
173 UCHAR ucGetData[1];
174
175 if ('\0' == rContext->readerState.readerName[0])
176 {
177 Log1(PCSC_LOG_INFO, "Thread already stomped.");
178 return;
179 }
180
181 /*
182 * Set the thread to 0 to exit thread
183 */
184 rContext->hLockId = 0xFFFF;
185
186 Log1(PCSC_LOG_INFO, "Stomping thread.");
187
188 /* kill the "polling" thread */
189 dwGetSize = sizeof(ucGetData);
191 &dwGetSize, ucGetData);
192
193 if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
194 {
195 Log1(PCSC_LOG_INFO, "Killing polling thread");
196 (void)pthread_cancel(rContext->pthThread);
197 }
198 else
199 {
200 /* ask to stop the "polling" thread */
201 RESPONSECODE (*fct)(DWORD) = NULL;
202
203 dwGetSize = sizeof(fct);
205 &dwGetSize, (PUCHAR)&fct);
206
207 if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
208 {
209 Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
210 fct(rContext->slot);
211 }
212 else
213 Log1(PCSC_LOG_INFO, "Waiting polling thread");
214 }
215
216 /* wait for the thread to finish */
217 rv = pthread_join(rContext->pthThread, NULL);
218 if (rv)
219 Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
220
221 /* Zero the thread */
222 rContext->pthThread = 0;
223
224 Log1(PCSC_LOG_INFO, "Thread stomped.");
225
226 return;
227}
228
229LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
230{
231 LONG rv;
232 DWORD dwStatus = 0;
233
234 rv = IFDStatusICC(rContext, &dwStatus, false);
235 if (rv != SCARD_S_SUCCESS)
236 {
237 Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
238 rContext->readerState.readerName);
240 }
241
242 rv = ThreadCreate(&rContext->pthThread, 0,
243 (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
244 if (rv)
245 {
246 Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
247 return SCARD_E_NO_MEMORY;
248 }
249 else
250 return SCARD_S_SUCCESS;
251}
252
253static void * EHStatusHandlerThread(READER_CONTEXT * rContext)
254{
255 LONG rv;
256#ifndef NO_LOG
257 const char *readerName;
258#endif
259 DWORD dwStatus;
260 uint32_t readerState;
261 int32_t readerSharing;
262 DWORD dwCurrentState;
263#ifndef DISABLE_AUTO_POWER_ON
264 DWORD dwAtrLen;
265#endif
266
267 /*
268 * Zero out everything
269 */
270 dwStatus = 0;
271
272#ifndef NO_LOG
273 readerName = rContext->readerState.readerName;
274#endif
275
276 rv = IFDStatusICC(rContext, &dwStatus, true);
277
278 if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
279 {
280#ifdef DISABLE_AUTO_POWER_ON
281 rContext->readerState.cardAtrLength = 0;
283 readerState = SCARD_PRESENT;
284 Log1(PCSC_LOG_INFO, "Skip card power on");
285#else
286 dwAtrLen = sizeof(rContext->readerState.cardAtr);
287 rv = IFDPowerICC(rContext, IFD_POWER_UP,
288 rContext->readerState.cardAtr, &dwAtrLen);
289 rContext->readerState.cardAtrLength = dwAtrLen;
290
291 /* the protocol is unset after a power on */
293
294 if (rv == IFD_SUCCESS)
295 {
297 RFSetPowerState(rContext, POWER_STATE_POWERED);
298 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
299
300 if (rContext->readerState.cardAtrLength > 0)
301 {
302 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
303 rContext->readerState.cardAtr,
304 rContext->readerState.cardAtrLength);
305 }
306 else
307 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
308 }
309 else
310 {
311 readerState = SCARD_PRESENT | SCARD_SWALLOWED;
312 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
313 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
314 Log2(PCSC_LOG_ERROR, "Error powering up card: %s", rv2text(rv));
315 }
316#endif
317
318 dwCurrentState = SCARD_PRESENT;
319 }
320 else
321 {
322 readerState = SCARD_ABSENT;
323 rContext->readerState.cardAtrLength = 0;
325
326 dwCurrentState = SCARD_ABSENT;
327 }
328
329 /*
330 * Set all the public attributes to this reader
331 */
332 rContext->readerState.readerState = readerState;
333 rContext->readerState.readerSharing = readerSharing = rContext->contexts;
334
336
337 while (1)
338 {
339 dwStatus = 0;
340
341 rv = IFDStatusICC(rContext, &dwStatus, true);
342
343 if (rv != SCARD_S_SUCCESS)
344 {
345 Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
346
347 /*
348 * Set error status on this reader while errors occur
349 */
351 rContext->readerState.cardAtrLength = 0;
353
354 dwCurrentState = SCARD_UNKNOWN;
355
357 }
358
359 if (dwStatus & SCARD_ABSENT)
360 {
361 if (dwCurrentState == SCARD_PRESENT ||
362 dwCurrentState == SCARD_UNKNOWN)
363 {
364 /*
365 * Change the status structure
366 */
367 Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
368 /*
369 * Notify the card has been removed
370 */
371 (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
372
373 rContext->readerState.cardAtrLength = 0;
376 dwCurrentState = SCARD_ABSENT;
377
378 rContext->readerState.eventCounter++;
379 if (rContext->readerState.eventCounter > 0xFFFF)
380 rContext->readerState.eventCounter = 0;
381
383 }
384
385 }
386 else if (dwStatus & SCARD_PRESENT)
387 {
388 if (dwCurrentState == SCARD_ABSENT ||
389 dwCurrentState == SCARD_UNKNOWN)
390 {
391#ifdef DISABLE_AUTO_POWER_ON
392 rContext->readerState.cardAtrLength = 0;
395 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
396 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
397 rv = IFD_SUCCESS;
398 Log1(PCSC_LOG_INFO, "Skip card power on");
399#else
400 /*
401 * Power and reset the card
402 */
403 dwAtrLen = sizeof(rContext->readerState.cardAtr);
404 rv = IFDPowerICC(rContext, IFD_POWER_UP,
405 rContext->readerState.cardAtr, &dwAtrLen);
406 rContext->readerState.cardAtrLength = dwAtrLen;
407
408 /* the protocol is unset after a power on */
410
411 if (rv == IFD_SUCCESS)
412 {
414 RFSetPowerState(rContext, POWER_STATE_POWERED);
415 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
416 }
417 else
418 {
420 RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
421 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
422 rContext->readerState.cardAtrLength = 0;
423 }
424#endif
425
426 dwCurrentState = SCARD_PRESENT;
427
428 rContext->readerState.eventCounter++;
429 if (rContext->readerState.eventCounter > 0xFFFF)
430 rContext->readerState.eventCounter = 0;
431
432 Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
433
435
436 if (rv == IFD_SUCCESS)
437 {
438 if (rContext->readerState.cardAtrLength > 0)
439 {
440 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
441 rContext->readerState.cardAtr,
442 rContext->readerState.cardAtrLength);
443 }
444 else
445 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
446 }
447 else
448 Log1(PCSC_LOG_ERROR,"Error powering up card.");
449 }
450 }
451
452 /*
453 * Sharing may change w/o an event pass it on
454 */
455 if (readerSharing != rContext->contexts)
456 {
457 readerSharing = rContext->contexts;
458 rContext->readerState.readerSharing = readerSharing;
460 }
461
462 if (rContext->pthCardEvent)
463 {
464 int ret;
465 int timeout;
466
467#ifndef DISABLE_ON_DEMAND_POWER_ON
468 if (POWER_STATE_POWERED == RFGetPowerState(rContext))
469 /* The card is powered but not yet used */
470 timeout = PCSCLITE_POWER_OFF_GRACE_PERIOD;
471 else
472 /* The card is already in use or not used at all */
473#endif
474 timeout = PCSCLITE_STATUS_EVENT_TIMEOUT;
475
476 ret = rContext->pthCardEvent(rContext->slot, timeout);
477 if (IFD_SUCCESS != ret)
478 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
479 }
480 else
481 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
482
483#ifndef DISABLE_ON_DEMAND_POWER_ON
484 /* the card is powered but not used */
485 (void)pthread_mutex_lock(&rContext->powerState_lock);
486 if (POWER_STATE_POWERED == rContext->powerState)
487 {
488 /* power down */
489 IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
490 rContext->powerState = POWER_STATE_UNPOWERED;
491 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
492
493 /* the protocol is unset after a power down */
495 }
496
497 /* the card was in use */
498 if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
499 {
500 /* the next state should be UNPOWERED unless the
501 * card is used again */
502 rContext->powerState = POWER_STATE_POWERED;
503 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
504 }
505 (void)pthread_mutex_unlock(&rContext->powerState_lock);
506#endif
507
508 if (rContext->hLockId == 0xFFFF)
509 {
510 /*
511 * Exit and notify the caller
512 */
513 Log1(PCSC_LOG_INFO, "Die");
514 rContext->hLockId = 0;
515 (void)pthread_exit(NULL);
516 }
517 }
518}
519
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 SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#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
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus, bool hotplug)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc.
Definition ifdwrapper.c:346
RESPONSECODE IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Gets capabilities in the reader.
Definition ifdwrapper.c:238
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.