[Spice-devel] [PATCH 09/13] smartcard: client side (not enabled yet)

Alon Levy alevy at redhat.com
Mon Dec 6 08:16:02 PST 2010


---
 client/application.cpp       |   45 +++++
 client/application.h         |   12 ++
 client/smartcard_channel.cpp |  449 ++++++++++++++++++++++++++++++++++++++++++
 client/smartcard_channel.h   |  133 +++++++++++++
 4 files changed, 639 insertions(+), 0 deletions(-)
 create mode 100644 client/smartcard_channel.cpp
 create mode 100644 client/smartcard_channel.h

diff --git a/client/application.cpp b/client/application.cpp
index c380373..ae19785 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -47,6 +47,10 @@
 #include <stdio.h>
 #include <time.h>
 
+#ifdef USE_SMARTCARD
+#include <smartcard_channel.h>
+#endif
+
 #define STICKY_KEY_PIXMAP ALT_IMAGE_RES_ID
 #define STICKY_KEY_TIMEOUT 750
 
@@ -364,6 +368,9 @@ Application::Application()
 #endif // USE_GUI
     , _during_host_switch(false)
     , _state (DISCONNECTED)
+#ifdef USE_SMARTCARD
+    , _smartcard_options(new SmartcardOptions())
+#endif
 {
     DBG(0, "");
     Platform::set_process_loop(*this);
@@ -447,6 +454,9 @@ Application::~Application()
 
     _main_screen->unref();
     destroy_monitors();
+#ifdef USE_SMARTCARD
+    delete _smartcard_options;
+#endif
 }
 
 void Application::init_menu()
@@ -2148,6 +2158,12 @@ void Application::register_channels()
         _client.register_channel_factory(TunnelChannel::Factory());
     }
 #endif
+#ifdef USE_SMARTCARD
+    if (_enabled_channels[SPICE_CHANNEL_SMARTCARD] && _smartcard_options->enable) {
+        smartcard_init(_smartcard_options); // throws Exception
+        _client.register_channel_factory(SmartCardChannel::Factory());
+    }
+#endif
 }
 
 bool Application::process_cmd_line(int argc, char** argv)
@@ -2177,6 +2193,12 @@ bool Application::process_cmd_line(int argc, char** argv)
         SPICE_OPT_DISPLAY_COLOR_DEPTH,
         SPICE_OPT_DISABLE_DISPLAY_EFFECTS,
         SPICE_OPT_CONTROLLER,
+#ifdef USE_SMARTCARD
+        SPICE_OPT_SMARTCARD,
+        SPICE_OPT_NOSMARTCARD,
+        SPICE_OPT_SMARTCARD_CERT,
+        SPICE_OPT_SMARTCARD_DB,
+#endif
     };
 
 #ifdef USE_GUI
@@ -2235,6 +2257,15 @@ bool Application::process_cmd_line(int argc, char** argv)
 
     parser.add(SPICE_OPT_CONTROLLER, "controller", "enable external controller");
 
+#ifdef USE_SMARTCARD
+    parser.add(SPICE_OPT_SMARTCARD, "smartcard", "enable smartcard channel");
+    parser.add(SPICE_OPT_NOSMARTCARD, "nosmartcard", "disable smartcard channel");
+    parser.add(SPICE_OPT_SMARTCARD_CERT, "smartcard-cert", "Use virtual reader+card with given cert(s)",
+        "smartcard-cert", true);
+    parser.set_multi(SPICE_OPT_SMARTCARD_CERT, ',');
+    parser.add(SPICE_OPT_SMARTCARD_DB, "smartcard-db", "Use given db for smartcard certs");
+#endif
+
     for (int i = SPICE_CHANNEL_MAIN; i < SPICE_END_CHANNEL; i++) {
         _peer_con_opt[i] = RedPeer::ConnectionOptions::CON_OP_INVALID;
     }
@@ -2340,6 +2371,20 @@ bool Application::process_cmd_line(int argc, char** argv)
             }
             _enable_controller = true;
             return true;
+#ifdef USE_SMARTCARD
+        case SPICE_OPT_SMARTCARD:
+            _smartcard_options->enable= true;
+            break;
+        case SPICE_OPT_NOSMARTCARD:
+            _smartcard_options->enable= false; // default
+            break;
+        case SPICE_OPT_SMARTCARD_CERT:
+            do {
+                _smartcard_options->certs.insert(
+                    _smartcard_options->certs.end(), std::string(val));
+            } while ((val=parser.next_argument()));
+            break;
+#endif
         case CmdLineParser::OPTION_HELP:
             parser.show_help();
             return false;
