PCSC那事儿(二十四--SCardStatus)

来源:互联网 发布:程序员吴云洋 编辑:程序博客网 时间:2024/06/05 08:44

 

SCardStatus

 

1532 LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName,

1533         LPDWORD pcchReaderLen, LPDWORD pdwState,

1534         LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)

1535 {

1536         DWORD dwReaderLen, dwAtrLen;

1537         LONG rv;

1538         int i;

1539         status_struct scStatusStruct;

1540         sharedSegmentMsg msgStruct;

1541         DWORD dwContextIndex, dwChannelIndex;

1542         char *r;

1543         char *bufReader = NULL;

1544         LPBYTE bufAtr = NULL;

1545         DWORD dummy;

1546

1547         PROFILE_START

1548

1549         /* default output values */

1550         if (pdwState)

1551                 *pdwState = 0;

1552

1553         if (pdwProtocol)

1554                 *pdwProtocol = 0;

1555

1556         /* Check for NULL parameters */

1557         if (pcchReaderLen == NULL)

1558                 pcchReaderLen = &dummy;

1559

1560         if (pcbAtrLen == NULL)

1561                 pcbAtrLen = &dummy;

1562

1563         /* length passed from caller */

1564         dwReaderLen = *pcchReaderLen;

1565         dwAtrLen = *pcbAtrLen;

1566

1567         *pcchReaderLen = 0;

1568         *pcbAtrLen = 0;

1569

 

 

1535~1555行,多说无益。

1557行,和前面的API实现有些不太一样,如果读卡器名字长度的指针

pcchReaderLen NULL,则把dummy的地址给它。做什么用?往前走吧。

1560~1561行,和上面一个说法。

 

1570         rv = SCardCheckDaemonAvailability();

1571         if (rv != SCARD_S_SUCCESS)

1572                 return rv;

1573

1574         /*

1575          * Make sure this handle has been opened

1576          */

1577         rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);

1578         if (rv == -1)

1579                 return SCARD_E_INVALID_HANDLE;

1580

1581         (void)SYS_MutexLock(psContextMap[dwContextIndex].mMutex);

1582

1583         /* check the handle is still valid */

1584         rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);

1585         if (rv == -1)

1586                 /* the handle is now invalid

1587                  * -> another thread may have called SCardReleaseContext

1588                  * -> so the mMutex has been unlocked */

1589                 return SCARD_E_INVALID_HANDLE;

 

 

1570~1589行,前面提过了。

1590

1591         r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;

1592         for (i = 0; i <PCSCLITE_MAX_READERS_CONTEXTS; i++)

1593         {

1594                 /* by default r == NULL */

1595                 if (r && strcmp(r,(readerStates[i])->readerName) == 0)

1596                         break;

1597         }

1598

1599         if (i ==PCSCLITE_MAX_READERS_CONTEXTS)

1600         {

1601                 rv =SCARD_E_READER_UNAVAILABLE;

1602                 goto end;

1603         }

1604

 

根据目前readerStates(共享内存)的状态,寻找和dwContextIndexdwChangelIndex

对应的读卡器名字是否匹配。

特殊情况,如果r==NULL,也会走到1604行。

1605         /* initialise the structure */

1606         memset(&scStatusStruct, 0, sizeof(scStatusStruct));

1607         scStatusStruct.hCard = hCard;

1608

1609         /* those sizes need to be initialised */

1610         scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);

1611         scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);

1612

1613         rv = WrapSHMWrite(SCARD_STATUS, psContextMap[dwContextIndex].dwClientID,

1614                 sizeof(scStatusStruct),

1615                 PCSCLITE_CLIENT_ATTEMPTS, (void *) &scStatusStruct);

1616

1617         if (rv == -1)

1618         {

1619                 rv = SCARD_E_NO_SERVICE;

1620                 goto end;

1621         }

1622

1623         /*

1624          * Read a message from the server

1625          */

1626         rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,

1627                 PCSCLITE_CLIENT_ATTEMPTS);

1628

1629         memcpy(&scStatusStruct, &msgStruct.data, sizeof(scStatusStruct));

1630

1631         if (rv == -1)

1632         {

1633                 rv = SCARD_F_COMM_ERROR;

1634                 goto end;

1635         }

1636

1637         rv = scStatusStruct.rv;

1638         if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)

