108#include <sys/types.h>
137static bool sharing_shall_block =
true;
139#define COLOR_RED "\33[01;31m"
140#define COLOR_GREEN "\33[32m"
141#define COLOR_BLUE "\33[34m"
142#define COLOR_MAGENTA "\33[35m"
143#define COLOR_NORMAL "\33[0m"
150static void trace(
const char *func,
const char direction,
const char *fmt, ...)
154 fprintf(stderr, COLOR_GREEN
"%c " COLOR_BLUE
"[%lX] " COLOR_GREEN
"%s ",
155 direction, pthread_self(), func);
157 fprintf(stderr, COLOR_MAGENTA);
159 vfprintf(stderr, fmt, args);
162 fprintf(stderr, COLOR_NORMAL
"\n");
165#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
166#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
168#define API_TRACE_IN(...)
169#define API_TRACE_OUT(...)
174#define PROFILE_FILE "/tmp/pcsc_profile"
180pthread_t threads[MAX_THREADS];
181struct timeval profile_time_start[MAX_THREADS];
185#define PROFILE_START profile_start();
186#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
188static void profile_start(
void)
190 static bool initialized =
false;
199 sprintf(filename,
"%s-%d", PROFILE_FILE, getuid());
200 profile_fd = fopen(filename,
"a+");
201 if (NULL == profile_fd)
203 fprintf(stderr, COLOR_RED
"Can't open %s: %s" COLOR_NORMAL
"\n",
204 PROFILE_FILE, strerror(errno));
207 fprintf(profile_fd,
"\nStart a new profile\n");
209 if (isatty(fileno(stderr)))
216 for (i=0; i<MAX_THREADS; i++)
217 if (pthread_equal(0, threads[i]))
223 gettimeofday(&profile_time_start[i], NULL);
226static void profile_end(
const char *f, LONG rv)
228 struct timeval profile_time_end;
233 gettimeofday(&profile_time_end, NULL);
236 for (i=0; i<MAX_THREADS; i++)
237 if (pthread_equal(t, threads[i]))
242 fprintf(stderr, COLOR_BLUE
" WARNING: no start info for %s\n", f);
246 d =
time_sub(&profile_time_end, &profile_time_start[i]);
254 COLOR_RED
"RESULT %s " COLOR_MAGENTA
"%ld "
255 COLOR_BLUE
"0x%08lX" COLOR_NORMAL
"\n",
258 fprintf(profile_fd,
"%s %ld\n", f, d);
264#define PROFILE_END(rv)
279static int CHANNEL_MAP_seeker(
const void *el,
const void *key)
281 const CHANNEL_MAP * channelMap = el;
283 if ((el == NULL) || (key == NULL))
285 Log3(PCSC_LOG_CRITICAL,
286 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
317static list_t contextMapList;
320static int SCONTEXTMAP_seeker(
const void *el,
const void *key)
324 if ((el == NULL) || (key == NULL))
326 Log3(PCSC_LOG_CRITICAL,
327 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
342static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
355static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
365static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE,
367static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE,
371static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
372 LPBYTE pbAttr, LPDWORD pcbAttrLen);
374static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents);
375static LONG getReaderStates(
SCONTEXTMAP * currentContextMap);
376static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap);
377static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap);
420 return currentContextMap != NULL;
462 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
466 API_TRACE_IN(
"%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
476 pvReserved2, phContext);
481 API_TRACE_OUT(
"%ld", *phContext)
487DESTRUCTOR
static void destructor(
void)
490 list_destroy(&contextMapList);
501static void init_lib(
void)
508 lrv = list_init(&contextMapList);
511 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d",
516 lrv = list_attributes_seeker(&contextMapList,
520 Log2(PCSC_LOG_CRITICAL,
521 "list_attributes_seeker failed with return value: %d", lrv);
522 list_destroy(&contextMapList);
528 Log1(PCSC_LOG_INFO,
"Disable shared blocking");
529 sharing_shall_block =
false;
566 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
570 uint32_t dwClientID = 0;
574 if (phContext == NULL)
579 pthread_once(&init_lib_control, init_lib);
605 Log1(PCSC_LOG_CRITICAL,
606 "Your pcscd is too old and does not support CMD_VERSION");
610 Log3(PCSC_LOG_INFO,
"Server is protocol version %d:%d",
624 scEstablishStruct.dwScope = dwScope;
625 scEstablishStruct.hContext = 0;
629 sizeof(scEstablishStruct), (
void *) &scEstablishStruct);
637 rv =
MessageReceive(&scEstablishStruct,
sizeof(scEstablishStruct),
645 rv = scEstablishStruct.rv;
655 *phContext = scEstablishStruct.hContext;
697 API_TRACE_IN(
"%ld", hContext)
705 if (NULL == currentContextMap)
711 scReleaseStruct.hContext = hContext;
715 currentContextMap->dwClientID,
716 sizeof(scReleaseStruct), (
void *) &scReleaseStruct);
725 currentContextMap->dwClientID);
730 rv = scReleaseStruct.rv;
732 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
804 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
805 LPDWORD pdwActiveProtocol)
812 API_TRACE_IN(
"%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
817 if (phCard == NULL || pdwActiveProtocol == NULL)
822 if (szReader == NULL)
828 if (strlen(szReader) > MAX_READERNAME)
835 if (NULL == currentContextMap)
838 memset(scConnectStruct.szReader, 0,
sizeof scConnectStruct.szReader);
839 strncpy(scConnectStruct.szReader, szReader,
sizeof scConnectStruct.szReader);
840 scConnectStruct.szReader[
sizeof scConnectStruct.szReader -1] =
'\0';
842 scConnectStruct.hContext = hContext;
843 scConnectStruct.dwShareMode = dwShareMode;
844 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
845 scConnectStruct.hCard = 0;
846 scConnectStruct.dwActiveProtocol = 0;
850 sizeof(scConnectStruct), (
void *) &scConnectStruct);
859 currentContextMap->dwClientID);
864 *phCard = scConnectStruct.hCard;
865 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
872 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
875 rv = scConnectStruct.rv;
878 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
881 API_TRACE_OUT(
"%d", *pdwActiveProtocol)
959 DWORD dwPreferredProtocols, DWORD dwInitialization,
960 LPDWORD pdwActiveProtocol)
965 CHANNEL_MAP * pChannelMap;
968 API_TRACE_IN(
"%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
970 if (pdwActiveProtocol == NULL)
979 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
984 scReconnectStruct.hCard = hCard;
985 scReconnectStruct.dwShareMode = dwShareMode;
986 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
987 scReconnectStruct.dwInitialization = dwInitialization;
988 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
992 sizeof(scReconnectStruct), (
void *) &scReconnectStruct);
1000 rv =
MessageReceive(&scReconnectStruct,
sizeof(scReconnectStruct),
1001 currentContextMap->dwClientID);
1006 rv = scReconnectStruct.rv;
1010 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1015 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1018 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1021 API_TRACE_OUT(
"%ld", *pdwActiveProtocol)
1062 CHANNEL_MAP * pChannelMap;
1065 API_TRACE_IN(
"%ld %ld", hCard, dwDisposition)
1070 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1078 scDisconnectStruct.hCard = hCard;
1079 scDisconnectStruct.dwDisposition = dwDisposition;
1083 sizeof(scDisconnectStruct), (
void *) &scDisconnectStruct);
1091 rv =
MessageReceive(&scDisconnectStruct,
sizeof(scDisconnectStruct),
1092 currentContextMap->dwClientID);
1098 SCardRemoveHandle(hCard);
1099 rv = scDisconnectStruct.rv;
1102 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1153 CHANNEL_MAP * pChannelMap;
1156 API_TRACE_IN(
"%ld", hCard)
1168 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1173 scBeginStruct.hCard = hCard;
1177 currentContextMap->dwClientID,
1178 sizeof(scBeginStruct), (
void *) &scBeginStruct);
1187 currentContextMap->dwClientID);
1192 rv = scBeginStruct.rv;
1197 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1201 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1253 CHANNEL_MAP * pChannelMap;
1256 API_TRACE_IN(
"%ld", hCard)
1261 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1266 scEndStruct.hCard = hCard;
1267 scEndStruct.dwDisposition = dwDisposition;
1271 currentContextMap->dwClientID,
1272 sizeof(scEndStruct), (
void *) &scEndStruct);
1281 currentContextMap->dwClientID);
1286 rv = scEndStruct.rv;
1289 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1393 LPDWORD pcchReaderLen, LPDWORD pdwState,
1394 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1396 DWORD dwReaderLen, dwAtrLen;
1401 CHANNEL_MAP * pChannelMap;
1403 char *bufReader = NULL;
1404 LPBYTE bufAtr = NULL;
1417 if (pcchReaderLen == NULL)
1418 pcchReaderLen = &dummy;
1420 if (pcbAtrLen == NULL)
1424 dwReaderLen = *pcchReaderLen;
1425 dwAtrLen = *pcbAtrLen;
1436 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1442 (void)pthread_mutex_lock(&readerStatesMutex);
1445 rv = getReaderStates(currentContextMap);
1449 r = pChannelMap->readerName;
1453 if (r && strcmp(r, readerStates[i].readerName) == 0)
1464 memset(&scStatusStruct, 0,
sizeof(scStatusStruct));
1465 scStatusStruct.hCard = hCard;
1468 sizeof(scStatusStruct), (
void *) &scStatusStruct);
1477 currentContextMap->dwClientID);
1482 rv = scStatusStruct.rv;
1486 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1487 (void)pthread_mutex_unlock(&readerStatesMutex);
1504 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1505 *pcbAtrLen = readerStates[i].cardAtrLength;
1508 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1511 *pdwProtocol = readerStates[i].cardProtocol;
1515 dwReaderLen = *pcchReaderLen;
1516 if (NULL == szReaderName)
1521 bufReader = malloc(dwReaderLen);
1522 if (NULL == bufReader)
1527 *(
char **)szReaderName = bufReader;
1530 bufReader = szReaderName;
1535 if (*pcchReaderLen > dwReaderLen)
1538 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1543 dwAtrLen = *pcbAtrLen;
1549 bufAtr = malloc(dwAtrLen);
1555 *(LPBYTE *)pbAtr = bufAtr;
1562 if (*pcbAtrLen > dwAtrLen)
1565 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1569 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1570 (void)pthread_mutex_unlock(&readerStatesMutex);
1694 DWORD dwBreakFlag = 0;
1697 int currentReaderCount = 0;
1699 int pnp_reader = -1;
1702 API_TRACE_IN(
"%ld %ld %d", hContext, dwTimeout, cReaders)
1704 for (j=0; j<cReaders; j++)
1706 API_TRACE_IN(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1707 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1708 rgReaderStates[j].cbAtr)
1712 if ((rgReaderStates == NULL && cReaders > 0)
1720 for (j = 0; j < cReaders; j++)
1722 if (rgReaderStates[j].szReader == NULL)
1729 int nbNonIgnoredReaders = cReaders;
1731 for (j=0; j<cReaders; j++)
1733 nbNonIgnoredReaders--;
1735 if (0 == nbNonIgnoredReaders)
1752 if (NULL == currentContextMap)
1759 (void)pthread_mutex_lock(&readerStatesMutex);
1762 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1766 (void)pthread_mutex_unlock(&readerStatesMutex);
1771 for (j=0; j<cReaders; j++)
1773 const char *readerName;
1776 readerName = rgReaderStates[j].szReader;
1779 if (strcmp(readerName, readerStates[i].readerName) == 0)
1787 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") != 0)
1790 (void)pthread_mutex_unlock(&readerStatesMutex);
1797 (void)pthread_mutex_unlock(&readerStatesMutex);
1800 for (j = 0; j < cReaders; j++)
1801 rgReaderStates[j].dwEventState = 0;
1804 Log2(PCSC_LOG_DEBUG,
"Event Loop Start, dwTimeout: %ld", dwTimeout);
1807 if (pnp_reader >= 0)
1810 currReader = &rgReaderStates[pnp_reader];
1813 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1815 int previousReaderEvents = currReader->dwCurrentState >> 16;
1818 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1821 (previousReaderEvents != readerEvents)
1824 && previousReaderEvents)
1835 if (readerStates[j].readerName[0] !=
'\0')
1836 currentReaderCount++;
1839 if ((DWORD)-1 == dwTimeout)
1849 currReader = &rgReaderStates[j];
1854 const char *readerName;
1858 (void)pthread_mutex_lock(&readerStatesMutex);
1861 readerName = currReader->szReader;
1864 if (strcmp(readerName, readerStates[i].readerName) == 0)
1872 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") == 0)
1874 int k, newReaderCount = 0;
1877 if (readerStates[k].readerName[0] !=
'\0')
1880 if (newReaderCount != currentReaderCount)
1884 Log1(PCSC_LOG_INFO,
"Reader list changed");
1885 currentReaderCount = newReaderCount;
1887 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1890 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1899 currReader->dwEventState =
1915 uint32_t readerState;
1922 Log0(PCSC_LOG_DEBUG);
1927 rContext = &readerStates[i];
1933 if (currReader->dwCurrentState & 0xFFFF0000)
1935 unsigned int currentCounter;
1937 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1943 Log0(PCSC_LOG_DEBUG);
1949 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1961 Log0(PCSC_LOG_DEBUG);
1972 Log0(PCSC_LOG_DEBUG);
1980#ifndef DISABLE_AUTO_POWER_ON
1984 (void)
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1988 memcpy(currReader->rgbAtr, rContext->
cardAtr,
1992 currReader->cbAtr = 0;
2011 Log0(PCSC_LOG_DEBUG);
2029 Log0(PCSC_LOG_DEBUG);
2039 Log0(PCSC_LOG_DEBUG);
2049 Log0(PCSC_LOG_DEBUG);
2063 Log0(PCSC_LOG_DEBUG);
2077 Log0(PCSC_LOG_DEBUG);
2090 Log0(PCSC_LOG_DEBUG);
2093 else if (currReader-> dwCurrentState
2097 Log0(PCSC_LOG_DEBUG);
2109 Log0(PCSC_LOG_DEBUG);
2114 (void)pthread_mutex_unlock(&readerStatesMutex);
2127 if (dwBreakFlag == 1)
2133 struct timeval before, after;
2135 gettimeofday(&before, NULL);
2146 &waitStatusStruct,
sizeof(waitStatusStruct),
2157 rv = unregisterFromEvents(currentContextMap);
2166 rv = waitStatusStruct.rv;
2171 (void)pthread_mutex_lock(&readerStatesMutex);
2172 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2173 (void)pthread_mutex_unlock(&readerStatesMutex);
2181 gettimeofday(&after, NULL);
2183 dwTime -= diff/1000;
2203 Log1(PCSC_LOG_DEBUG,
"Event Loop End");
2208 (void)unregisterFromEvents(currentContextMap);
2210 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2215 for (j=0; j<cReaders; j++)
2217 API_TRACE_OUT(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2218 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2219 rgReaderStates[j].cbAtr)
2277 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2278 LPDWORD lpBytesReturned)
2283 CHANNEL_MAP * pChannelMap;
2288 if (NULL != lpBytesReturned)
2289 *lpBytesReturned = 0;
2294 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2308 scControlStruct.hCard = hCard;
2309 scControlStruct.dwControlCode = dwControlCode;
2310 scControlStruct.cbSendLength = cbSendLength;
2311 scControlStruct.cbRecvLength = cbRecvLength;
2312 scControlStruct.dwBytesReturned = 0;
2313 scControlStruct.rv = 0;
2316 sizeof(scControlStruct), &scControlStruct);
2322 rv =
MessageSend((
char *)pbSendBuffer, cbSendLength,
2323 currentContextMap->dwClientID);
2332 currentContextMap->dwClientID);
2339 if (scControlStruct.dwBytesReturned > cbRecvLength)
2341 if (NULL != lpBytesReturned)
2342 *lpBytesReturned = scControlStruct.dwBytesReturned;
2348 rv =
MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2349 currentContextMap->dwClientID);
2356 if (NULL != lpBytesReturned)
2357 *lpBytesReturned = scControlStruct.dwBytesReturned;
2359 rv = scControlStruct.rv;
2362 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2491 unsigned char *buf = NULL;
2495 if (NULL == pcbAttrLen)
2507 buf = malloc(*pcbAttrLen);
2514 *(
unsigned char **)pbAttr = buf;
2577 if (NULL == pbAttr || 0 == cbAttrLen)
2588static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
2589 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2594 CHANNEL_MAP * pChannelMap;
2599 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2610 scGetSetStruct.hCard = hCard;
2611 scGetSetStruct.dwAttrId = dwAttrId;
2613 memset(scGetSetStruct.pbAttr, 0,
sizeof(scGetSetStruct.pbAttr));
2616 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2617 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2621 scGetSetStruct.cbAttrLen =
sizeof scGetSetStruct.pbAttr;
2624 sizeof(scGetSetStruct), &scGetSetStruct);
2633 currentContextMap->dwClientID);
2643 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2647 DWORD correct_value = scGetSetStruct.cbAttrLen;
2648 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2649 *pcbAttrLen = correct_value;
2654 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2657 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2659 memset(scGetSetStruct.pbAttr, 0x00,
sizeof(scGetSetStruct.pbAttr));
2661 rv = scGetSetStruct.rv;
2664 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2728 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2730 LPDWORD pcbRecvLength)
2734 CHANNEL_MAP * pChannelMap;
2739 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2740 pcbRecvLength == NULL || pioSendPci == NULL)
2749 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2764 scTransmitStruct.hCard = hCard;
2765 scTransmitStruct.cbSendLength = cbSendLength;
2766 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2767 scTransmitStruct.ioSendPciProtocol = pioSendPci->
dwProtocol;
2768 scTransmitStruct.ioSendPciLength = pioSendPci->
cbPciLength;
2773 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->
dwProtocol;
2774 scTransmitStruct.ioRecvPciLength = pioRecvPci->
cbPciLength;
2783 sizeof(scTransmitStruct), (
void *) &scTransmitStruct);
2789 rv =
MessageSend((
void *)pbSendBuffer, cbSendLength,
2806 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2808 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2814 rv =
MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2822 pioRecvPci->
dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2823 pioRecvPci->
cbPciLength = scTransmitStruct.ioRecvPciLength;
2827 rv = scTransmitStruct.rv;
2831 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2836 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2839 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2913 LPSTR mszReaders, LPDWORD pcchReaders)
2915 DWORD dwReadersLen = 0;
2923 API_TRACE_IN(
"%ld", hContext)
2928 if (pcchReaders == NULL)
2935 if (NULL == currentContextMap)
2942 (void)pthread_mutex_lock(&readerStatesMutex);
2945 rv = getReaderStates(currentContextMap);
2951 if (readerStates[i].readerName[0] !=
'\0')
2952 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2957 if (1 == dwReadersLen)
2965 if (NULL == mszReaders)
2970 buf = malloc(dwReadersLen);
2976 *(
char **)mszReaders = buf;
2983 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2990 if (mszReaders == NULL)
2995 if (readerStates[i].readerName[0] !=
'\0')
3000 strcpy(buf, readerStates[i].readerName);
3001 buf += strlen(readerStates[i].readerName)+1;
3008 *pcchReaders = dwReadersLen;
3010 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3011 (void)pthread_mutex_unlock(&readerStatesMutex);
3014 API_TRACE_OUT(
"%d", *pcchReaders)
3044 free((
void *)pvMem);
3112 const char ReaderGroup[] =
"SCard$DefaultReaders\0";
3113 const unsigned int dwGroups =
sizeof(ReaderGroup);
3119 if (NULL == currentContextMap)
3124 if (NULL == mszGroups)
3129 buf = malloc(dwGroups);
3135 *(
char **)mszGroups = buf;
3141 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3149 memcpy(buf, ReaderGroup, dwGroups);
3152 *pcchGroups = dwGroups;
3154 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3196 uint32_t dwClientID = 0;
3201 API_TRACE_IN(
"%ld", hContext)
3209 if (NULL == currentContextMap)
3231 scCancelStruct.hContext = hContext;
3235 sizeof(scCancelStruct), (
void *) &scCancelStruct);
3243 rv =
MessageReceive(&scCancelStruct,
sizeof(scCancelStruct), dwClientID);
3248 rv = scCancelStruct.rv;
3287 API_TRACE_IN(
"%ld", hContext)
3325 if (NULL == newContextMap)
3328 Log2(PCSC_LOG_DEBUG,
"Allocating new SCONTEXTMAP @%p", newContextMap);
3329 newContextMap->
hContext = hContext;
3333 (void)pthread_mutex_init(&newContextMap->
mMutex, NULL);
3335 lrv = list_init(&newContextMap->channelMapList);
3338 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
3342 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3343 CHANNEL_MAP_seeker);
3346 Log2(PCSC_LOG_CRITICAL,
3347 "list_attributes_seeker failed with return value: %d", lrv);
3348 list_destroy(&newContextMap->channelMapList);
3353 lrv = list_append(&contextMapList, newContextMap);
3357 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3359 list_destroy(&newContextMap->channelMapList);
3367 (void)pthread_mutex_destroy(&newContextMap->
mMutex);
3368 free(newContextMap);
3397 if (NULL != currentContextMap)
3398 (void)pthread_mutex_lock(¤tContextMap->
mMutex);
3402 return currentContextMap;
3422 currentContextMap = list_seek(&contextMapList, &hContext);
3425 return currentContextMap;
3439 if (NULL != currentContextMap)
3440 SCardCleanContext(currentContextMap);
3443static void SCardCleanContext(
SCONTEXTMAP * targetContextMap)
3445 int list_index, lrv;
3447 CHANNEL_MAP * currentChannelMap;
3452 (void)pthread_mutex_destroy(&targetContextMap->
mMutex);
3454 listSize = list_size(&targetContextMap->channelMapList);
3455 for (list_index = 0; list_index < listSize; list_index++)
3457 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3459 if (NULL == currentChannelMap)
3461 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3467 free(currentChannelMap->readerName);
3468 free(currentChannelMap);
3472 list_destroy(&targetContextMap->channelMapList);
3475 lrv = list_delete(&contextMapList, targetContextMap);
3479 Log2(PCSC_LOG_CRITICAL,
3480 "list_delete failed with return value: %d", lrv);
3483 free(targetContextMap);
3495 CHANNEL_MAP * newChannelMap;
3498 newChannelMap = malloc(
sizeof(CHANNEL_MAP));
3499 if (NULL == newChannelMap)
3502 newChannelMap->hCard = hCard;
3503 newChannelMap->readerName = strdup(readerName);
3505 lrv = list_append(¤tContextMap->channelMapList, newChannelMap);
3508 free(newChannelMap->readerName);
3509 free(newChannelMap);
3510 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3521 CHANNEL_MAP * currentChannelMap;
3525 rv = SCardGetContextAndChannelFromHandleTH(hCard, ¤tContextMap,
3526 ¤tChannelMap);
3530 free(currentChannelMap->readerName);
3532 lrv = list_delete(¤tContextMap->channelMapList, currentChannelMap);
3535 Log2(PCSC_LOG_CRITICAL,
3536 "list_delete failed with return value: %d", lrv);
3539 free(currentChannelMap);
3544static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE hCard,
3545 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3553 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3557 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3564static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE hCard,
3565 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3571 CHANNEL_MAP * currentChannelMap;
3574 *targetContextMap = NULL;
3575 *targetChannelMap = NULL;
3578 listSize = list_size(&contextMapList);
3580 for (list_index = 0; list_index < listSize; list_index++)
3582 currentContextMap = list_get_at(&contextMapList, list_index);
3583 if (currentContextMap == NULL)
3585 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3589 currentChannelMap = list_seek(¤tContextMap->channelMapList,
3591 if (currentChannelMap != NULL)
3593 *targetContextMap = currentContextMap;
3594 *targetChannelMap = currentChannelMap;
3615 struct stat statBuffer;
3618 socketName = getSocketName();
3619 rv = stat(socketName, &statBuffer);
3623 Log3(PCSC_LOG_INFO,
"PCSC Not Running: %s: %s",
3624 socketName, strerror(errno));
3631static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents)
3633 int32_t dwClientID = currentContextMap->
dwClientID;
3651static LONG getReaderStates(
SCONTEXTMAP * currentContextMap)
3653 int32_t dwClientID = currentContextMap->
dwClientID;
3661 rv =
MessageReceive(&readerStates,
sizeof(readerStates), dwClientID);
3668static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap)
3670 int32_t dwClientID = currentContextMap->
dwClientID;
3680 rv =
MessageReceive(&readerStates,
sizeof(readerStates), dwClientID);
3684static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap)
3686 int32_t dwClientID = currentContextMap->
dwClientID;
3692 dwClientID, 0, NULL);
3709 rv = waitStatusStruct.rv;
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
struct pubReaderStatesList READER_STATE
Define an exported public reader state structure so each application gets instant notification of cha...
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader.
LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
#define SCARD_S_SUCCESS
No error was encountered.
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
#define SCARD_STATE_IGNORE
Ignore this reader.
#define SCARD_SWALLOWED
Card not powered.
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_PRESENT
Card is present.
#define SCARD_STATE_INUSE
Shared Mode.
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
#define SCARD_STATE_PRESENT
Card inserted.
#define SCARD_ABSENT
Card is absent.
#define SCARD_UNKNOWN
Unknown state.
#define SCARD_STATE_UNKNOWN
Reader unknown.
#define INFINITE
Infinite timeout.
#define SCARD_STATE_EMPTY
Card removed.
#define SCARD_STATE_ATRMATCH
ATR matches card.
#define SCARD_STATE_MUTE
Unresponsive card.
#define SCARD_STATE_CHANGED
State has changed.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
#define SCARD_STATE_UNAWARE
App wants status.
LONG SCARDHANDLE
hCard returned by SCardConnect()
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader).
Protocol Control Information (PCI).
unsigned long dwProtocol
Protocol identifier.
unsigned long cbPciLength
Protocol Control Inf Length.
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
bool cancellable
We are in a cancellable call.
contained in SCARD_BEGIN_TRANSACTION Messages.
contained in SCARD_CANCEL Messages.
contained in SCARD_CONNECT Messages.
contained in SCARD_CONTROL Messages.
contained in SCARD_DISCONNECT Messages.
contained in SCARD_END_TRANSACTION Messages.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
contained in SCARD_GET_ATTRIB and Messages.
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
uint32_t eventCounter
number of card events
_Atomic uint32_t cardAtrLength
ATR length.
uint32_t readerState
SCARD_* bit field.
contained in SCARD_RECONNECT Messages.
Information contained in SCARD_RELEASE_CONTEXT Messages.
contained in SCARD_STATUS Messages.
contained in SCARD_TRANSMIT Messages.
Information transmitted in CMD_VERSION Messages.
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
This handles smart card reader communications.
static bool isExecuted
Make sure the initialization code is executed only once.
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
static bool SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
pthread_mutex_t contextMapList_lock
lock for the above list
struct _psContextMap SCONTEXTMAP
Represents an Application Context on the Client side.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
@ SCARD_DISCONNECT
used by SCardDisconnect()
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
@ CMD_GET_READERS_STATE
get the readers state
@ SCARD_CONTROL
used by SCardControl()
@ CMD_VERSION
get the client/server protocol version
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
@ SCARD_RECONNECT
used by SCardReconnect()
@ SCARD_STATUS
used by SCardStatus()
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
@ CMD_GET_READER_EVENTS
get the number of reader events
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
@ SCARD_TRANSMIT
used by SCardTransmit()
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
@ SCARD_CANCEL
used by SCardCancel()
@ SCARD_CONNECT
used by SCardConnect()
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()