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)
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;
319static int SCONTEXTMAP_seeker(
const void *el,
const void *key)
323 if ((el == NULL) || (key == NULL))
325 Log3(PCSC_LOG_CRITICAL,
326 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
341static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
354static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
364static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE,
366static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE,
370static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
371 LPBYTE pbAttr, LPDWORD pcbAttrLen);
373static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents);
374static LONG getReaderStates(
SCONTEXTMAP * currentContextMap);
375static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap);
376static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap);
419 return currentContextMap != NULL;
461 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
465 API_TRACE_IN(
"%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
475 pvReserved2, phContext);
480 API_TRACE_OUT(
"%ld", *phContext)
486DESTRUCTOR
static void destructor(
void)
488 list_destroy(&contextMapList);
496static void init_lib(
void)
503 lrv = list_init(&contextMapList);
506 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d",
511 lrv = list_attributes_seeker(&contextMapList,
515 Log2(PCSC_LOG_CRITICAL,
516 "list_attributes_seeker failed with return value: %d", lrv);
517 list_destroy(&contextMapList);
523 Log1(PCSC_LOG_INFO,
"Disable shared blocking");
524 sharing_shall_block =
false;
559 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
563 uint32_t dwClientID = 0;
567 if (phContext == NULL)
572 pthread_once(&init_lib_control, init_lib);
598 Log1(PCSC_LOG_CRITICAL,
599 "Your pcscd is too old and does not support CMD_VERSION");
603 Log3(PCSC_LOG_INFO,
"Server is protocol version %d:%d",
617 scEstablishStruct.dwScope = dwScope;
618 scEstablishStruct.hContext = 0;
622 sizeof(scEstablishStruct), (
void *) &scEstablishStruct);
630 rv =
MessageReceive(&scEstablishStruct,
sizeof(scEstablishStruct),
638 rv = scEstablishStruct.rv;
648 *phContext = scEstablishStruct.hContext;
690 API_TRACE_IN(
"%ld", hContext)
698 if (NULL == currentContextMap)
704 scReleaseStruct.hContext = hContext;
708 currentContextMap->dwClientID,
709 sizeof(scReleaseStruct), (
void *) &scReleaseStruct);
718 currentContextMap->dwClientID);
723 rv = scReleaseStruct.rv;
725 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
797 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
798 LPDWORD pdwActiveProtocol)
805 API_TRACE_IN(
"%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
810 if (phCard == NULL || pdwActiveProtocol == NULL)
815 if (szReader == NULL)
821 if (strlen(szReader) > MAX_READERNAME)
828 if (NULL == currentContextMap)
831 memset(scConnectStruct.szReader, 0,
sizeof scConnectStruct.szReader);
832 strncpy(scConnectStruct.szReader, szReader,
sizeof scConnectStruct.szReader);
833 scConnectStruct.szReader[
sizeof scConnectStruct.szReader -1] =
'\0';
835 scConnectStruct.hContext = hContext;
836 scConnectStruct.dwShareMode = dwShareMode;
837 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
838 scConnectStruct.hCard = 0;
839 scConnectStruct.dwActiveProtocol = 0;
843 sizeof(scConnectStruct), (
void *) &scConnectStruct);
852 currentContextMap->dwClientID);
857 *phCard = scConnectStruct.hCard;
858 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
865 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
868 rv = scConnectStruct.rv;
871 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
874 API_TRACE_OUT(
"%d", *pdwActiveProtocol)
952 DWORD dwPreferredProtocols, DWORD dwInitialization,
953 LPDWORD pdwActiveProtocol)
961 API_TRACE_IN(
"%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
963 if (pdwActiveProtocol == NULL)
972 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
977 scReconnectStruct.hCard = hCard;
978 scReconnectStruct.dwShareMode = dwShareMode;
979 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
980 scReconnectStruct.dwInitialization = dwInitialization;
981 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
985 sizeof(scReconnectStruct), (
void *) &scReconnectStruct);
993 rv =
MessageReceive(&scReconnectStruct,
sizeof(scReconnectStruct),
994 currentContextMap->dwClientID);
999 rv = scReconnectStruct.rv;
1003 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1008 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1011 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1014 API_TRACE_OUT(
"%ld", *pdwActiveProtocol)
1058 API_TRACE_IN(
"%ld %ld", hCard, dwDisposition)
1063 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1071 scDisconnectStruct.hCard = hCard;
1072 scDisconnectStruct.dwDisposition = dwDisposition;
1076 sizeof(scDisconnectStruct), (
void *) &scDisconnectStruct);
1084 rv =
MessageReceive(&scDisconnectStruct,
sizeof(scDisconnectStruct),
1085 currentContextMap->dwClientID);
1091 SCardRemoveHandle(hCard);
1092 rv = scDisconnectStruct.rv;
1095 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1149 API_TRACE_IN(
"%ld", hCard)
1161 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1166 scBeginStruct.hCard = hCard;
1170 currentContextMap->dwClientID,
1171 sizeof(scBeginStruct), (
void *) &scBeginStruct);
1180 currentContextMap->dwClientID);
1185 rv = scBeginStruct.rv;
1190 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1194 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1249 API_TRACE_IN(
"%ld", hCard)
1254 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1259 scEndStruct.hCard = hCard;
1260 scEndStruct.dwDisposition = dwDisposition;
1264 currentContextMap->dwClientID,
1265 sizeof(scEndStruct), (
void *) &scEndStruct);
1274 currentContextMap->dwClientID);
1279 rv = scEndStruct.rv;
1282 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1386 LPDWORD pcchReaderLen, LPDWORD pdwState,
1387 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1389 DWORD dwReaderLen, dwAtrLen;
1396 char *bufReader = NULL;
1397 LPBYTE bufAtr = NULL;
1410 if (pcchReaderLen == NULL)
1411 pcchReaderLen = &dummy;
1413 if (pcbAtrLen == NULL)
1417 dwReaderLen = *pcchReaderLen;
1418 dwAtrLen = *pcbAtrLen;
1429 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1435 (void)pthread_mutex_lock(&readerStatesMutex);
1438 rv = getReaderStates(currentContextMap);
1442 r = pChannelMap->readerName;
1457 memset(&scStatusStruct, 0,
sizeof(scStatusStruct));
1458 scStatusStruct.hCard = hCard;
1461 sizeof(scStatusStruct), (
void *) &scStatusStruct);
1470 currentContextMap->dwClientID);
1475 rv = scStatusStruct.rv;
1479 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1480 (void)pthread_mutex_unlock(&readerStatesMutex);
1497 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1508 dwReaderLen = *pcchReaderLen;
1509 if (NULL == szReaderName)
1514 bufReader = malloc(dwReaderLen);
1515 if (NULL == bufReader)
1520 *(
char **)szReaderName = bufReader;
1523 bufReader = szReaderName;
1528 if (*pcchReaderLen > dwReaderLen)
1531 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1536 dwAtrLen = *pcbAtrLen;
1542 bufAtr = malloc(dwAtrLen);
1548 *(LPBYTE *)pbAtr = bufAtr;
1555 if (*pcbAtrLen > dwAtrLen)
1558 memcpy(bufAtr,
readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1562 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1563 (void)pthread_mutex_unlock(&readerStatesMutex);
1687 DWORD dwBreakFlag = 0;
1690 int currentReaderCount = 0;
1692 int pnp_reader = -1;
1695 API_TRACE_IN(
"%ld %ld %d", hContext, dwTimeout, cReaders)
1697 for (j=0; j<cReaders; j++)
1699 API_TRACE_IN(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1700 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1701 rgReaderStates[j].cbAtr)
1705 if ((rgReaderStates == NULL && cReaders > 0)
1713 for (j = 0; j < cReaders; j++)
1715 if (rgReaderStates[j].szReader == NULL)
1722 int nbNonIgnoredReaders = cReaders;
1724 for (j=0; j<cReaders; j++)
1726 nbNonIgnoredReaders--;
1728 if (0 == nbNonIgnoredReaders)
1745 if (NULL == currentContextMap)
1752 (void)pthread_mutex_lock(&readerStatesMutex);
1755 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1759 (void)pthread_mutex_unlock(&readerStatesMutex);
1764 for (j=0; j<cReaders; j++)
1766 const char *readerName;
1769 readerName = rgReaderStates[j].szReader;
1772 if (strcmp(readerName,
readerStates[i].readerName) == 0)
1780 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") != 0)
1783 (void)pthread_mutex_unlock(&readerStatesMutex);
1790 (void)pthread_mutex_unlock(&readerStatesMutex);
1793 for (j = 0; j < cReaders; j++)
1794 rgReaderStates[j].dwEventState = 0;
1797 Log2(PCSC_LOG_DEBUG,
"Event Loop Start, dwTimeout: %ld", dwTimeout);
1800 if (pnp_reader >= 0)
1803 currReader = &rgReaderStates[pnp_reader];
1806 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1808 int previousReaderEvents = currReader->dwCurrentState >> 16;
1811 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1814 (previousReaderEvents != readerEvents)
1817 && previousReaderEvents)
1829 currentReaderCount++;
1832 if ((DWORD)-1 == dwTimeout)
1842 currReader = &rgReaderStates[j];
1847 const char *readerName;
1851 (void)pthread_mutex_lock(&readerStatesMutex);
1854 readerName = currReader->szReader;
1857 if (strcmp(readerName,
readerStates[i].readerName) == 0)
1865 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") == 0)
1867 int k, newReaderCount = 0;
1873 if (newReaderCount != currentReaderCount)
1877 Log1(PCSC_LOG_INFO,
"Reader list changed");
1878 currentReaderCount = newReaderCount;
1880 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1883 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1892 currReader->dwEventState =
1908 uint32_t readerState;
1914 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1915 Log0(PCSC_LOG_DEBUG);
1926 if (currReader->dwCurrentState & 0xFFFF0000)
1928 unsigned int currentCounter;
1930 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1936 Log0(PCSC_LOG_DEBUG);
1942 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1954 Log0(PCSC_LOG_DEBUG);
1963 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1965 Log0(PCSC_LOG_DEBUG);
1973#ifndef DISABLE_AUTO_POWER_ON
1977 (void)
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1981 memcpy(currReader->rgbAtr, rContext->
cardAtr,
1985 currReader->cbAtr = 0;
1991 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1992 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1993 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1994 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1995 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1996 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1997 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1998 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2004 Log0(PCSC_LOG_DEBUG);
2012 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2013 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2014 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2015 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2016 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2017 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2022 Log0(PCSC_LOG_DEBUG);
2032 Log0(PCSC_LOG_DEBUG);
2042 Log0(PCSC_LOG_DEBUG);
2052 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2056 Log0(PCSC_LOG_DEBUG);
2066 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2070 Log0(PCSC_LOG_DEBUG);
2077 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2078 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2083 Log0(PCSC_LOG_DEBUG);
2086 else if (currReader-> dwCurrentState
2090 Log0(PCSC_LOG_DEBUG);
2102 Log0(PCSC_LOG_DEBUG);
2107 (void)pthread_mutex_unlock(&readerStatesMutex);
2120 if (dwBreakFlag == 1)
2126 struct timeval before, after;
2128 gettimeofday(&before, NULL);
2139 &waitStatusStruct,
sizeof(waitStatusStruct),
2150 rv = unregisterFromEvents(currentContextMap);
2159 rv = waitStatusStruct.rv;
2164 (void)pthread_mutex_lock(&readerStatesMutex);
2165 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2166 (void)pthread_mutex_unlock(&readerStatesMutex);
2174 gettimeofday(&after, NULL);
2176 dwTime -= diff/1000;
2196 Log1(PCSC_LOG_DEBUG,
"Event Loop End");
2201 (void)unregisterFromEvents(currentContextMap);
2203 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2208 for (j=0; j<cReaders; j++)
2210 API_TRACE_OUT(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2211 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2212 rgReaderStates[j].cbAtr)
2270 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2271 LPDWORD lpBytesReturned)
2281 if (NULL != lpBytesReturned)
2282 *lpBytesReturned = 0;
2287 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2301 scControlStruct.hCard = hCard;
2302 scControlStruct.dwControlCode = dwControlCode;
2303 scControlStruct.cbSendLength = cbSendLength;
2304 scControlStruct.cbRecvLength = cbRecvLength;
2305 scControlStruct.dwBytesReturned = 0;
2306 scControlStruct.rv = 0;
2309 sizeof(scControlStruct), &scControlStruct);
2315 rv =
MessageSend((
char *)pbSendBuffer, cbSendLength,
2316 currentContextMap->dwClientID);
2325 currentContextMap->dwClientID);
2332 if (scControlStruct.dwBytesReturned > cbRecvLength)
2334 if (NULL != lpBytesReturned)
2335 *lpBytesReturned = scControlStruct.dwBytesReturned;
2341 rv =
MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2342 currentContextMap->dwClientID);
2349 if (NULL != lpBytesReturned)
2350 *lpBytesReturned = scControlStruct.dwBytesReturned;
2352 rv = scControlStruct.rv;
2355 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2484 unsigned char *buf = NULL;
2488 if (NULL == pcbAttrLen)
2500 buf = malloc(*pcbAttrLen);
2507 *(
unsigned char **)pbAttr = buf;
2570 if (NULL == pbAttr || 0 == cbAttrLen)
2581static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
2582 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2592 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2603 scGetSetStruct.hCard = hCard;
2604 scGetSetStruct.dwAttrId = dwAttrId;
2606 memset(scGetSetStruct.pbAttr, 0,
sizeof(scGetSetStruct.pbAttr));
2609 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2610 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2614 scGetSetStruct.cbAttrLen =
sizeof scGetSetStruct.pbAttr;
2617 sizeof(scGetSetStruct), &scGetSetStruct);
2626 currentContextMap->dwClientID);
2636 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2640 DWORD correct_value = scGetSetStruct.cbAttrLen;
2641 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2642 *pcbAttrLen = correct_value;
2647 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2650 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2652 memset(scGetSetStruct.pbAttr, 0x00,
sizeof(scGetSetStruct.pbAttr));
2654 rv = scGetSetStruct.rv;
2657 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2721 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2723 LPDWORD pcbRecvLength)
2732 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2733 pcbRecvLength == NULL || pioSendPci == NULL)
2742 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2757 scTransmitStruct.hCard = hCard;
2758 scTransmitStruct.cbSendLength = cbSendLength;
2759 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2760 scTransmitStruct.ioSendPciProtocol = pioSendPci->
dwProtocol;
2761 scTransmitStruct.ioSendPciLength = pioSendPci->
cbPciLength;
2766 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->
dwProtocol;
2767 scTransmitStruct.ioRecvPciLength = pioRecvPci->
cbPciLength;
2776 sizeof(scTransmitStruct), (
void *) &scTransmitStruct);
2782 rv =
MessageSend((
void *)pbSendBuffer, cbSendLength,
2799 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2801 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2807 rv =
MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2815 pioRecvPci->
dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2816 pioRecvPci->
cbPciLength = scTransmitStruct.ioRecvPciLength;
2820 rv = scTransmitStruct.rv;
2824 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2829 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2832 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2906 LPSTR mszReaders, LPDWORD pcchReaders)
2908 DWORD dwReadersLen = 0;
2916 API_TRACE_IN(
"%ld", hContext)
2921 if (pcchReaders == NULL)
2928 if (NULL == currentContextMap)
2935 (void)pthread_mutex_lock(&readerStatesMutex);
2938 rv = getReaderStates(currentContextMap);
2945 dwReadersLen += strlen(
readerStates[i].readerName) + 1;
2950 if (1 == dwReadersLen)
2958 if (NULL == mszReaders)
2963 buf = malloc(dwReadersLen);
2969 *(
char **)mszReaders = buf;
2976 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2983 if (mszReaders == NULL)
3001 *pcchReaders = dwReadersLen;
3003 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3004 (void)pthread_mutex_unlock(&readerStatesMutex);
3007 API_TRACE_OUT(
"%d", *pcchReaders)
3037 free((
void *)pvMem);
3105 const char ReaderGroup[] =
"SCard$DefaultReaders\0";
3106 const unsigned int dwGroups =
sizeof(ReaderGroup);
3112 if (NULL == currentContextMap)
3117 if (NULL == mszGroups)
3122 buf = malloc(dwGroups);
3128 *(
char **)mszGroups = buf;
3134 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3142 memcpy(buf, ReaderGroup, dwGroups);
3145 *pcchGroups = dwGroups;
3147 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3189 uint32_t dwClientID = 0;
3194 API_TRACE_IN(
"%ld", hContext)
3202 if (NULL == currentContextMap)
3224 scCancelStruct.hContext = hContext;
3228 sizeof(scCancelStruct), (
void *) &scCancelStruct);
3236 rv =
MessageReceive(&scCancelStruct,
sizeof(scCancelStruct), dwClientID);
3241 rv = scCancelStruct.rv;
3280 API_TRACE_IN(
"%ld", hContext)
3318 if (NULL == newContextMap)
3321 Log2(PCSC_LOG_DEBUG,
"Allocating new SCONTEXTMAP @%p", newContextMap);
3322 newContextMap->
hContext = hContext;
3326 (void)pthread_mutex_init(&newContextMap->
mMutex, NULL);
3328 lrv = list_init(&newContextMap->channelMapList);
3331 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
3335 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3336 CHANNEL_MAP_seeker);
3339 Log2(PCSC_LOG_CRITICAL,
3340 "list_attributes_seeker failed with return value: %d", lrv);
3341 list_destroy(&newContextMap->channelMapList);
3345 lrv = list_append(&contextMapList, newContextMap);
3348 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3350 list_destroy(&newContextMap->channelMapList);
3358 (void)pthread_mutex_destroy(&newContextMap->
mMutex);
3359 free(newContextMap);
3388 if (NULL != currentContextMap)
3389 (void)pthread_mutex_lock(¤tContextMap->
mMutex);
3393 return currentContextMap;
3410 return list_seek(&contextMapList, &hContext);
3424 if (NULL != currentContextMap)
3425 SCardCleanContext(currentContextMap);
3428static void SCardCleanContext(
SCONTEXTMAP * targetContextMap)
3430 int list_index, lrv;
3437 (void)pthread_mutex_destroy(&targetContextMap->
mMutex);
3439 listSize = list_size(&targetContextMap->channelMapList);
3440 for (list_index = 0; list_index < listSize; list_index++)
3442 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3444 if (NULL == currentChannelMap)
3446 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3452 free(currentChannelMap->readerName);
3453 free(currentChannelMap);
3457 list_destroy(&targetContextMap->channelMapList);
3459 lrv = list_delete(&contextMapList, targetContextMap);
3462 Log2(PCSC_LOG_CRITICAL,
3463 "list_delete failed with return value: %d", lrv);
3466 free(targetContextMap);
3482 if (NULL == newChannelMap)
3485 newChannelMap->hCard = hCard;
3486 newChannelMap->readerName = strdup(readerName);
3488 lrv = list_append(¤tContextMap->channelMapList, newChannelMap);
3491 free(newChannelMap->readerName);
3492 free(newChannelMap);
3493 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3508 rv = SCardGetContextAndChannelFromHandleTH(hCard, ¤tContextMap,
3509 ¤tChannelMap);
3513 free(currentChannelMap->readerName);
3515 lrv = list_delete(¤tContextMap->channelMapList, currentChannelMap);
3518 Log2(PCSC_LOG_CRITICAL,
3519 "list_delete failed with return value: %d", lrv);
3522 free(currentChannelMap);
3527static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE hCard,
3536 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3540 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3547static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE hCard,
3556 *targetContextMap = NULL;
3557 *targetChannelMap = NULL;
3559 listSize = list_size(&contextMapList);
3561 for (list_index = 0; list_index < listSize; list_index++)
3563 currentContextMap = list_get_at(&contextMapList, list_index);
3564 if (currentContextMap == NULL)
3566 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3570 currentChannelMap = list_seek(¤tContextMap->channelMapList,
3572 if (currentChannelMap != NULL)
3574 *targetContextMap = currentContextMap;
3575 *targetChannelMap = currentChannelMap;
3593 struct stat statBuffer;
3596 socketName = getSocketName();
3597 rv = stat(socketName, &statBuffer);
3601 Log3(PCSC_LOG_INFO,
"PCSC Not Running: %s: %s",
3602 socketName, strerror(errno));
3609static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents)
3611 int32_t dwClientID = currentContextMap->
dwClientID;
3629static LONG getReaderStates(
SCONTEXTMAP * currentContextMap)
3631 int32_t dwClientID = currentContextMap->
dwClientID;
3646static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap)
3648 int32_t dwClientID = currentContextMap->
dwClientID;
3662static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap)
3664 int32_t dwClientID = currentContextMap->
dwClientID;
3670 dwClientID, 0, NULL);
3687 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.
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_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.
Define an exported public reader state structure so each application gets instant notification of cha...
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
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.
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...
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
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()