implemented reversed connection establishment

vpcd can now be configured connect to a previously started vpicc.
This commit is contained in:
Frank Morgner
2013-07-14 23:03:43 +02:00
parent ce77625a60
commit 291178d139
12 changed files with 312 additions and 82 deletions

View File

@@ -14,6 +14,8 @@
1)
static struct vicc_ctx *ctx[VICC_MAX_SLOTS];
static char *hostname = NULL;
static const char openport[] = "/dev/null";
RESPONSECODE
IFDHCreateChannel (DWORD Lun, DWORD Channel)
@@ -22,12 +24,17 @@ IFDHCreateChannel (DWORD Lun, DWORD Channel)
if (slot >= VICC_MAX_SLOTS) {
return IFD_COMMUNICATION_ERROR;
}
ctx[slot] = vicc_init(Channel+slot);
if (!hostname)
Log2(PCSC_LOG_INFO, "Waiting for virtual ICC on port %hu",
(unsigned short) (Channel+slot));
ctx[slot] = vicc_init(hostname, Channel+slot);
if (!ctx[slot]) {
Log1(PCSC_LOG_ERROR, "Could not initialize connection to virtual ICC");
return IFD_COMMUNICATION_ERROR;
}
Log2(PCSC_LOG_INFO, "Waiting for virtual ICC on port %hu", (unsigned short) Channel+slot);
if (hostname)
Log3(PCSC_LOG_INFO, "Connected to virtual ICC on %s port %hu",
hostname, (unsigned short) (Channel+slot));
return IFD_SUCCESS;
}
@@ -35,27 +42,51 @@ IFDHCreateChannel (DWORD Lun, DWORD Channel)
RESPONSECODE
IFDHCreateChannelByName (DWORD Lun, LPSTR DeviceName)
{
RESPONSECODE r = IFD_NOT_SUPPORTED;
char *dots;
char _hostname[MAX_READERNAME];
size_t hostname_len;
unsigned long int port = VPCDPORT;
dots = strchr(DeviceName, ':');
if (dots) {
/* a port has been specified behind the device name */
/* skip '+' */
hostname_len = dots - DeviceName;
if (strlen(openport) != hostname_len
|| strncmp(DeviceName, openport, hostname_len) != 0) {
/* a hostname other than /dev/null has been specified,
* so we connect initialize hostname to connect to vicc */
if (hostname_len < sizeof _hostname)
memcpy(_hostname, DeviceName, hostname_len);
else {
Log3(PCSC_LOG_ERROR, "Not enough memory to hold hostname (have %u, need %u)", sizeof _hostname, hostname_len);
goto err;
}
_hostname[hostname_len] = '\0';
hostname = _hostname;
}
/* skip the ':' */
dots++;
errno = 0;
port = strtoul(dots, NULL, 0);
if (errno) {
Log2(PCSC_LOG_ERROR, "Could not parse port: %s", dots);
return IFD_NO_SUCH_DEVICE;
goto err;
}
} else {
Log1(PCSC_LOG_INFO, "Using default port.");
}
return IFDHCreateChannel (Lun, port);
r = IFDHCreateChannel (Lun, port);
err:
/* set hostname back to default in case it has been changed */
hostname = NULL;
return r;
}
RESPONSECODE

View File