1639         {

1640                 /*

1641                  * An event must have occurred

1642                  */

1643                 goto end;

1644         }

 

1645

1646         /*

1647          * Now continue with the client side SCardStatus

1648          */

1649

1650         *pcchReaderLen = strlen(psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName) + 1;

1651         *pcbAtrLen = (readerStates[i])->cardAtrLength;

 

 

 

接着进行通讯。

 

SCardStatus 与上面提到的SCardGetSetAttribSCardTransmitSCardControl

又有点不同,实际上上面提过了。这里的情况是几乎一致的算法,处理不一样的

数据结构。

 

发送采用status_struct结构,接收采用sharedSegmentMsg结构,data域内嵌status_struct结构。

 

1605~1644行,就没有什么内容可做特别说明的。该说的都说了。从后面的代码可以看到

返回的数据仅仅用到了通讯的结果

1637         rv = scStatusStruct.rv;

 

其它的数据都没有用到。因为用了共享内容,从readerStates就可以获取读卡器和卡的状态了。多做了这步吗?不算多做,因为这步实现了从远程判断和参数hCard对应的读卡器的存在。

 

1650行获得对应参数hCard的读卡器名字长度。

1651行获得对应参数hCard的读卡器中的卡的ATR字符串长度。

1652

 

 

1653         if (pdwState)

1654                 *pdwState = (readerStates[i])->readerState;

1655

1656         if (pdwProtocol)

1657                 *pdwProtocol = (readerStates[i])->cardProtocol;

1658

 

 

 

 

1653~1654行,获取读卡器状态。

1656~1658行,获取读卡器的通讯协议。

 

 

1659         if (SCARD_AUTOALLOCATE == dwReaderLen)

1660         {

1661                 dwReaderLen = *pcchReaderLen;

1662                 bufReader = malloc(dwReaderLen);

1663                 if (NULL == bufReader)

1664                 {

1665                         rv = SCARD_E_NO_MEMORY;

1666                         goto end;

1667                 }

1668                 if (NULL == mszReaderName)

1669                 {

1670                         rv = SCARD_E_INVALID_PARAMETER;

1671                         goto end;

1672                 }

1673                 *(char **)mszReaderName = bufReader;

1674         }

1675         else

1676                 bufReader = mszReaderName;

1677

 

 

 

 

1659~1677行,根据上面提到的两种情况,也就是是否由API内部分配内存。获得读卡器名字。

 

1678         /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */

1679         if (bufReader)

1680         {

1681                 if (*pcchReaderLen > dwReaderLen)

1682                         rv = SCARD_E_INSUFFICIENT_BUFFER;

1683

1684                 strncpy(bufReader,

1685                         psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName,

1686                         dwReaderLen);

1687         }

 

 

 

 

1678~1687行,实际填充mszReaderName,如果太长,则填入的读卡器名字是截断的。

1688

1689         if (SCARD_AUTOALLOCATE == dwAtrLen)

1690         {

1691                 dwAtrLen = *pcbAtrLen;

1692                 bufAtr = malloc(dwAtrLen);

1693                 if (NULL == bufAtr)

1694                 {

1695                         rv = SCARD_E_NO_MEMORY;

1696                         goto end;

1697                 }

1698                 if (NULL == pbAtr)

1699                 {

1700                         rv = SCARD_E_INVALID_PARAMETER;

1701                         goto end;

1702                 }

1703                 *(LPBYTE *)pbAtr = bufAtr;

1704         }

1705         else

1706                 bufAtr = pbAtr;

1707

1708         if (bufAtr)

1709         {

1710                 if (*pcbAtrLen > dwAtrLen)

1711                         rv = SCARD_E_INSUFFICIENT_BUFFER;

1712

1713                 memcpy(bufAtr, (readerStates[i])->cardAtr, min(*pcbAtrLen, dwAtrLen));

1714         }

1715

1716 end:

1717         (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);

1718

1719         PROFILE_END(rv)

1720

1721         return rv;

1722 }

 

 

1688~1714,与mszReaderName的填充类似,这次是填 pbAtr.

 

好了,想想上面提到的

 

 

1556         /* Check for NULL parameters */

1557         if (pcchReaderLen == NULL)

1558                 pcchReaderLen = &dummy;

1559

1560         if (pcbAtrLen == NULL)

1561                 pcbAtrLen = &dummy;

1564         dwReaderLen = *pcchReaderLen;

