SCardConnect
214 行, SCardConnect 定义在 winscard_clnt.c
实现如下:
734 LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, 735 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, 736 LPDWORD pdwActiveProtocol)
737 { 738 LONG rv; 739 connect_struct scConnectStruct; 740 sharedSegmentMsg msgStruct; 741 LONG dwContextIndex; 742 743 PROFILE_START 744 745 /* 746 * Check for NULL parameters 747 */ 748 if (phCard == NULL || pdwActiveProtocol == NULL) 749 return SCARD_E_INVALID_PARAMETER; 750 else 751 *phCard = 0; 752 753 if (szReader == NULL) 754 return SCARD_E_UNKNOWN_READER; 755 756 /* 757 * Check for uninitialized strings 758 */ 759 if (strlen(szReader) > MAX_READERNAME) 760 return SCARD_E_INVALID_VALUE; 761 762 rv = SCardCheckDaemonAvailability(); 763 if (rv != SCARD_S_SUCCESS) 764 return rv; 765 766 /* 767 * Make sure this context has been opened 768 */ 769 dwContextIndex = SCardGetContextIndice(hContext); 770 if (dwContextIndex == -1) 771 return SCARD_E_INVALID_HANDLE; 772 773 (void)SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 774 775 /* check the context is still opened */ 776 dwContextIndex = SCardGetContextIndice(hContext); 777 if (dwContextIndex == -1) 778 /* the context is now invalid 779 * -> another thread may have called SCardReleaseContext
780 * -> so the mMutex has been unlocked */ 781 return SCARD_E_INVALID_HANDLE; 782 783 strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME); 784 785 scConnectStruct.hContext = hContext; 786 scConnectStruct.dwShareMode = dwShareMode; 787 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols; 788 scConnectStruct.hCard = 0; 789 scConnectStruct.dwActiveProtocol = 0; 790 scConnectStruct.rv = SCARD_S_SUCCESS; 791 792 rv = WrapSHMWrite(SCARD_CONNECT, psContextMap[dwContextIndex].dwClientID, 793 sizeof(scConnectStruct), 794 PCSCLITE_CLIENT_ATTEMPTS, (void *) &scConnectStruct); 795 796 if (rv == -1) 797 { 798 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 799 return SCARD_E_NO_SERVICE; 800 } 801 802 /* 803 * Read a message from the server 804 */ 805 rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID, 806 PCSCLITE_CLIENT_ATTEMPTS); 807 808 memcpy(&scConnectStruct, &msgStruct.data, sizeof(scConnectStruct)); 809 810 if (rv == -1) 811 { 812 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 813 return SCARD_F_COMM_ERROR; 814 } 815 816 *phCard = scConnectStruct.hCard; 817 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol; 818 819 if (scConnectStruct.rv == SCARD_S_SUCCESS) 820 {
821 /* 822 * Keep track of the handle locally 823 */ 824 rv = SCardAddHandle(*phCard, dwContextIndex, szReader); 825 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 826 827 PROFILE_END(rv) 828 829 return rv; 830 } 831 832 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 833 834 PROFILE_END(scConnectStruct.rv) 835 836 return scConnectStruct.rv; 837 } |
SCardConnect 与参数 szReader 指定的读卡器进行通讯。
737~760 行,进行常规检查。
761~781 行,解释过 n 次了。
782~790 行,构造 connect_struct 结构体,初始化成员,准备和 pcscd 通讯,进行连接。
791~814 行,向 pcscd 发请求,收取回应。
问: SCardConnect 到底要从 pcscd 获取什么?
答案是,获取 SCARDHANDLE, 获取可用的通讯协议。
816 *phCard = scConnectStruct.hCard; 817 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol; |
可以看出, SCardConnect 的用心。
818 819 if (scConnectStruct.rv == SCARD_S_SUCCESS) 820 { 821 /* 822 * Keep track of the handle locally 823 */ 824 rv = SCardAddHandle(*phCard, dwContextIndex, szReader); 825 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
826 827 PROFILE_END(rv) 828 829 return rv; 830 } |
SCardAddHandle 定义在 winscard_clnt.c
实现如下:
3705 static LONG SCardAddHandle(SCARDHANDLE hCard, DWORD dwContextIndex, 3706 LPCSTR readerName) 3707 { 3708 int i; 3709 3710 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++) 3711 { 3712 if (psContextMap[dwContextIndex].psChannelMap[i].hCard == 0) 3713 { 3714 psContextMap[dwContextIndex].psChannelMap[i].hCard = hCard; 3715 psContextMap[dwContextIndex].psChannelMap[i].readerName = strdup(readerName); 3716 return SCARD_S_SUCCESS; 3717 } 3718 } 3719 3720 return SCARD_E_NO_MEMORY; 3721 } |
很早很早以前,就说过了, psContextMap 中有两个重要的句柄,它们都是 long 类型。
归 psContextMap 管。毫无疑问, SCardAddHandle 把得来的 hCard 注册入 psContextMap
. 应用上下文, APPLICATION 大爷。 SCardAddHandle 把得来的 hCard 进贡给这个大佬。
上面提过了,实际上,分析服务端代码,就可以知道 hContext 是一个随机索引,用于获取
客户端的应用上下文和服务端的应用上下文,而 hCard 用于获取客户端和服务端维护的一个 channel 也就是在一个应用上下文中的一个连接 ( 一个应用上下文可以有多个连接 ) 。
SCardConnect 结束。
218 219 switch(dwPref) 220 { 221 case SCARD_PROTOCOL_T0: 222 pioSendPci = *SCARD_PCI_T0;
223 break; 224 case SCARD_PROTOCOL_T1: 225 pioSendPci = *SCARD_PCI_T1; 226 break; 227 case SCARD_PROTOCOL_RAW: 228 pioSendPci = *SCARD_PCI_RAW; 229 break; 230 default: 231 printf("Unknown protocol/n"); 232 return -1; 233 } |
218~233 行说明对 根据 SCardConnect 返回的协议类型对 pioSendPci 赋值。
234 235 /* APDU select file */ 236 printf("Select file:"); 237 send_length = 7; 238 memcpy(bSendBuffer, "/x00/xA4/x00/x00/x02/x3F/x00", send_length); 239 for (i=0; i<send_length; i++) 240 printf(" %02X", bSendBuffer[i]); 241 printf("/n"); 242 length = sizeof(bRecvBuffer); |
234~242 做什么?
选择文件,而且是选择 MF(SMART CARD 的主文件 ). 往 bSendBuffer 中填充选择 MF 命令字符串。
243 244 printf("Testing SCardTransmit/t/t: "); 245 rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length, 246 &pioRecvPci, bRecvBuffer, &length); |