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

 

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( 共享内存 ) 的状态,寻找和 dwContextIndex dwChangelIndex

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

特殊情况,如果 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 与上面提到的 SCardGetSetAttrib SCardTransmit SCardControl

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

数据结构。

 

发送采用 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;

 

 

这样 dwReaderLen dwAtrLen 都是未知的。

比如 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 的时候,不要传入为 0 pcchReaderLen ,为 0 pcbAtrLen.

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

参数的判断。

因为当两者为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;

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

所以只要 pcchReaderLen pcbAtrLen 0 的时候,函数实现中,出现 dwReaderLen dwAtrLen 的地方,

( 不仅仅是 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_T0 1 开始的。

 

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         }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值