PCSC那事儿(十--SCardEstablishContext)

本文深入解析智能卡系统中testpcsc与pcscd间的通信流程,包括共享内存初始化、上下文建立及socket非阻塞性读写等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 写操作。采用非阻塞方式写数据。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值