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(共享内存)的状态,寻找和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 }
- PCSC那事儿(二十四--SCardStatus)
- PCSC那事儿(二)
- PCSC那事儿(十四--SCardReleaseContext)
- PCSC那事儿(二十--SCardTransmit)
- PCSC那事儿(二十一--SCardControl)
- PCSC那事儿(二十二--SCardGetAttrib)
- PCSC那事儿(二十三--SCardSetAttrib)
- PCSC那事儿(二十五--SCardDisconnect)
- PCSC那事儿(二十六--SCardReconnect)
- PCSC那事儿(二十八--PCSCD)
- PCSC那事儿(二十九--PCSCD)
- PCSC那事儿(一)
- PCSC那事儿(三)
- PCSC那事儿(四)
- PCSC那事儿(五)
- PCSC那事儿(六)
- PCSC那事儿(七)
- PCSC那事儿(二十七--开始服务端代码分析)
- oracle 定时备份
- C++中处理XML文件
- java 简单工厂设计模式
- PCSC那事儿(二十三--SCardSetAttrib)
- 权限系统
- PCSC那事儿(二十四--SCardStatus)
- J2SE API读取Properties文件六种方法
- 项目经理职责
- PCSC那事儿(二十五--SCardDisconnect)
- 智能家居系统设计关键技术
- 使用PHP的gd库出现问题
- PCSC那事儿(二十六--SCardReconnect)
- 用SetProcessAffinityMask为进程指定CPU
- 找到并执着于自己喜爱的事情---史蒂夫·乔布斯在斯坦福大学毕业典礼上的演讲