Projekt

Allgemein

Profil

Herunterladen (57,2 KB) Statistiken
| Zweig: | Markierung: | Revision:
/***************************************************************************
$RCSfile$
-------------------
cvs : $Id$
begin : Mon Mar 01 2004
copyright : (C) 2004 by Martin Preuss
email : martin@libchipcard.de

***************************************************************************
* Please see toplevel file COPYING for license details *
***************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif


#include "driver_p.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/nettransportsock.h>
#include <gwenhywfar/nettransportssl.h>
#include <gwenhywfar/net.h>
#include <gwenhywfar/directory.h>

#include <chipcard2/chipcard2.h>

#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include <time.h>

static GWEN_TYPE_UINT32 LCD_Driver__LastCardNum=0;


GWEN_INHERIT_FUNCTIONS(LCD_DRIVER)


void LCD_Driver_Usage(const char *prgName) {
fprintf(stdout,
"%s [OPTONS] \n"
"[-v] verbous\n"
"[--logfile ARG] name of the logfile\n"
"[--logtype ARG] log type\n"
"[--loglevel ARG] log level\n"
"[-d ARG] driver data folder\n"
"-b ARG server id\n"
"[-u ARG] customer id of this driver\n"
"[-a ARG] server IP address (or hostname)\n"
"[-p ARG] server TCP port\n"
"-l ARG name of the library driver file\n"
"-i ARG driver id for this session\n"
"\n"
"The following arguments are used in test/remote mode only\n"
"--test enter test mode, check for a given reader\n"
"-rp ARG reader port\n"
"-rs ARG reader slots\n"
"-rn ARG reader name\n"
"--remote driver is in remote mode\n"
"[-rt ARG] reader type (only for remote drivers)\n"
"[-dt ARG] driver type (only for remote drivers)\n"
"--accept-all-certs accept all server certificates"
, prgName
);
}



LCD_DRIVER_CHECKARGS_RESULT LCD_Driver_CheckArgs(LCD_DRIVER *d,
int argc, char **argv) {
int i;

assert(d);

d->verbous=0;
d->rslots=1;
d->testMode=0;
d->rport=0;
d->rname=0;
d->rtype=0;
d->dtype=0;
d->remoteMode=0;
d->logType=GWEN_LoggerTypeConsole;
d->logFile=strdup("driver.log");
d->logLevel=GWEN_LoggerLevelNotice;
d->serverPort=LC_DEFAULT_PORT;
d->typ="local";
d->certFile=0;
d->certDir=0;
d->serverAddr=0;
d->acceptAllCerts=0;

i=1;
while (i<argc){
if (strcmp(argv[i],"--logfile")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
free(d->logFile);
d->logFile=strdup(argv[i]);
}
else if (strcmp(argv[i],"--logtype")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->logType=GWEN_Logger_Name2Logtype(argv[i]);
if (d->logType==GWEN_LoggerTypeUnknown) {
DBG_ERROR(0, "Unknown log type \"%s\"\n", argv[i]);
return LCD_DriverCheckArgsResultError;
}
}
else if (strcmp(argv[i],"--loglevel")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->logLevel=GWEN_Logger_Name2Level(argv[i]);
if (d->logLevel==GWEN_LoggerLevelUnknown) {
DBG_ERROR(0, "Unknown log level \"%s\"\n", argv[i]);
return LCD_DriverCheckArgsResultError;
}
}
else if (strcmp(argv[i], "--accept-all-certs")==0) {
d->acceptAllCerts=1;
}
else if (strcmp(argv[i],"-d")==0) {
i++;
if (i>=argc)
return -1;
d->driverDataDir=argv[i];
}
else if (strcmp(argv[i],"-t")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->typ=argv[i];
}
else if (strcmp(argv[i],"-i")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->driverId=argv[i];
}
else if (strcmp(argv[i],"-a")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->serverAddr=argv[i];
}
else if (strcmp(argv[i],"-p")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->serverPort=atoi(argv[i]);
}
else if (strcmp(argv[i],"-l")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->libraryFile=argv[i];
}
else if (strcmp(argv[i],"-c")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->certFile=argv[i];
}
else if (strcmp(argv[i],"-C")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->certDir=argv[i];
}
else if (strcmp(argv[i],"--test")==0) {
d->testMode=1;
}
else if (strcmp(argv[i],"-rn")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->rname=argv[i];
}
else if (strcmp(argv[i],"-rp")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->rport=atoi(argv[i]);
}
else if (strcmp(argv[i],"-rs")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->rslots=atoi(argv[i]);
}
else if (strcmp(argv[i],"-rt")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->rtype=argv[i];
}
else if (strcmp(argv[i],"-dt")==0) {
i++;
if (i>=argc)
return LCD_DriverCheckArgsResultError;
d->dtype=argv[i];
}
else if (strcmp(argv[i],"--remote")==0) {
DBG_ERROR(0, "Remote mode is on");
d->remoteMode=1;
}
else if (strcmp(argv[i],"-h")==0 || strcmp(argv[i],"--help")==0) {
LCD_Driver_Usage(argv[0]);
return LCD_DriverCheckArgsResultHelp;
}
else if (strcmp(argv[i],"-V")==0 || strcmp(argv[i],"--version")==0) {
return LCD_DriverCheckArgsResultVersion;
}
else if (strcmp(argv[i],"-v")==0) {
d->verbous=1;
}
else {
DBG_ERROR(0, "Unknown argument \"%s\"", argv[i]);
return LCD_DriverCheckArgsResultError;
}
i++;
} /* while */

/* check for missing arguments */
if (!d->testMode) {
if (!d->serverAddr) {
DBG_ERROR(0, "Server address missing");
return LCD_DriverCheckArgsResultError;
}
if (!d->driverId && !d->remoteMode) {
DBG_ERROR(0, "Driver id missing");
return LCD_DriverCheckArgsResultError;
}
}

if (!d->libraryFile) {
DBG_ERROR(0, "Name of driver library file missing");
return LCD_DriverCheckArgsResultError;
}

if (d->logFile==0) {
GWEN_BUFFER *mbuf;

mbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(mbuf, "driver");
GWEN_Buffer_AppendString(mbuf, ".log");
d->logFile=strdup(GWEN_Buffer_GetStart(mbuf));
GWEN_Buffer_free(mbuf);
}

if (d->logFile) {
GWEN_BUFFER *mbuf;

if (strstr(d->logFile, "@reader@")) {
free(d->readerLogFile);
d->readerLogFile=strdup(d->logFile);
mbuf=GWEN_Buffer_new(0, 256, 0, 1);
LCD_Driver_ReplaceVar(d->logFile, "reader", "driver", mbuf);
free(d->logFile);
d->logFile=strdup(GWEN_Buffer_GetStart(mbuf));
GWEN_Buffer_free(mbuf);
}
}

if (d->remoteMode) {
if (!d->rname ||
!d->rtype ||
!d->dtype) {
DBG_ERROR(0, "Reader properties missing");
return LCD_DriverCheckArgsResultError;
}
}

/* now setup reader if in remote mode */
if (d->remoteMode) {
LCD_READER *r;

/* setup remote mode */
DBG_ERROR(0, "Creating reader...");
r=LCD_Driver_CreateReader(d, 0,
d->rname,
d->rport, d->rslots,
d->rflags);
if (!r) {
DBG_ERROR(0, "Could not create reader, aborting.");
return LCD_DriverCheckArgsResultError;
}
LCD_Reader_SetReaderType(r, d->rtype);
LCD_Reader_SetDriversReaderId(r, ++(d->lastReaderId));
LCD_Driver_AddReader(d, r);
}

