--- winscard_msg.c	Wed Aug 22 02:32:00 2001
+++ /home/arne/goelro/src/thirdparty/pcsc-lite/src/winscard_msg.c	Thu Nov  1 21:54:08 2001
@@ -24,6 +24,8 @@
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/un.h>
+#include <sys/ioctl.h>
+#include <errno.h>
 #include <stdio.h>
 
 
@@ -50,10 +52,10 @@
   char serverSockName[80];
   int serverSock;
   struct sockaddr_un svc_addr, local_addr, new_addr;
-  fd_set read_fd, write_fd;
   int svc_len, selret, rv, local_len, new_len;
   struct timeval timeout;
   sharedSegmentMsg msgStruct;
+  int one;
 
   serverSock=0; localSock=0;
 
@@ -148,6 +150,15 @@
     return -1;    
   }
 
+  one= 1;
+  if(ioctl(appSocket, FIONBIO, &one) < 0){
+    DebugLogA("SHMInitializeSharedSegment: Error: cannot set socket nonblocking.\n",
+	      __FILE__, __LINE__);    
+    SHMCleanupSharedSegment( localSock, clientSockName );
+    close(serverSock);
+    return -1;    
+  }
+
   /* Read the ACK packet from the dedicated channel that has been created */  
   
   rv = SHMMessageReceive( &msgStruct, appSocket,  
@@ -219,8 +230,7 @@
   struct timeval timeout;
   struct sockaddr_un clnt_addr, serv_adr;
   char clientSockName[80];
-  fd_set read_fd, write_fd;
-
+  int one;
 
   clnt_len=0; i=0; currApp=0; new_sock=0; selret=0; rv=0; sd=0;
 
@@ -283,6 +293,15 @@
     return -1;  
   }
 
+  one= 1;
+  if(ioctl(clientSockets[i].sd, FIONBIO, &one) < 0){
+    DebugLogA("SHMInitializeSharedSegment: Error: cannot set socket nonblocking.\n",
+	      __FILE__, __LINE__);    
+    close(clientSockets[i].sd);
+    clientSockets[i].sd = 0;
+    return -1;    
+  }
+
   msgStruct->mtype = CMD_ACK;
   rv = SHMMessageSend( msgStruct, clientSockets[i].sd,  
 		       PCSCLITE_SERVER_ATTEMPTS );
@@ -317,7 +336,7 @@
     if ( clientSockets[i].sd != 0 ) {
       FD_SET( clientSockets[i].sd, &read_fd );
       if ( clientSockets[i].sd > largeSock ) {
-	largeSock = clientSockets[i].sd;
+        largeSock = clientSockets[i].sd;
       }
     }
   }
