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-2010
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  *
00009  * $Id: eventhandler.c 5123 2010-08-13 10:09:10Z 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     {
00186         /* ask to stop the "polling" thread */
00187         RESPONSECODE (*fct)(DWORD) = NULL;
00188 
00189         dwGetSize = sizeof(fct);
00190         rv = IFDGetCapabilities(rContext, TAG_IFD_STOP_POLLING_THREAD,
00191             &dwGetSize, (PUCHAR)&fct);
00192 
00193         if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
00194         {
00195             Log1(PCSC_LOG_INFO, "Request stoping of polling thread");
00196             fct(rContext->slot);
00197         }
00198         else
00199             Log1(PCSC_LOG_INFO, "Waiting polling thread");
00200     }
00201 
00202     /* wait for the thread to finish */
00203     rv = pthread_join(rContext->pthThread, NULL);
00204     if (rv)
00205         Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
00206 
00207     /*
00208      * Zero out the public status struct to allow it to be recycled and
00209      * used again
00210      */
00211     memset(rContext->readerState->readerName, 0,
00212         sizeof(rContext->readerState->readerName));
00213     memset(rContext->readerState->cardAtr, 0,
00214         sizeof(rContext->readerState->cardAtr));
00215     rContext->readerState->readerID = 0;
00216     rContext->readerState->readerState = 0;
00217     rContext->readerState->readerSharing = 0;
00218     rContext->readerState->cardAtrLength = 0;
00219     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00220 
00221     /* Zero the thread */
00222     rContext->pthThread = 0;
00223 
00224     Log1(PCSC_LOG_INFO, "Thread stomped.");
00225 
00226     return SCARD_S_SUCCESS;
00227 }
00228 
00229 LONG EHSpawnEventHandler(READER_CONTEXT * rContext,
00230     RESPONSECODE (*card_event)(DWORD))
00231 {
00232     LONG rv;
00233     DWORD dwStatus = 0;
00234     int i;
00235     UCHAR ucAtr[MAX_ATR_SIZE];
00236     DWORD dwAtrLen = 0;
00237 
00238     rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
00239     if (rv != SCARD_S_SUCCESS)
00240     {
00241         Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader);
00242         return SCARD_F_UNKNOWN_ERROR;
00243     }
00244 
00245     /*
00246      * Find an empty reader slot and insert the new reader
00247      */
00248     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00249     {
00250         if (readerStates[i].readerID == 0)
00251             break;
00252     }
00253 
00254     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
00255         return SCARD_F_INTERNAL_ERROR;
00256 
00257     /*
00258      * Set all the attributes to this reader
00259      */
00260     rContext->readerState = &readerStates[i];
00261     (void)strlcpy(rContext->readerState->readerName, rContext->lpcReader,
00262         sizeof(rContext->readerState->readerName));
00263     memcpy(rContext->readerState->cardAtr, ucAtr, dwAtrLen);
00264     rContext->readerState->readerID = i + 100;
00265     rContext->readerState->readerState = dwStatus;
00266     rContext->readerState->readerSharing = rContext->contexts;
00267     rContext->readerState->cardAtrLength = dwAtrLen;
00268     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00269 
00270     rContext->pthCardEvent = card_event;
00271     rv = ThreadCreate(&rContext->pthThread, 0,
00272         (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
00273     if (rv)
00274     {
00275         Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
00276         return SCARD_E_NO_MEMORY;
00277     }
00278     else
00279         return SCARD_S_SUCCESS;
00280 }
00281 
00282 static void incrementEventCounter(struct pubReaderStatesList *readerState)
00283 {
00284     int counter;
00285 
00286     counter = (readerState -> readerState >> 16) & 0xFFFF;
00287     counter++;
00288     readerState -> readerState = (readerState -> readerState & 0xFFFF)
00289         + (counter << 16);
00290 }
00291 
00292 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
00293 {
00294     LONG rv;
00295     LPCSTR lpcReader;
00296     DWORD dwStatus;
00297     int32_t readerSharing;
00298     DWORD dwCurrentState;
00299     DWORD dwAtrLen;
00300 
00301     /*
00302      * Zero out everything
00303      */
00304     dwStatus = 0;
00305     readerSharing = 0;
00306     dwCurrentState = 0;
00307 
00308     lpcReader = rContext->lpcReader;
00309 
00310     dwAtrLen = rContext->readerState->cardAtrLength;
00311     rv = IFDStatusICC(rContext, &dwStatus, rContext->readerState->cardAtr,
00312         &dwAtrLen);
00313     rContext->readerState->cardAtrLength = dwAtrLen;
00314 
00315     if (dwStatus & SCARD_PRESENT)
00316     {
00317         dwAtrLen = MAX_ATR_SIZE;
00318         rv = IFDPowerICC(rContext, IFD_POWER_UP,
00319             rContext->readerState->cardAtr,
00320             &dwAtrLen);
00321         rContext->readerState->cardAtrLength = dwAtrLen;
00322 
00323         /* the protocol is unset after a power on */
00324         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00325 
00326         if (rv == IFD_SUCCESS)
00327         {
00328             dwStatus |= SCARD_PRESENT;
00329             dwStatus &= ~SCARD_ABSENT;
00330             dwStatus |= SCARD_POWERED;
00331             dwStatus |= SCARD_NEGOTIABLE;
00332             dwStatus &= ~SCARD_SPECIFIC;
00333             dwStatus &= ~SCARD_SWALLOWED;
00334             dwStatus &= ~SCARD_UNKNOWN;
00335 
00336             if (rContext->readerState->cardAtrLength > 0)
00337             {
00338                 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00339                     rContext->readerState->cardAtr,
00340                     rContext->readerState->cardAtrLength);
00341             }
00342             else
00343                 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00344         }
00345         else
00346         {
00347             dwStatus |= SCARD_PRESENT;
00348             dwStatus &= ~SCARD_ABSENT;
00349             dwStatus |= SCARD_SWALLOWED;
00350             dwStatus &= ~SCARD_POWERED;
00351             dwStatus &= ~SCARD_NEGOTIABLE;
00352             dwStatus &= ~SCARD_SPECIFIC;
00353             dwStatus &= ~SCARD_UNKNOWN;
00354             Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
00355         }
00356 
00357         dwCurrentState = SCARD_PRESENT;
00358     }
00359     else
00360     {
00361         dwStatus |= SCARD_ABSENT;
00362         dwStatus &= ~SCARD_PRESENT;
00363         dwStatus &= ~SCARD_POWERED;
00364         dwStatus &= ~SCARD_NEGOTIABLE;
00365         dwStatus &= ~SCARD_SPECIFIC;
00366         dwStatus &= ~SCARD_SWALLOWED;
00367         dwStatus &= ~SCARD_UNKNOWN;
00368         rContext->readerState->cardAtrLength = 0;
00369         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00370 
00371         dwCurrentState = SCARD_ABSENT;
00372     }
00373 
00374     /*
00375      * Set all the public attributes to this reader
00376      */
00377     rContext->readerState->readerState = dwStatus;
00378     rContext->readerState->readerSharing = readerSharing =
00379         rContext->contexts;
00380 
00381     (void)EHSignalEventToClients();
00382 
00383     while (1)
00384     {
00385         dwStatus = 0;
00386 
00387         dwAtrLen = rContext->readerState->cardAtrLength;
00388         rv = IFDStatusICC(rContext, &dwStatus,
00389             rContext->readerState->cardAtr,
00390             &dwAtrLen);
00391         rContext->readerState->cardAtrLength = dwAtrLen;
00392 
00393         if (rv != SCARD_S_SUCCESS)
00394         {
00395             Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);
00396 
00397             /*
00398              * Set error status on this reader while errors occur
00399              */
00400             rContext->readerState->readerState &= ~SCARD_ABSENT;
00401             rContext->readerState->readerState &= ~SCARD_PRESENT;
00402             rContext->readerState->readerState &= ~SCARD_POWERED;
00403             rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00404             rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00405             rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00406             rContext->readerState->readerState |= SCARD_UNKNOWN;
00407             rContext->readerState->cardAtrLength = 0;
00408             rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00409 
00410             dwCurrentState = SCARD_UNKNOWN;
00411 
00412             (void)EHSignalEventToClients();
00413         }
00414 
00415         if (dwStatus & SCARD_ABSENT)
00416         {
00417             if (dwCurrentState == SCARD_PRESENT ||
00418                 dwCurrentState == SCARD_UNKNOWN)
00419             {
00420                 /*
00421                  * Change the status structure
00422                  */
00423                 Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
00424                 /*
00425                  * Notify the card has been removed
00426                  */
00427                 (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
00428 
00429                 rContext->readerState->cardAtrLength = 0;
00430                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00431                 rContext->readerState->readerState |= SCARD_ABSENT;
00432                 rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00433                 rContext->readerState->readerState &= ~SCARD_PRESENT;
00434                 rContext->readerState->readerState &= ~SCARD_POWERED;
00435                 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00436                 rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00437                 rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00438                 dwCurrentState = SCARD_ABSENT;
00439 
00440                 incrementEventCounter(rContext->readerState);
00441 
00442                 (void)EHSignalEventToClients();
00443             }
00444 
00445         }
00446         else if (dwStatus & SCARD_PRESENT)
00447         {
00448             if (dwCurrentState == SCARD_ABSENT ||
00449                 dwCurrentState == SCARD_UNKNOWN)
00450             {
00451                 /*
00452                  * Power and reset the card
00453                  */
00454                 dwAtrLen = MAX_ATR_SIZE;
00455                 rv = IFDPowerICC(rContext, IFD_POWER_UP,
00456                     rContext->readerState->cardAtr,
00457                     &dwAtrLen);
00458                 rContext->readerState->cardAtrLength = dwAtrLen;
00459 
00460                 /* the protocol is unset after a power on */
00461                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00462 
00463                 if (rv == IFD_SUCCESS)
00464                 {
00465                     rContext->readerState->readerState |= SCARD_PRESENT;
00466                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00467                     rContext->readerState->readerState |= SCARD_POWERED;
00468                     rContext->readerState->readerState |= SCARD_NEGOTIABLE;
00469                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00470                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00471                     rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00472                 }
00473                 else
00474                 {
00475                     rContext->readerState->readerState |= SCARD_PRESENT;
00476                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00477                     rContext->readerState->readerState |= SCARD_SWALLOWED;
00478                     rContext->readerState->readerState &= ~SCARD_POWERED;
00479                     rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00480                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00481                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00482                     rContext->readerState->cardAtrLength = 0;
00483                 }
00484 
00485                 dwCurrentState = SCARD_PRESENT;
00486 
00487                 incrementEventCounter(rContext->readerState);
00488 
00489                 Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);
00490 
00491                 (void)EHSignalEventToClients();
00492 
00493                 if (rv == IFD_SUCCESS)
00494                 {
00495                     if (rContext->readerState->cardAtrLength > 0)
00496                     {
00497                         LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00498                             rContext->readerState->cardAtr,
00499                             rContext->readerState->cardAtrLength);
00500                     }
00501                     else
00502                         Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00503                 }
00504                 else
00505                     Log1(PCSC_LOG_ERROR,"Error powering up card.");
00506             }
00507         }
00508 
00509         /*
00510          * Sharing may change w/o an event pass it on
00511          */
00512         if (readerSharing != rContext->contexts)
00513         {
00514             readerSharing = rContext->contexts;
00515             rContext->readerState->readerSharing = readerSharing;
00516             (void)EHSignalEventToClients();
00517         }
00518 
00519         if (rContext->pthCardEvent)
00520         {
00521             int ret;
00522 
00523             ret = rContext->pthCardEvent(rContext->slot);
00524             if (IFD_NO_SUCH_DEVICE == ret)
00525                 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00526         }
00527         else
00528             (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00529 
00530         if (rContext->hLockId == 0xFFFF)
00531         {
00532             /*
00533              * Exit and notify the caller
00534              */
00535             (void)EHSignalEventToClients();
00536             Log1(PCSC_LOG_INFO, "Die");
00537             rContext->hLockId = 0;
00538             (void)pthread_exit(NULL);
00539         }
00540     }
00541 }
00542