Initial Implementation

This commit is contained in:
Santiago Gimeno
2012-05-02 12:46:42 +02:00
parent 0484b764bf
commit b40f9a2f88
15 changed files with 1270 additions and 0 deletions

11
src/addon.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include <v8.h>
#include "pcsclite.h"
#include "cardreader.h"
void init_all(v8::Handle<v8::Object> target) {
PCSCLite::init(target);
CardReader::init(target);
}
NODE_MODULE(pcsclite, init_all);

470
src/cardreader.cpp Normal file
View File

@@ -0,0 +1,470 @@
#include "cardreader.h"
#include "common.h"
#include <v8.h>
#include <node_buffer.h>
#include <pcsclite.h>
#include <string.h>
using namespace v8;
using namespace node;
Persistent<Function> CardReader::constructor;
void CardReader::init(Handle<Object> target) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("CardReader"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Symbol
name_symbol = NODE_PSYMBOL("name");
connected_symbol = NODE_PSYMBOL("connected");
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "get_status", GetStatus);
NODE_SET_PROTOTYPE_METHOD(tpl, "_connect", Connect);
NODE_SET_PROTOTYPE_METHOD(tpl, "_disconnect", Disconnect);
NODE_SET_PROTOTYPE_METHOD(tpl, "_transmit", Transmit);
NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close);
constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("CardReader"), constructor);
}
CardReader::CardReader(const std::string &reader_name): m_card_context(0),
m_card_handle(0),
m_name(reader_name) {
pthread_mutex_init(&m_mutex, NULL);
}
CardReader::~CardReader() {
fprintf(stderr, "CARDREADER destructor\n");
if (m_card_context) {
SCardReleaseContext(m_card_context);
}
if (m_status_card_context) {
LONG result = SCardCancel(m_status_card_context);
fprintf(stderr, "RESULT: 0x%.8lx", result);
}
pthread_mutex_destroy(&m_mutex);
}
Handle<Value> CardReader::New(const Arguments& args) {
HandleScope scope;
v8::String::Utf8Value reader_name(args[0]->ToString());
CardReader* obj = new CardReader(*reader_name);
obj->Wrap(args.Holder());
obj->handle_->Set(name_symbol, args[0]->ToString());
obj->handle_->Set(connected_symbol, Boolean::New(false));
return scope.Close(args.Holder());
}
Handle<Value> CardReader::GetStatus(const Arguments& args) {
HandleScope scope;
CardReader* obj = ObjectWrap::Unwrap<CardReader>(args.This());
Local<Function> cb = Local<Function>::Cast(args[0]);
AsyncBaton *async_baton = new AsyncBaton();
async_baton->async.data = async_baton;
async_baton->callback = Persistent<Function>::New(cb);
async_baton->reader = obj;
uv_async_init(uv_default_loop(), &async_baton->async, HandleReaderStatusChange);
pthread_create(&obj->m_status_thread, NULL, HandlerFunction, async_baton);
pthread_detach(obj->m_status_thread);
return scope.Close(Undefined());
}
Handle<Value> CardReader::Connect(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("First argument must be a callback function")));
}
Local<Function> cb = Local<Function>::Cast(args[0]);
// This creates our work request, including the libuv struct.
Baton* baton = new Baton();
baton->request.data = baton;
baton->callback = Persistent<Function>::New(cb);
baton->reader = ObjectWrap::Unwrap<CardReader>(args.This());
// Schedule our work request with libuv. Here you can specify the functions
// that should be executed in the threadpool and back in the main thread
// after the threadpool function completed.
int status = uv_queue_work(uv_default_loop(), &baton->request, DoConnect, AfterConnect);
assert(status == 0);
return scope.Close(Undefined());
}
Handle<Value> CardReader::Disconnect(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("First argument must be a callback function")));
}
Local<Function> cb = Local<Function>::Cast(args[0]);
// This creates our work request, including the libuv struct.
Baton* baton = new Baton();
baton->request.data = baton;
baton->callback = Persistent<Function>::New(cb);
baton->reader = ObjectWrap::Unwrap<CardReader>(args.This());
// Schedule our work request with libuv. Here you can specify the functions
// that should be executed in the threadpool and back in the main thread
// after the threadpool function completed.
int status = uv_queue_work(uv_default_loop(), &baton->request, DoDisconnect, AfterDisconnect);
assert(status == 0);
return scope.Close(Undefined());
}
Handle<Value> CardReader::Transmit(const Arguments& args) {
HandleScope scope;
// The first argument is the buffer to be transmitted.
if (!Buffer::HasInstance(args[0])) {
return ThrowException(Exception::TypeError(
String::New("First argument must be a Buffer")));
}
// The second argument is the length of the data to be received
if (!args[1]->IsUint32()) {
return ThrowException(Exception::TypeError(
String::New("Second argument must be an integer")));
}
// The third argument is the protocol to be used
if (!args[2]->IsUint32()) {
return ThrowException(Exception::TypeError(
String::New("Third argument must be an integer")));
}
// The fourth argument is the callback function
if (!args[3]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("Fourth argument must be a callback function")));
}
Local<Object> buffer_data = args[0]->ToObject();
uint32_t out_len = args[1]->Uint32Value();
uint32_t protocol = args[2]->Uint32Value();
Local<Function> cb = Local<Function>::Cast(args[3]);
// This creates our work request, including the libuv struct.
Baton* baton = new Baton();
baton->request.data = baton;
baton->callback = Persistent<Function>::New(cb);
baton->reader = ObjectWrap::Unwrap<CardReader>(args.This());
TransmitInput *ti = new TransmitInput();
ti->card_protocol = protocol;
ti->in_data = new unsigned char[Buffer::Length(buffer_data)];
ti->in_len = Buffer::Length(buffer_data);
memcpy(ti->in_data, Buffer::Data(buffer_data), ti->in_len);
ti->out_len = out_len;
baton->input = ti;
// Schedule our work request with libuv. Here you can specify the functions
// that should be executed in the threadpool and back in the main thread
// after the threadpool function completed.
int status = uv_queue_work(uv_default_loop(), &baton->request, DoTransmit, AfterTransmit);
assert(status == 0);
return scope.Close(Undefined());
}
Handle<Value> CardReader::Close(const Arguments& args) {
HandleScope scope;
CardReader* obj = ObjectWrap::Unwrap<CardReader>(args.This());
LONG result = SCardCancel(obj->m_status_card_context);
obj->m_status_card_context = 0;
return scope.Close(Integer::New(result));
}
void CardReader::HandleReaderStatusChange(uv_async_t *handle, int status) {
AsyncBaton* async_baton = static_cast<AsyncBaton*>(handle->data);
AsyncResult* ar = async_baton->async_result;
if (ar->do_exit) {
uv_close(reinterpret_cast<uv_handle_t*>(&async_baton->async), CloseCallback); // necessary otherwise UV will block
/* Emit end event */
Handle<Value> argv[1] = {
String::New("end"), // event name
};
MakeCallback(async_baton->reader->handle_, "emit", 1, argv);
return;
}
if (ar->result == SCARD_S_SUCCESS) {
const unsigned argc = 2;
Handle<Value> argv[argc] = {
Undefined(), // argument
Integer::New(ar->status)
};
PerformCallback(async_baton->reader->handle_, async_baton->callback, argc, argv);
} else {
Local<Value> err = Exception::Error(String::New(pcsc_stringify_error(ar->result)));
// Prepare the parameters for the callback function.
const unsigned argc = 1;
Handle<Value> argv[argc] = { err };
PerformCallback(async_baton->reader->handle_, async_baton->callback, argc, argv);
}
}
void* CardReader::HandlerFunction(void* arg) {
AsyncBaton* async_baton = static_cast<AsyncBaton*>(arg);
CardReader* reader = async_baton->reader;
async_baton->async_result = new AsyncResult();
async_baton->async_result->do_exit = false;
/* Lock mutex */
pthread_mutex_lock(&reader->m_mutex);
LONG result = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &reader->m_status_card_context);
/* Unlock the mutex */
pthread_mutex_unlock(&reader->m_mutex);
SCARD_READERSTATE card_reader_state;
card_reader_state.szReader = reader->m_name.c_str();
card_reader_state.dwCurrentState = SCARD_STATE_UNAWARE;
while(result == SCARD_S_SUCCESS &&
!((card_reader_state.dwCurrentState & SCARD_STATE_UNKNOWN) ||
(card_reader_state.dwCurrentState & SCARD_STATE_UNAVAILABLE))) {
result = SCardGetStatusChange(reader->m_status_card_context, INFINITE, &card_reader_state, 1);
async_baton->async_result->result = result;
async_baton->async_result->status = card_reader_state.dwEventState;
uv_async_send(&async_baton->async);
card_reader_state.dwCurrentState = card_reader_state.dwEventState;
}
async_baton->async_result->do_exit = true;
uv_async_send(&async_baton->async);
return NULL;
}
void CardReader::DoConnect(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data);
unsigned long card_protocol;
LONG result = SCARD_S_SUCCESS;
CardReader* obj = baton->reader;
/* Lock mutex */
pthread_mutex_lock(&obj->m_mutex);
/* Is context established */
if (!obj->m_card_context) {
result = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &obj->m_card_context);
}
/* Connect */
if (result == SCARD_S_SUCCESS) {
result = SCardConnect(obj->m_card_context, obj->m_name.c_str(),
SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
&obj->m_card_handle, &card_protocol);
}
/* Unlock the mutex */
pthread_mutex_unlock(&obj->m_mutex);
ConnectResult *cr = new ConnectResult();
cr->result = result;
if (!result) {
cr->card_protocol = card_protocol;
}
baton->result = cr;
}
void CardReader::AfterConnect(uv_work_t* req) {
HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);
ConnectResult *cr = static_cast<ConnectResult*>(baton->result);
if (cr->result) {
Local<Value> err = Exception::Error(String::New(pcsc_stringify_error(cr->result)));
// Prepare the parameters for the callback function.
const unsigned argc = 1;
Handle<Value> argv[argc] = { err };
PerformCallback(baton->reader->handle_, baton->callback, argc, argv);
} else {
baton->reader->handle_->Set(connected_symbol, Boolean::New(true));
const unsigned argc = 2;
Handle<Value> argv[argc] = {
Local<Value>::New(Null()),
Integer::New(cr->card_protocol)
};
PerformCallback(baton->reader->handle_, baton->callback, argc, argv);
}
// The callback is a permanent handle, so we have to dispose of it manually.
baton->callback.Dispose();
delete cr;
delete baton;
}
void CardReader::DoDisconnect(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data);
LONG result = SCARD_S_SUCCESS;
CardReader* obj = baton->reader;
/* Lock mutex */
pthread_mutex_lock(&obj->m_mutex);
/* Connect */
if (obj->m_card_handle) {
result = SCardDisconnect(obj->m_card_handle, SCARD_UNPOWER_CARD);
if (result == SCARD_S_SUCCESS) {
obj->m_card_handle = 0;
}
}
/* Unlock the mutex */
pthread_mutex_unlock(&obj->m_mutex);
baton->result = reinterpret_cast<void*>(result);
}
void CardReader::AfterDisconnect(uv_work_t* req) {
HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);
LONG result = reinterpret_cast<LONG>(baton->result);
if (result) {
Local<Value> err = Exception::Error(String::New(pcsc_stringify_error(result)));
// Prepare the parameters for the callback function.
const unsigned argc = 1;
Handle<Value> argv[argc] = { err };
PerformCallback(baton->reader->handle_, baton->callback, argc, argv);
} else {
baton->reader->handle_->Set(connected_symbol, Boolean::New(false));
const unsigned argc = 1;
Handle<Value> argv[argc] = {
Local<Value>::New(Null())
};
PerformCallback(baton->reader->handle_, baton->callback, argc, argv);
}
// The callback is a permanent handle, so we have to dispose of it manually.
baton->callback.Dispose();
delete baton;
}
void CardReader::DoTransmit(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data);
TransmitInput *ti = static_cast<TransmitInput*>(baton->input);
CardReader* obj = baton->reader;
SCARD_IO_REQUEST io_request;
TransmitResult *tr = new TransmitResult();
tr->data = new unsigned char[ti->out_len];
tr->len = ti->out_len;
LONG result = SCARD_E_INVALID_HANDLE;
/* Lock mutex */
pthread_mutex_lock(&obj->m_mutex);
/* Connected? */
if (obj->m_card_handle) {
result = SCardTransmit(obj->m_card_handle, SCARD_PCI_T0, ti->in_data, ti->in_len,
&io_request, tr->data, &tr->len);
}
/* Unlock the mutex */
pthread_mutex_unlock(&obj->m_mutex);
tr->result = result;
baton->result = tr;
}
void CardReader::AfterTransmit(uv_work_t* req) {
HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);
TransmitInput *ti = static_cast<TransmitInput*>(baton->input);
TransmitResult *tr = static_cast<TransmitResult*>(baton->result);
if (tr->result) {
Local<Value> err = Exception::Error(String::New(pcsc_stringify_error(tr->result)));
// Prepare the parameters for the callback function.
const unsigned argc = 1;
Handle<Value> argv[argc] = { err };
PerformCallback(baton->reader->handle_, baton->callback, argc, argv);
} else {
const unsigned argc = 2;
// get Buffer from global scope.
Local<Object> global = v8::Context::GetCurrent()->Global();
Local<Value> bv = global->Get(String::NewSymbol("Buffer"));
assert(bv->IsFunction());
Local<Function> b = Local<Function>::Cast(bv);
Handle<Value> argv1[3] = { Buffer::New(reinterpret_cast<char*>(tr->data), tr->len)->handle_, Integer::New(tr->len) , Integer::New(0) };
Handle<Object> instance = b->NewInstance(3, argv1);
Handle<Value> argv[argc] = {
Local<Value>::New(Null()),
instance
};
PerformCallback(baton->reader->handle_, baton->callback, argc, argv);
}
// The callback is a permanent handle, so we have to dispose of it manually.
baton->callback.Dispose();
delete [] ti->in_data;
delete ti;
delete [] tr->data;
delete tr;
delete baton;
}
void CardReader::CloseCallback(uv_handle_t *handle) {
/* cleanup process */
AsyncBaton* async_baton = static_cast<AsyncBaton*>(handle->data);
AsyncResult* ar = async_baton->async_result;
delete ar;
async_baton->callback.Dispose();
SCardReleaseContext(async_baton->reader->m_status_card_context);
delete async_baton;
}

