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

Generated on Thu Aug 28 20:14:31 2008 for pcsc-lite by  doxygen 1.5.6