return 0;
}



int LCD_Driver_Init(LCD_DRIVER *d, int argc, char **argv) {
LCD_DRIVER_CHECKARGS_RESULT res;
GWEN_NETTRANSPORT *tr;
GWEN_SOCKET *sk;
GWEN_INETADDRESS *addr;
GWEN_TYPE_UINT32 sid;

res=LCD_Driver_CheckArgs(d, argc, argv);
if (res!=LCD_DriverCheckArgsResultOk) {
return -1;
}

if (GWEN_Directory_GetPath(d->logFile,
GWEN_PATH_FLAGS_VARIABLE)) {
DBG_ERROR(0, "Could not create log file for driver ");
GWEN_Logger_Open(0, "driver",
0,
GWEN_LoggerTypeConsole,
GWEN_LoggerFacilityUser);
}
else {
GWEN_Logger_Open(0, "driver",
d->logFile,
d->logType,
GWEN_LoggerFacilityUser);
}
GWEN_Logger_SetLevel(0, d->logLevel);

if (!d->testMode) {
DBG_NOTICE(0, "Starting driver \"%s\" with lowlevel \"%s\"",
argv[0], d->libraryFile);

d->ipcManager=GWEN_IPCManager_new();

if (strcasecmp(d->typ, "local")==0) {
/* HTTP over UDS */
sk=GWEN_Socket_new(GWEN_SocketTypeUnix);
addr=GWEN_InetAddr_new(GWEN_AddressFamilyUnix);
GWEN_InetAddr_SetAddress(addr, d->serverAddr);
tr=GWEN_NetTransportSocket_new(sk, 1);
}
else if (strcasecmp(d->typ, "public")==0) {
/* HTTP over TCP */
sk=GWEN_Socket_new(GWEN_SocketTypeTCP);
addr=GWEN_InetAddr_new(GWEN_AddressFamilyIP);
GWEN_InetAddr_SetAddress(addr, d->serverAddr);
GWEN_InetAddr_SetPort(addr, d->serverPort);
tr=GWEN_NetTransportSocket_new(sk, 1);
}
else {
addr=GWEN_InetAddr_new(GWEN_AddressFamilyIP);
GWEN_InetAddr_SetAddress(addr, d->serverAddr);
GWEN_InetAddr_SetPort(addr, d->serverPort);
if (strcasecmp(d->typ, "private")==0) {
/* HTTP over SSL */
sk=GWEN_Socket_new(GWEN_SocketTypeTCP);
tr=GWEN_NetTransportSSL_new(sk,
d->certDir,
0,
d->certFile,
0,
0,
1);
}
else if (strcasecmp(d->typ, "secure")==0) {
/* HTTP over SSL with certificates */
sk=GWEN_Socket_new(GWEN_SocketTypeTCP);
tr=GWEN_NetTransportSSL_new(sk,
d->certDir,
0,
d->certFile,
0,
1,
1);
}
else {
DBG_ERROR(0, "Unknown mode \"%s\"", d->typ);
GWEN_InetAddr_free(addr);
return -1;
}
}

GWEN_NetTransport_SetPeerAddr(tr, addr);
GWEN_InetAddr_free(addr);
sid=GWEN_IPCManager_AddClient(d->ipcManager,
tr,
0,0,
LCD_DRIVER_MARK_DRIVER);
if (sid==0) {
DBG_ERROR(0, "Could not add IPC client");
return -1;
}

d->ipcId=sid;
DBG_INFO(0, "IPC stuff initialized");
}
return 0;
}



LCD_DRIVER *LCD_Driver_new() {
LCD_DRIVER *d;

GWEN_NEW_OBJECT(LCD_DRIVER, d);
GWEN_INHERIT_INIT(LCD_DRIVER, d);
d->readers=LCD_Reader_List_new();

GWEN_NetTransportSSL_SetAskAddCertFn2(LCD_Driver_AskAddCert, (void*)d);

return d;
}



void LCD_Driver_free(LCD_DRIVER *d) {
if (d) {
GWEN_INHERIT_FINI(LCD_DRIVER, d);
LCD_Reader_List_free(d->readers);
GWEN_IPCManager_free(d->ipcManager);
free(d->logFile);
free(d->readerLogFile);
GWEN_FREE_OBJECT(d);
}
}



int LCD_Driver_IsTestMode(const LCD_DRIVER *d) {
assert(d);
return d->testMode;
}



int LCD_Driver_Test(LCD_DRIVER *d) {
LCD_READER *r;
GWEN_TYPE_UINT32 res;

assert(d);
if (!d->testMode) {
DBG_ERROR(0, "Not in test mode");
return -1;
}

r=LCD_Driver_CreateReader(d,
1,
d->rname,
d->rport,
d->rslots,
0);
assert(r);
fprintf(stdout, "Connecting reader...\n");
res=LCD_Driver_ConnectReader(d, r);
if (res!=0) {
fprintf(stderr, "-> Could not connect reader (%s)\n",
LCD_Driver_GetErrorText(d, res));
LCD_Reader_free(r);
return -1;
}
fprintf(stdout, "-> Reader connected.\n");

fprintf(stdout, "Disconnecting reader...\n");
res=LCD_Driver_DisconnectReader(d, r);
if (res!=0) {
fprintf(stderr, "-> Could not disconnect reader (%s)\n",
LCD_Driver_GetErrorText(d, res));
LCD_Reader_free(r);
return -1;
}
fprintf(stdout, "-> Reader disconnected.\n");

fprintf(stdout, "Reader is available.\n");
LCD_Reader_free(r);
return 0;
}



const char *LCD_Driver_GetDriverDataDir(const LCD_DRIVER *d){
assert(d);
return d->driverDataDir;
}



const char *LCD_Driver_GetLibraryFile(const LCD_DRIVER *d){
assert(d);
return d->libraryFile;
}



const char *LCD_Driver_GetDriverId(const LCD_DRIVER *d){
assert(d);
return d->driverId;
}



GWEN_TYPE_UINT32 LCD_Driver_SendCommand(LCD_DRIVER *d,
GWEN_DB_NODE *dbCommand) {
return GWEN_IPCManager_SendRequest(d->ipcManager,
d->ipcId, dbCommand);
}



int LCD_Driver_SendResponse(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
GWEN_DB_NODE *dbCommand) {
return GWEN_IPCManager_SendResponse(d->ipcManager,
rid, dbCommand);
}



int LCD_Driver_SendResult(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
const char *name,
const char *code,
const char *text){
GWEN_DB_NODE *db;

db=GWEN_DB_Group_new(name);
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_DEFAULT,
"code", code);
if (text)
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_DEFAULT,
"text", text);
return LCD_Driver_SendResponse(d, rid, db);
}



GWEN_TYPE_UINT32 LCD_Driver_GetNextInRequest(LCD_DRIVER *d) {
assert(d);
return GWEN_IPCManager_GetNextInRequest(d->ipcManager,
LCD_DRIVER_MARK_DRIVER);
}



GWEN_DB_NODE *LCD_Driver_GetInRequestData(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid) {
assert(d);
return GWEN_IPCManager_GetInRequestData(d->ipcManager, rid);
}