93
src/cardreader.h Normal file
View File

@@ -0,0 +1,93 @@
#ifndef CARDREADER_H
#define CARDREADER_H
#include <node.h>
#include <winscard.h>
#include <string>
#include <pthread.h>
static v8::Persistent<v8::String> name_symbol;
static v8::Persistent<v8::String> connected_symbol;
class CardReader: public node::ObjectWrap {
// We use a struct to store information about the asynchronous "work request".
struct Baton {
uv_work_t request;
v8::Persistent<v8::Function> callback;
CardReader *reader;
void *input;
void *result;
};
struct ConnectResult {
LONG result;
unsigned long card_protocol;
};
struct TransmitInput {
uint32_t card_protocol;
unsigned char *in_data;
unsigned long in_len;
unsigned long out_len;
};
struct TransmitResult {
LONG result;
unsigned char *data;
unsigned long len;
};
struct AsyncResult {
LONG result;
unsigned long status;
bool do_exit;
};
struct AsyncBaton {
uv_async_t async;
v8::Persistent<v8::Function> callback;
CardReader *reader;
AsyncResult *async_result;
};
public:
static void init(v8::Handle<v8::Object> target);
private:
CardReader(const std::string &reader_name);
~CardReader();
static v8::Persistent<v8::Function> constructor;
static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> GetStatus(const v8::Arguments& args);
static v8::Handle<v8::Value> Connect(const v8::Arguments& args);
static v8::Handle<v8::Value> Disconnect(const v8::Arguments& args);
static v8::Handle<v8::Value> Transmit(const v8::Arguments& args);
static v8::Handle<v8::Value> Close(const v8::Arguments& args);
static void HandleReaderStatusChange(uv_async_t *handle, int status);
static void* HandlerFunction(void* arg);
static void DoConnect(uv_work_t* req);
static void AfterConnect(uv_work_t* req);
static void DoDisconnect(uv_work_t* req);
static void AfterDisconnect(uv_work_t* req);
static void DoTransmit(uv_work_t* req);
static void AfterTransmit(uv_work_t* req);
static void CloseCallback(uv_handle_t *handle);
private:
SCARDCONTEXT m_card_context;
SCARDCONTEXT m_status_card_context;
SCARDHANDLE m_card_handle;
std::string m_name;
pthread_t m_status_thread;
pthread_mutex_t m_mutex;
};
#endif /* CARDREADER_H */

