pcsc-lite 1.7.2
winscard_msg.c
Go to the documentation of this file.
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 5440 2010-12-11 15:41:35Z 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 #include <stdlib.h>
00037 #ifdef HAVE_SYS_FILIO_H
00038 #include <sys/filio.h>
00039 #endif
00040 
00041 #include "misc.h"
00042 #include "pcscd.h"
00043 #include "winscard.h"
00044 #include "debuglog.h"
00045 #include "winscard_msg.h"
00046 #include "sys_generic.h"
00047 #include "utils.h"
00048 #include "strlcpycat.h"
00049 
00050 #ifdef PCSCD
00051 
00052 /* functions used by pcscd only */
00053 
00054 #else
00055 
00056 /* functions used by libpcsclite only */
00057 
00058 char *getSocketName(void)
00059 {
00060     static char socketName[sizeof(struct sockaddr_un)];
00061 
00062     if ('\0' == socketName[0])
00063     {
00064         /* socket name not yet initialized */
00065         char *socketNameEnv;
00066 
00067         socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
00068         if (socketNameEnv)
00069             strlcpy(socketName, socketNameEnv, sizeof(socketName));
00070         else
00071             strlcpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
00072     }
00073 
00074     return socketName;
00075 }
00076 
00090 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
00091 {
00092     struct sockaddr_un svc_addr;
00093     int one;
00094     int ret;
00095     char *socketName;
00096 
00097     ret = socket(PF_UNIX, SOCK_STREAM, 0);
00098     if (ret < 0)
00099     {
00100         Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
00101             strerror(errno));
00102         return -1;
00103     }
00104     *pdwClientID = ret;
00105 
00106     socketName = getSocketName();
00107     svc_addr.sun_family = AF_UNIX;
00108     strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
00109 
00110     if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
00111             sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
00112     {
00113         Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
00114             socketName, strerror(errno));
00115         (void)close(*pdwClientID);
00116         return -1;
00117     }
00118 
00119     one = 1;
00120     if (ioctl(*pdwClientID, FIONBIO, &one) < 0)
00121     {
00122         Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
00123             socketName, strerror(errno));
00124         (void)close(*pdwClientID);
00125         return -1;
00126     }
00127 
00128     return 0;
00129 }
00130 
00138 INTERNAL int ClientCloseSession(uint32_t dwClientID)
00139 {
00140     return close(dwClientID);
00141 }
00142 
00159 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
00160     uint64_t buffer_size, int32_t filedes, int32_t timeOut)
00161 {
00162     char *buffer = buffer_void;
00163 
00164     /* default is success */
00165     LONG retval = SCARD_S_SUCCESS;
00166 
00167     /* record the time when we started */
00168     struct timeval start;
00169 
00170     /* how many bytes we must read */
00171     size_t remaining = buffer_size;
00172 
00173     gettimeofday(&start, NULL);
00174 
00175     /* repeat until we get the whole message */
00176     while (remaining > 0)
00177     {
00178         fd_set read_fd;
00179         struct timeval timeout, now;
00180         int selret;
00181         long delta;
00182 
00183         gettimeofday(&now, NULL);
00184         delta = time_sub(&now, &start);
00185 
00186         if (delta > timeOut*1000)
00187         {
00188             /* we already timed out */
00189             retval = SCARD_E_TIMEOUT;
00190             break;
00191         }
00192 
00193         /* remaining time to wait */
00194         delta = timeOut*1000 - delta;
00195 
00196         FD_ZERO(&read_fd);
00197         FD_SET(filedes, &read_fd);
00198 
00199         timeout.tv_sec = delta/1000000;
00200         timeout.tv_usec = delta - timeout.tv_sec*1000000;
00201 
00202         selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
00203 
00204         /* try to read only when socket is readable */
00205         if (selret > 0)
00206         {
00207             int readed;
00208 
00209             if (!FD_ISSET(filedes, &read_fd))
00210             {
00211                 /* very strange situation. it should be an assert really */
00212                 retval = SCARD_F_COMM_ERROR;
00213                 break;
00214             }
00215             readed = read(filedes, buffer, remaining);
00216 
00217             if (readed > 0)
00218             {
00219                 /* we got something */
00220                 buffer += readed;
00221                 remaining -= readed;
00222             } else if (readed == 0)
00223             {
00224                 /* peer closed the socket */
00225                 retval = SCARD_F_COMM_ERROR;
00226                 break;
00227             } else
00228             {
00229                 /* we ignore the signals and empty socket situations, all
00230                  * other errors are fatal */
00231                 if (errno != EINTR && errno != EAGAIN)
00232                 {
00233                     retval = SCARD_F_COMM_ERROR;
00234                     break;
00235                 }
00236             }
00237         } else if (selret == 0)
00238         {
00239             /* is the daemon still there? */
00240             retval  =  SCardCheckDaemonAvailability();
00241             if (retval != SCARD_S_SUCCESS)
00242             {
00243                 /* timeout */
00244                 break;
00245             }
00246 
00247             /* you need to set the env variable PCSCLITE_DEBUG=0 since
00248              * this is logged on the client side and not on the pcscd
00249              * side*/
00250             Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
00251         } else
00252         {
00253             /* we ignore signals, all other errors are fatal */
00254             if (errno != EINTR)
00255             {
00256                 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
00257                     strerror(errno));
00258                 retval = SCARD_F_COMM_ERROR;
00259                 break;
00260             }
00261         }
00262     }
00263 
00264     return retval;
00265 }
00266 
00281 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
00282     uint64_t size, void *data_void)
00283 {
00284     struct rxHeader header;
00285     LONG ret;
00286 
00287     /* header */
00288     header.command = command;
00289     header.size = size;
00290     ret = MessageSend(&header, sizeof(header), dwClientID);
00291 
00292     /* command */
00293     if (size > 0)
00294         ret = MessageSend(data_void, size, dwClientID);
00295 
00296     return ret;
00297 }
00298 
00299 #endif
00300 
00301 /* functions used by pcscd and libpcsclite */
00302 
00317 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
00318     int32_t filedes)
00319 {
00320     char *buffer = buffer_void;
00321 
00322     /* default is success */
00323     LONG retval = SCARD_S_SUCCESS;
00324 
00325     /* how many bytes remains to be written */
00326     size_t remaining = buffer_size;
00327 
00328     /* repeat until all data is written */
00329     while (remaining > 0)
00330     {
00331         fd_set write_fd;
00332         int selret;
00333 
00334         FD_ZERO(&write_fd);
00335         FD_SET(filedes, &write_fd);
00336 
00337         selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
00338 
00339         /* try to write only when the file descriptor is writable */
00340         if (selret > 0)
00341         {
00342             int written;
00343 
00344             if (!FD_ISSET(filedes, &write_fd))
00345             {
00346                 /* very strange situation. it should be an assert really */
00347                 retval = SCARD_F_COMM_ERROR;
00348                 break;
00349             }
00350             /* since we are a user library we can't play with signals
00351              * The signals may already be used by the application */
00352 #ifdef MSG_NOSIGNAL
00353             /* Get EPIPE return code instead of SIGPIPE signal
00354              * Works on Linux */
00355             written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
00356 #else
00357             /* we may get a SIGPIPE signal if the other side has closed */
00358             written = write(filedes, buffer, remaining);
00359 #endif
00360 
00361             if (written > 0)
00362             {
00363                 /* we wrote something */
00364                 buffer += written;
00365                 remaining -= written;
00366             } else if (written == 0)
00367             {
00368                 /* peer closed the socket */
00369                 retval = SCARD_F_COMM_ERROR;
00370                 break;
00371             } else
00372             {
00373                 /* we ignore the signals and socket full situations, all
00374                  * other errors are fatal */
00375                 if (errno != EINTR && errno != EAGAIN)
00376                 {
00377                     retval = SCARD_E_NO_SERVICE;
00378                     break;
00379                 }
00380             }
00381         } else if (selret == 0)
00382         {
00383             /* timeout */
00384             retval = SCARD_E_TIMEOUT;
00385             break;
00386         } else
00387         {
00388             /* ignore signals */
00389             if (errno != EINTR)
00390             {
00391                 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
00392                     strerror(errno));
00393                 retval = SCARD_F_COMM_ERROR;
00394                 break;
00395             }
00396         }
00397     }
00398 
00399     return retval;
00400 }
00401 
00415 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
00416     int32_t filedes)
00417 {
00418     char *buffer = buffer_void;
00419 
00420     /* default is success */
00421     LONG retval = SCARD_S_SUCCESS;
00422 
00423     /* how many bytes we must read */
00424     size_t remaining = buffer_size;
00425 
00426     /* repeat until we get the whole message */
00427     while (remaining > 0)
00428     {
00429         fd_set read_fd;
00430         int selret;
00431 
00432         FD_ZERO(&read_fd);
00433         FD_SET(filedes, &read_fd);
00434 
00435         selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
00436 
00437         /* try to read only when socket is readable */
00438         if (selret > 0)
00439         {
00440             int readed;
00441 
00442             if (!FD_ISSET(filedes, &read_fd))
00443             {
00444                 /* very strange situation. it should be an assert really */
00445                 retval = SCARD_F_COMM_ERROR;
00446                 break;
00447             }
00448             readed = read(filedes, buffer, remaining);
00449 
00450             if (readed > 0)
00451             {
00452                 /* we got something */
00453                 buffer += readed;
00454                 remaining -= readed;
00455             } else if (readed == 0)
00456             {
00457                 /* peer closed the socket */
00458                 retval = SCARD_F_COMM_ERROR;
00459                 break;
00460             } else
00461             {
00462                 /* we ignore the signals and empty socket situations, all
00463                  * other errors are fatal */
00464                 if (errno != EINTR && errno != EAGAIN)
00465                 {
00466                     retval = SCARD_F_COMM_ERROR;
00467                     break;
00468                 }
00469             }
00470         }
00471         else
00472         {
00473             /* we ignore signals, all other errors are fatal */
00474             if (errno != EINTR)
00475             {
00476                 Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
00477                     strerror(errno));
00478                 retval = SCARD_F_COMM_ERROR;
00479                 break;
00480             }
00481         }
00482     }
00483 
00484     return retval;
00485 }
00486