int LCD_Driver__Work(LCD_DRIVER *d, int timeout, int maxmsg){
GWEN_NETCONNECTION_WORKRESULT res;
int rv;

if (!GWEN_Net_HasActiveConnections()) {
DBG_ERROR(0, "No active connections, stopping");
return -1;
}

res=GWEN_Net_HeartBeat(timeout);
if (res==GWEN_NetConnectionWorkResult_Error) {
DBG_ERROR(0, "Network error");
return -1;
}
else if (res==GWEN_NetConnectionWorkResult_NoChange) {
DBG_VERBOUS(0, "No activity");
}

while(1) {
DBG_DEBUG(0, "Driver: Working");
/* activity detected, work with it */
rv=GWEN_IPCManager_Work(d->ipcManager, maxmsg);
if (rv==-1) {
DBG_ERROR(0, "Error while working with IPC");
return -1;
}
else if (rv==1)
break;
}

return 0;
}



int LCD_Driver_CheckResponses(GWEN_DB_NODE *db) {
const char *name;

name=GWEN_DB_GetCharValue(db, "command/vars/cmd", 0, 0);
if (!name) {
DBG_ERROR(0, "Bad IPC message (no command)");
return -1;
}

if (strcasecmp(name, "Error")==0) {
int numCode;

numCode=GWEN_DB_GetIntValue(db, "body/code", 0, -1);
if (numCode==-1) {
const char *code;

code=GWEN_DB_GetCharValue(db, "body/code", 0, "ERROR");
if (strcasecmp(code, "OK")!=0)
numCode=LC_ERROR_GENERIC;
else
numCode=0;
}

if (numCode) {
DBG_ERROR(0, "Error %d: %s", numCode,
GWEN_DB_GetCharValue(db,
"body/text", 0, "(empty)"));
return -1;
}
}
return 0;
}



int LCD_Driver_Connect(LCD_DRIVER *d, const char *code, const char *text){
GWEN_DB_NODE *dbReq;
GWEN_DB_NODE *dbRsp;
time_t startt;
GWEN_TYPE_UINT32 rid;

assert(d);

if (d->testMode) {
DBG_INFO(0, "Testmode, will not connect");
return 0;
}
startt=time(0);

/* tell the server about our status */
dbReq=GWEN_DB_Group_new("DriverReady");
if (d->driverId)
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"driverId", d->driverId);

if (d->remoteMode) {
/* send some additional information in remote mode */
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"driverType", d->dtype);
} /* if remote mode */

