这个很典型的, socket 写操作。采用非阻塞方式写数据。
同样的 SHMMessageReceive 也很典型, socket 读操作。采用非阻塞方式读数据。不再罗列了。
提前说明, testpcsc 和 pcscd 之间的通讯,是通过结构体 sharedSegmentMsg ( 仅仅是通用的一个,后续的
用到的 API 会详细解说 ) ,无论收还是发,都是通过这个结构体解包数据和打包数据。
364 sharedSegmentMsg msgStruct; |
在 winscard_msg.h 中定义:
typedef struct rxSharedSegment { uint32_t mtype; /** one of the /c pcsc_adm_commands */ uint32_t user_id; uint32_t group_id; uint32_t command; /** one of the /c pcsc_msg_commands */ uint64_t date; unsigned char key[PCSCLITE_MSG_KEY_LEN]; /* 16 bytes */ union { unsigned char data[PCSCLITE_MAX_MESSAGE_SIZE]; struct version_struct veStr; }; } sharedSegmentMsg, *psharedSegmentMsg; |
到这里, testpcsc 第一次运行的上下文建立的特别处理结束了。第一次,容易吗?
不容易。设置 isExecuted = 1.
511~545 行,
建立 establish_struct 结构,进行通讯。
363 establish_struct scEstablishStruct; |
并向 pcscd 发送请求,请求在 pcscd 内部建立对应的上下文 ( 服务器应用程序上下文 ) 。
519 行, WrapSHMWrite
是 SHMMessageSend 的一个包装。
定义在 winscard_msg.c 中
实现如下:
412 INTERNAL int32_t WrapSHMWrite(uint32_t command, uint32_t dwClientID, 413 uint64_t size, uint32_t blockAmount, void *data_void) 414 { 415 char *data = data_void; 416 417 sharedSegmentMsg msgStruct; 418 int ret; 419 420 /* 421 * Set the appropriate packet parameters
422 */ 423 424 memset(&msgStruct, 0, sizeof(msgStruct)); 425 msgStruct.mtype = CMD_FUNCTION; 426 msgStruct.user_id = SYS_GetUID(); 427 msgStruct.group_id = SYS_GetGID(); 428 msgStruct.command = command; 429 msgStruct.date = time(NULL); 430 memset(msgStruct.key, 0, sizeof(msgStruct.key)); 431 if ((SCARD_TRANSMIT_EXTENDED == command) 432 || (SCARD_CONTROL_EXTENDED == command)) 433 { 434 /* first block */ 435 if (size > sizeof(msgStruct.data)) 436 memcpy(msgStruct.data, data, sizeof(msgStruct.data)); 437 else 438 { 439 memcpy(msgStruct.data, data, size); 440 memset(msgStruct.data+size, 0, sizeof(msgStruct.data)-size); 441 } 442 443 ret = SHMMessageSend(&msgStruct, sizeof(msgStruct), dwClientID, 444 blockAmount); 445 446 /* do not send an empty second block */ 447 if ((0 == ret) && (size > sizeof(msgStruct.data))) 448 { 449 /* second block */ 450 ret = SHMMessageSend(data+sizeof(msgStruct.data), 451 size-sizeof(msgStruct.data), dwClientID, blockAmount); 452 } 453 } 454 else 455 { 456 memcpy(msgStruct.data, data, size); 457 458 ret = SHMMessageSend(&msgStruct, sizeof(msgStruct), dwClientID, 459 blockAmount); 460 } 461 462 if (SCARD_TRANSMIT == command) 463 /* clean APDU buffer to remove any possible PIN or secret value */ 464 memset(msgStruct.data, 0, min(size, sizeof(msgStruct.data)));
465 466 return ret; 467 } |
实际上分了两次发送,第一次发送了 size 大小数据的前 PCSCLITE_MAX_MESSAGE_SIZE 字节,余下的作为一次性发送 .
而这里的接收采用 SHMClientRead 仅仅是 SHMMessageReceive 的简单包装。
SHMClientRead 定义在 winscard_msg.c
实现如下:
57 INTERNAL int32_t SHMClientRead(psharedSegmentMsg msgStruct, uint32_t dwClien tID, int32_t blockamount) 58 { 59 return SHMMessageReceive(msgStruct, sizeof(*msgStruct), dwClientID, blockamount); 60 } |
远远没有 WrapSHMWrite 麻烦 ( 麻烦不代表复杂 ) 。
SHMMessageReceive, 就是非阻塞读取,提过了。
540 行, SCardGetContextIndiceTH(scEstablishStruct.hContext)
定义在 winscard_clnt.c ,实现如下:
3640 static LONG SCardGetContextIndiceTH(SCARDCONTEXT hContext) 3641 { 3642 int i; 3643 3644 /* 3645 * Find this context and return its spot in the array 3646 */ 3647 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3648 { 3649 if ((hContext == psContextMap[i].hContext) && (hContext != 0)) 3650 return i; 3651 } 3652 3653 return -1; 3654 } |
540~543 行,检查 testpcsc 内的上下文的 hContext 是否与接收回来的申请到的
hContext 重复。如果重复,则重新发出请求。重复的原因是 pcscd 产生
hContext 的方式。实际上, hContext 来自于服务端发出的一个 long 数据 ( 和随机数有关,所以存在重复 ) 。
而服务端不做重复的检测,产生数据后,直接发回给客户端。
具体见后文 ( 服务端 ) 分析。
545 *phContext = scEstablishStruct.hContext; |
看到吗?上面忙的那么多,仅仅为了这一行,终于获取到了上下文和 dwClientID 。
这就是客户端想要 “ 的结果的结果 ” 。
550 rv = SCardAddContext(*phContext, dwClientID); |
这行又做了什么 ?
3585 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID) 3586 { 3587 int i; 3588 3589 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3590 { 3591 if (psContextMap[i].hContext == 0) 3592 { 3593 psContextMap[i].hContext = hContext; 3594 psContextMap[i].dwClientID = dwClientID; 3595 psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME; 3596 psContextMap[i].mMutex = malloc(sizeof(PCSCLITE_MUTEX)); 3597 (void)SYS_MutexInit(psContextMap[i].mMutex); 3598 return SCARD_S_SUCCESS; 3599 } 3600 } 3601 3602 return SCARD_E_NO_MEMORY; 3603 } |
这个是? ... 那还用说吗?上面取得了 hContext,dwClientID, 当然要提交给上下文,
psContextMap, 进行上下文注册,并初始化其它的结构。
很象官场,不是吗 ? 要注册,要管理。
客户端的 SCardEstablishContext 分析完成。
很容易理解吧。那么继续前进。
问:到哪里了?
答案是,别晕了。回去了。
回到 testpcsc.c 的 101 行了。
101 rv = SCardIsValidContext(hContext); |