eventhandler.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2000
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2004
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  *
00009  * $Id: eventhandler.c 2613 2007-08-13 07:13:30Z 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 
00026 #include "misc.h"
00027 #include "pcscd.h"
00028 #include "ifdhandler.h"
00029 #include "debuglog.h"
00030 #include "thread_generic.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 
00039 static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
00040 
00041 void EHStatusHandlerThread(PREADER_CONTEXT);
00042 
00043 LONG EHInitializeEventStructures(void)
00044 {
00045     int fd, i, pageSize;
00046 
00047     fd = 0;
00048     i = 0;
00049     pageSize = 0;
00050 
00051     SYS_RemoveFile(PCSCLITE_PUBSHM_FILE);
00052 
00053     fd = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDWR | O_CREAT, 00644);
00054     if (fd < 0)
00055     {
00056         Log3(PCSC_LOG_CRITICAL, "Cannot create public shared file %s: %s",
00057             PCSCLITE_PUBSHM_FILE, strerror(errno));
00058         exit(1);
00059     }
00060 
00061     SYS_Chmod(PCSCLITE_PUBSHM_FILE,
00062         S_IRGRP | S_IREAD | S_IWRITE | S_IROTH);
00063 
00064     pageSize = SYS_GetPageSize();
00065 
00066     /*
00067      * Jump to end of file space and allocate zero's
00068      */
00069     SYS_SeekFile(fd, pageSize * PCSCLITE_MAX_READERS_CONTEXTS);
00070     SYS_WriteFile(fd, "", 1);
00071 
00072     /*
00073      * Allocate each reader structure
00074      */
00075     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00076     {
00077         readerStates[i] = (PREADER_STATE)
00078             SYS_MemoryMap(sizeof(READER_STATE), fd, (i * pageSize));
00079         if (readerStates[i] == MAP_FAILED)
00080         {
00081             Log3(PCSC_LOG_CRITICAL, "Cannot memory map public shared file %s: %s",
00082                 PCSCLITE_PUBSHM_FILE, strerror(errno));
00083             exit(1);
00084         }
00085 
00086         /*
00087          * Zero out each value in the struct
00088          */
00089         memset((readerStates[i])->readerName, 0, MAX_READERNAME);
00090         memset((readerStates[i])->cardAtr, 0, MAX_ATR_SIZE);
00091         (readerStates[i])->readerID = 0;
00092         (readerStates[i])->readerState = 0;
00093         (readerStates[i])->readerSharing = 0;
00094         (readerStates[i])->cardAtrLength = 0;
00095         (readerStates[i])->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00096     }
00097 
00098     return SCARD_S_SUCCESS;
00099 }
00100 
00101 LONG EHDestroyEventHandler(PREADER_CONTEXT rContext)
00102 {
00103     if (NULL == rContext->readerState)
00104     {
00105         Log1(PCSC_LOG_ERROR, "Thread never started (reader init failed?)");
00106         return SCARD_S_SUCCESS;
00107     }
00108 
00109     if ('\0' == rContext->readerState->readerName[0])
00110     {
00111         Log1(PCSC_LOG_INFO, "Thread already stomped.");
00112         return SCARD_S_SUCCESS;
00113     }
00114 
00115     /*
00116      * Set the thread to 0 to exit thread
00117      */
00118     rContext->dwLockId = 0xFFFF;
00119 
00120     Log1(PCSC_LOG_INFO, "Stomping thread.");
00121 
00122     do
00123     {
00124         /*
00125          * Wait 0.05 seconds for the child to respond
00126          */
00127         SYS_USleep(50000);
00128     }
00129     while (rContext->dwLockId == 0xFFFF);
00130     /*
00131      * Zero out the public status struct to allow it to be recycled and
00132      * used again
00133      */
00134 
00135     memset(rContext->readerState->readerName, 0,
00136         sizeof(rContext->readerState->readerName));
00137     memset(rContext->readerState->cardAtr, 0,
00138         sizeof(rContext->readerState->cardAtr));
00139     rContext->readerState->readerID = 0;
00140     rContext->readerState->readerState = 0;
00141     rContext->readerState->readerSharing = 0;
00142     rContext->readerState->cardAtrLength = 0;
00143     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00144 
00145     /* Zero the thread */
00146     rContext->pthThread = 0;
00147 
00148     Log1(PCSC_LOG_INFO, "Thread stomped.");
00149 
00150     return SCARD_S_SUCCESS;
00151 }
00152 
00153 LONG EHSpawnEventHandler(PREADER_CONTEXT rContext)
00154 {
00155     LONG rv;
00156     DWORD dwStatus = 0;
00157     int i;
00158     UCHAR ucAtr[MAX_ATR_SIZE];
00159     DWORD dwAtrLen = 0;
00160 
00161     rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
00162     if (rv != SCARD_S_SUCCESS)
00163     {
00164         Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader);
00165         return SCARD_F_UNKNOWN_ERROR;
00166     }
00167 
00168     /*
00169      * Find an empty reader slot and insert the new reader
00170      */
00171     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00172     {
00173         if ((readerStates[i])->readerID == 0)
00174             break;
00175     }
00176 
00177     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
00178         return SCARD_F_INTERNAL_ERROR;
00179 
00180     /*
00181      * Set all the attributes to this reader
00182      */
00183     rContext->readerState = readerStates[i];
00184     strlcpy(rContext->readerState->readerName, rContext->lpcReader,
00185         sizeof(rContext->readerState->readerName));
00186     memcpy(rContext->readerState->cardAtr, ucAtr, dwAtrLen);
00187     rContext->readerState->readerID = i + 100;
00188     rContext->readerState->readerState = dwStatus;
00189     rContext->readerState->readerSharing = rContext->dwContexts;
00190     rContext->readerState->cardAtrLength = dwAtrLen;
00191     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00192 
00193     rv = SYS_ThreadCreate(&rContext->pthThread, THREAD_ATTR_DETACHED,
00194         (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
00195     if (rv == 1)
00196         return SCARD_S_SUCCESS;
00197     else
00198         return SCARD_E_NO_MEMORY;
00199 }
00200 
00201 static void incrementEventCounter(struct pubReaderStatesList *readerState)
00202 {
00203     int counter;
00204 
00205     counter = (readerState -> readerState >> 16) & 0xFFFF;
00206     counter++;
00207     readerState -> readerState = (readerState -> readerState & 0xFFFF)
00208         + (counter << 16);
00209 }
00210 
00211 void EHStatusHandlerThread(PREADER_CONTEXT rContext)
00212 {
00213     LONG rv;
00214     LPCSTR lpcReader;
00215     DWORD dwStatus, dwReaderSharing;
00216     DWORD dwCurrentState;
00217     int pageSize;
00218 
00219     /*
00220      * Zero out everything
00221      */
00222     dwStatus = 0;
00223     dwReaderSharing = 0;
00224     dwCurrentState = 0;
00225 
00226     lpcReader = rContext->lpcReader;
00227 
00228     pageSize = SYS_GetPageSize();
00229 
00230     rv = IFDStatusICC(rContext, &dwStatus, rContext->readerState->cardAtr,
00231             &rContext->readerState->cardAtrLength);
00232     if (dwStatus & SCARD_PRESENT)
00233     {
00234         rContext->readerState->cardAtrLength = MAX_ATR_SIZE;
00235         rv = IFDPowerICC(rContext, IFD_POWER_UP,
00236             rContext->readerState->cardAtr,
00237             &rContext->readerState->cardAtrLength);
00238 
00239         /* the protocol is unset after a power on */
00240         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00241 
00242         if (rv == IFD_SUCCESS)
00243         {
00244             dwStatus |= SCARD_PRESENT;
00245             dwStatus &= ~SCARD_ABSENT;
00246             dwStatus |= SCARD_POWERED;
00247             dwStatus |= SCARD_NEGOTIABLE;
00248             dwStatus &= ~SCARD_SPECIFIC;
00249             dwStatus &= ~SCARD_SWALLOWED;
00250             dwStatus &= ~SCARD_UNKNOWN;
00251 
00252             if (rContext->readerState->cardAtrLength > 0)
00253             {
00254                 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00255                     rContext->readerState->cardAtr,
00256                     rContext->readerState->cardAtrLength);
00257             }
00258             else
00259                 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00260         }
00261         else
00262         {
00263             dwStatus |= SCARD_PRESENT;
00264             dwStatus &= ~SCARD_ABSENT;
00265             dwStatus |= SCARD_SWALLOWED;
00266             dwStatus &= ~SCARD_POWERED;
00267             dwStatus &= ~SCARD_NEGOTIABLE;
00268             dwStatus &= ~SCARD_SPECIFIC;
00269             dwStatus &= ~SCARD_UNKNOWN;
00270             Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
00271         }
00272 
00273         dwCurrentState = SCARD_PRESENT;
00274     }
00275     else
00276     {
00277         dwStatus |= SCARD_ABSENT;
00278         dwStatus &= ~SCARD_PRESENT;
00279         dwStatus &= ~SCARD_POWERED;
00280         dwStatus &= ~SCARD_NEGOTIABLE;
00281         dwStatus &= ~SCARD_SPECIFIC;
00282         dwStatus &= ~SCARD_SWALLOWED;
00283         dwStatus &= ~SCARD_UNKNOWN;
00284         rContext->readerState->cardAtrLength = 0;
00285         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00286 
00287         dwCurrentState = SCARD_ABSENT;
00288     }
00289 
00290     /*
00291      * Set all the public attributes to this reader
00292      */
00293     rContext->readerState->readerState = dwStatus;
00294     rContext->readerState->readerSharing = dwReaderSharing =
00295         rContext->dwContexts;
00296 
00297     SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00298 
00299     while (1)
00300     {
00301         dwStatus = 0;
00302 
00303         rv = IFDStatusICC(rContext, &dwStatus,
00304             rContext->readerState->cardAtr,
00305             &rContext->readerState->cardAtrLength);
00306 
00307         if (rv != SCARD_S_SUCCESS)
00308         {
00309             Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);
00310 
00311             /*
00312              * Set error status on this reader while errors occur
00313              */
00314 
00315             rContext->readerState->readerState &= ~SCARD_ABSENT;
00316             rContext->readerState->readerState &= ~SCARD_PRESENT;
00317             rContext->readerState->readerState &= ~SCARD_POWERED;
00318             rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00319             rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00320             rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00321             rContext->readerState->readerState |= SCARD_UNKNOWN;
00322             rContext->readerState->cardAtrLength = 0;
00323             rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00324 
00325             dwCurrentState = SCARD_UNKNOWN;
00326 
00327             SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00328 
00329             /*
00330              * This code causes race conditions on G4's with USB
00331              * insertion
00332              */
00333             /*
00334              * dwErrorCount += 1; SYS_Sleep(1);
00335              */
00336             /*
00337              * After 10 seconds of errors, try to reinitialize the reader
00338              * This sometimes helps bring readers out of *crazy* states.
00339              */
00340             /*
00341              * if ( dwErrorCount == 10 ) { RFUnInitializeReader( rContext
00342              * ); RFInitializeReader( rContext ); dwErrorCount = 0; }
00343              */
00344 
00345             /*
00346              * End of race condition code block
00347              */
00348         }
00349 
00350         if (dwStatus & SCARD_ABSENT)
00351         {
00352             if (dwCurrentState == SCARD_PRESENT ||
00353                 dwCurrentState == SCARD_UNKNOWN)
00354             {
00355                 /*
00356                  * Change the status structure
00357                  */
00358                 Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
00359                 /*
00360                  * Notify the card has been removed
00361                  */
00362                 RFSetReaderEventState(rContext, SCARD_REMOVED);
00363 
00364                 rContext->readerState->cardAtrLength = 0;
00365                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00366                 rContext->readerState->readerState |= SCARD_ABSENT;
00367                 rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00368                 rContext->readerState->readerState &= ~SCARD_PRESENT;
00369                 rContext->readerState->readerState &= ~SCARD_POWERED;
00370                 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00371                 rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00372                 rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00373                 dwCurrentState = SCARD_ABSENT;
00374 
00375                 incrementEventCounter(rContext->readerState);
00376 
00377                 SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00378             }
00379 
00380         }
00381         else if (dwStatus & SCARD_PRESENT)
00382         {
00383             if (dwCurrentState == SCARD_ABSENT ||
00384                 dwCurrentState == SCARD_UNKNOWN)
00385             {
00386                 /*
00387                  * Power and reset the card
00388                  */
00389                 SYS_USleep(PCSCLITE_STATUS_WAIT);
00390                 rContext->readerState->cardAtrLength = MAX_ATR_SIZE;
00391                 rv = IFDPowerICC(rContext, IFD_POWER_UP,
00392                     rContext->readerState->cardAtr,
00393                     &rContext->readerState->cardAtrLength);
00394 
00395                 /* the protocol is unset after a power on */
00396                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00397 
00398                 if (rv == IFD_SUCCESS)
00399                 {
00400                     rContext->readerState->readerState |= SCARD_PRESENT;
00401                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00402                     rContext->readerState->readerState |= SCARD_POWERED;
00403                     rContext->readerState->readerState |= SCARD_NEGOTIABLE;
00404                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00405                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00406                     rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00407 
00408                     /*
00409                      * Notify the card has been reset
00410                      */
00411                     RFSetReaderEventState(rContext, SCARD_RESET);
00412                 }
00413                 else
00414                 {
00415                     rContext->readerState->readerState |= SCARD_PRESENT;
00416                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00417                     rContext->readerState->readerState |= SCARD_SWALLOWED;
00418                     rContext->readerState->readerState &= ~SCARD_POWERED;
00419                     rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00420                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00421                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00422                     rContext->readerState->cardAtrLength = 0;
00423                 }
00424 
00425                 dwCurrentState = SCARD_PRESENT;
00426 
00427                 incrementEventCounter(rContext->readerState);
00428 
00429                 SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00430 
00431                 Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);
00432 
00433                 if (rv == IFD_SUCCESS)
00434                 {
00435                     if (rContext->readerState->cardAtrLength > 0)
00436                     {
00437                         LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00438                             rContext->readerState->cardAtr,
00439                             rContext->readerState->cardAtrLength);
00440                     }
00441                     else
00442                         Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00443                 }
00444                 else
00445                     Log1(PCSC_LOG_ERROR,"Error powering up card.");
00446             }
00447         }
00448 
00449         if (rContext->dwLockId == 0xFFFF)
00450         {
00451             /*
00452              * Exit and notify the caller
00453              */
00454             rContext->dwLockId = 0;
00455             SYS_ThreadDetach(rContext->pthThread);
00456             SYS_ThreadExit(NULL);
00457         }
00458 
00459         /*
00460          * Sharing may change w/o an event pass it on
00461          */
00462 
00463         if (dwReaderSharing != rContext->dwContexts)
00464         {
00465             dwReaderSharing = rContext->dwContexts;
00466             rContext->readerState->readerSharing = dwReaderSharing;
00467             SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00468         }
00469 
00470         SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00471     }
00472 }
00473 

Generated on Thu Jul 15 08:33:23 2010 for pcsc-lite by  doxygen 1.4.7