/* send information about every reader we already now.
* Normally we don't know any reader by now, since the server informs us
* about that later upon a StartReader request.
* However, in remote mode (or later for PC/SC drivers) we in fact do have
* some readers already, so we now inform the server about readers we can
* offer.
*/
if (LCD_Reader_List_GetCount(d->readers)) {
GWEN_DB_NODE *dbReaders;
LCD_READER *r;

dbReaders=GWEN_DB_GetGroup(dbReq, GWEN_DB_FLAGS_OVERWRITE_GROUPS,
"readers");
assert(dbReaders);

r=LCD_Reader_List_First(d->readers);
while(r) {
GWEN_DB_NODE *dbReader;
GWEN_TYPE_UINT32 flags;

dbReader=GWEN_DB_GetGroup(dbReaders, GWEN_DB_FLAGS_OVERWRITE_GROUPS,
"reader");
assert(dbReader);
GWEN_DB_SetIntValue(dbReader, GWEN_DB_FLAGS_OVERWRITE_VARS,
"driversReaderId",
LCD_Reader_GetDriversReaderId(r));
GWEN_DB_SetCharValue(dbReader, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerType", d->rtype);
GWEN_DB_SetCharValue(dbReader, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerName", d->rname);
GWEN_DB_SetIntValue(dbReader, GWEN_DB_FLAGS_OVERWRITE_VARS,
"port", d->rport);
GWEN_DB_SetIntValue(dbReader, GWEN_DB_FLAGS_OVERWRITE_VARS,
"slots", d->rslots);

flags=LCD_Reader_GetReaderFlags(r);
LC_ReaderFlags_toDb(dbReader, "readerFlags", flags);

r=LCD_Reader_List_Next(r);
} /* while */
} /* if readers */


GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", code);
if (text)
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", text);

rid=GWEN_IPCManager_SendRequest(d->ipcManager,
d->ipcId,
dbReq);
if (rid==0) {
DBG_ERROR(0, "Could not send command");
return -1;
}

/* this sends the message and hopefully receives an answer */
DBG_INFO(0, "Sending Ready Report");
dbRsp=0;
while (1) {
dbRsp=GWEN_IPCManager_GetResponseData(d->ipcManager, rid);
if (dbRsp) {
DBG_DEBUG(0, "Command answered");
break;
}
DBG_VERBOUS(0, "Working...");
if (LCD_Driver__Work(d, 1000, 0)) {
DBG_ERROR(0, "Error at work");
GWEN_IPCManager_RemoveRequest(d->ipcManager, d->ipcId, 1);
return -1;
}

if (difftime(time(0), startt)>=LCD_DRIVER_STARTTIMEOUT) {
DBG_ERROR(0, "Timeout");
GWEN_IPCManager_RemoveRequest(d->ipcManager, d->ipcId, 1);
return -1;
}
} /* while */

DBG_DEBUG(0, "Answer received");
if (LCD_Driver_CheckResponses(dbRsp)) {
DBG_ERROR(0, "Error returned by server, aborting");
GWEN_IPCManager_RemoveRequest(d->ipcManager, rid, 1);
return -1;
}
GWEN_IPCManager_RemoveRequest(d->ipcManager, rid, 1);

DBG_NOTICE(0, "Connected to server");
return 0;
}



void LCD_Driver_Disconnect(LCD_DRIVER *d){
assert(d);
if (d->testMode) {
DBG_INFO(0, "Testmode, will not disconnect (since I'm not connected)");
return;
}

if (GWEN_IPCManager_Disconnect(d->ipcManager, d->ipcId)) {
DBG_ERROR(0, "Error while disconnecting");
}
}



LCD_READER *LCD_Driver_FindReaderByName(const LCD_DRIVER *d, const char *name) {
LCD_READER *r;

assert(d);
r=LCD_Reader_List_First(d->readers);
while(r) {
if (strcasecmp(name, LCD_Reader_GetName(r))==0)
return r;
r=LCD_Reader_List_Next(r);
} /* while */
return 0;
}



LCD_READER *LCD_Driver_FindReaderByPort(const LCD_DRIVER *d, int port) {
LCD_READER *r;

assert(d);
r=LCD_Reader_List_First(d->readers);
while(r) {
if (port==LCD_Reader_GetPort(r))
return r;
r=LCD_Reader_List_Next(r);
} /* while */
return 0;
}



LCD_READER *LCD_Driver_FindReaderById(const LCD_DRIVER *d, GWEN_TYPE_UINT32 id){
LCD_READER *r;

assert(d);
r=LCD_Reader_List_First(d->readers);
while(r) {
if (id==LCD_Reader_GetReaderId(r))
return r;
r=LCD_Reader_List_Next(r);
} /* while */
return 0;
}



LCD_READER *LCD_Driver_FindReaderByDriversId(const LCD_DRIVER *d,
GWEN_TYPE_UINT32 id){
LCD_READER *r;

assert(d);
r=LCD_Reader_List_First(d->readers);
while(r) {
if (id==LCD_Reader_GetDriversReaderId(r))
return r;
r=LCD_Reader_List_Next(r);
} /* while */
return 0;
}



void LCD_Driver_AddReader(LCD_DRIVER *d, LCD_READER *r){
assert(d);
assert(r);

LCD_Reader_List_Add(r, d->readers);
}



void LCD_Driver_DelReader(LCD_DRIVER *d, LCD_READER *r){
assert(d);
assert(r);

LCD_Reader_List_Del(r);
}



LCD_READER_LIST *LCD_Driver_GetReaders(const LCD_DRIVER *d){
assert(d);
return d->readers;
}



GWEN_TYPE_UINT32 LCD_Driver_SendAPDU(LCD_DRIVER *d,
int toReader,
LCD_READER *r,
LCD_SLOT *slot,
const unsigned char *apdu,
unsigned int apdulen,
unsigned char *buffer,
int *bufferlen){
assert(d);
assert(d->sendApduFn);
return d->sendApduFn(d, toReader, r, slot, apdu, apdulen,
buffer, bufferlen);
}



GWEN_TYPE_UINT32 LCD_Driver_ConnectSlot(LCD_DRIVER *d, LCD_SLOT *sl){
assert(d);
assert(d->connectSlotFn);
return d->connectSlotFn(d, sl);
}



GWEN_TYPE_UINT32 LCD_Driver_ConnectReader(LCD_DRIVER *d, LCD_READER *r){
GWEN_TYPE_UINT32 rv;

assert(d);
assert(d->connectReaderFn);
rv=d->connectReaderFn(d, r);
if (rv==0)
LCD_Reader_AddStatus(r, LCD_READER_STATUS_UP);
return rv;
}



GWEN_TYPE_UINT32 LCD_Driver_DisconnectSlot(LCD_DRIVER *d, LCD_SLOT *sl){
assert(d);
assert(d->disconnectSlotFn);
return d->disconnectSlotFn(d, sl);
}



GWEN_TYPE_UINT32 LCD_Driver_DisconnectReader(LCD_DRIVER *d, LCD_READER *r){
GWEN_TYPE_UINT32 rv;

assert(d);
assert(d->disconnectReaderFn);
rv=d->disconnectReaderFn(d, r);
LCD_Reader_SubStatus(r, LCD_READER_STATUS_UP);
return rv;
}



GWEN_TYPE_UINT32 LCD_Driver_ResetSlot(LCD_DRIVER *d, LCD_SLOT *sl){
assert(d);
assert(d->resetSlotFn);
return d->resetSlotFn(d, sl);
}



GWEN_TYPE_UINT32 LCD_Driver_ReaderStatus(LCD_DRIVER *d, LCD_READER *r){
assert(d);
assert(d->readerStatusFn);
return d->readerStatusFn(d, r);
}



GWEN_TYPE_UINT32 LCD_Driver_ReaderInfo(LCD_DRIVER *d,
LCD_READER *r,
GWEN_BUFFER *buf){
assert(d);
assert(d->readerInfoFn);
return d->readerInfoFn(d, r, buf);
}



LCD_READER *LCD_Driver_CreateReader(LCD_DRIVER *d,
GWEN_TYPE_UINT32 readerId,
const char *name,
int port,
unsigned int slots,
GWEN_TYPE_UINT32 flags){
LCD_READER *r;

assert(d);
if (d->createReaderFn==0) {
r=LCD_Reader_new(readerId, name, port, slots, flags);
}
else {
r=d->createReaderFn(d, readerId, name, port, slots, flags);
}

return r;
}



const char *LCD_Driver_GetErrorText(LCD_DRIVER *d, GWEN_TYPE_UINT32 err){
assert(d);
assert(d->getErrorTextFn);
return d->getErrorTextFn(d, err);
}



void LCD_Driver_SetSendApduFn(LCD_DRIVER *d, LCD_DRIVER_SENDAPDU_FN fn){
assert(d);
d->sendApduFn=fn;
}



void LCD_Driver_SetConnectSlotFn(LCD_DRIVER *d, LCD_DRIVER_CONNECTSLOT_FN fn){
assert(d);
d->connectSlotFn=fn;
}



void LCD_Driver_SetDisconnectSlotFn(LCD_DRIVER *d,
LCD_DRIVER_DISCONNECTSLOT_FN fn){
assert(d);
d->disconnectSlotFn=fn;
}



void LCD_Driver_SetConnectReaderFn(LCD_DRIVER *d,
LCD_DRIVER_CONNECTREADER_FN fn){
assert(d);
d->connectReaderFn=fn;
}



void LCD_Driver_SetDisconnectReaderFn(LCD_DRIVER *d,
LCD_DRIVER_DISCONNECTREADER_FN fn){
assert(d);
d->disconnectReaderFn=fn;
}



void LCD_Driver_SetResetSlotFn(LCD_DRIVER *d, LCD_DRIVER_RESETSLOT_FN fn){
assert(d);
d->resetSlotFn=fn;
}



void LCD_Driver_SetReaderStatusFn(LCD_DRIVER *d,
LCD_DRIVER_READERSTATUS_FN fn){
assert(d);
d->readerStatusFn=fn;
}



void LCD_Driver_SetReaderInfoFn(LCD_DRIVER *d,
LCD_DRIVER_READERINFO_FN fn){
assert(d);
d->readerInfoFn=fn;
}



void LCD_Driver_SetCreateReaderFn(LCD_DRIVER *d,
LCD_DRIVER_CREATEREADER_FN fn){
assert(d);
d->createReaderFn=fn;
}



void LCD_Driver_SetGetErrorTextFn(LCD_DRIVER *d,
LCD_DRIVER_GETERRORTEXT_FN fn){
assert(d);
d->getErrorTextFn=fn;
}



void LCD_Driver_SetHandleRequestFn(LCD_DRIVER *d,
LCD_DRIVER_HANDLEREQUEST_FN fn) {
assert(d);
d->handleRequestFn=fn;
}



int LCD_Driver_SendStatusChangeNotification(LCD_DRIVER *d,
LCD_SLOT *sl) {
GWEN_DB_NODE *dbReq;
char numbuf[16];
int rv;
int slot;
int cardnum;
GWEN_BUFFER *atr;
int isInserted;
LCD_READER *r;
GWEN_TYPE_UINT32 rid;

r=LCD_Slot_GetReader(sl);
slot=LCD_Slot_GetSlotNum(sl);
cardnum=LCD_Slot_GetCardNum(sl);
atr=LCD_Slot_GetAtr(sl);
isInserted=(LCD_Slot_GetStatus(sl) & LCD_SLOT_STATUS_CARD_CONNECTED);

dbReq=GWEN_DB_Group_new(isInserted?"CardInserted":"CardRemoved");

rv=snprintf(numbuf, sizeof(numbuf)-1, "%08x", LCD_Reader_GetReaderId(r));
assert(rv>0 && rv<sizeof(numbuf)-1);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerId", numbuf);

rv=snprintf(numbuf, sizeof(numbuf)-1, "%08x",
LCD_Reader_GetDriversReaderId(r));
assert(rv>0 && rv<sizeof(numbuf)-1);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"driversReaderId", numbuf);

GWEN_DB_SetIntValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"slotnum", slot);

GWEN_DB_SetIntValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"cardnum", cardnum);

if (isInserted) {
if (atr)
if (GWEN_Buffer_GetUsedBytes(atr))
GWEN_DB_SetBinValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"atr",
GWEN_Buffer_GetStart(atr),
GWEN_Buffer_GetUsedBytes(atr));
if (LCD_Slot_GetFlags(sl) & LCD_SLOT_FLAGS_PROCESSORCARD)
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"cardType", "PROCESSOR");
else
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"cardType", "MEMORY");
} /* if inserted */