diff --git a/client/application.h b/client/application.h
index 5a5a488..f9bbd53 100644
--- a/client/application.h
+++ b/client/application.h
@@ -29,6 +29,9 @@
 #include "foreign_menu.h"
 #include "controller.h"
 
+#ifdef USE_SMARTCARD
+struct SmartcardOptions;
+#endif
 class RedScreen;
 class Application;
 class ScreenLayer;
@@ -268,6 +271,12 @@ public:
     void message_box_test();
 #endif
 
+#ifdef USE_SMARTCARD
+    const SmartcardOptions* get_smartcard_options() const {
+        return _smartcard_options;
+    }
+#endif
+
     static int main(int argc, char** argv, const char* version_str);
 
 private:
@@ -386,6 +395,9 @@ private:
     bool _during_host_switch;
 
     State _state;
+#ifdef USE_SMARTCARD
+    SmartcardOptions* _smartcard_options;
+#endif
 };
 
 #endif
diff --git a/client/smartcard_channel.cpp b/client/smartcard_channel.cpp
new file mode 100644
index 0000000..d585c9a
--- /dev/null
+++ b/client/smartcard_channel.cpp
@@ -0,0 +1,449 @@
+#include <spice/enums.h>
+
+#include "client/red_client.h"
+#include "mutex.h"
+
+extern "C" {
+#include "vscard_common.h"
+#include "vreader.h"
+#include "vcard_emul.h"
+#include "vevent.h"
+}
+
+#include "smartcard_channel.h"
+
+#define APDUBufSize 270
+
+#define MAX_ATR_LEN 40
+
+//#define DEBUG_SMARTCARD
+
+#ifdef DEBUG_SMARTCARD
+void PrintByteArray(uint8_t *arrBytes, unsigned int nSize)
+{
+    int i;
+
+    for (i=0; i < nSize; i++) {
+        DBG(0, "%X ", arrBytes[i]);
+    }
+    DBG(0, "\n");
+}
+#define DEBUG_PRINT_BYTE_ARRAY(arrBytes, nSize) PrintByteArray(arrBytes, nSize)
+#else
+#define DEBUG_PRINT_BYTE_ARRAY(arrBytes, nSize)
+#endif
+
+SmartCardChannel* g_smartcard_channel = NULL; // used for insert/remove of virtual card. Can be
+                                // changed if we let Application store the SmartCard instance.
+
+class SmartCardHandler: public MessageHandlerImp<SmartCardChannel, SPICE_CHANNEL_SMARTCARD> {
+public:
+    SmartCardHandler(SmartCardChannel& channel)
+        : MessageHandlerImp<SmartCardChannel, SPICE_CHANNEL_SMARTCARD>(channel) {}
+};
+
+
+SmartCardChannel::SmartCardChannel(RedClient& client, uint32_t id)
+    : RedChannel(client, SPICE_CHANNEL_SMARTCARD, id, new SmartCardHandler(*this))
+{
+    SmartCardHandler* handler = static_cast<SmartCardHandler*>(get_message_handler());
+
+    g_smartcard_channel = this;
+    handler->set_handler(SPICE_MSG_SMARTCARD_DATA,
+                        &SmartCardChannel::handle_smartcard_data);
+}
+
+ReaderData* SmartCardChannel::reader_data_from_vreader(VReader* vreader)
+{
+    if (vreader == NULL) {
+        assert(_readers_by_vreader.size() > 0);
+        return _readers_by_vreader.begin()->second;
+    }
+    if (_readers_by_vreader.count(vreader) > 0) {
+        return _readers_by_vreader.find(vreader)->second;
+    }
+    assert(_unallocated_readers_by_vreader.count(vreader) > 0);
+    return _unallocated_readers_by_vreader.find(vreader)->second;
+}
+
+ReaderData* SmartCardChannel::reader_data_from_reader_id(reader_id_t reader_id)
+{
+    if (_readers_by_id.count(reader_id) > 0) {
+        return _readers_by_id.find(reader_id)->second;
+    }
+    return NULL;
+}
+
+/** On VEVENT_READER_INSERT we call this, send a VSC_ReaderAdd, and wait for a VSC_ReaderAddResponse
+ */
+void SmartCardChannel::add_unallocated_reader(VReader* vreader, const char* name)
+{
+    ReaderData* data = new ReaderData();
+
+    data->vreader = vreader;
+    data->reader_id = VSCARD_UNDEFINED_READER_ID;
+    data->name = spice_strdup(name);
+    _unallocated_readers_by_vreader.insert(std::pair<VReader*, ReaderData*>(vreader, data));
+}
+
+/** called upon the VSC_ReaderAddResponse
+ */
+ReaderData* SmartCardChannel::add_reader(reader_id_t reader_id)
+{
+    ReaderData* data;
+    size_t unallocated = _unallocated_readers_by_vreader.size();
+
+    assert(unallocated > 0);
+    data = _unallocated_readers_by_vreader.begin()->second;
+    data->reader_id = reader_id;
+    _readers_by_vreader.insert(
+        std::pair<VReader*, ReaderData*>(data->vreader, data));
+    assert(_readers_by_vreader.count(data->vreader) == 1);
+    _readers_by_id.insert(std::pair<reader_id_t, ReaderData*>(reader_id, data));
+    assert(_readers_by_id.count(reader_id) == 1);
+    _unallocated_readers_by_vreader.erase(_unallocated_readers_by_vreader.begin());
+    assert(_unallocated_readers_by_vreader.size() == unallocated - 1);
+    assert(_unallocated_readers_by_vreader.count(data->vreader) == 0);
+    return data;
+}
+
+void* SmartCardChannel::cac_card_events_thread_entry(void* data)
+{
+    static_cast<SmartCardChannel*>(data)->cac_card_events_thread_main();
+    return NULL;
+}
+
+VEventEvent::VEventEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+    : _smartcard_channel(smartcard_channel)
+    , _vreader(vevent->reader)
+    , _vevent(vevent)
+{
+}
+
+VEventEvent::~VEventEvent()
+{
+    vevent_delete(_vevent);
+}
+
+void ReaderAddEvent::response(AbstractProcessLoop& events_loop)
+{
+    static int num = 0;
+    char name[20];
+
+    sprintf(name, "test%4d", num++);
+    _smartcard_channel->add_unallocated_reader(_vreader, name);
+    _smartcard_channel->send_reader_added(name);
+}
+
+void ReaderRemoveEvent::response(AbstractProcessLoop& events_loop)
+{
+    ReaderData* data;
+
+    data = _smartcard_channel->reader_data_from_vreader(_vreader);
+    _smartcard_channel->send_reader_removed(data->reader_id);
+    _smartcard_channel->remove_reader(data);
+}
+
+void CardInsertEvent::response(AbstractProcessLoop& events_loop)
+{
+    ReaderData* data = _smartcard_channel->reader_data_from_vreader(
+                                                    _vreader);
+
+    if (data->reader_id == VSCARD_UNDEFINED_READER_ID) {
+        data->card_insert_pending = true;
+    } else {
+        _smartcard_channel->send_atr(_vreader);
+    }
+}
+
+void CardRemoveEvent::response(AbstractProcessLoop& events_loop)
+{
+    ReaderData* data = _smartcard_channel->reader_data_from_vreader(
+                                                    _vreader);
+
+    ASSERT(data->reader_id != VSCARD_UNDEFINED_READER_ID);
+    _smartcard_channel->send_message(data->reader_id, VSC_CardRemove, NULL, 0);
+}
+
+void SmartCardChannel::remove_reader(ReaderData* data)
+{
+    // TODO - untested code (caccard doesn't produce these events yet)
+    if (_readers_by_vreader.count(data->vreader) > 0) {
+        _readers_by_vreader.erase(_readers_by_vreader.find(data->vreader));
+        _readers_by_id.erase(_readers_by_id.find(data->reader_id));
+    } else {
+        _unallocated_readers_by_vreader.erase(
+            _unallocated_readers_by_vreader.find(data->vreader));
+    }
+    free(data->name);
+    delete data;
+}
+
+void SmartCardChannel::cac_card_events_thread_main()
+{
+    VEvent *vevent = NULL;
+    bool cont = true;
+
+    while (cont) {
+        vevent = vevent_wait_next_vevent();
+        if (vevent == NULL) {
+            break;
+        }
+        switch (vevent->type) {
+        case VEVENT_READER_INSERT:
+            LOG_INFO("VEVENT_READER_INSERT");
+            {
+                AutoRef<ReaderAddEvent> event(new ReaderAddEvent(this, vevent));
+                get_client().push_event(*event);
+            }
+            break;
+        case VEVENT_READER_REMOVE:
+            LOG_INFO("VEVENT_READER_REMOVE");
+            {
+                AutoRef<ReaderRemoveEvent> event(new ReaderRemoveEvent(this, vevent));
+                get_client().push_event(*event);
+            }
+            break;
+        case VEVENT_CARD_INSERT:
+            LOG_INFO("VEVENT_CARD_INSERT");
+            {
+                AutoRef<CardInsertEvent> event(new CardInsertEvent(this, vevent));
+                get_client().push_event(*event);
+            }
+            break;
+        case VEVENT_CARD_REMOVE:
+            LOG_INFO("VEVENT_CARD_REMOVE");
+            {
+                AutoRef<CardRemoveEvent> event(new CardRemoveEvent(this, vevent));
+                get_client().push_event(*event);
+            }
+            break;
+        case VEVENT_LAST:
+            cont = false;
+        default:
+           /* anything except VEVENT_LAST and default
+            * gets to VEventEvent which does vevent_delete in VEventEvent~ */
+            vevent_delete(vevent);
+        }
+    }
+}
+
+#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
+#define CERTIFICATES_ARGS_TEMPLATE "db=\"%s\" use_hw=no soft=(,Virtual Card,CAC,,%s,%s,%s)"
+
+SmartcardOptions::SmartcardOptions() :
+dbname(CERTIFICATES_DEFAULT_DB),
+enable(false)
+{
+}
+
+static VCardEmulError init_vcard_local_certs(const char* dbname, const char* cert1,
+    const char* cert2, const char* cert3)
+{
+    char emul_args[200];
+    VCardEmulOptions *options = NULL;
+
+    snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
+        dbname, cert1, cert2, cert3);
+    options = vcard_emul_options(emul_args);
+    if (options == NULL) {
+        LOG_WARN("not using certificates due to initialization error");
+    }
+    return vcard_emul_init(options);
+}
+
+static bool g_vcard_inited = false;
+
+void smartcard_init(const SmartcardOptions* options)
+{
+    if (g_vcard_inited) {
+        return;
+    }
+    if (options->certs.size() == 3) {
+        const char* dbname = options->dbname.c_str();
+        if (init_vcard_local_certs(dbname, options->certs[0].c_str(),
+            options->certs[1].c_str(), options->certs[2].c_str()) != VCARD_EMUL_OK) {
+            throw Exception("smartcard: emulated card initialization failed (check certs/db)");
+        }
+    } else {
+        if (options->certs.size() > 0) {
+            LOG_WARN("Ignoring smartcard certificates - must be exactly three for virtual card emulation");
+        }
+        if (vcard_emul_init(NULL) != VCARD_EMUL_OK) {
+            throw Exception("smartcard: vcard initialization failed (check hardware/drivers)");
+        }
+    }
+    g_vcard_inited = true;
+}
+
+void SmartCardChannel::on_connect()
+{
+    _event_thread = new Thread(SmartCardChannel::cac_card_events_thread_entry, this);
+}
+
+void SmartCardChannel::on_disconnect()
+{
+    VEvent *stop_event;
+
+    if (_event_thread == NULL) {
+        return;
+    }
+    stop_event = vevent_new(VEVENT_LAST, NULL, NULL);
+    vevent_queue_vevent(stop_event);
+    _event_thread->join();
+    delete _event_thread;
+    _event_thread = NULL;
+}
+
+
+void SmartCardChannel::send_reader_removed(reader_id_t reader_id)
+{
+    send_message(reader_id, VSC_ReaderRemove, NULL, 0);
+}
+
+void SmartCardChannel::send_reader_added(const char* reader_name)
+{
+    send_message(VSCARD_UNDEFINED_READER_ID,
+        VSC_ReaderAdd, (uint8_t*)reader_name, strlen(reader_name));
+}
+
+void SmartCardChannel::send_atr(VReader* vreader)
+{
+    unsigned char atr[ MAX_ATR_LEN];
+    int atr_len = MAX_ATR_LEN;
+    reader_id_t reader_id = reader_data_from_vreader(vreader)->reader_id;
+
+    assert(reader_id != VSCARD_UNDEFINED_READER_ID);
+    vreader_power_on(vreader, atr, &atr_len);
+    DBG(0, "ATR: ");
+    DEBUG_PRINT_BYTE_ARRAY(atr, atr_len);
+    send_message(reader_id, VSC_ATR, (uint8_t*)atr, atr_len);
+}
+
+void SmartCardChannel::send_message(uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
+{
+    VSCMsgHeader mhHeader;
+    Message* msg = new Message(SPICE_MSGC_SMARTCARD_DATA);
+    SpiceMarshaller* m = msg->marshaller();
+
+    mhHeader.type = type;
+    mhHeader.length = len;
+    mhHeader.reader_id = reader_id;
+    spice_marshaller_add(m, (uint8_t*)&mhHeader, sizeof(mhHeader));
+    spice_marshaller_add(m, data, len);
+    post_message(msg);
+}
+
+VSCMessageEvent::VSCMessageEvent(SmartCardChannel* smartcard_channel,
+    VSCMsgHeader* vheader)
+    : _smartcard_channel(smartcard_channel)
+    , _vheader(NULL)
+{
+    _vheader = (VSCMsgHeader*)spice_memdup(vheader,
+                        sizeof(VSCMsgHeader) + vheader->length);
+    ASSERT(_vheader);
+}
+
+VSCMessageEvent::~VSCMessageEvent()
+{
+    free(_vheader);
+}
+
+void VSCMessageEvent::response(AbstractProcessLoop& loop)
+{
+    static int recv_count = 0;
+    int dwSendLength;
+    int dwRecvLength;
+    uint8_t* pbSendBuffer = _vheader->data;
+    uint8_t pbRecvBuffer[APDUBufSize+sizeof(uint32_t)];
+    VReaderStatus reader_status;
+    uint32_t rv;
+    ReaderData* data;
+
+    switch (_vheader->type) {
+        case (VSC_ReaderAddResponse):
+            data = _smartcard_channel->add_reader(_vheader->reader_id);
+            if (data->card_insert_pending) {
+                data->card_insert_pending = false;
+                _smartcard_channel->send_atr(data->vreader);
+            }
+            return;
+            break;
+        case VSC_APDU:
+            break;
+        case VSC_Error:
+            {
+                VSCMsgError *error = (VSCMsgError*)_vheader->data;
+                LOG_WARN("VSC Error: reader %d, code %d",
+                    _vheader->reader_id, error->code);
+            }
+            return;
+        default:
+            LOG_WARN("unhandled VSC %d of length %d, reader %d",
+                _vheader->type, _vheader->length, _vheader->reader_id);
+            return;
+    }
+
+    /* Transmit recieved APDU */
+    dwSendLength = _vheader->length;
+    dwRecvLength = sizeof(pbRecvBuffer);
+
+    DBG(0, " %3d: recv APDU: ", recv_count++);
+    DEBUG_PRINT_BYTE_ARRAY(pbSendBuffer, _vheader->length);
+
+    ReaderData* reader_data = _smartcard_channel->reader_data_from_reader_id(
+                                                        _vheader->reader_id);
+    if (reader_data == NULL) {
+        LOG_WARN("got message for non existant reader");
+        return;
+    }
+
+    VReader* vreader = reader_data->vreader;
+
+    reader_status = vreader_xfr_bytes(vreader,
+        pbSendBuffer, dwSendLength,
+        pbRecvBuffer, &dwRecvLength);
+    if (reader_status == VREADER_OK) {
+        DBG(0, " sent APDU: ");
+        DEBUG_PRINT_BYTE_ARRAY(pbRecvBuffer, dwRecvLength);
+        _smartcard_channel->send_message (
+            _vheader->reader_id,
+            VSC_APDU,
+            pbRecvBuffer,
+            dwRecvLength
+        );
+    } else {
+        rv = reader_status; /* warning: not meaningful */
+        _smartcard_channel->send_message (
+            _vheader->reader_id,
+            VSC_Error,
+            (uint8_t*)&rv,
+            sizeof (uint32_t)
+        );
+    }
+}
+
+void SmartCardChannel::handle_smartcard_data(RedPeer::InMessage* message)
+{
+    VSCMsgHeader* mhHeader = (VSCMsgHeader*)(message->data());
+
+    AutoRef<VSCMessageEvent> event(new VSCMessageEvent(this, mhHeader));
+    get_client().push_event(*event);
+}
+
+class SmartCardFactory: public ChannelFactory {
+public:
+    SmartCardFactory() : ChannelFactory(SPICE_CHANNEL_SMARTCARD) {}
+    virtual RedChannel* construct(RedClient& client, uint32_t id)
+    {
+        return new SmartCardChannel(client, id);
+    }
+};
+
+static SmartCardFactory factory;
+
+ChannelFactory& SmartCardChannel::Factory()
+{
+    return factory;
+}
+
diff --git a/client/smartcard_channel.h b/client/smartcard_channel.h
new file mode 100644
index 0000000..ee0d0d0
--- /dev/null
+++ b/client/smartcard_channel.h
@@ -0,0 +1,133 @@
+#ifndef __SMART_CARD_H__
+#define __SMART_CARD_H__
+
+#include <map>
+
+#include <vreadert.h>
+#include <vscard_common.h>
+#include <eventt.h>
+
+#include "red_channel.h"
+#include "red_peer.h"
+
+class Application;
+
+struct SmartcardOptions {
+    std::vector<std::string> certs;
+    std::string dbname;
+    bool enable;
+    SmartcardOptions();
+};
+
+void smartcard_init(const SmartcardOptions* options);
+
+struct ReaderData {
+    ReaderData() :
+        vreader(NULL),
+        reader_id(VSCARD_UNDEFINED_READER_ID),
+        name(NULL),
+        card_insert_pending(false)
+    {}
+    VReader *vreader;
+    reader_id_t reader_id;
+    char* name;
+    bool card_insert_pending;
+};
+
+void virtual_card_remove();
+void virtual_card_insert();
+
+class SmartCardChannel;
+
+class VEventEvent : public Event {
+public:
+    VEventEvent(SmartCardChannel* smartcard_channel, VEvent* vevent);
+    ~VEventEvent();
+    SmartCardChannel* _smartcard_channel;
+    VReader* _vreader;
+    VEvent* _vevent;
+};
+
+class ReaderAddEvent: public VEventEvent {
+public:
+    ReaderAddEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+        : VEventEvent(smartcard_channel, vevent) {}
+    virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class ReaderRemoveEvent: public VEventEvent {
+public:
+    ReaderRemoveEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+        : VEventEvent(smartcard_channel, vevent) {}
+    virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class CardInsertEvent: public VEventEvent {
+public:
+    CardInsertEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+        : VEventEvent(smartcard_channel, vevent) {}
+    virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class CardRemoveEvent: public VEventEvent {
+public:
+    CardRemoveEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
+        : VEventEvent(smartcard_channel, vevent) {}
+    virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class VSCMessageEvent: public Event {
+public:
+    VSCMessageEvent(SmartCardChannel* smartcard_channel,
+        VSCMsgHeader* vheader);
+    ~VSCMessageEvent();
+    SmartCardChannel* _smartcard_channel;
+    VSCMsgHeader* _vheader;
+    virtual void response(AbstractProcessLoop& events_loop);
+};
+
+class SmartCardChannel : public RedChannel {
+
+public:
+    SmartCardChannel(RedClient& client, uint32_t id);
+    void handle_smartcard_data(RedPeer::InMessage* message);
+
+    static ChannelFactory& Factory();
+protected:
+    virtual void on_connect();
+    virtual void on_disconnect();
+
+private:
+    static void* cac_card_events_thread_entry(void* data);
+    void cac_card_events_thread_main();
+    void send_message(reader_id_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len);
+
+    Thread* _event_thread;
+
+    Application* _app;
+
+    VReaderList *_reader_list;
+    typedef std::map<reader_id_t, ReaderData*> readers_by_id_t;
+    readers_by_id_t _readers_by_id;
+    typedef std::map<VReader*, ReaderData*> readers_by_vreader_t;
+    readers_by_vreader_t _readers_by_vreader;
+    readers_by_vreader_t _unallocated_readers_by_vreader;
+
+    ReaderData* reader_data_from_vreader(VReader* vreader);
+    ReaderData* reader_data_from_reader_id(reader_id_t reader_id);
+    void add_unallocated_reader(VReader* vreader, const char* name);
+    ReaderData* add_reader(reader_id_t reader_id);
+    void remove_reader(ReaderData* data);
+    void send_reader_added(const char* reader_name);
+    void send_reader_removed(reader_id_t reader_id);
+    void send_atr(VReader* vreader);
+
+    friend class ReaderAddEvent;
+    friend class ReaderRemoveEvent;
+    friend class CardInsertEvent;
+    friend class CardRemoveEvent;
+    friend class VSCMessageEvent;
+};
+
+#endif // __SMART_CARD_H__
+
-- 
1.7.3.2



More information about the Spice-devel mailing list