eventhandler.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2000-2002
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2002-2009
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  *
00009  * $Id: eventhandler.c 4912 2010-05-03 09:30:25Z rousseau $
00010  */
00011 
00018 #include "config.h"
00019 #include <sys/types.h>
00020 #include <sys/stat.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <pthread.h>
00026 
00027 #include "misc.h"
00028 #include "pcscd.h"
00029 #include "ifdhandler.h"
00030 #include "debuglog.h"
00031 #include "readerfactory.h"
00032 #include "eventhandler.h"
00033 #include "dyn_generic.h"
00034 #include "sys_generic.h"
00035 #include "ifdwrapper.h"
00036 #include "prothandler.h"
00037 #include "strlcpycat.h"
00038 #include "utils.h"
00039 #include "winscard_svc.h"
00040 #include "simclist.h"
00041 
00042 READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
00043 static list_t ClientsWaitingForEvent;   
00044 pthread_mutex_t ClientsWaitingForEvent_lock;    
00046 static void EHStatusHandlerThread(READER_CONTEXT *);
00047 
00048 LONG EHRegisterClientForEvent(int32_t filedes)
00049 {
00050     (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
00051 
00052     (void)list_append(&ClientsWaitingForEvent, &filedes);
00053     
00054     (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
00055 
00056     return SCARD_S_SUCCESS;
00057 } /* EHRegisterClientForEvent */
00058 
00063 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
00064 {
00065     LONG rv = SCARD_S_SUCCESS;
00066     int ret;
00067 
00068     (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
00069 
00070     ret = list_delete(&ClientsWaitingForEvent, &filedes);
00071     
00072     (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
00073     
00074     if (ret < 0)
00075         rv = SCARD_F_INTERNAL_ERROR;
00076 
00077     return rv;
00078 } /* EHTryToUnregisterClientForEvent */
00079 
00083 LONG EHUnregisterClientForEvent(int32_t filedes)
00084 {
00085     LONG rv = EHTryToUnregisterClientForEvent(filedes);
00086     
00087     if (rv < 0)
00088         Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
00089 
00090     return rv;
00091 } /* EHUnregisterClientForEvent */
00092 
00096 LONG EHSignalEventToClients(void)
00097 {
00098     LONG rv = SCARD_S_SUCCESS;
00099     int32_t filedes;
00100 
00101     (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
00102 
00103     (void)list_iterator_start(&ClientsWaitingForEvent);
00104     while (list_iterator_hasnext(&ClientsWaitingForEvent))
00105     {
00106         filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
00107         rv = MSGSignalClient(filedes, SCARD_S_SUCCESS);
00108     }
00109     (void)list_iterator_stop(&ClientsWaitingForEvent);
00110 
00111     (void)list_clear(&ClientsWaitingForEvent);
00112 
00113     (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
00114 
00115     return rv;
00116 } /* EHSignalEventToClients */
00117 
00118 LONG EHInitializeEventStructures(void)
00119 {
00120     int i;
00121 
00122     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00123     {
00124         /* Zero out each value in the struct */
00125         memset(readerStates[i].readerName, 0, MAX_READERNAME);
00126         memset(readerStates[i].cardAtr, 0, MAX_ATR_SIZE);
00127         readerStates[i].readerID = 0;
00128         readerStates[i].readerState = 0;
00129         readerStates[i].readerSharing = 0;
00130         readerStates[i].cardAtrLength = 0;
00131         readerStates[i].cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00132     }
00133 
00134     (void)list_init(&ClientsWaitingForEvent);
00135 
00136     /* request to store copies, and provide the metric function */
00137     (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
00138 
00139     /* setting the comparator, so the list can sort, find the min, max etc */
00140     (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
00141 
00142     (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
00143 
00144     return SCARD_S_SUCCESS;
00145 }
00146 
00147 LONG EHDestroyEventHandler(READER_CONTEXT * rContext)
00148 {
00149     int rv;
00150     DWORD dwGetSize;
00151     UCHAR ucGetData[1];
00152 
00153     if (NULL == rContext->readerState)
00154     {
00155         Log1(PCSC_LOG_ERROR, "Thread never started (reader init failed?)");
00156         return SCARD_S_SUCCESS;
00157     }
00158 
00159     if ('\0' == rContext->readerState->readerName[0])
00160     {
00161         Log1(PCSC_LOG_INFO, "Thread already stomped.");
00162         return SCARD_S_SUCCESS;
00163     }
00164 
00165     /*
00166      * Set the thread to 0 to exit thread
00167      */
00168     rContext->hLockId = 0xFFFF;
00169 
00170     Log1(PCSC_LOG_INFO, "Stomping thread.");
00171 
00172     /* kill the "polling" thread */
00173     dwGetSize = sizeof(ucGetData);
00174     rv = IFDGetCapabilities(rContext, TAG_IFD_POLLING_THREAD_KILLABLE,
00175         &dwGetSize, ucGetData);
00176 
00177 #ifdef HAVE_PTHREAD_CANCEL
00178     if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
00179     {
00180         Log1(PCSC_LOG_INFO, "Killing polling thread");
00181         (void)pthread_cancel(rContext->pthThread);
00182     }
00183     else
00184 #endif
00185         Log1(PCSC_LOG_INFO, "Waiting polling thread");
00186 
00187     /* wait for the thread to finish */
00188     rv = pthread_join(rContext->pthThread, NULL);
00189     if (rv)
00190         Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
00191 
00192     /*
00193      * Zero out the public status struct to allow it to be recycled and
00194      * used again
00195      */
00196     memset(rContext->readerState->readerName, 0,
00197         sizeof(rContext->readerState->readerName));
00198     memset(rContext->readerState->cardAtr, 0,
00199         sizeof(rContext->readerState->cardAtr));
00200     rContext->readerState->readerID = 0;
00201     rContext->readerState->readerState = 0;
00202     rContext->readerState->readerSharing = 0;
00203     rContext->readerState->cardAtrLength = 0;
00204     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00205 
00206     /* Zero the thread */
00207     rContext->pthThread = 0;
00208 
00209     Log1(PCSC_LOG_INFO, "Thread stomped.");
00210 
00211     return SCARD_S_SUCCESS;
00212 }
00213 
00214 LONG EHSpawnEventHandler(READER_CONTEXT * rContext,
00215     RESPONSECODE (*card_event)(DWORD))
00216 {
00217     LONG rv;
00218     DWORD dwStatus = 0;
00219     int i;
00220     UCHAR ucAtr[MAX_ATR_SIZE];
00221     DWORD dwAtrLen = 0;
00222 
00223     rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
00224     if (rv != SCARD_S_SUCCESS)
00225     {
00226         Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader);
00227         return SCARD_F_UNKNOWN_ERROR;
00228     }
00229 
00230     /*
00231      * Find an empty reader slot and insert the new reader
00232      */
00233     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00234     {
00235         if (readerStates[i].readerID == 0)
00236             break;
00237     }
00238 
00239     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
00240         return SCARD_F_INTERNAL_ERROR;
00241 
00242     /*
00243      * Set all the attributes to this reader
00244      */
00245     rContext->readerState = &readerStates[i];
00246     (void)strlcpy(rContext->readerState->readerName, rContext->lpcReader,
00247         sizeof(rContext->readerState->readerName));
00248     memcpy(rContext->readerState->cardAtr, ucAtr, dwAtrLen);
00249     rContext->readerState->readerID = i + 100;
00250     rContext->readerState->readerState = dwStatus;
00251     rContext->readerState->readerSharing = rContext->contexts;
00252     rContext->readerState->cardAtrLength = dwAtrLen;
00253     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00254 
00255     rContext->pthCardEvent = card_event;
00256     rv = ThreadCreate(&rContext->pthThread, 0,
00257         (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
00258     if (rv)
00259     {
00260         Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
00261         return SCARD_E_NO_MEMORY;
00262     }
00263     else
00264         return SCARD_S_SUCCESS;
00265 }
00266 
00267 static void incrementEventCounter(struct pubReaderStatesList *readerState)
00268 {
00269     int counter;
00270 
00271     counter = (readerState -> readerState >> 16) & 0xFFFF;
00272     counter++;
00273     readerState -> readerState = (readerState -> readerState & 0xFFFF)
00274         + (counter << 16);
00275 }
00276 
00277 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
00278 {
00279     LONG rv;
00280     LPCSTR lpcReader;
00281     DWORD dwStatus;
00282     int32_t readerSharing;
00283     DWORD dwCurrentState;
00284     DWORD dwAtrLen;
00285 
00286     /*
00287      * Zero out everything
00288      */
00289     dwStatus = 0;
00290     readerSharing = 0;
00291     dwCurrentState = 0;
00292 
00293     lpcReader = rContext->lpcReader;
00294 
00295     dwAtrLen = rContext->readerState->cardAtrLength;
00296     rv = IFDStatusICC(rContext, &dwStatus, rContext->readerState->cardAtr,
00297         &dwAtrLen);
00298     rContext->readerState->cardAtrLength = dwAtrLen;
00299 
00300     if (dwStatus & SCARD_PRESENT)
00301     {
00302         dwAtrLen = MAX_ATR_SIZE;
00303         rv = IFDPowerICC(rContext, IFD_POWER_UP,
00304             rContext->readerState->cardAtr,
00305             &dwAtrLen);
00306         rContext->readerState->cardAtrLength = dwAtrLen;
00307 
00308         /* the protocol is unset after a power on */
00309         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00310 
00311         if (rv == IFD_SUCCESS)
00312         {
00313             dwStatus |= SCARD_PRESENT;
00314             dwStatus &= ~SCARD_ABSENT;
00315             dwStatus |= SCARD_POWERED;
00316             dwStatus |= SCARD_NEGOTIABLE;
00317             dwStatus &= ~SCARD_SPECIFIC;
00318             dwStatus &= ~SCARD_SWALLOWED;
00319             dwStatus &= ~SCARD_UNKNOWN;
00320 
00321             if (rContext->readerState->cardAtrLength > 0)
00322             {
00323                 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00324                     rContext->readerState->cardAtr,
00325                     rContext->readerState->cardAtrLength);
00326             }
00327             else
00328                 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00329         }
00330         else
00331         {
00332             dwStatus |= SCARD_PRESENT;
00333             dwStatus &= ~SCARD_ABSENT;
00334             dwStatus |= SCARD_SWALLOWED;
00335             dwStatus &= ~SCARD_POWERED;
00336             dwStatus &= ~SCARD_NEGOTIABLE;
00337             dwStatus &= ~SCARD_SPECIFIC;
00338             dwStatus &= ~SCARD_UNKNOWN;
00339             Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
00340         }
00341 
00342         dwCurrentState = SCARD_PRESENT;
00343     }
00344     else
00345     {
00346         dwStatus |= SCARD_ABSENT;
00347         dwStatus &= ~SCARD_PRESENT;
00348         dwStatus &= ~SCARD_POWERED;
00349         dwStatus &= ~SCARD_NEGOTIABLE;
00350         dwStatus &= ~SCARD_SPECIFIC;
00351         dwStatus &= ~SCARD_SWALLOWED;
00352         dwStatus &= ~SCARD_UNKNOWN;
00353         rContext->readerState->cardAtrLength = 0;
00354         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00355 
00356         dwCurrentState = SCARD_ABSENT;
00357     }
00358 
00359     /*
00360      * Set all the public attributes to this reader
00361      */
00362     rContext->readerState->readerState = dwStatus;
00363     rContext->readerState->readerSharing = readerSharing =
00364         rContext->contexts;
00365 
00366     (void)EHSignalEventToClients();
00367 
00368     while (1)
00369     {
00370         dwStatus = 0;
00371 
00372         dwAtrLen = rContext->readerState->cardAtrLength;
00373         rv = IFDStatusICC(rContext, &dwStatus,
00374             rContext->readerState->cardAtr,
00375             &dwAtrLen);
00376         rContext->readerState->cardAtrLength = dwAtrLen;
00377 
00378         if (rv != SCARD_S_SUCCESS)
00379         {
00380             Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);
00381 
00382             /*
00383              * Set error status on this reader while errors occur
00384              */
00385             rContext->readerState->readerState &= ~SCARD_ABSENT;
00386             rContext->readerState->readerState &= ~SCARD_PRESENT;
00387             rContext->readerState->readerState &= ~SCARD_POWERED;
00388             rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00389             rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00390             rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00391             rContext->readerState->readerState |= SCARD_UNKNOWN;
00392             rContext->readerState->cardAtrLength = 0;
00393             rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00394 
00395             dwCurrentState = SCARD_UNKNOWN;
00396 
00397             (void)EHSignalEventToClients();
00398         }
00399 
00400         if (dwStatus & SCARD_ABSENT)
00401         {
00402             if (dwCurrentState == SCARD_PRESENT ||
00403                 dwCurrentState == SCARD_UNKNOWN)
00404             {
00405                 /*
00406                  * Change the status structure
00407                  */
00408                 Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
00409                 /*
00410                  * Notify the card has been removed
00411                  */
00412                 (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
00413 
00414                 rContext->readerState->cardAtrLength = 0;
00415                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00416                 rContext->readerState->readerState |= SCARD_ABSENT;
00417                 rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00418                 rContext->readerState->readerState &= ~SCARD_PRESENT;
00419                 rContext->readerState->readerState &= ~SCARD_POWERED;
00420                 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00421                 rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00422                 rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00423                 dwCurrentState = SCARD_ABSENT;
00424 
00425                 incrementEventCounter(rContext->readerState);
00426 
00427                 (void)EHSignalEventToClients();
00428             }
00429 
00430         }
00431         else if (dwStatus & SCARD_PRESENT)
00432         {
00433             if (dwCurrentState == SCARD_ABSENT ||
00434                 dwCurrentState == SCARD_UNKNOWN)
00435             {
00436                 /*
00437                  * Power and reset the card
00438                  */
00439                 dwAtrLen = MAX_ATR_SIZE;
00440                 rv = IFDPowerICC(rContext, IFD_POWER_UP,
00441                     rContext->readerState->cardAtr,
00442                     &dwAtrLen);
00443                 rContext->readerState->cardAtrLength = dwAtrLen;
00444 
00445                 /* the protocol is unset after a power on */
00446                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00447 
00448                 if (rv == IFD_SUCCESS)
00449                 {
00450                     rContext->readerState->readerState |= SCARD_PRESENT;
00451                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00452                     rContext->readerState->readerState |= SCARD_POWERED;
00453                     rContext->readerState->readerState |= SCARD_NEGOTIABLE;
00454                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00455                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00456                     rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00457                 }
00458                 else
00459                 {
00460                     rContext->readerState->readerState |= SCARD_PRESENT;
00461                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00462                     rContext->readerState->readerState |= SCARD_SWALLOWED;
00463                     rContext->readerState->readerState &= ~SCARD_POWERED;
00464                     rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00465                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00466                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00467                     rContext->readerState->cardAtrLength = 0;
00468                 }
00469 
00470                 dwCurrentState = SCARD_PRESENT;
00471 
00472                 incrementEventCounter(rContext->readerState);
00473 
00474                 Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);
00475 
00476                 (void)EHSignalEventToClients();
00477 
00478                 if (rv == IFD_SUCCESS)
00479                 {
00480                     if (rContext->readerState->cardAtrLength > 0)
00481                     {
00482                         LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00483                             rContext->readerState->cardAtr,
00484                             rContext->readerState->cardAtrLength);
00485                     }
00486                     else
00487                         Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00488                 }
00489                 else
00490                     Log1(PCSC_LOG_ERROR,"Error powering up card.");
00491             }
00492         }
00493 
00494         /*
00495          * Sharing may change w/o an event pass it on
00496          */
00497         if (readerSharing != rContext->contexts)
00498         {
00499             readerSharing = rContext->contexts;
00500             rContext->readerState->readerSharing = readerSharing;
00501             (void)EHSignalEventToClients();
00502         }
00503 
00504         if (rContext->pthCardEvent)
00505         {
00506             int ret;
00507 
00508             ret = rContext->pthCardEvent(rContext->slot);
00509             if (IFD_NO_SUCH_DEVICE == ret)
00510                 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00511         }
00512         else
00513             (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00514 
00515         if (rContext->hLockId == 0xFFFF)
00516         {
00517             /*
00518              * Exit and notify the caller
00519              */
00520             (void)EHSignalEventToClients();
00521             Log1(PCSC_LOG_INFO, "Die");
00522             rContext->hLockId = 0;
00523             (void)pthread_exit(NULL);
00524         }
00525     }
00526 }
00527