rid=LCD_Driver_SendCommand(d, dbReq);
if (rid==0) {
DBG_ERROR(0, "Could not send command");
return -1;
}

GWEN_IPCManager_RemoveRequest(d->ipcManager, rid, 1);
DBG_DEBUG(0, "Command sent");
return 0;
}



int LCD_Driver_SendReaderErrorNotification(LCD_DRIVER *d,
LCD_READER *r,
const char *text) {
GWEN_DB_NODE *dbReq;
char numbuf[16];
int rv;
GWEN_TYPE_UINT32 rid;

assert(d);
dbReq=GWEN_DB_Group_new("ReaderError");

rv=snprintf(numbuf, sizeof(numbuf)-1, "%08x", LCD_Reader_GetReaderId(r));
assert(rv>0 && rv<sizeof(numbuf)-1);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerId", numbuf);

rv=snprintf(numbuf, sizeof(numbuf)-1, "%08x",
LCD_Reader_GetDriversReaderId(r));
assert(rv>0 && rv<sizeof(numbuf)-1);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"driversReaderId", numbuf);

GWEN_DB_SetCharValue(dbReq, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", text);

rid=LCD_Driver_SendCommand(d, dbReq);
if (rid==0) {
DBG_ERROR(0, "Could not send command");
return -1;
}

GWEN_IPCManager_RemoveRequest(d->ipcManager, rid, 1);
DBG_DEBUG(0, "Command sent");

return 0;
}



int LCD_Driver_RemoveCommand(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
int outbound){
assert(d);
return GWEN_IPCManager_RemoveRequest(d->ipcManager, rid, outbound);
}



int LCD_Driver_CheckStatusChanges(LCD_DRIVER *d) {
LCD_READER *r;

r=LCD_Reader_List_First(LCD_Driver_GetReaders(d));
while(r) {
LCD_READER *rnext;
GWEN_TYPE_UINT32 retval;

rnext=LCD_Reader_List_Next(r);

if (LCD_Reader_GetStatus(r) & LCD_READER_STATUS_UP) {
retval=LCD_Driver_ReaderStatus(d, r);
if (retval) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Error getting reader status");
LCD_Driver_SendReaderErrorNotification(d, r,
LCD_Driver_GetErrorText(d, retval));
DBG_NOTICE(LCD_Reader_GetLogger(r),
"Reader \"%s\" had an error, shutting down",
LCD_Reader_GetName(r));
LCD_Reader_List_Del(r);
LCD_Reader_free(r);
}
else {
LCD_SLOT_LIST *slList;
LCD_SLOT *sl;
slList=LCD_Reader_GetSlots(r);
sl=LCD_Slot_List_First(slList);
while(sl) {
int isInserted;
GWEN_TYPE_UINT32 newStatus, oldStatus;
int cardNum;
newStatus=LCD_Slot_GetStatus(sl);
if (!(newStatus & LCD_SLOT_STATUS_DISABLED)) {
oldStatus=LCD_Slot_GetLastStatus(sl);
if (((newStatus^oldStatus) & LCD_SLOT_STATUS_CARD_INSERTED) &&
/*!(newStatus & LCD_SLOT_STATUS_CARD_CONNECTED) && */
(newStatus & LCD_SLOT_STATUS_CARD_INSERTED)){
/* card has just been inserted, try to connect it */
DBG_NOTICE(LCD_Reader_GetLogger(r),
"Card inserted, trying to connect it");
if (LCD_Driver_ConnectSlot(d, sl)) {
DBG_ERROR(0, "Card inserted, but I can't connect to it");
}
newStatus=LCD_Slot_GetStatus(sl);
}
isInserted=(newStatus & LCD_SLOT_STATUS_CARD_CONNECTED);
if ((newStatus^oldStatus) &
(LCD_SLOT_STATUS_CARD_CONNECTED)){
DBG_NOTICE(LCD_Reader_GetLogger(r),
"Status changed on slot %d (%08x->%08x) (cardnum %d)",
LCD_Slot_GetSlotNum(sl),
oldStatus, newStatus,
LCD_Slot_GetCardNum(sl));
if (isInserted) {
DBG_INFO(LCD_Reader_GetLogger(r), "Card is now connected");
cardNum=++LCD_Driver__LastCardNum;
LCD_Slot_SetCardNum(sl, cardNum);
}
else {
DBG_INFO(LCD_Reader_GetLogger(r), "Card is not connected");
cardNum=LCD_Slot_GetCardNum(sl);
}
DBG_INFO(LCD_Reader_GetLogger(r), "Card number is %d", cardNum);
if (LCD_Driver_SendStatusChangeNotification(d,
sl)) {
DBG_ERROR(0, "Error sending status change notification");
}
else {
DBG_INFO(0, "Server informed");
}
LCD_Slot_SetLastStatus(sl, newStatus);
}
else {
DBG_DEBUG(LCD_Reader_GetLogger(r), "Status on slot %d unchanged",
LCD_Slot_GetSlotNum(sl));
}
}
sl=LCD_Slot_List_Next(sl);
} /* while slots */
} /* if getting reader status worked */
} /* if reader is up */
r=rnext;
} /* while reader */

return 0;
}



int LCD_Driver_HandleStartReader(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
GWEN_DB_NODE *dbReq){
GWEN_TYPE_UINT32 readerId;
GWEN_TYPE_UINT32 driversReaderId;
const char *name;
int port;
int slots;
GWEN_TYPE_UINT32 flags;
LCD_READER *r;
char numbuf[16];
GWEN_TYPE_UINT32 retval;
GWEN_DB_NODE *dbRsp;

assert(d);
assert(dbReq);
DBG_NOTICE(0, "Command: Start reader");

if (1!=sscanf(GWEN_DB_GetCharValue(dbReq, "body/readerId", 0, "0"),
"%x",
&readerId)) {
DBG_ERROR(0, "Bad readerId");
/* TODO: send error result */
return -1;
}

if (1!=sscanf(GWEN_DB_GetCharValue(dbReq, "body/driversReaderId", 0, "0"),
"%x",
&driversReaderId)) {
DBG_ERROR(0, "Bad driversReaderId");
/* TODO: send error result */
return -1;
}

name=GWEN_DB_GetCharValue(dbReq, "body/name", 0, "noname");
port=GWEN_DB_GetIntValue(dbReq, "body/port", 0, 0);
flags=GWEN_DB_GetIntValue(dbReq, "body/flags", 0, 0);
slots=GWEN_DB_GetIntValue(dbReq, "body/slots", 0, 0);
if (!slots || slots>16) {
DBG_ERROR(0, "Bad number of slots (%d)", slots);
/* TODO: send error result */
return -1;
}

/* prepare response */
dbRsp=GWEN_DB_Group_new("StartReaderResponse");
snprintf(numbuf, sizeof(numbuf)-1, "%08x", readerId);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerId", numbuf);

/* check whether we have a reader of that id */
r=LCD_Driver_FindReaderById(d, readerId);
if (r) {
DBG_WARN(0, "A reader with id \"%08x\" already exists", readerId);

DBG_NOTICE(LCD_Reader_GetLogger(r), "Restarting reader");
retval=LCD_Driver_DisconnectReader(d, r);
if (retval==0)
retval=LCD_Driver_ConnectReader(d, r);

if (retval) {
DBG_ERROR(0, "Could not restart reader");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text",
LCD_Driver_GetErrorText(d, retval));
}
else {
if (LCD_Reader_GetReaderFlags(r) & LC_READER_FLAGS_NOINFO) {
DBG_WARN(0, "ReaderInfo disabled");
}
else {
GWEN_BUFFER *ibuf;
GWEN_TYPE_UINT32 rv;

ibuf=GWEN_Buffer_new(0, 256, 0, 1);
rv=LCD_Driver_ReaderInfo(d, r, ibuf);
if (rv) {
DBG_WARN(0, "ReaderInfo not available (%s)",
LCD_Driver_GetErrorText(d, rv));
}
else {
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"info",
GWEN_Buffer_GetStart(ibuf));
}
GWEN_Buffer_free(ibuf);
}

GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "OK");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", "Reader up and waiting");
}

if (LCD_Driver_SendResponse(d, rid, dbRsp)) {
DBG_ERROR(0, "Could not send response");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
} /* if reader found */
else {
/* search by driversReaderId */
if (driversReaderId) {
r=LCD_Driver_FindReaderByDriversId(d, driversReaderId);
if (r) {
if (LCD_Reader_GetReaderId(r)==0) {
/* The reader exists but has no reader id. So this is the first time
* the reader has been accessed. Assign the reader id from the
* server so that the next calls will find it. */
LCD_Reader_SetReaderId(r, readerId);
}
else {
DBG_ERROR(0, "Uups, reader already has an id ?");
/* send error result */
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text",
"Internal error (reader already has an id)");

LCD_Driver_SendResponse(d, rid, dbRsp);
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
}
else {
DBG_ERROR(0, "Reader not found");
}
}
else {
DBG_ERROR(0, "No DriversReaderId");
}

if (!r) {
/* check whether we have a reader at that port */
r=LCD_Driver_FindReaderByPort(d, port);
if (r) {
DBG_ERROR(0, "A reader with port \"%08x\" already exists", port);
/* send error result */
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text",
"There already is a reader at the given port");
LCD_Driver_SendResponse(d, rid, dbRsp);
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
/* if not found it is ok to create the reader */
r=LCD_Driver_CreateReader(d, readerId, name, port, slots, flags);
assert(r);
LCD_Driver_AddReader(d, r);
}

if (d->readerLogFile) {
GWEN_BUFFER *mbuf;

mbuf=GWEN_Buffer_new(0, 256, 0, 1);
LCD_Driver_ReplaceVar(d->readerLogFile, "reader", name, mbuf);
if (GWEN_Directory_GetPath(GWEN_Buffer_GetStart(mbuf),
GWEN_PATH_FLAGS_VARIABLE)) {
DBG_ERROR(0, "Could not create log file for reader \"%s\"", name);
}
else {
if (GWEN_Logger_Open(name,
name,
GWEN_Buffer_GetStart(mbuf),
GWEN_LoggerTypeFile,
GWEN_LoggerFacilityDaemon)) {
DBG_ERROR(0, "Could not open logger for reader \"%s\"", name);
}
else {
DBG_NOTICE(0, "Reader \"%s\" logs to \"%s\"", name,
GWEN_Buffer_GetStart(mbuf));
LCD_Reader_SetLogger(r, name);
}
GWEN_Buffer_free(mbuf);
}
} /* if reader log file */
else {
if (GWEN_Logger_Open(name,
name,
0,
GWEN_LoggerTypeConsole,
GWEN_LoggerFacilityDaemon)) {
DBG_ERROR(0, "Could not open logger for reader \"%s\"", name);
}
}
GWEN_Logger_SetLevel(name, d->logLevel);

/* init reader */
DBG_NOTICE(LCD_Reader_GetLogger(r),
"Init reader %s", LCD_Reader_GetName(r));
retval=LCD_Driver_ConnectReader(d, r);
if (retval) {
DBG_ERROR(LCD_Reader_GetLogger(r),
"Could not connect reader %s (%d: %s)",
LCD_Reader_GetName(r),
retval,
LCD_Driver_GetErrorText(d, retval));
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text",
LCD_Driver_GetErrorText(d, retval));
}
else {
GWEN_BUFFER *ibuf;
GWEN_TYPE_UINT32 rv;

ibuf=GWEN_Buffer_new(0, 256, 0, 1);
rv=LCD_Driver_ReaderInfo(d, r, ibuf);
if (rv) {
DBG_WARN(0, "ReaderInfo not available (%s)",
LCD_Driver_GetErrorText(d, rv));
}
else {
DBG_NOTICE(LCD_Reader_GetLogger(r), "ReaderInfo: %s",
GWEN_Buffer_GetStart(ibuf));
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"info",
GWEN_Buffer_GetStart(ibuf));
}
GWEN_Buffer_free(ibuf);

DBG_NOTICE(LCD_Reader_GetLogger(r), "Reader up and waiting");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "OK");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", "Reader up and waiting");
}

if (LCD_Driver_SendResponse(d, rid, dbRsp)) {
DBG_ERROR(0, "Could not send response");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
DBG_NOTICE(LCD_Reader_GetLogger(r), "Reader start handled");
}
LCD_Driver_RemoveCommand(d, rid, 0);

return 0;
}


int LCD_Driver_ReplaceVar(const char *path,
const char *var,
const char *value,
GWEN_BUFFER *nbuf) {
unsigned int vlen;

vlen=strlen(var);

while(*path) {
int handled;

handled=0;
if (*path=='@') {
if (strncmp(path+1, var, vlen)==0) {
if (path[vlen+1]=='@') {
/* found variable, replace it */
GWEN_Buffer_AppendString(nbuf, value);
path+=vlen+2;
handled=1;
}
}
}
if (!handled) {
GWEN_Buffer_AppendByte(nbuf, *path);
path++;
}
} /* while */

return 0;
}


int LCD_Driver_HandleStopReader(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
GWEN_DB_NODE *dbReq){
GWEN_TYPE_UINT32 readerId;
GWEN_DB_NODE *dbRsp;
LCD_READER *r;
char numbuf[16];
GWEN_TYPE_UINT32 retval;

assert(d);
assert(dbReq);
if (1!=sscanf(GWEN_DB_GetCharValue(dbReq, "body/readerId", 0, "0"),
"%x",
&readerId)) {
DBG_ERROR(0, "Bad readerId");
/* TODO: send error result */
return -1;
}

/* check whether we have a reader of that id */
r=LCD_Driver_FindReaderById(d, readerId);
if (!r) {
DBG_ERROR(0, "A reader with id \"%08x\" does not exists", readerId);
/* TODO: send error result */
return -1;
}

/* deinit reader */
DBG_NOTICE(LCD_Reader_GetLogger(r), "Disconnecting reader");
dbRsp=GWEN_DB_Group_new("StopReaderResponse");
retval=LCD_Driver_DisconnectReader(d, r);
if (retval!=0) {
DBG_INFO(LCD_Reader_GetLogger(r), "Could not disconnect reader");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text",
LCD_Driver_GetErrorText(d, retval));
}
else {
/* init ok */
DBG_NOTICE(LCD_Reader_GetLogger(r), "Deinit succeeded");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "OK");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", "Reader down as requested");
}

