pcsc-lite 1.6.4
|
00001 /* 00002 * MUSCLE SmartCard Development ( http://www.linuxnet.com ) 00003 * 00004 * Copyright (C) 2001-2004 00005 * David Corcoran <corcoran@linuxnet.com> 00006 * Copyright (C) 2003-2004 00007 * Damien Sauveron <damien.sauveron@labri.fr> 00008 * Copyright (C) 2002-2010 00009 * Ludovic Rousseau <ludovic.rousseau@free.fr> 00010 * 00011 * $Id: winscard_msg.c 4952 2010-05-18 13:42:25Z rousseau $ 00012 */ 00013 00023 #include "config.h" 00024 #include <fcntl.h> 00025 #include <unistd.h> 00026 #include <sys/types.h> 00027 #include <sys/stat.h> 00028 #include <sys/socket.h> 00029 #include <sys/time.h> 00030 #include <sys/un.h> 00031 #include <sys/ioctl.h> 00032 #include <errno.h> 00033 #include <stdio.h> 00034 #include <time.h> 00035 #include <string.h> 00036 #ifdef HAVE_SYS_FILIO_H 00037 #include <sys/filio.h> 00038 #endif 00039 00040 #include "misc.h" 00041 #include "pcscd.h" 00042 #include "winscard.h" 00043 #include "debuglog.h" 00044 #include "winscard_msg.h" 00045 #include "sys_generic.h" 00046 #include "utils.h" 00047 00061 INTERNAL int ClientSetupSession(uint32_t *pdwClientID) 00062 { 00063 struct sockaddr_un svc_addr; 00064 int one; 00065 int ret; 00066 00067 ret = socket(PF_UNIX, SOCK_STREAM, 0); 00068 if (ret < 0) 00069 { 00070 Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s", 00071 strerror(errno)); 00072 return -1; 00073 } 00074 *pdwClientID = ret; 00075 00076 svc_addr.sun_family = AF_UNIX; 00077 strncpy(svc_addr.sun_path, PCSCLITE_CSOCK_NAME, 00078 sizeof(svc_addr.sun_path)); 00079 00080 if (connect(*pdwClientID, (struct sockaddr *) &svc_addr, 00081 sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0) 00082 { 00083 Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s", 00084 PCSCLITE_CSOCK_NAME, strerror(errno)); 00085 (void)close(*pdwClientID); 00086 return -1; 00087 } 00088 00089 one = 1; 00090 if (ioctl(*pdwClientID, FIONBIO, &one) < 0) 00091 { 00092 Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s", 00093 PCSCLITE_CSOCK_NAME, strerror(errno)); 00094 (void)close(*pdwClientID); 00095 return -1; 00096 } 00097 00098 return 0; 00099 } 00100 00108 INTERNAL int ClientCloseSession(uint32_t dwClientID) 00109 { 00110 return close(dwClientID); 00111 } 00112 00128 INTERNAL int32_t MessageSend(void *buffer_void, uint64_t buffer_size, 00129 int32_t filedes) 00130 { 00131 char *buffer = buffer_void; 00132 00133 /* default is success */ 00134 int retval = 0; 00135 00136 /* how many bytes remains to be written */ 00137 size_t remaining = buffer_size; 00138 00139 /* repeat until all data is written */ 00140 while (remaining > 0) 00141 { 00142 fd_set write_fd; 00143 int selret; 00144 00145 FD_ZERO(&write_fd); 00146 FD_SET(filedes, &write_fd); 00147 00148 selret = select(filedes + 1, NULL, &write_fd, NULL, NULL); 00149 00150 /* try to write only when the file descriptor is writable */ 00151 if (selret > 0) 00152 { 00153 int written; 00154 00155 if (!FD_ISSET(filedes, &write_fd)) 00156 { 00157 /* very strange situation. it should be an assert really */ 00158 retval = -1; 00159 break; 00160 } 00161 /* since we are a user library we can't play with signals 00162 * The signals may already be used by the application */ 00163 #ifdef MSG_NOSIGNAL 00164 /* Get EPIPE return code instead of SIGPIPE signal 00165 * Works on Linux */ 00166 written = send(filedes, buffer, remaining, MSG_NOSIGNAL); 00167 #else 00168 /* we may get a SIGPIPE signal if the other side has closed */ 00169 written = write(filedes, buffer, remaining); 00170 #endif 00171 00172 if (written > 0) 00173 { 00174 /* we wrote something */ 00175 buffer += written; 00176 remaining -= written; 00177 } else if (written == 0) 00178 { 00179 /* peer closed the socket */ 00180 retval = -1; 00181 break; 00182 } else 00183 { 00184 /* we ignore the signals and socket full situations, all 00185 * other errors are fatal */ 00186 if (errno != EINTR && errno != EAGAIN) 00187 { 00188 retval = -1; 00189 break; 00190 } 00191 } 00192 } else if (selret == 0) 00193 { 00194 /* timeout */ 00195 retval = -1; 00196 break; 00197 } else 00198 { 00199 /* ignore signals */ 00200 if (errno != EINTR) 00201 { 00202 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00203 strerror(errno)); 00204 retval = -1; 00205 break; 00206 } 00207 } 00208 } 00209 00210 return retval; 00211 } 00212 00226 INTERNAL int32_t MessageReceive(void *buffer_void, uint64_t buffer_size, 00227 int32_t filedes) 00228 { 00229 char *buffer = buffer_void; 00230 00231 /* default is success */ 00232 int retval = 0; 00233 00234 /* how many bytes we must read */ 00235 size_t remaining = buffer_size; 00236 00237 /* repeat until we get the whole message */ 00238 while (remaining > 0) 00239 { 00240 fd_set read_fd; 00241 int selret; 00242 00243 FD_ZERO(&read_fd); 00244 FD_SET(filedes, &read_fd); 00245 00246 selret = select(filedes + 1, &read_fd, NULL, NULL, NULL); 00247 00248 /* try to read only when socket is readable */ 00249 if (selret > 0) 00250 { 00251 int readed; 00252 00253 if (!FD_ISSET(filedes, &read_fd)) 00254 { 00255 /* very strange situation. it should be an assert really */ 00256 retval = -1; 00257 break; 00258 } 00259 readed = read(filedes, buffer, remaining); 00260 00261 if (readed > 0) 00262 { 00263 /* we got something */ 00264 buffer += readed; 00265 remaining -= readed; 00266 } else if (readed == 0) 00267 { 00268 /* peer closed the socket */ 00269 retval = -1; 00270 break; 00271 } else 00272 { 00273 /* we ignore the signals and empty socket situations, all 00274 * other errors are fatal */ 00275 if (errno != EINTR && errno != EAGAIN) 00276 { 00277 retval = -1; 00278 break; 00279 } 00280 } 00281 } 00282 else 00283 { 00284 /* we ignore signals, all other errors are fatal */ 00285 if (errno != EINTR) 00286 { 00287 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00288 strerror(errno)); 00289 retval = -1; 00290 break; 00291 } 00292 } 00293 } 00294 00295 return retval; 00296 } 00297 00314 INTERNAL int32_t MessageReceiveTimeout(uint32_t command, void *buffer_void, 00315 uint64_t buffer_size, int32_t filedes, int32_t timeOut) 00316 { 00317 char *buffer = buffer_void; 00318 00319 /* default is success */ 00320 int retval = 0; 00321 00322 /* record the time when we started */ 00323 struct timeval start; 00324 00325 /* how many bytes we must read */ 00326 size_t remaining = buffer_size; 00327 00328 gettimeofday(&start, NULL); 00329 00330 /* repeat until we get the whole message */ 00331 while (remaining > 0) 00332 { 00333 fd_set read_fd; 00334 struct timeval timeout, now; 00335 int selret; 00336 long delta; 00337 00338 gettimeofday(&now, NULL); 00339 delta = time_sub(&now, &start); 00340 00341 if (delta > timeOut*1000) 00342 { 00343 /* we already timed out */ 00344 retval = -2; 00345 break; 00346 } 00347 00348 /* remaining time to wait */ 00349 delta = timeOut*1000 - delta; 00350 00351 FD_ZERO(&read_fd); 00352 FD_SET(filedes, &read_fd); 00353 00354 timeout.tv_sec = delta/1000000; 00355 timeout.tv_usec = delta - timeout.tv_sec*1000000; 00356 00357 selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout); 00358 00359 /* try to read only when socket is readable */ 00360 if (selret > 0) 00361 { 00362 int readed; 00363 00364 if (!FD_ISSET(filedes, &read_fd)) 00365 { 00366 /* very strange situation. it should be an assert really */ 00367 retval = -1; 00368 break; 00369 } 00370 readed = read(filedes, buffer, remaining); 00371 00372 if (readed > 0) 00373 { 00374 /* we got something */ 00375 buffer += readed; 00376 remaining -= readed; 00377 } else if (readed == 0) 00378 { 00379 /* peer closed the socket */ 00380 retval = -1; 00381 break; 00382 } else 00383 { 00384 /* we ignore the signals and empty socket situations, all 00385 * other errors are fatal */ 00386 if (errno != EINTR && errno != EAGAIN) 00387 { 00388 retval = -1; 00389 break; 00390 } 00391 } 00392 } else if (selret == 0) 00393 { 00394 #ifdef PCSCD 00395 (void)command; 00396 00397 /* timeout */ 00398 retval = -1; 00399 break; 00400 #else 00401 /* is the daemon still there? */ 00402 if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS) 00403 { 00404 /* timeout */ 00405 retval = -1; 00406 break; 00407 } 00408 00409 /* you need to set the env variable PCSCLITE_DEBUG=0 since 00410 * this is logged on the client side and not on the pcscd 00411 * side*/ 00412 Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command); 00413 #endif 00414 } else 00415 { 00416 /* we ignore signals, all other errors are fatal */ 00417 if (errno != EINTR) 00418 { 00419 Log2(PCSC_LOG_ERROR, "select returns with failure: %s", 00420 strerror(errno)); 00421 retval = -1; 00422 break; 00423 } 00424 } 00425 } 00426 00427 return retval; 00428 } 00429 00445 INTERNAL int32_t MessageSendWithHeader(uint32_t command, uint32_t dwClientID, 00446 uint64_t size, void *data_void) 00447 { 00448 struct rxHeader header; 00449 int ret; 00450 00451 /* header */ 00452 header.command = command; 00453 header.size = size; 00454 ret = MessageSend(&header, sizeof(header), dwClientID); 00455 00456 /* command */ 00457 ret = MessageSend(data_void, size, dwClientID); 00458 00459 return ret; 00460 } 00461 00471 INTERNAL void CleanupSharedSegment(int sockValue, const char *pcFilePath) 00472 { 00473 (void)close(sockValue); 00474 (void)remove(pcFilePath); 00475 } 00476