From 21fe5ef918a47745a3293556ac987732a68e4919 Mon Sep 17 00:00:00 2001 From: okir Date: Fri, 3 Jan 2003 16:32:06 +0000 Subject: [PATCH] - Patch from Stef to implement sc_wait_for_event, slightly enhanced by yours truly. git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@825 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/opensc.h | 34 +++++++++--- src/libopensc/reader-pcsc.c | 108 ++++++++++++++++++++++++++++++++++++ src/libopensc/sc.c | 57 ++++++++----------- 3 files changed, 159 insertions(+), 40 deletions(-) diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index b04eeaef..859d2598 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -178,6 +178,10 @@ extern "C" { #define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000080 #define SC_ALGORITHM_RSA_HASH_RIPEMD160 0x00000100 +/* Event masks for sc_wait_for_event() */ +#define SC_EVENT_CARD_INSERTED 0x0001 +#define SC_EVENT_CARD_REMOVED 0x0002 + struct sc_security_env { unsigned long flags; int operation; @@ -361,6 +365,7 @@ struct sc_reader_operations { int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot); int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot, unsigned int proto); + /* Not sure what that is supposed to do --okir */ int (*add_callback)(struct sc_reader *reader, struct sc_slot_info *slot, const struct sc_event_listener *, void *arg); @@ -369,6 +374,15 @@ struct sc_reader_operations { const char *); int (*enter_pin)(struct sc_reader *, struct sc_slot_info *, struct sc_pin_cmd_data *); + + /* Wait for an event */ + int (*wait_for_event)(struct sc_reader **readers, + struct sc_slot_info **slots, + size_t nslots, + unsigned int event_mask, + int *reader_index, + unsigned int *event, + int timeout); }; @@ -620,17 +634,23 @@ inline int sc_card_valid(const struct sc_card *card); int sc_detect_card_presence(struct sc_reader *reader, int slot_id); /** - * Waits for an event on a reader - * @param reader Reader structure + * Waits for an event on readers. Note: only the event is detected, + * there is no update of any card or other info. + * @param readers array of pointer to a Reader structure + * @param reader_count amount of readers in the array * @param slot_id Slot ID - * @param event_mask The types of events to wait for + * @param event_mask The types of events to wait for, currently only + * SC_EVENT_CARD_INSERT_REMOVAL is supported + * @param reader (OUT) the reader on which the event was detected + * @param event (OUT) the type of event that occurred * @param timeout Amount of millisecs to wait; -1 means forever - * @retval 1 if a card was inserted - * @retval 0 if operation timed out * @retval < 0 if an error occured + * @retval = 0 if a an event happened + * @retval = 1 if the timeout occured */ -int sc_wait_for_event(struct sc_reader *reader, int slot_id, - unsigned int event_mask, int timeout); +int sc_wait_for_event(struct sc_reader **readers, int *slots, size_t nslots, + unsigned int event_mask, + int *reader, unsigned int *event, int timeout); /** * Locks the card against modification from other threads. diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 1b543f4a..ee4ff22b 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -235,6 +235,113 @@ static int pcsc_detect_card_presence(struct sc_reader *reader, struct sc_slot_in return (slot->flags & SC_SLOT_CARD_PRESENT)? 1 : 0; } +/* Wait for an event to occur. + * This function ignores the list of slots, because with + * pcsc we have a 1:1 mapping of readers and slots anyway + */ +static int pcsc_wait_for_event(struct sc_reader **readers, + struct sc_slot_info **slots, + size_t nslots, + unsigned int event_mask, + int *reader, + unsigned int *event, int timeout) +{ + struct sc_context *ctx; + SCARDCONTEXT pcsc_ctx; + LONG ret; + SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; + unsigned long on_bits, off_bits; + time_t end_time, now, delta; + int i; + + /* Prevent buffer overflow */ + if (nslots >= SC_MAX_READERS) + return SC_ERROR_INVALID_ARGUMENTS; + + on_bits = off_bits = 0; + if (event_mask & SC_EVENT_CARD_INSERTED) { + event_mask &= ~SC_EVENT_CARD_INSERTED; + on_bits |= SCARD_STATE_PRESENT; + } + if (event_mask & SC_EVENT_CARD_REMOVED) { + event_mask &= ~SC_EVENT_CARD_REMOVED; + off_bits |= SCARD_STATE_PRESENT; + } + if (event_mask != 0) + return SC_ERROR_INVALID_ARGUMENTS; + + // Find out the current status + ctx = readers[0]->ctx; + pcsc_ctx = GET_PRIV_DATA(readers[0])->pcsc_ctx; + for (i = 0; i < nslots; i++) { + struct pcsc_private_data *priv = GET_PRIV_DATA(readers[i]); + + rgReaderStates[i].szReader = priv->reader_name; + rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; + rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; + + /* Can we handle readers from different PCSC contexts? */ + if (priv->pcsc_ctx != pcsc_ctx) + return SC_ERROR_INVALID_ARGUMENTS; + } + + ret = SCardGetStatusChange(pcsc_ctx, 0, rgReaderStates, nslots); + if (ret != 0) { + PCSC_ERROR(ctx, "SCardGetStatusChange(1) failed", ret); + return pcsc_ret_to_error(ret); + } + + time(&now); + end_time = now + timeout; + + /* Wait for a status change and return if it's a card insert/removal + */ + for( ; ; ) { + /* Scan the current state of all readers to see if they + * match any of the events we're polling for */ + *event = 0; + for (i = 0; i < nslots; i++) { + unsigned long state; + + state = rgReaderStates[i].dwEventState; + if (state & on_bits & SCARD_STATE_PRESENT) + *event |= SC_EVENT_CARD_INSERTED; + if (~state & off_bits & SCARD_STATE_PRESENT) + *event |= SC_EVENT_CARD_REMOVED; + if (*event) { + *reader = i; + return 0; + } + + /* No match - copy the state so pcscd knows + * what to watch out for */ + rgReaderStates[i].dwCurrentState = rgReaderStates[i].dwEventState; + } + + /* Set the timeout if caller wants to time out */ + if (timeout == 0) + return SC_ERROR_EVENT_TIMEOUT; + if (timeout > 0) { + time(&now); + if (now >= end_time) + return SC_ERROR_EVENT_TIMEOUT; + delta = end_time - now; + } else { + delta = 3600; + } + + ret = SCardGetStatusChange(pcsc_ctx, delta, + rgReaderStates, nslots); + if (ret == SCARD_E_TIMEOUT) + return SC_ERROR_EVENT_TIMEOUT; + if (ret != 0) { + PCSC_ERROR(ctx, "SCardGetStatusChange(2) failed", ret); + return pcsc_ret_to_error(ret); + } + + } +} + static int pcsc_connect(struct sc_reader *reader, struct sc_slot_info *slot) { DWORD active_proto; @@ -443,6 +550,7 @@ const struct sc_reader_driver * sc_get_pcsc_driver() pcsc_ops.connect = pcsc_connect; pcsc_ops.disconnect = pcsc_disconnect; pcsc_ops.enter_pin = ctbcs_pin_cmd; + pcsc_ops.wait_for_event = pcsc_wait_for_event; return &pcsc_drv; } diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index da071406..724f480e 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -126,45 +126,36 @@ int sc_detect_card_presence(struct sc_reader *reader, int slot_id) SC_FUNC_RETURN(reader->ctx, 1, r); } -#if 0 -int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout) +int sc_wait_for_event(struct sc_reader *readers[], int slot_id[], size_t nslots, + unsigned int event_mask, + int *reader, unsigned int *event, int timeout) { - LONG ret; - SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; - int count = 0, i; + struct sc_slot_info *slotp[SC_MAX_SLOTS * SC_MAX_READERS]; + struct sc_context *ctx; + unsigned int j; + int r; + + if (nslots == 0 || nslots > SC_MAX_SLOTS * SC_MAX_READERS) + return SC_ERROR_INVALID_ARGUMENTS; + ctx = readers[0]->ctx; - assert(ctx != NULL); SC_FUNC_CALLED(ctx, 1); - if (reader >= ctx->reader_count) - SC_FUNC_RETURN(ctx, 1, SC_ERROR_INVALID_ARGUMENTS); + for (j = 0; j < nslots; j++) { + slotp[j] = _sc_get_slot_info(readers[j], slot_id[j]); - if (reader < 0) { - if (ctx->reader_count == 0) - SC_FUNC_RETURN(ctx, 1, SC_ERROR_NO_READERS_FOUND); - for (i = 0; i < ctx->reader_count; i++) { - rgReaderStates[i].szReader = ctx->readers[i]; - rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; - } - count = ctx->reader_count; - } else { - rgReaderStates[0].szReader = ctx->readers[reader]; - rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[0].dwEventState = SCARD_STATE_UNAWARE; - count = 1; + if (slotp[j] == NULL) + SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND); + /* XXX check to make sure all readers share the same operations + * struct */ } - ret = SCardGetStatusChange(ctx->pcsc_ctx, timeout, rgReaderStates, count); - if (ret != 0) { - error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret)); - SC_FUNC_RETURN(ctx, 1, -1); - } - for (i = 0; i < count; i++) { - if (rgReaderStates[i].dwEventState & SCARD_STATE_CHANGED) - SC_FUNC_RETURN(ctx, 1, 1); - } - SC_FUNC_RETURN(ctx, 1, 0); + + if (readers[0]->ops->wait_for_event == NULL) + SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED); + + r = readers[0]->ops->wait_for_event(readers, slotp, nslots, + event_mask, reader, event, timeout); + SC_FUNC_RETURN(ctx, 1, r); } -#endif void sc_format_path(const char *str, struct sc_path *path) {