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 } |