1565         dwAtrLen = *pcbAtrLen;

 

 

这样dwReaderLendwAtrLen都是未知的。

比如dwReaderLen拥有未知值,则

1679         if (bufReader)

 

1680         {

 

1681                 if (*pcchReaderLen > dwReaderLen)

 

1682                         rv = SCARD_E_INSUFFICIENT_BUFFER;

 

1683

 

1684                 strncpy(bufReader,

 

1685                         psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName,

 

1686                         dwReaderLen);

//这里就存在bug了。

 

1687         }

 

这样调用SCardStatus的时候,不要传入为0pcchReaderLen,为0pcbAtrLen.

不要传入就好了。这样就天下太平了。或修改前部的参数判断部分,增加对这两个

参数的判断。

因为当两者为0的时候,

1557         if (pcchReaderLen == NULL)

1558                 pcchReaderLen = &dummy;

1559

1560         if (pcbAtrLen == NULL)

1561                 pcbAtrLen = &dummy;

1563         /* length passed from caller */

1564         dwReaderLen = *pcchReaderLen;

1565         dwAtrLen = *pcbAtrLen;

1566

1567         *pcchReaderLen = 0;

1568         *pcbAtrLen = 0;

dwReaderLendwAtrLen的值,是dummy的值。而在1567行之前,dummy是未被初始化的。

所以只要pcchReaderLenpcbAtrLen0的时候,函数实现中,出现dwReaderLendwAtrLen的地方,

(不仅仅是1684~1686)都存在问题。

只要把1567~1568行,放在1564行之前,就可以解决这个问题。或者用上面所说的办法来解决,也是可以的。

 

 

SCardStatus解说结束。

 

 

迷失方向了?回头,回到 testpcsc.c

 

361         test_rv(rv, hContext, PANIC);

362

 

363         printf("Current Reader Name/t/t: " GREEN "%s/n" NORMAL, pcReaders);

364         printf("Current Reader State/t/t: " GREEN "0x%.4lx/n" NORMAL, dwState);

365         printf("Current Reader Protocol/t/t: T=" GREEN "%ld/n" NORMAL, dwProt - 1);

366         printf("Current Reader ATR Size/t/t: " GREEN "%ld" NORMAL " bytes/n",

367                 dwAtrLen);

368         printf("Current Reader ATR Value/t: " GREEN);

369

370         for (i = 0; i < dwAtrLen; i++)

371         {

372                 printf("%02X ", pbAtr[i]);

373         }

374         printf(NORMAL "/n");

 

 

SCardStatus后,开始处理得到的结果。

363行打印读卡器名字。

364行打印读卡器状态。

365行打印读卡器的通讯协议。 dwProt - 1?为什么 ?

因为协议的类型...,算了,长话短说,在/PCSC/pcsclite.h

 

#define SCARD_PROTOCOL_UNDEFINED        0x0000  /**< protocol not set */

#define SCARD_PROTOCOL_UNSET SCARD_PROTOCOL_UNDEFINED   /* backward compat */

#define SCARD_PROTOCOL_T0               0x0001  /**< T=0 active protocol. */

#define SCARD_PROTOCOL_T1               0x0002  /**< T=1 active protocol. */

#define SCARD_PROTOCOL_RAW              0x0004  /**< Raw active protocol. */

#define SCARD_PROTOCOL_T15              0x0008  /**< T=15 protocol. */

 

 

明白了吧。SCARD_PROTOCOL_T01开始的。

 

366~374行打印读卡器中的卡ATR长度。

 

375

376 #ifdef USE_AUTOALLOCATE

377         printf("Testing SCardFreeMemory/t/t: ");

378         rv = SCardFreeMemory(hContext, pcReaders);

379         test_rv(rv, hContext, PANIC);

380         printf("Testing SCardFreeMemory/t/t: ");

381         rv = SCardFreeMemory(hContext, pbAtr);

382         test_rv(rv, hContext, PANIC);

383 #else

384         if (pcReaders)

 

385                 free(pcReaders);

386 #endif

 

 

 

 

375~386行,前面讲解过了。

 

 

387

388         if (rv != SCARD_S_SUCCESS)

389         {

390                 (void)SCardDisconnect(hCard, SCARD_RESET_CARD);

391                 (void)SCardReleaseContext(hContext);

392         }

 

原创粉丝点击