21
src/common.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef COMMON_H
#define COMMON_H
#include <node.h>
static void PerformCallback(v8::Handle<v8::Object> object,
v8::Persistent<v8::Function> &callback,
const unsigned argc, v8::Handle<v8::Value> *argv) {
// Wrap the callback function call in a TryCatch so that we can call
// node's FatalException afterwards. This makes it possible to catch
// the exception from JavaScript land using the
// process.on('uncaughtException') event.
v8::TryCatch try_catch;
callback->Call(object, argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
#endif /* COMMON_H */

197
src/pcsclite.cpp Normal file
View File

@@ -0,0 +1,197 @@
#include "pcsclite.h"
#include "common.h"
#include <v8.h>
#include <pcsclite.h>
#include <node_buffer.h>
#include <string>
#include <string.h>
using namespace v8;
using namespace node;
Persistent<Function> PCSCLite::constructor;
void PCSCLite::init(Handle<Object> target) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("PCSCLite"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "start", Start);
NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close);
constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("PCSCLite"), constructor);
}
PCSCLite::PCSCLite(): m_card_context(0) {
pthread_mutex_init(&m_mutex, NULL);
}
PCSCLite::~PCSCLite() {
fprintf(stderr, "PCSCLite destructor\n");
if (m_card_context) {
SCardReleaseContext(m_card_context);
}
pthread_mutex_destroy(&m_mutex);
pthread_cancel(m_status_thread);
}
Handle<Value> PCSCLite::New(const Arguments& args) {
HandleScope scope;
PCSCLite* obj = new PCSCLite();
obj->Wrap(args.Holder());
return scope.Close(args.Holder());
}
Handle<Value> PCSCLite::Start(const Arguments& args) {
HandleScope scope;
PCSCLite* obj = ObjectWrap::Unwrap<PCSCLite>(args.This());
Local<Function> cb = Local<Function>::Cast(args[0]);
AsyncBaton *async_baton = new AsyncBaton();
async_baton->async.data = async_baton;
async_baton->callback = Persistent<Function>::New(cb);
async_baton->pcsclite = obj;
uv_async_init(uv_default_loop(), &async_baton->async, HandleReaderStatusChange);
pthread_create(&obj->m_status_thread, NULL, HandlerFunction, async_baton);
pthread_detach(obj->m_status_thread);
return scope.Close(Undefined());
}
Handle<Value> PCSCLite::Close(const Arguments& args) {
HandleScope scope;
PCSCLite* obj = ObjectWrap::Unwrap<PCSCLite>(args.This());
LONG result = SCardCancel(obj->m_card_context);
return scope.Close(Integer::New(result));
}
void PCSCLite::HandleReaderStatusChange(uv_async_t *handle, int status) {
AsyncBaton* async_baton = static_cast<AsyncBaton*>(handle->data);
PCSCLite* pcsclite = async_baton->pcsclite;
AsyncResult* ar = async_baton->async_result;
if (ar->do_exit) {
uv_close(reinterpret_cast<uv_handle_t*>(&async_baton->async), CloseCallback); // necessary otherwise UV will block
return;
}
if ((ar->result == SCARD_S_SUCCESS) || (ar->result == (LONG)SCARD_E_NO_READERS_AVAILABLE)) {
const unsigned argc = 2;
Handle<Value> argv[argc] = {
Undefined(), // argument
Buffer::New(ar->readers_name, ar->readers_name_length)->handle_
};
PerformCallback(async_baton->pcsclite->handle_, async_baton->callback, argc, argv);
} else {
Local<Value> err = Exception::Error(String::New(pcsc_stringify_error(ar->result)));
// Prepare the parameters for the callback function.
const unsigned argc = 1;
Handle<Value> argv[argc] = { err };
PerformCallback(async_baton->pcsclite->handle_, async_baton->callback, argc, argv);
}
/* reset AsyncResult */
delete [] ar->readers_name;
ar->readers_name = NULL;
ar->readers_name_length = 0;
ar->result = SCARD_S_SUCCESS;
/* Unlock the mutex */
pthread_mutex_unlock(&pcsclite->m_mutex);
}
void* PCSCLite::HandlerFunction(void* arg) {
LONG result = SCARD_S_SUCCESS;
AsyncBaton* async_baton = static_cast<AsyncBaton*>(arg);
PCSCLite* pcsclite = async_baton->pcsclite;
async_baton->async_result = new AsyncResult();
SCARD_READERSTATE card_reader_state;
card_reader_state.szReader = "\\\\?PnP?\\Notification";
card_reader_state.dwCurrentState = SCARD_STATE_UNAWARE;
while(result == SCARD_S_SUCCESS) {
/* Lock mutex. It'll be unlocked after the callback has been sent */
pthread_mutex_lock(&pcsclite->m_mutex);
/* Get card readers */
result = pcsclite->get_card_readers(pcsclite, async_baton->async_result);
/* Store the result in the baton */
async_baton->async_result->result = result;
/* Notify the nodejs thread */
uv_async_send(&async_baton->async);
/* Start checking for status change */
result = SCardGetStatusChange(pcsclite->m_card_context, INFINITE, &card_reader_state, 1);
}
async_baton->async_result->do_exit = true;
uv_async_send(&async_baton->async);
return NULL;
}
void PCSCLite::CloseCallback(uv_handle_t *handle) {
/* cleanup process */
AsyncBaton* async_baton = static_cast<AsyncBaton*>(handle->data);
AsyncResult* ar = async_baton->async_result;
delete [] ar->readers_name;
delete ar;
async_baton->callback.Dispose();
delete async_baton;
}
LONG PCSCLite::get_card_readers(PCSCLite* pcsclite, AsyncResult* async_result) {
LONG result = SCARD_S_SUCCESS;
/* Reset the readers_name in the baton */
async_result->readers_name = NULL;
async_result->readers_name_length = 0;
if (!pcsclite->m_card_context) {
result = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &pcsclite->m_card_context);
}
if (result != SCARD_S_SUCCESS) {
return result;
}
/* Find out ReaderNameLength */
unsigned long readers_name_length;
result = SCardListReaders(pcsclite->m_card_context, NULL, NULL, &readers_name_length);
if (result != SCARD_S_SUCCESS) {
return result;
}
/* Allocate Memory for ReaderName and retrieve all readers in the terminal */
char* readers_name = new char[readers_name_length];
result = SCardListReaders(pcsclite->m_card_context, NULL, readers_name, &readers_name_length);
if (result != SCARD_S_SUCCESS) {
delete [] readers_name;
readers_name = NULL;
readers_name_length = 0;
}
/* Store the readers_name in the baton */
async_result->readers_name = readers_name;
async_result->readers_name_length = readers_name_length;
return result;
}

51
src/pcsclite.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef PCSCLITE_H
#define PCSCLITE_H
#include <node.h>
#include <winscard.h>
class PCSCLite: public node::ObjectWrap {
struct AsyncResult {
LONG result;
char *readers_name;
unsigned long readers_name_length;
bool do_exit;
};
struct AsyncBaton {
uv_async_t async;
v8::Persistent<v8::Function> callback;
PCSCLite *pcsclite;
AsyncResult *async_result;
};
public:
static void init(v8::Handle<v8::Object> target);
private:
PCSCLite();
~PCSCLite();
static v8::Persistent<v8::Function> constructor;
static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
static v8::Handle<v8::Value> Close(const v8::Arguments& args);
static void HandleReaderStatusChange(uv_async_t *handle, int status);
static void* HandlerFunction(void* arg);
static void CloseCallback(uv_handle_t *handle);
LONG get_card_readers(PCSCLite* pcsclite, AsyncResult* async_result);
private:
SCARDCONTEXT m_card_context;
pthread_t m_status_thread;
pthread_mutex_t m_mutex;
};
#endif /* PCSCLITE_H */