- 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:
parent
8d7fd40e80
commit
21fe5ef918
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue