pcsc-lite 1.6.4
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 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