@@ -22,9 +22,13 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#define close(s) closesocket(s)
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV 0
#endif
typedef WORD uint16_t;
#else
#include <arpa/inet.h>
#include <netdb.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -32,6 +36,7 @@ typedef WORD uint16_t;
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -43,29 +48,27 @@ typedef WORD uint16_t;
#define VPCD_CTRL_RESET 2
#define VPCD_CTRL_ATR 4
ssize_t sendToVICC(struct vicc_ctx *ctx, size_t size, const unsigned char *buffer);
ssize_t recvFromVICC(struct vicc_ctx *ctx, unsigned char **buffer);
static ssize_t sendToVICC(struct vicc_ctx *ctx, size_t size, const unsigned char *buffer);
static ssize_t recvFromVICC(struct vicc_ctx *ctx, unsigned char **buffer);
static ssize_t sendall(int sock, const void *buffer, size_t size);
static ssize_t recvall(int sock, void *buffer, size_t size);
static int opensock(unsigned short port);
static int connectsock(const char *hostname, unsigned short port);
ssize_t sendall(int sock, const void *buffer, size_t size)
{
size_t sent = 0;
size_t sent;
ssize_t r;
const unsigned char *p = buffer;
while (sent < size) {
r = send(sock, (void *) p, size-sent, 0);
if (r < 0)
return r;
for (sent = 0; sent < size; sent += r) {
r = send(sock, (void *) (buffer+sent), size-sent, 0);
sent += r;
p += r;
}
if (r < 0)
return r;
}
return sent;
}
@@ -74,7 +77,7 @@ ssize_t recvall(int sock, void *buffer, size_t size) {
return recv(sock, buffer, size, MSG_WAITALL);
}
int opensock(unsigned short port)
static int opensock(unsigned short port)
{
int sock;
socklen_t yes = 1;
@@ -102,6 +105,40 @@ int opensock(unsigned short port)
return sock;
}
static int connectsock(const char *hostname, unsigned short port)
{
struct addrinfo hints, *res = NULL, *cur;
int sock = -1;
char _port[10];
if (snprintf(_port, sizeof _port, "%hu", port) < 0)
goto err;
_port[(sizeof _port) -1] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
if (getaddrinfo(hostname, _port, &hints, &res) != 0)
goto err;
for (cur = res; cur; cur = cur->ai_next) {
sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
if (sock < 0)
continue;
if (connect(sock, cur->ai_addr, cur->ai_addrlen) != -1)
break;
close(sock);
}
err:
freeaddrinfo(res);
return sock;
}
int waitforclient(int server, long secs, long usecs)
{
fd_set rfds;
@@ -132,7 +169,7 @@ int waitforclient(int server, long secs, long usecs)
return 0;
}
ssize_t sendToVICC(struct vicc_ctx *ctx, size_t length, const unsigned char* buffer)
static ssize_t sendToVICC(struct vicc_ctx *ctx, size_t length, const unsigned char* buffer)
{
ssize_t r;
uint16_t size;
@@ -155,7 +192,7 @@ ssize_t sendToVICC(struct vicc_ctx *ctx, size_t length, const unsigned char* buf
return r;
}
ssize_t recvFromVICC(struct vicc_ctx *ctx, unsigned char **buffer)
static ssize_t recvFromVICC(struct vicc_ctx *ctx, unsigned char **buffer)
{
ssize_t r;
uint16_t size;
@@ -186,29 +223,45 @@ ssize_t recvFromVICC(struct vicc_ctx *ctx, unsigned char **buffer)
int vicc_eject(struct vicc_ctx *ctx)
{
int r = 0;
if (ctx && ctx->client_sock > 0) {
ctx->client_sock = close(ctx->client_sock);
if (ctx->client_sock < 0) {
return -1;
if (close(ctx->client_sock) < 0) {
r -= 1;
}
ctx->client_sock = -1;
}
return 0;
return r;
}
struct vicc_ctx * vicc_init(unsigned short port)
struct vicc_ctx * vicc_init(const char *hostname, unsigned short port)
{
struct vicc_ctx *ctx = malloc(sizeof *ctx);
if (!ctx) {
return NULL;
}
ctx->server_sock = opensock(port);
if (ctx->server_sock < 0) {
free(ctx);
return NULL;
}
if (hostname) {
ctx->hostname = strdup(hostname);
if (!ctx->hostname) {
free(ctx);
return NULL;
}
ctx->client_sock = -1;
ctx->server_sock = -1;
ctx->client_sock = connectsock(hostname, port);
} else {
ctx->hostname = NULL;
ctx->server_sock = opensock(port);
if (ctx->server_sock < 0) {
free(ctx);
return NULL;
}
ctx->client_sock = -1;
}
ctx->port = port;
return ctx;
}
@@ -217,6 +270,7 @@ int vicc_exit(struct vicc_ctx *ctx)
{
int r = vicc_eject(ctx);
if (ctx) {
free(ctx->hostname);
if (ctx->server_sock > 0) {
ctx->server_sock = close(ctx->server_sock);
if (ctx->server_sock < 0) {
@@ -248,23 +302,30 @@ ssize_t vicc_transmit(struct vicc_ctx *ctx,
int vicc_present(struct vicc_ctx *ctx) {
unsigned char *atr = NULL;
if (ctx->client_sock <= 0)
/* return immediately */
ctx->client_sock = waitforclient(ctx->server_sock, 0, 0);
if (ctx->client_sock < 0) {
if (ctx->server_sock) {
/* server mode, try to accept a client */
ctx->client_sock = waitforclient(ctx->server_sock, 0, 0);
if (!ctx->client_sock) {
ctx->client_sock = -1;
}
} else {
/* client mode, try to connect (again) */
ctx->client_sock = connectsock(ctx->hostname, ctx->port);
}
}
if (ctx->client_sock < 0)
return -1;
if (ctx->client_sock > 0) {
if (vicc_getatr(ctx, &atr) <= 0)
return 0;
free(atr);
return 1;
} else {
/* not connected */
return 0;
}
/* get the atr to check if the card is still alive */
if (vicc_getatr(ctx, &atr) <= 0)
return 0;
free(atr);
return 1;
}
ssize_t vicc_getatr(struct vicc_ctx *ctx, unsigned char **atr) {

View File

@@ -29,6 +29,8 @@ typedef int ssize_t;
struct vicc_ctx {
int server_sock;
int client_sock;
char *hostname;
unsigned short port;
};
#ifdef __cplusplus
@@ -39,7 +41,20 @@ extern "C" {
/** Standard port of the virtual smart card reader */
#define VPCDPORT 35963
struct vicc_ctx * vicc_init(unsigned short port);
/**
* @brief Initialize the module
*
* @param[in] hostname Set hostname to something different to NULL if you want
* to connect the vpcd to a socket opened by vicc.
* Otherwise (default behavior) the vpcd will open a port
* for vicc
* @param[in] port Port to connect to or to open (see \a hostname)
*
* @return On success, the call returns the initialized context
* On error, NULL is returned.
*/
struct vicc_ctx * vicc_init(const char *hostname, unsigned short port);
int vicc_exit(struct vicc_ctx *ctx);
int vicc_eject(struct vicc_ctx *ctx);