/* create response */
snprintf(numbuf, sizeof(numbuf)-1, "%08x", readerId);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerId", numbuf);
if (LCD_Driver_SendResponse(d, rid, dbRsp)) {
DBG_ERROR(0, "Could not send response");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
LCD_Driver_RemoveCommand(d, rid, 0);

DBG_NOTICE(0, "Reader down");
LCD_Driver_DelReader(d, r);
LCD_Reader_free(r);
return 0;
}



int LCD_Driver_HandleResetCard(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
GWEN_DB_NODE *dbReq){
GWEN_TYPE_UINT32 readerId;
LCD_READER *r;
int slotNum;
int cardNum;
LCD_SLOT *slot;
char retval;

assert(d);
assert(dbReq);
if (1!=sscanf(GWEN_DB_GetCharValue(dbReq, "body/readerId", 0, "0"),
"%x",
&readerId)) {
DBG_ERROR(0, "Bad readerId");
/* TODO: send error result */
return -1;
}

slotNum=GWEN_DB_GetIntValue(dbReq, "body/slotnum", 0, -1);
if (slotNum==-1) {
DBG_ERROR(0, "Bad slot number");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

cardNum=GWEN_DB_GetIntValue(dbReq, "body/cardnum", 0, -1);
if (cardNum==-1) {
DBG_ERROR(0, "Bad card number");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

/* check whether we have a reader of that id */
r=LCD_Driver_FindReaderById(d, readerId);
if (!r) {
DBG_ERROR(0, "A reader with id \"%08x\" does not exists", readerId);
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

/* get the referenced slot */
slot=LCD_Reader_FindSlot(r, slotNum);
if (!slot) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Slot \"%d\" not found", slotNum);
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

if (LCD_Slot_GetStatus(slot) & LCD_SLOT_STATUS_DISABLED) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Slot \"%d\" disabled",
LCD_Slot_GetSlotNum(slot));
LCD_Driver_RemoveCommand(d, rid, 0);
return 0;
}

/* check card number and reader status */
if ((LCD_Slot_GetCardNum(slot)!=cardNum) ||
!(LCD_Slot_GetStatus(slot) & LCD_SLOT_STATUS_CARD_CONNECTED)) {
DBG_ERROR(0, "Card \"%d\" has been removed", cardNum);
LCD_Driver_RemoveCommand(d, rid, 0);
return 0;
}

DBG_NOTICE(LCD_Reader_GetLogger(r), "Resetting card");
retval=LCD_Driver_ResetSlot(d, slot);
if (retval!=0) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Error resetting slot (%d: %s)",
retval,
LCD_Driver_GetErrorText(d, retval));
LCD_Driver_SendReaderErrorNotification(d, r,
LCD_Driver_GetErrorText(d, retval));
DBG_NOTICE(LCD_Reader_GetLogger(r),
"Reader \"%s\" had an error, shutting down",
LCD_Reader_GetName(r));
LCD_Reader_List_Del(r);
LCD_Reader_free(r);
}
else {
/* reset ok */
DBG_INFO(LCD_Reader_GetLogger(r), "Reset succeeded");
}

LCD_Driver_RemoveCommand(d, rid, 0);

return 0;
}



int LCD_Driver_HandleCardCommand(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
GWEN_DB_NODE *dbReq){
GWEN_TYPE_UINT32 readerId;
GWEN_DB_NODE *dbRsp;
LCD_READER *r;
char numbuf[16];
unsigned char rspbuffer[300];
const unsigned char *apdu;
unsigned int apdulen;
int rsplen;
int slotNum;
int cardNum;
LCD_SLOT *slot;
char retval;
const char *target;
int toReader;
int readerError;

assert(d);
assert(dbReq);

if (1!=sscanf(GWEN_DB_GetCharValue(dbReq, "body/readerId", 0, "0"),
"%x",
&readerId)) {
DBG_ERROR(0, "Bad readerId");
/* TODO: send error result */
return -1;
}

apdu=GWEN_DB_GetBinValue(dbReq, "body/data", 0, 0, 0, &apdulen);
if (!apdu || apdulen<4) {
DBG_ERROR(0, "APDU too small");
/* send error result */
LCD_Driver_SendResult(d,
rid,
"CardCommandResponse",
"ERROR", "APDU too small");
LCD_Driver_RemoveCommand(d, rid, 0);
return 0;
}

slotNum=GWEN_DB_GetIntValue(dbReq, "body/slotnum", 0, -1);
if (slotNum==-1) {
DBG_ERROR(0, "Bad slot number");
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Bad slot number");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

cardNum=GWEN_DB_GetIntValue(dbReq, "body/cardnum", 0, -1);
if (cardNum==-1) {
DBG_ERROR(0, "Bad card number");
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Bad card number");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

target=GWEN_DB_GetCharValue(dbReq, "body/target", 0, 0);
if (!target) {
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "No target");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
if (strcasecmp(target, "reader")==0)
toReader=1;
else if (strcasecmp(target, "card")==0)
toReader=0;
else {
DBG_ERROR(0, "Bad target \"%s\"", target);
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Bad target");
LCD_Driver_RemoveCommand(d, rid, 0);
return 0;
}

/* check whether we have a reader of that id */
r=LCD_Driver_FindReaderById(d, readerId);
if (!r) {
DBG_ERROR(0, "A reader with id \"%08x\" does not exists", readerId);
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Reader not found");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

/* get the referenced slot */
slot=LCD_Reader_FindSlot(r, slotNum);
if (!slot) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Slot \"%d\" not found", slotNum);
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Slot not found");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}

if (LCD_Slot_GetStatus(slot) & LCD_SLOT_STATUS_DISABLED) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Slot \"%d\" disabled",
LCD_Slot_GetSlotNum(slot));
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Slot diabled");
LCD_Driver_RemoveCommand(d, rid, 0);
return 0;
}

/* check card number and reader status */
if ((LCD_Slot_GetCardNum(slot)!=cardNum) ||
!(LCD_Slot_GetStatus(slot) & LCD_SLOT_STATUS_CARD_CONNECTED)) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Card \"%d\" has been removed", cardNum);
/* send error result */
LCD_Driver_SendResult(d, rid, "CardCommandResponse",
"ERROR", "Card has been removed");
LCD_Driver_RemoveCommand(d, rid, 0);
return 0;
}

DBG_DEBUG(LCD_Reader_GetLogger(r), "Executing command");
GWEN_Text_LogString((const char*)apdu, apdulen, 0, GWEN_LoggerLevelDebug);
dbRsp=GWEN_DB_Group_new("CardCommandResponse");
rsplen=sizeof(rspbuffer)-1;
retval=LCD_Driver_SendAPDU(d, toReader, r, slot, apdu, apdulen,
rspbuffer, &rsplen);
if (retval!=0) {
DBG_ERROR(LCD_Reader_GetLogger(r), "Error executing APDU (%08x)", retval);
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", LCD_Driver_GetErrorText(d, retval));
readerError=retval;
}
else {
if (rsplen<2) {
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "ERROR");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", "Too short answer");
readerError=-1;
}
else {
/* init ok */
DBG_DEBUG(LCD_Reader_GetLogger(r), "Command succeeded");
GWEN_Text_LogString((const char*)rspbuffer, rsplen, 0, GWEN_LoggerLevelDebug);

GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"code", "OK");
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"text", "Command executed");
assert(rsplen);
GWEN_DB_SetBinValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"data", rspbuffer, rsplen);
readerError=0;
}
}

