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

Generated on Mon Aug 17 01:00:09 2009 for pcsc-lite by  doxygen 1.5.9