SCardEstablishContext
305 LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, 306 LPCVOID pvReserved2, LPSCARDCONTEXT phContext) 307 { 308 LONG rv; 309 310 PROFILE_START 311 312 /* Check if the server is running */ 313 rv = SCardCheckDaemonAvailability(); 314 if (SCARD_E_INVALID_HANDLE == rv) 315 /* we reconnected to a daemon or we got called from a forked child */ 316 rv = SCardCheckDaemonAvailability(); 317 318 if (rv != SCARD_S_SUCCESS) 319 return rv; 320 321 (void) SCardLockThread (); 322 rv = SCardEstablishContextTH (dwScope, pvReserved1, 323 pvReserved2, phContext); 324 (void) SCardUnlockThread (); 325 326 PROFILE_END (rv) 327 328 return rv; 329 } |
312~319 都在 SCardCheckDaemonAvailability ,
也在 winscard_clnt.c 中实现。
3790 LONG SCardCheckDaemonAvailability(void) 3791 { 3792 LONG rv; 3793 struct stat statBuffer; 3794 int need_restart = 0; 3795 3796 rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &statBuffer); 3797 3798 if (rv != 0) 3799 { 3800 Log2(PCSC_LOG_INFO, "PCSC Not Running: " PCSCLITE_PUBSHM_FILE ": %s", 3801 strerror(errno)); 3802 return SCARD_E_NO_SERVICE;
3803 } 3804 3805 /* when the _first_ reader is connected the ctime changes 3806 * I don't know why yet */ 3807 if (daemon_ctime && statBuffer.st_ctime > daemon_ctime) 3808 { 3809 /* so we also check the daemon pid to be sure it is a new pcscd */ 3810 if (GetDaemonPid() != daemon_pid) 3811 { 3812 Log1(PCSC_LOG_INFO, "PCSC restarted"); 3813 need_restart = 1; 3814 } 3815 } 3816 3817 /* after fork() need to restart */ 3818 if (client_pid && client_pid != getpid()) 3819 { 3820 Log1(PCSC_LOG_INFO, "Client forked"); 3821 need_restart = 1; 3822 } 3823 3824 if (need_restart) 3825 { 3826 int i; 3827 3828 /* invalid all handles */ 3829 (void)SCardLockThread(); 3830 3831 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 3832 if (psContextMap[i].hContext) 3833 (void)SCardCleanContext(i); 3834 3835 (void)SCardUnlockThread(); 3836 3837 /* reset pcscd status */ 3838 daemon_ctime = 0; 3839 client_pid = 0; 3840 3841 /* reset the lib */ 3842 SCardUnload(); 3843 3844 return SCARD_E_INVALID_HANDLE; 3845 }
3846 3847 daemon_ctime = statBuffer.st_ctime; 3848 daemon_pid = GetDaemonPid(); 3849 client_pid = getpid(); 3850 3851 return SCARD_S_SUCCESS; 3852 } |
pcscd.h:
#define PCSCLITE_PUBSHM_FILE PCSCLITE_IPC_DIR "/pcscd.pub"
#define PCSCLITE_IPC_DIR /var/run/pcscd
原来 PCSCLITE_PUBSHM_FILE 表示临时文件。
3896~3803 行,首先应用探测这个临时文件是否存在,如果不存在,就表示服务器 pcscd 例程还没有启动。
原因是 pcscd 启动的时候会创建这个临时文件。
先启动 pcscd ,再启动 testpcsc 后, daemon_ctime , daemon_pid , client_pid
都是 0. 所以
3807 行,条件判断无法成立。
3818 行,也无法成立,则越过 3824 行,并首次
对以上 3 个变量进行了初始化。
如果启动 pcscd 后,再启动 testpcsc, 但是正如
3805~3815 行, pcscd 因为某种原因,重新启动或者正如
3817~3822 行,应用
本身 clone 自身,则 need_restart=1
回到 SCardEstablishContext, 再次出现调用 SCardCheckDaemonAvailability
313~316 行,处理处理上一次 SCardCheckDaemonAvailability 调用过程中 need_restart 等于 1 的情况,
因为上一次调用 SCardCheckDaemonAvailability 如果 need_restart 等于 1 ,则会返回 SCARD_E_INVALID_HANDLE, 引起第二次调用 SCardCheckDaemonAvailability.
目的是正确设置 daemon_ctime , daemon_pid , client_pid 这些变量。
SCardEstablishContext 就做了这些,加锁后,然后代理给 SCardEstablishContextTH.
357 static LONG SCardEstablishContextTH(DWORD dwScope, 358 /*@unused@*/ LPCVOID pvReserved1, 359 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext) 360 { 361 LONG rv; 362 int i; 363 establish_struct scEstablishStruct; 364 sharedSegmentMsg msgStruct; 365 uint32_t dwClientID = 0; 366 367 (void)pvReserved1; 368 (void)pvReserved2;
369 if (phContext == NULL)
370 return SCARD_E_INVALID_PARAMETER; 371 else 372 *phContext = 0; 373 374 /* 375 * Do this only once: 376 * - Initialize debug of need. 377 * - Set up the memory mapped structures for reader states. 378 * - Allocate each reader structure. 379 * - Initialize context struct. 380 */ 381 if (isExecuted == 0) 382 { 383 int pageSize; 384 385 /* 386 * Do any system initilization here 387 */ 388 (void)SYS_Initialize(); 389 390 /* 391 * Set up the memory mapped reader stats structures 392 */ 393 mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0); 394 if (mapAddr < 0) 395 { 396 Log3(PCSC_LOG_CRITICAL, "Cannot open public shared file %s: %s", 397 PCSCLITE_PUBSHM_FILE, strerror(errno)); 398 return SCARD_E_NO_SERVICE; 399 } 400 401 /* close on exec so that child processes do not inherits the file 402 * descriptor. The child process will call SCardEstablishContext() 403 * if needed. */
404 (void)fcntl(mapAddr, F_SETFD, FD_CLOEXEC); 405 406 pageSize = SYS_GetPageSize(); 407 408 /*
409 * Allocate each reader structure in the memory map
410 */ 411 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 412 { 413 readerStates[i] = 414 (PREADER_STATE)SYS_PublicMemoryMap(sizeof(READER_STATE), 415 mapAddr, (i * pageSize)); 416 if (readerStates[i] == NULL) 417 { 418 Log2(PCSC_LOG_CRITICAL, "Cannot public memory map: %s", 419 strerror(errno)); 420 (void)SYS_CloseFile(mapAddr); /* Close the memory map file */ 421 return SCARD_F_INTERNAL_ERROR; 422 } 423 } 424 425 /* 426 * Initializes the application contexts and all channels for each one 427 */ 428 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 429 { 430 int j; 431 432 /* 433 * Initially set the context struct to zero 434 */ 435 psContextMap[i].dwClientID = 0; 436 psContextMap[i].hContext = 0; 437 psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME; 438 psContextMap[i].mMutex = NULL; 439 440 for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++) 441 { 442 /* 443 * Initially set the hcard structs to zero 444 */ 445 psContextMap[i].psChannelMap[j].hCard = 0; 446 psContextMap[i].psChannelMap[j].readerName = NULL; 447 } 448 }
449 450 } 451 452 /* 453 * Is there a free slot for this connection ? 454 */ 455 456 for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++) 457 { 458 if (psContextMap[i].dwClientID == 0) 459 break; 460 } 461 462 if (i == PCSCLITE_MAX_APPLICATION_CONTEXTS) 463 { 464 return SCARD_E_NO_MEMORY; 465 } 466 467 /* Establishes a connection to the server */ 468 if (SHMClientSetupSession(&dwClientID) != 0) 469 { 470 (void)SYS_CloseFile(mapAddr); 471 return SCARD_E_NO_SERVICE; 472 } 473 474 { /* exchange client/server protocol versions */ 475 version_struct *veStr; 476 477 memset(&msgStruct, 0, sizeof(msgStruct)); 478 msgStruct.mtype = CMD_VERSION; 479 msgStruct.user_id = SYS_GetUID(); 480 msgStruct.group_id = SYS_GetGID(); 481 msgStruct.command = 0; 482 msgStruct.date = time(NULL); 483 484 veStr = &msgStruct.veStr; 485 veStr->major = PROTOCOL_VERSION_MAJOR; 486 veStr->minor = PROTOCOL_VERSION_MINOR; 487 488 if (-1 == SHMMessageSend(&msgStruct, sizeof(msgStruct), dwClientID, 489 PCSCLITE_MCLIENT_ATTEMPTS)) 490 return SCARD_E_NO_SERVICE; 491
492 /* 493 * Read a message from the server 494 */ 495 if (-1 == SHMMessageReceive(&msgStruct, sizeof(msgStruct), dwClientID, 496 PCSCLITE_CLIENT_ATTEMPTS)) 497 { 498 Log1(PCSC_LOG_CRITICAL, "Your pcscd is too old and does not support CMD_VERSION"); 499 return SCARD_F_COMM_ERROR; 500 } 501 502 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d", 503 veStr->major, veStr->minor); 504 505 if (veStr->rv != SCARD_S_SUCCESS) 506 return veStr->rv; 507 508 isExecuted = 1; 509 } 510 511 again: 512 /* 513 * Try to establish an Application Context with the server 514 */ 515 scEstablishStruct.dwScope = dwScope; 516 scEstablishStruct.hContext = 0; 517 scEstablishStruct.rv = SCARD_S_SUCCESS; 518 519 rv = WrapSHMWrite(SCARD_ESTABLISH_CONTEXT, dwClientID, 520 sizeof(scEstablishStruct), PCSCLITE_MCLIENT_ATTEMPTS, 521 (void *) &scEstablishStruct); 522 523 if (rv == -1) 524 return SCARD_E_NO_SERVICE; 525 526 /* 527 * Read the response from the server 528 */ 529 rv = SHMClientRead(&msgStruct, dwClientID, PCSCLITE_CLIENT_ATTEMPTS); 530 531 if (rv == -1)
532 return SCARD_F_COMM_ERROR; 533 534 memcpy(&scEstablishStruct, &msgStruct.data, sizeof(scEstablishStruct)); 535 536 if (scEstablishStruct.rv != SCARD_S_SUCCESS) 537 return scEstablishStruct.rv; 538 539 /* check we do not reuse an existing phContext */ 540 if (-1 != SCardGetContextIndiceTH(scEstablishStruct.hContext)) 541 /* we do not need to release the allocated context since 542 * SCardReleaseContext() does nothing on the server side */ 543 goto again; 544 545 *phContext = scEstablishStruct.hContext; 546 547 /* 548 * Allocate the new hContext - if allocator full return an error 549 */ 550 rv = SCardAddContext(*phContext, dwClientID); 551 552 return rv; 553 } |