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 2917 2008-04-29 14:08:13Z 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     /* kill the "polling" thread */
00123     SYS_ThreadCancel(rContext->pthThread);
00124 
00125     /* wait for the thread to finish */
00126     SYS_ThreadJoin(rContext->pthThread, NULL);
00127 
00128     /*
00129      * Zero out the public status struct to allow it to be recycled and
00130      * used again
00131      */
00132     memset(rContext->readerState->readerName, 0,
00133         sizeof(rContext->readerState->readerName));
00134     memset(rContext->readerState->cardAtr, 0,
00135         sizeof(rContext->readerState->cardAtr));
00136     rContext->readerState->readerID = 0;
00137     rContext->readerState->readerState = 0;
00138     rContext->readerState->readerSharing = 0;
00139     rContext->readerState->cardAtrLength = 0;
00140     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00141 
00142     /* Zero the thread */
00143     rContext->pthThread = 0;
00144 
00145     Log1(PCSC_LOG_INFO, "Thread stomped.");
00146 
00147     return SCARD_S_SUCCESS;
00148 }
00149 
00150 LONG EHSpawnEventHandler(PREADER_CONTEXT rContext,
00151     RESPONSECODE (*card_event)(DWORD))
00152 {
00153     LONG rv;
00154     DWORD dwStatus = 0;
00155     int i;
00156     UCHAR ucAtr[MAX_ATR_SIZE];
00157     DWORD dwAtrLen = 0;
00158 
00159     rv = IFDStatusICC(rContext, &dwStatus, ucAtr, &dwAtrLen);
00160     if (rv != SCARD_S_SUCCESS)
00161     {
00162         Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s", rContext->lpcReader);
00163         return SCARD_F_UNKNOWN_ERROR;
00164     }
00165 
00166     /*
00167      * Find an empty reader slot and insert the new reader
00168      */
00169     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00170     {
00171         if ((readerStates[i])->readerID == 0)
00172             break;
00173     }
00174 
00175     if (i == PCSCLITE_MAX_READERS_CONTEXTS)
00176         return SCARD_F_INTERNAL_ERROR;
00177 
00178     /*
00179      * Set all the attributes to this reader
00180      */
00181     rContext->readerState = readerStates[i];
00182     strlcpy(rContext->readerState->readerName, rContext->lpcReader,
00183         sizeof(rContext->readerState->readerName));
00184     memcpy(rContext->readerState->cardAtr, ucAtr, dwAtrLen);
00185     rContext->readerState->readerID = i + 100;
00186     rContext->readerState->readerState = dwStatus;
00187     rContext->readerState->readerSharing = rContext->dwContexts;
00188     rContext->readerState->cardAtrLength = dwAtrLen;
00189     rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00190 
00191     rContext->pthCardEvent = card_event;
00192     rv = SYS_ThreadCreate(&rContext->pthThread, THREAD_ATTR_DETACHED,
00193         (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
00194     if (rv == 1)
00195         return SCARD_S_SUCCESS;
00196     else
00197         return SCARD_E_NO_MEMORY;
00198 }
00199 
00200 static void incrementEventCounter(struct pubReaderStatesList *readerState)
00201 {
00202     int counter;
00203 
00204     counter = (readerState -> readerState >> 16) & 0xFFFF;
00205     counter++;
00206     readerState -> readerState = (readerState -> readerState & 0xFFFF)
00207         + (counter << 16);
00208 }
00209 
00210 void EHStatusHandlerThread(PREADER_CONTEXT rContext)
00211 {
00212     LONG rv;
00213     LPCSTR lpcReader;
00214     DWORD dwStatus, dwReaderSharing;
00215     DWORD dwCurrentState;
00216     DWORD dwAtrLen;
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     dwAtrLen = rContext->readerState->cardAtrLength;
00231     rv = IFDStatusICC(rContext, &dwStatus, rContext->readerState->cardAtr,
00232         &dwAtrLen);
00233     rContext->readerState->cardAtrLength = dwAtrLen;
00234 
00235     if (dwStatus & SCARD_PRESENT)
00236     {
00237         dwAtrLen = MAX_ATR_SIZE;
00238         rv = IFDPowerICC(rContext, IFD_POWER_UP,
00239             rContext->readerState->cardAtr,
00240             &dwAtrLen);
00241         rContext->readerState->cardAtrLength = dwAtrLen;
00242 
00243         /* the protocol is unset after a power on */
00244         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00245 
00246         if (rv == IFD_SUCCESS)
00247         {
00248             dwStatus |= SCARD_PRESENT;
00249             dwStatus &= ~SCARD_ABSENT;
00250             dwStatus |= SCARD_POWERED;
00251             dwStatus |= SCARD_NEGOTIABLE;
00252             dwStatus &= ~SCARD_SPECIFIC;
00253             dwStatus &= ~SCARD_SWALLOWED;
00254             dwStatus &= ~SCARD_UNKNOWN;
00255 
00256             if (rContext->readerState->cardAtrLength > 0)
00257             {
00258                 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00259                     rContext->readerState->cardAtr,
00260                     rContext->readerState->cardAtrLength);
00261             }
00262             else
00263                 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00264         }
00265         else
00266         {
00267             dwStatus |= SCARD_PRESENT;
00268             dwStatus &= ~SCARD_ABSENT;
00269             dwStatus |= SCARD_SWALLOWED;
00270             dwStatus &= ~SCARD_POWERED;
00271             dwStatus &= ~SCARD_NEGOTIABLE;
00272             dwStatus &= ~SCARD_SPECIFIC;
00273             dwStatus &= ~SCARD_UNKNOWN;
00274             Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
00275         }
00276 
00277         dwCurrentState = SCARD_PRESENT;
00278     }
00279     else
00280     {
00281         dwStatus |= SCARD_ABSENT;
00282         dwStatus &= ~SCARD_PRESENT;
00283         dwStatus &= ~SCARD_POWERED;
00284         dwStatus &= ~SCARD_NEGOTIABLE;
00285         dwStatus &= ~SCARD_SPECIFIC;
00286         dwStatus &= ~SCARD_SWALLOWED;
00287         dwStatus &= ~SCARD_UNKNOWN;
00288         rContext->readerState->cardAtrLength = 0;
00289         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00290 
00291         dwCurrentState = SCARD_ABSENT;
00292     }
00293 
00294     /*
00295      * Set all the public attributes to this reader
00296      */
00297     rContext->readerState->readerState = dwStatus;
00298     rContext->readerState->readerSharing = dwReaderSharing =
00299         rContext->dwContexts;
00300 
00301     SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00302 
00303     while (1)
00304     {
00305         dwStatus = 0;
00306 
00307         dwAtrLen = rContext->readerState->cardAtrLength;
00308         rv = IFDStatusICC(rContext, &dwStatus,
00309             rContext->readerState->cardAtr,
00310             &dwAtrLen);
00311         rContext->readerState->cardAtrLength = dwAtrLen;
00312 
00313         if (rv != SCARD_S_SUCCESS)
00314         {
00315             Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);
00316 
00317             /*
00318              * Set error status on this reader while errors occur
00319              */
00320 
00321             rContext->readerState->readerState &= ~SCARD_ABSENT;
00322             rContext->readerState->readerState &= ~SCARD_PRESENT;
00323             rContext->readerState->readerState &= ~SCARD_POWERED;
00324             rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00325             rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00326             rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00327             rContext->readerState->readerState |= SCARD_UNKNOWN;
00328             rContext->readerState->cardAtrLength = 0;
00329             rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00330 
00331             dwCurrentState = SCARD_UNKNOWN;
00332 
00333             SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00334 
00335             /*
00336              * This code causes race conditions on G4's with USB
00337              * insertion
00338              */
00339             /*
00340              * dwErrorCount += 1; SYS_Sleep(1);
00341              */
00342             /*
00343              * After 10 seconds of errors, try to reinitialize the reader
00344              * This sometimes helps bring readers out of *crazy* states.
00345              */
00346             /*
00347              * if ( dwErrorCount == 10 ) { RFUnInitializeReader( rContext
00348              * ); RFInitializeReader( rContext ); dwErrorCount = 0; }
00349              */
00350 
00351             /*
00352              * End of race condition code block
00353              */
00354         }
00355 
00356         if (dwStatus & SCARD_ABSENT)
00357         {
00358             if (dwCurrentState == SCARD_PRESENT ||
00359                 dwCurrentState == SCARD_UNKNOWN)
00360             {
00361                 /*
00362                  * Change the status structure
00363                  */
00364                 Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
00365                 /*
00366                  * Notify the card has been removed
00367                  */
00368                 RFSetReaderEventState(rContext, SCARD_REMOVED);
00369 
00370                 rContext->readerState->cardAtrLength = 0;
00371                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00372                 rContext->readerState->readerState |= SCARD_ABSENT;
00373                 rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00374                 rContext->readerState->readerState &= ~SCARD_PRESENT;
00375                 rContext->readerState->readerState &= ~SCARD_POWERED;
00376                 rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00377                 rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00378                 rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00379                 dwCurrentState = SCARD_ABSENT;
00380 
00381                 incrementEventCounter(rContext->readerState);
00382 
00383                 SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00384             }
00385 
00386         }
00387         else if (dwStatus & SCARD_PRESENT)
00388         {
00389             if (dwCurrentState == SCARD_ABSENT ||
00390                 dwCurrentState == SCARD_UNKNOWN)
00391             {
00392                 /*
00393                  * Power and reset the card
00394                  */
00395                 dwAtrLen = MAX_ATR_SIZE;
00396                 rv = IFDPowerICC(rContext, IFD_POWER_UP,
00397                     rContext->readerState->cardAtr,
00398                     &dwAtrLen);
00399                 rContext->readerState->cardAtrLength = dwAtrLen;
00400 
00401                 /* the protocol is unset after a power on */
00402                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00403 
00404                 if (rv == IFD_SUCCESS)
00405                 {
00406                     rContext->readerState->readerState |= SCARD_PRESENT;
00407                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00408                     rContext->readerState->readerState |= SCARD_POWERED;
00409                     rContext->readerState->readerState |= SCARD_NEGOTIABLE;
00410                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00411                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00412                     rContext->readerState->readerState &= ~SCARD_SWALLOWED;
00413                 }
00414                 else
00415                 {
00416                     rContext->readerState->readerState |= SCARD_PRESENT;
00417                     rContext->readerState->readerState &= ~SCARD_ABSENT;
00418                     rContext->readerState->readerState |= SCARD_SWALLOWED;
00419                     rContext->readerState->readerState &= ~SCARD_POWERED;
00420                     rContext->readerState->readerState &= ~SCARD_NEGOTIABLE;
00421                     rContext->readerState->readerState &= ~SCARD_SPECIFIC;
00422                     rContext->readerState->readerState &= ~SCARD_UNKNOWN;
00423                     rContext->readerState->cardAtrLength = 0;
00424                 }
00425 
00426                 dwCurrentState = SCARD_PRESENT;
00427 
00428                 incrementEventCounter(rContext->readerState);
00429 
00430                 SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00431 
00432                 Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);
00433 
00434                 if (rv == IFD_SUCCESS)
00435                 {
00436                     if (rContext->readerState->cardAtrLength > 0)
00437                     {
00438                         LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00439                             rContext->readerState->cardAtr,
00440                             rContext->readerState->cardAtrLength);
00441                     }
00442                     else
00443                         Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00444                 }
00445                 else
00446                     Log1(PCSC_LOG_ERROR,"Error powering up card.");
00447             }
00448         }
00449 
00450         /*
00451          * Sharing may change w/o an event pass it on
00452          */
00453 
00454         if (dwReaderSharing != rContext->dwContexts)
00455         {
00456             dwReaderSharing = rContext->dwContexts;
00457             rContext->readerState->readerSharing = dwReaderSharing;
00458             SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
00459         }
00460 
00461         if (rContext->pthCardEvent)
00462         {
00463             int ret;
00464             
00465             ret = rContext->pthCardEvent(rContext->dwSlot);
00466             if (IFD_NO_SUCH_DEVICE == ret)
00467                 SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00468         }
00469         else
00470             SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00471 
00472         if (rContext->dwLockId == 0xFFFF)
00473         {
00474             /*
00475              * Exit and notify the caller
00476              */
00477             Log1(PCSC_LOG_CRITICAL, "Die");
00478             rContext->dwLockId = 0;
00479             SYS_ThreadDetach(rContext->pthThread);
00480             SYS_ThreadExit(NULL);
00481         }
00482     }
00483 }
00484 

Generated on Wed Apr 30 17:11:41 2008 for pcsc-lite by  doxygen 1.5.5