PCSC那事儿(二十八--PCSCD)
来源:互联网 发布:明天教室网络课好吗 编辑:程序博客网 时间:2024/05/22 04:50
Info.plist这个文件以后再说。
所以呢,serial和PCMCIA类型的读卡器在/etc/reader.conf配置。
usb类型的读卡器在/usr/local/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist配置。
307~312行,表示出现了不在上面提到的选项。则程序直接退出,而不是忽略。
313
314 /*
315 * test the presence of /var/run/pcscd/pcsc.pub
316 */
317
318 rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &fStatBuf);
319
317~319行,这个好像在哪里见过,当然了前面讲解客户端的时候,说过了。
PCSCLITE_PUBSHM_FILE,就是共享内存所在的文件路径。
而PCSCLITE_PUBSHM_FILE在前面说过了,是/var/run/pcscd/pcscd.pub
315行,实际上应该改成*test the presence of /var/run/pcscd/pcscd.pub
检测该文件是否存在,存在则返回0.
320 if (rv == 0)
321 {
322 pid_t pid;
323
324 /* read the pid file to get the old pid and test if the old pcscd is
325 * still running
326 */
327 pid = GetDaemonPid();
328
329 if (pid != -1)
330 {
331 if (HotPlug)
332 return SendHotplugSignal();
333
334 if (kill(pid, 0) == 0)
335 {
336 Log1(PCSC_LOG_CRITICAL,
337 "file " PCSCLITE_PUBSHM_FILE " already exists.");
338 Log2(PCSC_LOG_CRITICAL,
339 "Another pcscd (pid: %d) seems to be running.", pid);
340 return EXIT_FAILURE;
341 }
342 else
343 /* the old pcscd is dead. make some cleanup */
344 clean_temp_files();
345 }
346 else
320行,如果共享内存文件存在,则开始进入判断体。
327行,pid = GetDaemonPid();
GetDaemonPid定义在utils.c
实现如下:
31 pid_t GetDaemonPid(void)
32 {
33 FILE *f;
34 pid_t pid;
35
36 /* pids are only 15 bits but 4294967296
37 * (32 bits in case of a new system use it) is on 10 bytes
38 */
39 if ((f = fopen(PCSCLITE_RUN_PID, "rb")) != NULL)
40 {
41 char pid_ascii[PID_ASCII_SIZE];
42
43 (void)fgets(pid_ascii, PID_ASCII_SIZE, f);
44 (void)fclose(f);
45
46 pid = atoi(pid_ascii);
47 }
48 else
49 {
50 Log2(PCSC_LOG_CRITICAL, "Can't open " PCSCLITE_RUN_PID ": %s",
51 strerror(errno));
52 return -1;
53 }
54
55 return pid;
56 } /* GetDaemonPid */
PCSCLITE_RUN_PID /var/run/pcscd /pcscd.pid
首次检查这个文件是存在,存在则从中读取pid号。否则直接退出。
329行,说明存id的文件存在。
331~332行,说明如果pcscd传入的命令行选项有-H或--hotplug则
SendHotplugSignal
SendHotplugSignal定义在utils.c
实现如下:
58 int SendHotplugSignal(void)
59 {
60 pid_t pid;
61
62 pid = GetDaemonPid();
63
64 if (pid != -1)
65 {
66 Log2(PCSC_LOG_INFO, "Send hotplug signal to pcscd (pid=%d)", pid);
67 if (kill(pid, SIGUSR1) < 0)
68 {
69 Log3(PCSC_LOG_CRITICAL, "Can't signal pcscd (pid=%d): %s",
70 pid, strerror(errno));
71 return EXIT_FAILURE ;
72 }
73 (void)SYS_Sleep(1);
74 }
75
76 return EXIT_SUCCESS;
77 } /* SendHotplugSignal */
原来是这样。从上面提到的那个文件中读取pid,然后真正检测该pid进程是否存在于系统
中。这个检测出现在67行。
if(kill(pid, SIGUSR1) < 0)
kill 做什么?找man看看
man说
On success (at least one signal was sent),zero is returned. On error,
-1 is returned, and errno is setappropriately.
也就是说如果kill返回值<0则该pid对应的进程不存在。
所以SendHotplugSignal真正检测pcscd这个进程是否存在。如果存在则程序且能响应信号直接返回,目的是为了重新scan所有的设备。
如果旧pcscd进程不存在呢?
那么意味着,每次键入如下命令新的pcscd进程都会直接退出。
# pcscd -H
都会出现执行如下片段,而退出。
348 if (HotPlug)
349 {
350 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
351 Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
352 return EXIT_FAILURE;
353 }
这是个用户定义的Signal,看看SIGUSR1挂接了什么例程。
527 (void)signal(SIGUSR1, signal_reload);
571 static void signal_reload(/*@unused@*/ int sig)
572 {
573 (void)sig;
574
575 if (AraKiri)
576 return;
577
578 HPReCheckSerialReaders();
579 } /* signal_reload */
571~579行,没有做什么大事,仅仅检测serial类型的读卡器。
总的来说
331 if (HotPlug)
332 return SendHotplugSignal();
用来给原先存在的还正常运行的pcscd发信号,重新检测系统中的serial版本的读卡器.
无论成功,失败,新的pcscd都不再运行。
334行,又做什么?再次kill.
334 if (kill(pid, 0) == 0)
那是没有HotPlug时候的故事。
看看man如何解释。
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
If sig is0, then no signal is sent, but error checking is still per-
formed.
不发送信号,仅仅检测原先的pid是否还存在于系统中。
如果原先的pid存在,则返回。不再启动新的pid.
不存在则,
344 clean_temp_files();
clean_temp_files定义在同一个文件pcscdaemon.c
实现如下:
544 static void clean_temp_files(void)
545 {
546 int rv;
547
548 rv = SYS_RemoveFile(PCSCLITE_PUBSHM_FILE);
549 if (rv != 0)
550 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_PUBSHM_FILE ": %s",
551 strerror(errno));
552
553 rv = SYS_RemoveFile(PCSCLITE_CSOCK_NAME);
554 if (rv != 0)
555 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
556 strerror(errno));
557
558 rv = SYS_RemoveFile(PCSCLITE_RUN_PID);
559 if (rv != 0)
560 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
561 strerror(errno));
562
563 (void)StatSynchronize(NULL);
564 SYS_Sleep(1);
565 rv = SYS_RemoveFile(PCSCLITE_EVENTS_DIR);
566 if (rv != 0)
567 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_EVENTS_DIR ": %s",
568 strerror(errno));
569 }
clean_temp_files要干不少活?
具体做哪些?
一个一个来。
要删除4个文件。
这4个文件分别是:
PCSCLITE_PUBSHM_FILE /var/run/pcscd/pcscd.pub
共享内存文件,在APPLICATION和pcscd之间共享内存。
PCSCLITE_CSOCK_NAME/var/run/pcscd/pcscd.comm
本地socket通讯文件。
PCSCLITE_RUN_PID/var/run/pcscd/pcscd.pid
这个文件的存在目的,上面提过了。
PCSCLITE_EVENTS_DIR/var/run/pcscd/pcscd.events 这个是目录。
这个是... 正要解说。实际上关系到很久以前提到的问题(见64页提到的fifo)。
563行,StatSynchronize定义在utils.c
实现如下:
87 int StatSynchronize(struct pubReaderStatesList *readerState)
88 {
89 DIR *dir_fd;
90 struct dirent *dir;
91
92 if (readerState)
93 (void)SYS_MMapSynchronize((void *)readerState, SYS_GetPageSize() );
94
95 dir_fd = opendir(PCSCLITE_EVENTS_DIR);
96 if (NULL == dir_fd)
97 {
98 Log2(PCSC_LOG_ERROR, "Can't opendir " PCSCLITE_EVENTS_DIR ": %s",
99 strerror(errno));
100 return -1;
101 }
102
103 while ((dir = readdir(dir_fd)) != NULL)
104 {
105 char filename[FILENAME_MAX];
106 int fd;
107 char buf[] = { '/0' };
108 struct stat fstat_buf;
109
110 if ('.' == dir->d_name[0])
111 continue;
112
113 (void)snprintf(filename, sizeof(filename), "%s/%s", PCSCLITE_EVENTS_DIR,
114 dir->d_name);
115 Log2(PCSC_LOG_DEBUG, "status file: %s", filename);
116
117 fd = SYS_OpenFile(filename, O_WRONLY | O_APPEND | O_NONBLOCK, 0);
118 if (fd < 0)
119 {
120 /* ENXIO "No such device or address" is a normal error
121 * if the client is no more listening the pipe */
122 Log3(ENXIO == errno ? PCSC_LOG_DEBUG : PCSC_LOG_ERROR,
123 "Can't open %s: %s", filename, strerror(errno));
124 }
125 else
126 {
127 if (fstat(fd, &fstat_buf))
128 {
129 Log3(PCSC_LOG_ERROR, "Can't fstat %s: %s", filename,
130 strerror(errno));
131 }
132 else
133 {
134 /* check that the file is a FIFO */
135 if (!S_ISFIFO(fstat_buf.st_mode))
136 Log2(PCSC_LOG_ERROR, "%s is not a fifo", filename);
137 else
138 (void)SYS_WriteFile(fd, buf, sizeof(buf));
139 }
140
141 (void)SYS_CloseFile(fd);
142 }
143
144 /* remove files older than 60 seconds */
145 if ((difftime(time(NULL), fstat_buf.st_atime) > 60) && unlink(filename))
146 Log3(PCSC_LOG_ERROR, "Can't remove %s: %s", filename,
147 strerror(errno));
148 }
149 (void)closedir(dir_fd);
150
151 return 0;
152 } /* StatSynchronize */
92~94行,同步readerState共享内存。SYS_MMapSynchronize是 msync的一个wrapper,
pcscd用了很多系统调用的wrapper,都集中在sys_unix.c.对于这个文件的理解,实际上也不困难。最后的系统api调用,不熟悉或者忘记了,也可以再参考man.
95~101行,打开这个目录。
103~117行,遍历。逐个打开这个目录的目录项。
127行,fstat获取每个目录项的属性,如果是FIFO,则138行写入一个字节'/0'
144~147行,删除已经在系统中存在超过60s的fifo文件。因为fifo文件是由APPLICATION
mkfifo创建的,如果APPLICATION自己在删除fifo文件之前崩溃,则这个文件就留在系统中了。所以这样做的目的是保持系统的干净。可以再回头看看winscard_clnt.c1872行的
SCardGetStatusChange实现。服务端只是更新了一个读卡器的状态(StatSynchronize)却需要遍历所有的目录项并发出事件通知所有的APPLICATIONs。而SCardGetStatusChange,却要不停(可以采用超时机制)地遍历比较参数传入的rgReaderStates(1个或多个读卡器状态),
来最终确定是否是感兴趣的读卡器状态发生了变化。效率是比较低的。也只能如此。
回到clean_temp_files 563行,现在情况很清楚了。就是删除这四类文件。同时简单地往fifo写入'/0',告知APPLICATION有事件发生。
- PCSC那事儿(二十八--PCSCD)
- PCSC那事儿(二十九--PCSCD)
- PCSC那事儿(三十--PCSCD)
- PCSC那事儿(三十一--PCSCD)
- PCSC那事儿(三十二--PCSCD)
- PCSC那事儿(三十三--PCSCD)
- PCSC那事儿(三十四--PCSCD)
- PCSC那事儿(三十五--PCSCD)
- PCSC那事儿(三十六--PCSCD)
- PCSC那事儿(三十七--PCSCD)
- PCSC那事儿(十八--SCardCancel)
- PCSC那事儿(二)
- PCSC那事儿(二十--SCardTransmit)
- PCSC那事儿(二十一--SCardControl)
- PCSC那事儿(二十二--SCardGetAttrib)
- PCSC那事儿(二十三--SCardSetAttrib)
- PCSC那事儿(二十四--SCardStatus)
- PCSC那事儿(二十五--SCardDisconnect)
- 测试应该具备哪些特质
- 图片上传前的预览
- 鲁棒控制 自动化控制 反馈控制
- Irrlicht实现中文输入
- 发布MFC程序
- PCSC那事儿(二十八--PCSCD)
- 模态窗口传值
- Android系统原理及开发要点详解
- 反垃圾邮件技术学习
- apache+weblogic10g获取客户实际IP地址
- MySQL中的Show命令
- WINCE6 下枚举当前可用串口
- 谷歌中国员工自曝上班出工不出力
- PCSC那事儿(二十九--PCSCD)