pcsc-lite 1.7.2

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 5567 2011-01-29 13:18:49Z 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 "debuglog.h"
00030 #include "readerfactory.h"
00031 #include "eventhandler.h"
00032 #include "dyn_generic.h"
00033 #include "sys_generic.h"
00034 #include "ifdwrapper.h"
00035 #include "prothandler.h"
00036 #include "strlcpycat.h"
00037 #include "utils.h"
00038 #include "winscard_svc.h"
00039 #include "simclist.h"
00040 
00041 static list_t ClientsWaitingForEvent;   
00042 pthread_mutex_t ClientsWaitingForEvent_lock;    
00044 static void EHStatusHandlerThread(READER_CONTEXT *);
00045 
00046 LONG EHRegisterClientForEvent(int32_t filedes)
00047 {
00048     (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
00049 
00050     (void)list_append(&ClientsWaitingForEvent, &filedes);
00051 
00052     (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
00053 
00054     return SCARD_S_SUCCESS;
00055 } /* EHRegisterClientForEvent */
00056 
00061 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
00062 {
00063     LONG rv = SCARD_S_SUCCESS;
00064     int ret;
00065 
00066     (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
00067 
00068     ret = list_delete(&ClientsWaitingForEvent, &filedes);
00069 
00070     (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
00071 
00072     if (ret < 0)
00073         rv = SCARD_F_INTERNAL_ERROR;
00074 
00075     return rv;
00076 } /* EHTryToUnregisterClientForEvent */
00077 
00081 LONG EHUnregisterClientForEvent(int32_t filedes)
00082 {
00083     LONG rv = EHTryToUnregisterClientForEvent(filedes);
00084 
00085     if (rv < 0)
00086         Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
00087 
00088     return rv;
00089 } /* EHUnregisterClientForEvent */
00090 
00094 LONG EHSignalEventToClients(void)
00095 {
00096     LONG rv = SCARD_S_SUCCESS;
00097     int32_t filedes;
00098 
00099     (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
00100 
00101     (void)list_iterator_start(&ClientsWaitingForEvent);
00102     while (list_iterator_hasnext(&ClientsWaitingForEvent))
00103     {
00104         filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
00105         rv = MSGSignalClient(filedes, SCARD_S_SUCCESS);
00106     }
00107     (void)list_iterator_stop(&ClientsWaitingForEvent);
00108 
00109     (void)list_clear(&ClientsWaitingForEvent);
00110 
00111     (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
00112 
00113     return rv;
00114 } /* EHSignalEventToClients */
00115 
00116 LONG EHInitializeEventStructures(void)
00117 {
00118     (void)list_init(&ClientsWaitingForEvent);
00119 
00120     /* request to store copies, and provide the metric function */
00121     (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
00122 
00123     /* setting the comparator, so the list can sort, find the min, max etc */
00124     (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
00125 
00126     (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
00127 
00128     return SCARD_S_SUCCESS;
00129 }
00130 
00131 LONG EHDestroyEventHandler(READER_CONTEXT * rContext)
00132 {
00133     int rv;
00134     DWORD dwGetSize;
00135     UCHAR ucGetData[1];
00136 
00137     if ('\0' == rContext->readerState->readerName[0])
00138     {
00139         Log1(PCSC_LOG_INFO, "Thread already stomped.");
00140         return SCARD_S_SUCCESS;
00141     }
00142 
00143     /*
00144      * Set the thread to 0 to exit thread
00145      */
00146     rContext->hLockId = 0xFFFF;
00147 
00148     Log1(PCSC_LOG_INFO, "Stomping thread.");
00149 
00150     /* kill the "polling" thread */
00151     dwGetSize = sizeof(ucGetData);
00152     rv = IFDGetCapabilities(rContext, TAG_IFD_POLLING_THREAD_KILLABLE,
00153         &dwGetSize, ucGetData);
00154 
00155 #ifdef HAVE_PTHREAD_CANCEL
00156     if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
00157     {
00158         Log1(PCSC_LOG_INFO, "Killing polling thread");
00159         (void)pthread_cancel(rContext->pthThread);
00160     }
00161     else
00162 #endif
00163     {
00164         /* ask to stop the "polling" thread */
00165         RESPONSECODE (*fct)(DWORD) = NULL;
00166 
00167         dwGetSize = sizeof(fct);
00168         rv = IFDGetCapabilities(rContext, TAG_IFD_STOP_POLLING_THREAD,
00169             &dwGetSize, (PUCHAR)&fct);
00170 
00171         if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
00172         {
00173             Log1(PCSC_LOG_INFO, "Request stoping of polling thread");
00174             fct(rContext->slot);
00175         }
00176         else
00177             Log1(PCSC_LOG_INFO, "Waiting polling thread");
00178     }
00179 
00180     /* wait for the thread to finish */
00181     rv = pthread_join(rContext->pthThread, NULL);
00182     if (rv)
00183         Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
00184 
00185     /* Zero the thread */
00186     rContext->pthThread = 0;
00187 
00188     Log1(PCSC_LOG_INFO, "Thread stomped.");
00189 
00190     return SCARD_S_SUCCESS;
00191 }
00192 
00193 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
00194 {
00195     LONG rv;
00196     DWORD dwStatus = 0;
00197 
00198     rv = IFDStatusICC(rContext, &dwStatus);
00199     if (rv != SCARD_S_SUCCESS)
00200     {
00201         Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
00202             rContext->readerState->readerName);
00203         return SCARD_F_UNKNOWN_ERROR;
00204     }
00205 
00206     rv = ThreadCreate(&rContext->pthThread, 0,
00207         (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
00208     if (rv)
00209     {
00210         Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
00211         return SCARD_E_NO_MEMORY;
00212     }
00213     else
00214         return SCARD_S_SUCCESS;
00215 }
00216 
00217 static void EHStatusHandlerThread(READER_CONTEXT * rContext)
00218 {
00219     LONG rv;
00220     const char *readerName;
00221     DWORD dwStatus;
00222     uint32_t readerState;
00223     int32_t readerSharing;
00224     DWORD dwCurrentState;
00225     DWORD dwAtrLen;
00226 
00227     /*
00228      * Zero out everything
00229      */
00230     dwStatus = 0;
00231 
00232     readerName = rContext->readerState->readerName;
00233 
00234     rv = IFDStatusICC(rContext, &dwStatus);
00235 
00236     if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
00237     {
00238 #ifdef DISABLE_AUTO_POWER_ON
00239         rContext->readerState->cardAtrLength = 0;
00240         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00241         readerState = SCARD_PRESENT;
00242         Log1(PCSC_LOG_INFO, "Skip card power on");
00243 #else
00244         dwAtrLen = sizeof(rContext->readerState->cardAtr);
00245         rv = IFDPowerICC(rContext, IFD_POWER_UP,
00246             rContext->readerState->cardAtr, &dwAtrLen);
00247         rContext->readerState->cardAtrLength = dwAtrLen;
00248 
00249         /* the protocol is unset after a power on */
00250         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00251 
00252         if (rv == IFD_SUCCESS)
00253         {
00254             readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
00255             rContext->powerState = POWER_STATE_POWERED;
00256             Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
00257 
00258             if (rContext->readerState->cardAtrLength > 0)
00259             {
00260                 LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00261                     rContext->readerState->cardAtr,
00262                     rContext->readerState->cardAtrLength);
00263             }
00264             else
00265                 Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00266         }
00267         else
00268         {
00269             readerState = SCARD_PRESENT | SCARD_SWALLOWED;
00270             rContext->powerState = POWER_STATE_UNPOWERED;
00271             Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
00272             Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
00273         }
00274 #endif
00275 
00276         dwCurrentState = SCARD_PRESENT;
00277     }
00278     else
00279     {
00280         readerState = SCARD_ABSENT;
00281         rContext->readerState->cardAtrLength = 0;
00282         rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00283 
00284         dwCurrentState = SCARD_ABSENT;
00285     }
00286 
00287     /*
00288      * Set all the public attributes to this reader
00289      */
00290     rContext->readerState->readerState = readerState;
00291     rContext->readerState->readerSharing = readerSharing = rContext->contexts;
00292 
00293     (void)EHSignalEventToClients();
00294 
00295     while (1)
00296     {
00297         dwStatus = 0;
00298 
00299         rv = IFDStatusICC(rContext, &dwStatus);
00300 
00301         if (rv != SCARD_S_SUCCESS)
00302         {
00303             Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
00304 
00305             /*
00306              * Set error status on this reader while errors occur
00307              */
00308             rContext->readerState->readerState = SCARD_UNKNOWN;
00309             rContext->readerState->cardAtrLength = 0;
00310             rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00311 
00312             dwCurrentState = SCARD_UNKNOWN;
00313 
00314             (void)EHSignalEventToClients();
00315         }
00316 
00317         if (dwStatus & SCARD_ABSENT)
00318         {
00319             if (dwCurrentState == SCARD_PRESENT ||
00320                 dwCurrentState == SCARD_UNKNOWN)
00321             {
00322                 /*
00323                  * Change the status structure
00324                  */
00325                 Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
00326                 /*
00327                  * Notify the card has been removed
00328                  */
00329                 (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
00330 
00331                 rContext->readerState->cardAtrLength = 0;
00332                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00333                 rContext->readerState->readerState = SCARD_ABSENT;
00334                 dwCurrentState = SCARD_ABSENT;
00335 
00336                 rContext->readerState->eventCounter++;
00337 
00338                 (void)EHSignalEventToClients();
00339             }
00340 
00341         }
00342         else if (dwStatus & SCARD_PRESENT)
00343         {
00344             if (dwCurrentState == SCARD_ABSENT ||
00345                 dwCurrentState == SCARD_UNKNOWN)
00346             {
00347 #ifdef DISABLE_AUTO_POWER_ON
00348                 rContext->readerState->cardAtrLength = 0;
00349                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00350                 rContext->readerState->readerState = SCARD_PRESENT;
00351                 rContext->powerState = POWER_STATE_UNPOWERED;
00352                 Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
00353                 readerState = SCARD_PRESENT;
00354                 rv = IFD_SUCCESS;
00355                 Log1(PCSC_LOG_INFO, "Skip card power on");
00356 #else
00357                 /*
00358                  * Power and reset the card
00359                  */
00360                 dwAtrLen = sizeof(rContext->readerState->cardAtr);
00361                 rv = IFDPowerICC(rContext, IFD_POWER_UP,
00362                     rContext->readerState->cardAtr, &dwAtrLen);
00363                 rContext->readerState->cardAtrLength = dwAtrLen;
00364 
00365                 /* the protocol is unset after a power on */
00366                 rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00367 
00368                 if (rv == IFD_SUCCESS)
00369                 {
00370                     rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
00371                     rContext->powerState = POWER_STATE_POWERED;
00372                     Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
00373                 }
00374                 else
00375                 {
00376                     rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
00377                     rContext->powerState = POWER_STATE_UNPOWERED;
00378                     Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
00379                     rContext->readerState->cardAtrLength = 0;
00380                 }
00381 #endif
00382 
00383                 dwCurrentState = SCARD_PRESENT;
00384 
00385                 rContext->readerState->eventCounter++;
00386 
00387                 Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
00388 
00389                 (void)EHSignalEventToClients();
00390 
00391                 if (rv == IFD_SUCCESS)
00392                 {
00393                     if (rContext->readerState->cardAtrLength > 0)
00394                     {
00395                         LogXxd(PCSC_LOG_INFO, "Card ATR: ",
00396                             rContext->readerState->cardAtr,
00397                             rContext->readerState->cardAtrLength);
00398                     }
00399                     else
00400                         Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
00401                 }
00402                 else
00403                     Log1(PCSC_LOG_ERROR,"Error powering up card.");
00404             }
00405         }
00406 
00407         /*
00408          * Sharing may change w/o an event pass it on
00409          */
00410         if (readerSharing != rContext->contexts)
00411         {
00412             readerSharing = rContext->contexts;
00413             rContext->readerState->readerSharing = readerSharing;
00414             (void)EHSignalEventToClients();
00415         }
00416 
00417         if (rContext->pthCardEvent)
00418         {
00419             int ret;
00420             int timeout;
00421 
00422 #ifndef DISABLE_ON_DEMAND_POWER_ON
00423             if (POWER_STATE_POWERED == rContext->powerState)
00424                 /* The card is powered but not yet used */
00425                 timeout = PCSCLITE_POWER_OFF_GRACE_PERIOD;
00426             else
00427                 /* The card is already in use or not used at all */
00428 #endif
00429                 timeout = PCSCLITE_STATUS_EVENT_TIMEOUT;
00430 
00431             ret = rContext->pthCardEvent(rContext->slot, timeout);
00432             if (IFD_NO_SUCH_DEVICE == ret)
00433                 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00434         }
00435         else
00436             (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
00437 
00438 #ifndef DISABLE_ON_DEMAND_POWER_ON
00439         /* the card is powered but not used */
00440         (void)pthread_mutex_lock(&rContext->powerState_lock);
00441         if (POWER_STATE_POWERED == rContext->powerState)
00442         {
00443             /* power down */
00444             IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
00445             rContext->powerState = POWER_STATE_UNPOWERED;
00446             Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
00447 
00448             /* the protocol is unset after a power down */
00449             rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
00450         }
00451 
00452         /* the card was in use */
00453         if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
00454         {
00455             /* the next state should be UNPOWERED unless the
00456              * card is used again */
00457             rContext->powerState = POWER_STATE_POWERED;
00458             Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
00459         }
00460         (void)pthread_mutex_unlock(&rContext->powerState_lock);
00461 #endif
00462 
00463         if (rContext->hLockId == 0xFFFF)
00464         {
00465             /*
00466              * Exit and notify the caller
00467              */
00468             (void)EHSignalEventToClients();
00469             Log1(PCSC_LOG_INFO, "Die");
00470             rContext->hLockId = 0;
00471             (void)pthread_exit(NULL);
00472         }
00473     }
00474 }
00475