- 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_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.

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;
}
/* 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;
}

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);
}
#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)
{