381 行, isExecuted, 在本文件开头
187 static short isExecuted = 0; |
初始化为 0, 所以首次运行的时候会进入这个条件体。
393 行, mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0);
PCSCLITE_PUBSHM_FILE 定义在
src/pcscd.h:
33 #define PCSCLITE_PUBSHM_FILE PCSCLITE_IPC_DIR "/pcscd.pub" |
29 #define PCSCLITE_IPC_DIR USE_IPCDIR |
USE_IPCDIR 定义在
config.h
155 /* directory containing IPC files */ 156 #define USE_IPCDIR "/var/run/pcscd" |
原来 PCSCLITE_PUBSHM_FILE 表示临时文件,上面提过了。现在共提了两次了。
这行的目的是打开临时文件做为共享内存,无疑用于进程间通讯。当然是 testpcsc 和
pcscd 之间的通讯了。
404 行,很基本的了。多说无益。
411~423 行,映射 READERSTATEs 到共享内存。
READERSTATE 在 eventhandler.h 中定义
typedef struct pubReaderStatesList { int32_t readerID; char readerName[MAX_READERNAME]; uint32_t readerState; int32_t readerSharing;
UCHAR cardAtr[MAX_ATR_SIZE]; uint32_t cardAtrLength; uint32_t cardProtocol; } READER_STATE, *PREADER_STATE; |
428~450 行,初始化应用上下文。
应用上下文结构体定义如下:
static struct _psContextMap { DWORD dwClientID; /**< Client Connection ID */ SCARDCONTEXT hContext; /**< Application Context ID */ DWORD contextBlockStatus; PCSCLITE_MUTEX_T mMutex; /**< Mutex for this context */ CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS]; } psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS];
struct _psChannelMap { SCARDHANDLE hCard; LPSTR readerName; }; |
这个不算胖的上下文,包括了上面提到了两个都是 long 的 SCARDCONTEXT 和 SCARDHANDLE 联系起来了。连接句柄存在于 _psChannelMap, 客户端上下文句柄存在于 _psContextMap.
456~465 行, 在已经建立的上下文数组中找一个可用的,也就是 dwClientID
==0 的对应的数组,因为后面可以看到用过的还未释放的上下文 dwClientID 都不为0
继续往下看 ( 鼓励大家往 “ 前 ” 看 )SHMClientSetupSession , dwClientID 实际是客户端连接服务端的 socket 句柄。
468~472 行,
SHMClientSetupSession 主要建立
客户端 socket connect 上服务器 , 并设置为非阻塞。准备和 pccsd 进行通讯。
SHMClientSetupSession 定义在 winscard_msg.c
实现如下:
75 INTERNAL int SHMClientSetupSession(uint32_t *pdwClientID) 76 { 77 struct sockaddr_un svc_addr; 78 int one; 79 int ret; 80 81 ret = socket(AF_UNIX, SOCK_STREAM, 0); 82 if (ret < 0) 83 { 84 Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s", 85 strerror(errno)); 86 return -1; 87 } 88 *pdwClientID = ret; 89 90 svc_addr.sun_family = AF_UNIX; 91 strncpy(svc_addr.sun_path, PCSCLITE_CSOCK_NAME, 92 sizeof(svc_addr.sun_path)); 93 94 if (connect(*pdwClientID, (struct sockaddr *) &svc_addr, 95 sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0) 96 { 97 Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s", 98 PCSCLITE_CSOCK_NAME, strerror(errno)); 99 (void)SYS_CloseFile(*pdwClientID); 100 return -1; 101 } 102 103 one = 1; 104 if (ioctl(*pdwClientID, FIONBIO, &one) < 0) 105 { 106 Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s", 107 PCSCLITE_CSOCK_NAME, strerror(errno)); 108 (void)SYS_CloseFile(*pdwClientID); 109 return -1; 110 } 111
112 return 0; 113 } |
这个实现很通俗易懂的,逐个解释,就俗不可耐了。
474~509 行,发送数据包和接收数据包, testpcsc 和 pcscd 互相交流下版本号。
不满意,则退出。
上面的
SHMMessageSend 定义如下:
143 INTERNAL int32_t SHMMessageSend(void *buffer_void, uint64_t buffer_size, 144 int32_t filedes, int32_t blockAmount) 145 { 146 char *buffer = buffer_void; 147 148 /* 149 * default is success 150 */ 151 int retval = 0; 152 /* 153 * record the time when we started 154 */ 155 time_t start = time(0); 156 /* 157 * how many bytes remains to be written 158 */ 159 size_t remaining = buffer_size; 160 161 /* 162 * repeat until all data is written 163 */ 164 while (remaining > 0) 165 { 166 fd_set write_fd; 167 struct timeval timeout; 168 int selret; 169 170 FD_ZERO(&write_fd); 171 FD_SET(filedes, &write_fd); 172
173 timeout.tv_usec = 0; 174 if ((timeout.tv_sec = start + blockAmount - time(0)) < 0) 175 { 176 /* 177 * we already timed out 178 */ 179 retval = -1; 180 break; 181 } 182 183 selret = select(filedes + 1, NULL, &write_fd, NULL, &timeout); 184 185 /* 186 * try to write only when the file descriptor is writable 187 */ 188 if (selret > 0) 189 { 190 int written; 191 192 if (!FD_ISSET(filedes, &write_fd)) 193 { 194 /* 195 * very strange situation. it should be an assert really 196 */ 197 retval = -1; 198 break; 199 } 200 written = write(filedes, buffer, remaining); 201 202 if (written > 0) 203 { 204 /* 205 * we wrote something 206 */ 207 buffer += written; 208 remaining -= written; 209 } else if (written == 0) 210 { 211 /* 212 * peer closed the socket 213 */ 214 retval = -1; 215 break;
216 } else 217 { 218 /* 219 * we ignore the signals and socket full situations, all 220 * other errors are fatal 221 */ 222 if (errno != EINTR && errno != EAGAIN) 223 { 224 retval = -1; 225 break; 226 } 227 } 228 } else if (selret == 0) 229 { 230 /* 231 * timeout 232 */ 233 retval = -1; 234 break; 235 } else 236 { 237 /* 238 * ignore signals 239 */ 240 if (errno != EINTR) 241 { 242 Log2 (PCSC_LOG_ERROR, "select returns with failure: %s", 243 strerror(errno)); 244 retval = -1; 245 break; 246 } 247 } 248 } 249 250 return retval ; 251 } |
这个很典型的, socket 写操作。采用非阻塞方式写数据。