winscard_msg_srv.c [plain text]
#include "config.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h>
#endif
#include "wintypes.h"
#include "pcscexport.h"
#include "winscard.h"
#include "debuglog.h"
#include "winscard_msg.h"
#include "sys_generic.h"
static int commonSocket = 0;
extern char AraKiri;
extern char ReCheckSerialReaders;
static int SHMProcessCommonChannelRequest(uint32_t *pdwClientID)
{
socklen_t clnt_len;
int new_sock;
struct sockaddr_un clnt_addr;
int one;
clnt_len = sizeof(clnt_addr);
if ((new_sock = accept(commonSocket, (struct sockaddr *) &clnt_addr,
&clnt_len)) < 0)
{
Log2(PCSC_LOG_CRITICAL, "Accept on common socket: %s",
strerror(errno));
return -1;
}
*pdwClientID = new_sock;
one = 1;
if (ioctl(*pdwClientID, FIONBIO, &one) < 0)
{
Log2(PCSC_LOG_CRITICAL, "Error: cannot set socket nonblocking: %s",
strerror(errno));
SYS_CloseFile(*pdwClientID);
*pdwClientID = -1;
return -1;
}
return 0;
}
INTERNAL int SHMInitializeCommonSegment(void)
{
static struct sockaddr_un serv_adr;
if ((commonSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
Log2(PCSC_LOG_CRITICAL, "Unable to create common socket: %s",
strerror(errno));
return -1;
}
serv_adr.sun_family = AF_UNIX;
strncpy(serv_adr.sun_path, PCSCLITE_CSOCK_NAME,
sizeof(serv_adr.sun_path));
SYS_Unlink(PCSCLITE_CSOCK_NAME);
if (bind(commonSocket, (struct sockaddr *) &serv_adr,
sizeof(serv_adr.sun_family) + strlen(serv_adr.sun_path) + 1) < 0)
{
Log2(PCSC_LOG_CRITICAL, "Unable to bind common socket: %s",
strerror(errno));
SHMCleanupSharedSegment(commonSocket, PCSCLITE_CSOCK_NAME);
return -1;
}
if (listen(commonSocket, 1) < 0)
{
Log2(PCSC_LOG_CRITICAL, "Unable to listen common socket: %s",
strerror(errno));
SHMCleanupSharedSegment(commonSocket, PCSCLITE_CSOCK_NAME);
return -1;
}
SYS_Chmod(PCSCLITE_CSOCK_NAME, S_IRWXO | S_IRWXG | S_IRWXU);
return 0;
}
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#define DO_TIMEOUT
#endif
INTERNAL int32_t SHMProcessEventsServer(uint32_t *pdwClientID, int32_t blocktime)
{
fd_set read_fd;
int selret;
#ifdef DO_TIMEOUT
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
#endif
FD_ZERO(&read_fd);
FD_SET(commonSocket, &read_fd);
selret = select(commonSocket + 1, &read_fd, (fd_set *) NULL,
(fd_set *) NULL,
#ifdef DO_TIMEOUT
&tv
#else
NULL
#endif
);
if (selret < 0)
{
if (EINTR == errno)
return -2;
Log2(PCSC_LOG_CRITICAL, "Select returns with failure: %s",
strerror(errno));
return -1;
}
if (selret == 0)
return 2;
if (FD_ISSET(commonSocket, &read_fd))
{
Log1(PCSC_LOG_DEBUG, "Common channel packet arrival");
if (SHMProcessCommonChannelRequest(pdwClientID) == -1)
{
Log2(PCSC_LOG_ERROR,
"error in SHMProcessCommonChannelRequest: %d", *pdwClientID);
return -1;
} else
{
Log2(PCSC_LOG_DEBUG,
"SHMProcessCommonChannelRequest detects: %d", *pdwClientID);
return 0;
}
}
return -1;
}
INTERNAL int32_t SHMProcessEventsContext(uint32_t dwClientID,
psharedSegmentMsg msgStruct, int32_t blocktime)
{
fd_set read_fd;
int selret, rv;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&read_fd);
FD_SET(dwClientID, &read_fd);
selret = select(dwClientID + 1, &read_fd, (fd_set *) NULL,
(fd_set *) NULL, &tv);
if (selret < 0)
{
Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
strerror(errno));
return -1;
}
if (selret == 0)
{
return 2;
}
if (FD_ISSET(dwClientID, &read_fd))
{
rv = SHMClientReadMessage(msgStruct, dwClientID, 0, SHMCommunicationTimeout());
if (rv == -1)
{
Log2(PCSC_LOG_DEBUG, "Client has disappeared: %d", dwClientID);
msgStruct->mtype = CMD_CLIENT_DIED;
msgStruct->command = 0;
SYS_CloseFile(dwClientID);
return 0;
}
Log2(PCSC_LOG_DEBUG, "correctly processed client: %d", dwClientID);
return 1;
}
return -1;
}
INTERNAL int SHMCommunicationTimeout()
{
static int baseTimeout = 12000; volatile int timeOut = baseTimeout;
return timeOut;
}