/* create response */
snprintf(numbuf, sizeof(numbuf)-1, "%08x", readerId);
numbuf[sizeof(numbuf)-1]=0;
GWEN_DB_SetCharValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"readerId", numbuf);
GWEN_DB_SetIntValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"slotnum", slotNum);
GWEN_DB_SetIntValue(dbRsp, GWEN_DB_FLAGS_OVERWRITE_VARS,
"cardnum", cardNum);
if (LCD_Driver_SendResponse(d, rid, dbRsp)) {
DBG_ERROR(0, "Could not send response");
LCD_Driver_RemoveCommand(d, rid, 0);
return -1;
}
LCD_Driver_RemoveCommand(d, rid, 0);
DBG_DEBUG(0, "Response send");

if (readerError) {
DBG_NOTICE(LCD_Reader_GetLogger(r),
"Reader \"%s\" had an error, shutting down",
LCD_Reader_GetName(r));
LCD_Driver_SendReaderErrorNotification(d, r,
LCD_Driver_GetErrorText(d,
readerError));
LCD_Reader_List_Del(r);
LCD_Reader_free(r);
}

return 0;
}



int LCD_Driver_HandleStopDriver(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
GWEN_DB_NODE *dbReq){
LCD_READER_LIST *rl;
LCD_READER *r;

assert(d);
assert(dbReq);

rl=LCD_Driver_GetReaders(d);
assert(rl);
r=LCD_Reader_List_First(rl);
while(r) {
LCD_READER *nr;

nr=LCD_Reader_List_Next(r);
/* deinit reader */
DBG_INFO(LCD_Reader_GetLogger(r),
"Disconnecting reader \"%s\"", LCD_Reader_GetName(r));
if (LCD_Driver_DisconnectReader(d, r)) {
DBG_WARN(LCD_Reader_GetLogger(r), "Could not disconnect reader");
}
else {
DBG_INFO(LCD_Reader_GetLogger(r), "Reader \"%s\" disconnected", LCD_Reader_GetName(r));
}
LCD_Reader_List_Del(r);
LCD_Reader_free(r);
r=nr;
} /* while r */

LCD_Driver_RemoveCommand(d, rid, 0);

DBG_NOTICE(0, "Driver down");
d->stopDriver=1;
return 0;
}



int LCD_Driver_HandleRequest(LCD_DRIVER *d,
GWEN_TYPE_UINT32 rid,
const char *name,
GWEN_DB_NODE *dbReq){
int rv;

DBG_NOTICE(0, "Incoming request \"%s\"", name);

/* if there is a virtual function set go ask the function first */
if (d->handleRequestFn) {
rv=d->handleRequestFn(d, rid, name, dbReq);
if (rv!=1)
return rv;
}

if (strcasecmp(name, "StartReader")==0) {
rv=LCD_Driver_HandleStartReader(d, rid, dbReq);
}
else if (strcasecmp(name, "StopReader")==0) {
rv=LCD_Driver_HandleStopReader(d, rid, dbReq);
}
else if (strcasecmp(name, "CardCommand")==0) {
rv=LCD_Driver_HandleCardCommand(d, rid, dbReq);
}
else if (strcasecmp(name, "ResetCard")==0) {
rv=LCD_Driver_HandleResetCard(d, rid, dbReq);
}
else if (strcasecmp(name, "StopDriver")==0) {
rv=LCD_Driver_HandleStopDriver(d, rid, dbReq);
}
else
rv=1; /* not handled */

return rv;
}




int LCD_Driver_Work(LCD_DRIVER *d) {
time_t lastStatusCheckTime;
time_t t1;

lastStatusCheckTime=(time_t)0;
while(!d->stopDriver) {
GWEN_NETCONNECTION_WORKRESULT res;
GWEN_TYPE_UINT32 rid;
int needHeartbeat;

t1=time(0);
if (difftime(t1, lastStatusCheckTime)>=1) {
/* Do some hardware work */
DBG_VERBOUS(0, "Checking for status changes");
LCD_Driver_CheckStatusChanges(d);
lastStatusCheckTime=t1;
}

needHeartbeat=0;
while(!needHeartbeat) {
int j;

t1=time(0);
if (difftime(t1, lastStatusCheckTime)>=1) {
/* Do some hardware work */
DBG_VERBOUS(0, "Checking for status changes");
LCD_Driver_CheckStatusChanges(d);
lastStatusCheckTime=t1;
}
for(j=0; ; j++) {
int rv;

if (j>LCD_DRIVER_IPC_MAXWORK) {
DBG_ERROR(0, "IPC running wild, aborting driver");
return -1;
}
t1=time(0);
if (difftime(t1, lastStatusCheckTime)>=1) {
/* Do some hardware work */
DBG_VERBOUS(0, "Checking for status changes");
LCD_Driver_CheckStatusChanges(d);
lastStatusCheckTime=t1;
}
/* work as long as possible */
rv=GWEN_IPCManager_Work(d->ipcManager, 10);
if (rv==-1) {
DBG_ERROR(0, "Error while working with IPC");
return -1;
}
else if (rv==1)
break;
}

rid=LCD_Driver_GetNextInRequest(d);
if (rid) {
GWEN_DB_NODE *dbReq;
int rv;
const char *name;

dbReq=LCD_Driver_GetInRequestData(d, rid);
assert(dbReq);

/* we have an incoming message */
name=GWEN_DB_GetCharValue(dbReq, "command/vars/cmd", 0, 0);
if (!name) {
DBG_ERROR(0, "Bad IPC command (no command name), discarding");
LCD_Driver_RemoveCommand(d, rid, 0);
}
rv=LCD_Driver_HandleRequest(d, rid, name, dbReq);
if (rv==1) {
DBG_WARN(0, "Unknown command \"%s\", discarding", name);
if (GWEN_IPCManager_RemoveRequest(d->ipcManager, rid, 0)) {
DBG_ERROR(0, "Could not remove request");
abort();
}
}
else if (rv==-1) {
DBG_ERROR(0, "Error while handling request, going down");
return -1;
}
else {
for(j=0; ; j++) {
int rv;

if (j>LCD_DRIVER_IPC_MAXWORK) {
DBG_ERROR(0, "IPC running wild, aborting driver");
return -1;
}

/* work as long as possible (flush responses) */
rv=GWEN_IPCManager_Work(d->ipcManager, 10);
if (rv==-1) {
DBG_ERROR(0, "Error while working with IPC");
return -1;
}
else if (rv==1)
break;
}
} /* if something done */
} /* if incoming request */
else
needHeartbeat=1;
} /* while !needHeartbeat */

res=GWEN_Net_HeartBeat(750);
if (res==GWEN_NetConnectionWorkResult_Error) {
DBG_ERROR(0, "Network error");
return -1;
}
else if (res==GWEN_NetConnectionWorkResult_NoChange) {
DBG_VERBOUS(0, "No activity");
}
} /* while driver is not to be stopped */
return 0;
}



GWEN_NETTRANSPORTSSL_ASKADDCERT_RESULT
LCD_Driver_AskAddCert(GWEN_NETTRANSPORT *tr, GWEN_DB_NODE *cert,
void *user_data){
LCD_DRIVER *d;

d=(LCD_DRIVER*)user_data;
if (!d) {
DBG_ERROR(0, "No user data in AskAddCert function");
return GWEN_NetTransportSSL_AskAddCertResultNo;
}

if (d->acceptAllCerts)
return GWEN_NetTransportSSL_AskAddCertResultTmp;
return GWEN_NetTransportSSL_AskAddCertResultNo;
}












(2-2/10)