服务端代码分析
服务端,明显比客户端复杂,而且还用到了多线程。
从 pcscdaemon.c 开始。从 main 开始。
继续继续 ...
190 int main(int argc, char **argv) 191 { 192 int rv; 193 char setToForeground; 194 char HotPlug; 195 char *newReaderConfig; 196 struct stat fStatBuf; 197 int opt; 198 #ifdef HAVE_GETOPT_LONG 199 int option_index = 0; 200 static struct option long_options[] = { 201 {"config", 1, NULL, 'c'}, 202 {"foreground", 0, NULL, 'f'}, 203 {"help", 0, NULL, 'h'}, 204 {"version", 0, NULL, 'v'}, 205 {"apdu", 0, NULL, 'a'}, 206 {"debug", 0, NULL, 'd'}, 207 {"info", 0, NULL, 0}, 208 {"error", 0, NULL, 'e'}, 209 {"critical", 0, NULL, 'C'}, 210 {"hotplug", 0, NULL, 'H'}, 211 {"force-reader-polling", optional_argument, NULL, 0}, 212 {NULL, 0, NULL, 0} 213 }; 214 #endif |
200 行,看到 struct option long_options, 应该明白这些要做什么了。
就是解析命令行参数。
比如
输入命令: ./pcscd -f -d
程序要解析出 f 和 d 选项,进行对应的处理。
215 #define OPT_STRING "c:fdhvaeCH" 216 217 rv = 0; 218 newReaderConfig = NULL; 219 setToForeground = FALSE; 220 HotPlug = FALSE; 221 222 /* 223 * test the version 224 */ 225 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0) 226 { 227 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER/n"); 228 printf(" in pcsclite.h (%s) does not match the release version number/n", 229 PCSCLITE_VERSION_NUMBER); 230 printf(" generated in config.h (%s) (see configure.in)./n", VERSION); 231 232 return EXIT_FAILURE; 233 } |
215 行,短选项,这里关系到一个 linux 下,不可移植的 api ,
那就是 getopt_long 或 getopt .windows 中不存在这两个 api.
当然了,可以在 windows 下,自己重新实现这两个接口。
或者采用 boost 的可供移植的 program_options 库 .
225~233 行,进行版本比较。比较 config.h 的 VERSION 和 pcsclite.h 的
PCSCLITE_VERSION_NUMBER
PCSC/pcsclite.h
186 #define PCSCLITE_VERSION_NUMBER "1.5.5" /**< Current version */ |
config.h
158 /* Version number of package */ 159 #define VERSION "1.5.5" |
当然是一致的了。
234 235 /* 236 * By default we create a daemon (not connected to any output) 237 * so log to syslog to have error messages. 238 */ 239 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG); 240 |
234~240 行,系统日志相关。这个实现在一个单独的文件中。比较简单的。
现在的目标是,服务端。
241 /* 242 * Handle any command line arguments 243 */ 244 #ifdef HAVE_GETOPT_LONG 245 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) { 246 #else 247 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) { 248 #endif 249 switch (opt) { 250 #ifdef HAVE_GETOPT_LONG 251 case 0: 252 if (strcmp(long_options[option_index].name, 253 "force-reader-polling") == 0) 254 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1; 255 break; 256 #endif 257 case 'c': 258 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg); 259 newReaderConfig = optarg; 260 break; 261 262 case 'f': 263 setToForeground = TRUE; 264 /* debug to stderr instead of default syslog */ 265 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG); 266 Log1(PCSC_LOG_INFO, 267 "pcscd set to foreground with debug send to stderr"); 268 break; 269 270 case 'd': 271 DebugLogSetLevel(PCSC_LOG_DEBUG); 272 break; 273 274 case 'e': 275 DebugLogSetLevel(PCSC_LOG_ERROR); 276 break; 277 278 case 'C': 279 DebugLogSetLevel(PCSC_LOG_CRITICAL); 280 break; 281 282 case 'h': 283 print_usage (argv[0]); 284 return EXIT_SUCCESS; 285 286 case 'v': 287 print_version (); 288 return EXIT_SUCCESS; 289 290 case 'a': 291 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU); 292 break; 293 294 case 'H': 295 /* debug to stderr instead of default syslog */ 296 DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG); 297 HotPlug = TRUE; 298 break; 299 300 default: 301 print_usage (argv[0]); 302 return EXIT_FAILURE; 303 } 304 305 } 306 307 if (argv[optind]) 308 { 309 printf("Unknown option: %s/n/n", argv[optind]); 310 print_usage(argv[0]); 311 return EXIT_SUCCESS; 312 } |
245 行,
247 行开始参数解析了。
getopt_long 和 getopt ,要理解吗?
或者已经理解了。那么看看 man 吧。 linux 里的男人。不知道女权主义者会怎么看待这个
man 命令。
打开终端,输入
#man getopt_long
出来帮助。够详细的,还有两个例子帮助说明。
说说这些选项的意义:
-a, --apdu 把发送的 APDU 和接收的结果进入日志
-c, --config 读卡器路径配置 reader.conf ,一般在 /etc/reader.conf
-f, --foreground 直接运行,不要以 daemon 服务运行,把日志消息等都直接输入到终端
-h, --help 显示用法
-H, --hotplug 强制重新扫描可用的读卡器
-v, --version 显示程序的版本号
-d, --debug 显示 low level 级别的调试信息
--info 显示 info level 级别的调试信息 ( 默认的 level)
-e --error 显示 error level 级别的调试信息
-C --critical 仅仅显示 critical level 级别的调试信息
--force-reader-polling 查询方式检测设备的事件
满足下好奇心, reader.conf 的内容是?
# Configuration file for pcsc-lite
#
# This file has to be configured for serial and PCMCIA readers only.
# normal USB readers shall _not_ be configured here!( 这里是配置 serial 和 PCMCIA 用的 )
#
# David Corcoran <corcoran@linuxnet.com>
#FRIENDLYNAME "Generic Reader"
#DEVICENAME /dev/ttySx_not_configured
#LIBPATH /home/wjf/anotherday/pcsc/arm9/pcsc-lite-1.5.5/pcsc/drivers/libgen_ifd.so
#CHANNELID 0x0103F8
# End of file
这个文件是 serial 和 PCMCIA 类型读卡器的配置文件, usb 类型读卡器的配置还得靠 /usr/local/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist 文件。
Info.plist 这个文件以后再说。
所以呢, serial 和 PCMCIA 类型的读卡器在 /etc/reader.conf 配置。
usb 类型的读卡器在 /usr/local/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist 配置。