@@ -349,23 +368,23 @@
   for (i=0; i < PCSCLITE_MAX_APPLICATIONS; i++) {
     if ( clientSockets[i].sd != 0 ) {
       if ( FD_ISSET( clientSockets[i].sd, &read_fd ) ) {
-	/* Return the current handle */
-	rv = SHMMessageReceive(msgStruct, clientSockets[i].sd, 
+        /* Return the current handle */
+        rv = SHMMessageReceive(msgStruct, clientSockets[i].sd, 
 			       PCSCLITE_SERVER_ATTEMPTS);
 
-	if ( rv == -1 ) { /* The client has died */
-	  msgStruct->mtype     = CMD_CLIENT_DIED;
-	  msgStruct->request_id = clientSockets[i].sd;
-	  msgStruct->command   = 0;
-	  SHMCleanupSharedSegment( clientSockets[i].sd, 
-				   clientSockets[i].clnt_addr.sun_path );
-	  clientSockets[i].sd  = 0;
-	  return 0;
-	}
-	
-	/* Set the identifier handle */
-	msgStruct->request_id = clientSockets[i].sd;
-	return 1;
+        if ( rv == -1 ) { /* The client has died */
+          msgStruct->mtype     = CMD_CLIENT_DIED;
+          msgStruct->request_id = clientSockets[i].sd;
+          msgStruct->command   = 0;
+          SHMCleanupSharedSegment( clientSockets[i].sd, 
+                       clientSockets[i].clnt_addr.sun_path );
+          clientSockets[i].sd  = 0;
+          return 0;
+        }
+        
+        /* Set the identifier handle */
+        msgStruct->request_id = clientSockets[i].sd;
+        return 1;
       } 
     }
   }
@@ -376,80 +395,153 @@
 int SHMMessageSend( psharedSegmentMsg msgStruct, int filedes, 
 		    int blockAmount ) {
 
-  int writeReturn;
-  unsigned char *buffer;
-  int selret;
-  fd_set write_fd;
-  struct timeval timeout;
-
-  buffer = (unsigned char *)msgStruct;
-  
-  /* Buffer the output in case all doesn't write at once */
-  
-  FD_ZERO( &write_fd );
-  FD_SET( filedes, &write_fd );
-  
-  timeout.tv_sec  = blockAmount;
-  timeout.tv_usec = 0;
-  
-  selret = select( filedes + 1, (fd_set *)NULL, &write_fd,
-		   (fd_set *)NULL, &timeout );
+  /* default is success */
+  int retval= 0;
+  /* record the time when we started */
+  time_t start= time(0);
+  /* data to be written */
+  unsigned char *buffer = (unsigned char *)msgStruct;
+  /* how many bytes remains to be written */
+  size_t remaining= sizeof(sharedSegmentMsg);
+  
+  /* repeat until all data is written */
+  while(remaining > 0){
+    fd_set write_fd;
+    struct timeval timeout;
+    int selret;
+  
+    FD_ZERO( &write_fd );
+    FD_SET( filedes, &write_fd );
+  
+    timeout.tv_usec = 0;
+    if((timeout.tv_sec= start+ blockAmount- time(0)) < 0){
+      /* we already timed out */
+      retval= -1;
+      break;
+    }
   
-  if ( FD_ISSET( filedes, &write_fd ) && (selret >= 0) ) {   
-    writeReturn = write( filedes, buffer, 
-			 sizeof(sharedSegmentMsg) ); 
-  }
+    selret = select( filedes + 1, (fd_set *)NULL, &write_fd,
+             (fd_set *)NULL, &timeout );
+    
+    /* try to write only when the file descriptor is writable */
+    if(selret > 0){
+      int written;
+
+      if(!FD_ISSET( filedes, &write_fd )){
+        /* very strange situation. it should be an assert really */
+        retval= -1;
+        break;
+      }
+      written= write( filedes, buffer, remaining ); 
 
-  if ( selret < 0 ) { 
-    DebugLogA("SHMProcessEvents: Select returns with failure.\n",
-	      __FILE__, __LINE__);
-    return -1;
+      if(written > 0){
+        /* we wrote something */
+        buffer+= written;
+        remaining-= written;
+      }else if(written == 0){
+        /* peer closed the socket */
+        retval= -1;
+        break;
+      }else{
+        /* we ignore the signals and socket full situations, all other
+         * errors are fatal */
+        if(errno != EINTR && errno != EAGAIN){
+          retval= -1;
+          break;
+        }
+      }
+    }else if(selret == 0){
+      /* timeout */
+      retval= -1;
+      break;
+    }else{
+      /* ignore signals */
+      if(errno != EINTR){
+        DebugLogA("SHMProcessEvents: Select returns with failure.\n",
+              __FILE__, __LINE__);
+        retval= -1;
+        break;
+      }
+    }
   }
 
-  if ( writeReturn > 0 ) {
-    return 0;
-  } else {
-    return -1;
-  }
+  return retval;
 }
 
 int SHMMessageReceive( psharedSegmentMsg msgStruct, int filedes, 
 		       int blockAmount ) {
   
-  int readReturn;
-  unsigned char *buffer;
-  int selret;
-  fd_set read_fd;
-  struct timeval timeout;
-  selret     = 0;
-
-  buffer = (unsigned char *)msgStruct;
-  
-  FD_ZERO( &read_fd );
-  FD_SET( filedes, &read_fd );
-
-  timeout.tv_sec  = blockAmount;
-  timeout.tv_usec = 0;
-  
-  selret = select( filedes + 1, &read_fd, (fd_set *)NULL,
-		   (fd_set *)NULL, &timeout );
-  
-  if ( FD_ISSET( filedes, &read_fd ) && (selret >= 0) ) {
-    readReturn = read( filedes, buffer, sizeof(sharedSegmentMsg) );     
-  }
-
-  if ( selret < 0 ) { 
-    DebugLogA("SHMProcessEvents: Select returns with failure.\n",
-	      __FILE__, __LINE__);
-    return -1;
-  }
+  /* default is success */
+  int retval= 0;
+  /* record the time when we started */
+  time_t start= time(0);
+  /* buffer where we place the readed bytes */
+  unsigned char *buffer = (unsigned char *)msgStruct;
+  /* how many bytes we must read */
+  size_t remaining= sizeof(sharedSegmentMsg);
+  
+  /* repeate until we get the whole message */
+  while(remaining > 0){
+    fd_set read_fd;
+    struct timeval timeout;
+    int selret;
+
+    FD_ZERO( &read_fd );
+    FD_SET( filedes, &read_fd );
+
+    timeout.tv_usec = 0;
+    if((timeout.tv_sec= start+ blockAmount- time(0)) < 0){
+      /* we already timed out */
+      retval= -1;
+      break;
+    }
+    
+    selret = select( filedes + 1, &read_fd, (fd_set *)NULL,
+             (fd_set *)NULL, &timeout );
+    
+    /* try to read only when socket is readable */
+    if(selret > 0){
+      int readed;
+
+      if(!FD_ISSET( filedes, &read_fd ) ) {
+        /* very strange situation. it should be an assert really */
+        retval= -1;
+        break;
+      }
+      readed= read( filedes, buffer, remaining );     
 
-  if ( readReturn > 0 ) {
-    return 0;
-  } else {
-    return -1;
+      if(readed > 0){
+        /* we got something */
+        buffer+= readed;
+        remaining-= readed;
+      }else if(readed == 0){
+        /* peer closed the socket */
+        retval= -1;
+        break;
+      }else{
+        /* we ignore the signals and empty socket situations, all other
+         * errors are fatal */
+        if(errno != EINTR && errno != EAGAIN){
+          retval= -1;
+          break;
+        }
+      }
+    }else if(selret == 0){
+      /* timeout */
+      retval= -1;
+      break;
+    }else{
+      /* we ignore signals, all other errors are fatal */
+      if(errno != EINTR){
+        DebugLogA("SHMProcessEvents: Select returns with failure.\n",
+              __FILE__, __LINE__);
+        retval= -1;
+        break;
+      }
+    }
   }
 
+  return retval;
 }
 
 int WrapSHMWrite( unsigned int command, unsigned int pid, 
