SCardControl
SCardControl 定义在 winscard_clnt.c
实现如下:
2365 LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, 2366 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, 2367 LPDWORD lpBytesReturned) 2368 { 2369 LONG rv; 2370 control_struct scControlStruct; 2371 sharedSegmentMsg msgStruct; 2372 int i; 2373 DWORD dwContextIndex, dwChannelIndex; 2374 2375 PROFILE_START 2376 2377 /* 0 bytes received by default */ 2378 if (NULL != lpBytesReturned) 2379 *lpBytesReturned = 0; 2380 |
2365~2380 行,要多说吗?
2381 rv = SCardCheckDaemonAvailability(); 2382 if (rv != SCARD_S_SUCCESS) 2383 return rv; 2384 2385 /* 2386 * Make sure this handle has been opened 2387 */ 2388 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 2389 if (rv == -1) 2390 return SCARD_E_INVALID_HANDLE; 2391 2392 (void)SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 2393 2394 /* check the handle is still valid */ 2395 rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex); 2396 if (rv == -1) 2397 /* the handle is now invalid 2398 * -> another thread may have called SCardReleaseContext 2399 * -> so the mMutex has been unlocked */ 2400 return SCARD_E_INVALID_HANDLE; 2401 |
2381~2401 行,上面提过了。
问:有不少代码重复。
答案是,可以考虑 refator. 说说而已。
2402 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2403 { 2404 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName; 2405 2406 /* by default r == NULL */ 2407 if (r && strcmp(r, (readerStates[i])->readerName) == 0) 2408 break; 2409 } 2410 2411 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 2412 { 2413 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2414 return SCARD_E_READER_UNAVAILABLE; 2415 } 2416 2417 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED) 2418 || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED)) 2419 { 2420 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2421 return SCARD_E_INSUFFICIENT_BUFFER; 2422 } |
2402~2422 行, “ 豁然回首月明中,雕栏玉砌应犹在 ...”
看看这些在 SCardTransmit 都有。不用重复解说了。
2423 2424 if ((cbSendLength > MAX_BUFFER_SIZE) || (cbRecvLength > MAX_BUFFER_SIZE)) 2425 { 2426 /* extended control */ 2427 unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED]; 2428 control_struct_extended *scControlStructExtended = (control_struct_extended *)buffer;
2429 sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer; 2430 2431 scControlStructExtended->hCard = hCard; 2432 scControlStructExtended->dwControlCode = dwControlCode; 2433 scControlStructExtended->cbSendLength = cbSendLength; 2434 scControlStructExtended->cbRecvLength = cbRecvLength; 2435 scControlStructExtended->dwBytesReturned = 0; 2436 scControlStructExtended->rv = SCARD_S_SUCCESS; 2437 /* The size of data to send is the size of 2438 * struct control_struct_extended WITHOUT the data[] field 2439 * plus the effective data[] size 2440 */ 2441 scControlStructExtended->size = sizeof(*scControlStructExtended) 2442 - (sizeof(control_struct_extended) - offsetof(control_struct_extended, data)) 2443 + cbSendLength; 2444 memcpy(scControlStructExtended->data, pbSendBuffer, cbSendLength); |
2423~2444 行,这个是?好像在哪里看过。对了还是在 SCardTransmit 收发长 APDU
的时候。
上面提到了
长 APDU 用到的那两种结构。发送采用 transmit_struct_extended
结构,接收采用 sharedSegmentMsg 结构, data 域内嵌 transmit_struct_extended 结构。
相比,短 APDU 也用到了两种结构。发送采用 transmit_struct 结构,接收采用 sharedSegmentMsg 结构, data 域内嵌 transmit_struct 。
对于 SCardControl ,采用一样的策略,但不同的结构体。
想到什么了?没法使用模板,这里采用了 c 。
长 APDU 用到了两种结构。发送采用 control_struct_extended
结构,接收采用 sharedSegmentMsg 结构, data 域内嵌 control_struct_extended 结构。
相比,短 APDU 也用到了两种结构。发送采用 control_struct 结构,接收采用 sharedSegmentMsg 结构, data 域内嵌 control_struct 。
control_struct 定义在 winscard_msg.h
struct control_struct { int32_t hCard; uint32_t dwControlCode; uint8_t pbSendBuffer[MAX_BUFFER_SIZE];
uint32_t cbSendLength; uint8_t pbRecvBuffer[MAX_BUFFER_SIZE]; uint32_t cbRecvLength; uint32_t dwBytesReturned; uint32_t rv; }; typedef struct control_struct control_struct;
|
control_struct_extended 定义在 winscard_msg.h
struct control_struct_extended { int32_t hCard; uint32_t dwControlCode; uint32_t cbSendLength; uint32_t cbRecvLength; uint32_t dwBytesReturned; uint32_t rv; uint64_t size; uint8_t data[1]; }; typedef struct control_struct_extended control_struct_extended; |
2445 2446 rv = WrapSHMWrite(SCARD_CONTROL_EXTENDED, 2447 psContextMap[dwContextIndex].dwClientID, 2448 scControlStructExtended->size, 2449 PCSCLITE_CLIENT_ATTEMPTS, buffer); 2450 2451 if (rv == -1) 2452 { 2453 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2454 return SCARD_E_NO_SERVICE; 2455 } 2456 2457 /* 2458 * Read a message from the server 2459 */ 2460 /* read the first block */ 2461 rv = SHMMessageReceive(buffer, sizeof(sharedSegmentMsg),
2462 psContextMap[dwContextIndex].dwClientID, PCSCLITE_CLIENT_ATTEMPTS); 2463 if (rv == -1) 2464 { 2465 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2466 return SCARD_F_COMM_ERROR; 2467 } 2468 2469 /* we receive a sharedSegmentMsg and not a control_struct_extended */ 2470 scControlStructExtended = (control_struct_extended *)&(pmsgStruct -> data); 2471 2472 /* a second block is present */ 2473 if (scControlStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE) 2474 { 2475 rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg), 2476 scControlStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE, 2477 psContextMap[dwContextIndex].dwClientID, 2478 PCSCLITE_CLIENT_ATTEMPTS); 2479 if (rv == -1) 2480 { 2481 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2482 return SCARD_F_COMM_ERROR; 2483 } 2484 } 2485 2486 if (scControlStructExtended -> rv == SCARD_S_SUCCESS) 2487 { 2488 /* 2489 * Copy and zero it so any secret information is not leaked 2490 */ 2491 memcpy(pbRecvBuffer, scControlStructExtended -> data, 2492 scControlStructExtended -> dwBytesReturned); 2493 memset(scControlStructExtended -> data, 0x00, 2494 scControlStructExtended -> dwBytesReturned); 2495 } 2496 2497 if (NULL != lpBytesReturned) 2498 *lpBytesReturned = scControlStructExtended -> dwBytesReturned; 2499 2500 rv = scControlStructExtended -> rv; 2501 } |
2445~2501 行,长 APDU 处理完成。方法和 SCardTransmit 的长 APDU 一样。
仅仅是方法处理的数据结构不同。您会想到 “ 模板 ” 的好。
2502 else 2503 { 2504 scControlStruct.hCard = hCard; 2505 scControlStruct.dwControlCode = dwControlCode; 2506 scControlStruct.cbSendLength = cbSendLength; 2507 scControlStruct.cbRecvLength = cbRecvLength; 2508 memcpy(scControlStruct.pbSendBuffer, pbSendBuffer, cbSendLength); 2509 2510 rv = WrapSHMWrite(SCARD_CONTROL, 2511 psContextMap[dwContextIndex].dwClientID, 2512 sizeof(scControlStruct), PCSCLITE_CLIENT_ATTEMPTS, &scControlStruct); 2513 2514 if (rv == -1) 2515 { 2516 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2517 return SCARD_E_NO_SERVICE; 2518 } 2519 2520 /* 2521 * Read a message from the server 2522 */ 2523 rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID, 2524 PCSCLITE_CLIENT_ATTEMPTS); 2525 2526 if (rv == -1) 2527 { 2528 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2529 return SCARD_F_COMM_ERROR; 2530 } 2531 2532 memcpy(&scControlStruct, &msgStruct.data, sizeof(scControlStruct)); 2533 2534 if (NULL != lpBytesReturned) 2535 *lpBytesReturned = scControlStruct.dwBytesReturned; 2536 2537 if (scControlStruct.rv == SCARD_S_SUCCESS)
2538 { 2539 /* 2540 * Copy and zero it so any secret information is not leaked 2541 */ 2542 memcpy(pbRecvBuffer, scControlStruct.pbRecvBuffer, 2543 scControlStruct.cbRecvLength); 2544 memset(scControlStruct.pbRecvBuffer, 0x00, 2545 sizeof(scControlStruct.pbRecvBuffer)); 2546 } 2547 2548 rv = scControlStruct.rv; 2549 } 2550 2551 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2552 2553 PROFILE_END(rv) 2554 2555 return rv; 2556 } |
2502~2556 行,短 APDU 的处理。方法和 SCardTransmit 中短 APDU 的处理一样。
仅仅是方法处理的数据结构不同。
长 APDU 的处理还是比较有技巧的。通过一次发,两次收,就可以收到 PCSCLITE_MAX_MESSAGE_SIZE + MAX_BUFFER_SIZE_EXTENDED 这么长的交互数据。
或许会想到,要这么麻烦,结构嵌套结构?可以第一次仅仅返回数据长度,第二次返回所有数据。前面提到了, testpcsc 与 pcscd 之间采用 socket 通讯,虽然这里仅仅是一次发 ( 实际有可能是两次,详细见发送函数 WrapSHMWrite ) ,两次收,但对于底层来说,可能会被分解为多次的发,多次的收。如果第一次仅仅返回数据长度,这么小的信息量也要收一次,则发送效率比较低。所以第一次收的时候,除了返回数据长度,也返回了最大 PCSCLITE_MAX_MESSAGE_SIZE 长度的数据。
SCardControl 解说结束。
回头,回头。
回到 testpcsc.c
276 test_rv(rv, hContext, DONT_PANIC); 277 278 printf("Testing SCardGetAttrib/t/t: "); 279 #ifdef USE_AUTOALLOCATE 280 pcbAttrLen = SCARD_AUTOALLOCATE; 281 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, (unsigned char *)&pbAttr, 282 &pcbAttrLen); 283 #else 284 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &pcbAttrLen); 285 test_rv(rv, hContext, DONT_PANIC); 286 if (rv == SCARD_S_SUCCESS) 287 { 288 printf("SCARD_ATTR_ATR_STRING length: " GREEN "%ld/n" NORMAL , pcbAttrLen); 289 pbAttr = malloc(pcbAttrLen); 290 } 291 292 printf("Testing SCardGetAttrib/t/t: "); 293 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAttr, &pcbAttrLen); 294 #endif
|
281~282 行
rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, (unsigned char *)&pbAttr,
&pcbAttrLen);