- 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
This commit is contained in:
okir 2003-01-03 16:32:06 +00:00
parent 8d7fd40e80
commit 21fe5ef918
3 changed files with 159 additions and 40 deletions

View File

@ -178,6 +178,10 @@ extern "C" {
#define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000080 #define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000080
#define SC_ALGORITHM_RSA_HASH_RIPEMD160 0x00000100 #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 { struct sc_security_env {
unsigned long flags; unsigned long flags;
int operation; int operation;
@ -361,6 +365,7 @@ struct sc_reader_operations {
int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot); int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot);
int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot, int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot,
unsigned int proto); unsigned int proto);
/* Not sure what that is supposed to do --okir */
int (*add_callback)(struct sc_reader *reader, struct sc_slot_info *slot, int (*add_callback)(struct sc_reader *reader, struct sc_slot_info *slot,
const struct sc_event_listener *, void *arg); const struct sc_event_listener *, void *arg);
@ -369,6 +374,15 @@ struct sc_reader_operations {
const char *); const char *);
int (*enter_pin)(struct sc_reader *, struct sc_slot_info *, int (*enter_pin)(struct sc_reader *, struct sc_slot_info *,
struct sc_pin_cmd_data *); 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); int sc_detect_card_presence(struct sc_reader *reader, int slot_id);
/** /**
* Waits for an event on a reader * Waits for an event on readers. Note: only the event is detected,
* @param reader Reader structure * 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 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 * @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 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, int sc_wait_for_event(struct sc_reader **readers, int *slots, size_t nslots,
unsigned int event_mask, int timeout); unsigned int event_mask,
int *reader, unsigned int *event, int timeout);
/** /**
* Locks the card against modification from other threads. * Locks the card against modification from other threads.

View File

@ -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; 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) static int pcsc_connect(struct sc_reader *reader, struct sc_slot_info *slot)
{ {
DWORD active_proto; DWORD active_proto;
@ -443,6 +550,7 @@ const struct sc_reader_driver * sc_get_pcsc_driver()
pcsc_ops.connect = pcsc_connect; pcsc_ops.connect = pcsc_connect;
pcsc_ops.disconnect = pcsc_disconnect; pcsc_ops.disconnect = pcsc_disconnect;
pcsc_ops.enter_pin = ctbcs_pin_cmd; pcsc_ops.enter_pin = ctbcs_pin_cmd;
pcsc_ops.wait_for_event = pcsc_wait_for_event;
return &pcsc_drv; return &pcsc_drv;
} }

View File

@ -126,45 +126,36 @@ int sc_detect_card_presence(struct sc_reader *reader, int slot_id)
SC_FUNC_RETURN(reader->ctx, 1, r); SC_FUNC_RETURN(reader->ctx, 1, r);
} }
#if 0 int sc_wait_for_event(struct sc_reader *readers[], int slot_id[], size_t nslots,
int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout) unsigned int event_mask,
int *reader, unsigned int *event, int timeout)
{ {
LONG ret; struct sc_slot_info *slotp[SC_MAX_SLOTS * SC_MAX_READERS];
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; struct sc_context *ctx;
int count = 0, i; 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); SC_FUNC_CALLED(ctx, 1);
if (reader >= ctx->reader_count) for (j = 0; j < nslots; j++) {
SC_FUNC_RETURN(ctx, 1, SC_ERROR_INVALID_ARGUMENTS); slotp[j] = _sc_get_slot_info(readers[j], slot_id[j]);
if (reader < 0) { if (slotp[j] == NULL)
if (ctx->reader_count == 0) SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND);
SC_FUNC_RETURN(ctx, 1, SC_ERROR_NO_READERS_FOUND); /* XXX check to make sure all readers share the same operations
for (i = 0; i < ctx->reader_count; i++) { * struct */
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;
} }
ret = SCardGetStatusChange(ctx->pcsc_ctx, timeout, rgReaderStates, count);
if (ret != 0) { if (readers[0]->ops->wait_for_event == NULL)
error(ctx, "SCardGetStatusChange failed: %s\n", pcsc_stringify_error(ret)); SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED);
SC_FUNC_RETURN(ctx, 1, -1);
} r = readers[0]->ops->wait_for_event(readers, slotp, nslots,
for (i = 0; i < count; i++) { event_mask, reader, event, timeout);
if (rgReaderStates[i].dwEventState & SCARD_STATE_CHANGED) SC_FUNC_RETURN(ctx, 1, r);
SC_FUNC_RETURN(ctx, 1, 1);
}
SC_FUNC_RETURN(ctx, 1, 0);
} }
#endif
void sc_format_path(const char *str, struct sc_path *path) void sc_format_path(const char *str, struct sc_path *path)
{ {