Title: Re: [Muscle] Context handles and pcscd?

G'day,

>> If pcscd is restarted, SCardListReaders() and SCardGetStatusChange()
>> still act as before: zero readers are returned, and both functions
>> return SCARD_S_SUCCESS.
>
> I tried to reproduce the bug but I get a SCARD_E_NO_SERVICE error. I
> don't know how you can get a SCARD_S_SUCCESS.
>
> In fact I get a SIG_PIPE signal since libpcsclite is trying to write
> on a pipe closed when the old pcscd died. If I add a signal(SIGPIPE,
> SIG_IGN); in the application I get the SCARD_E_NO_SERVICE error.

 Attached is example code of a reader loop that calls SCardGetReaderList(), then SCardGetStatusChange(). The loop continues on success or timeout, and exits on error. Also attached is the pcscd output, and the output of the reader loop.

The reader loop output shows that, while the reader is attached, SCardGetReaderList() returns 1 reader, and SCardGetStatusChange() returns an event state indicating a card is present. Then pcscd is killed (as seen by the pcscd output), but the reader loop output then shows that SCardGetReaderList() returns 0 readers, and SCardGetStatusChange() times out, since no event is possible (and so on as it loops back). If I had called SCardGetStatusChange(), it would block indefinitely.

Maybe the code I've got here is wrong and I'm missing some fundamental point. But I cannot distinguish between "no readers attached, so keep waiting for an event" and "pcscd has stopped running and SCardEstablishContext() must be called again as the current context is invalid". Unless I create a new context every time 0 readers are returned, which does not seem to be optimal.

-- Geoff

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <winscard.h>

/* Get status change. Return 0 on success, non-zero on error */
static int get_status_change(SCARDCONTEXT context)
{
    LPTSTR string = NULL;
    DWORD size;
    int i, n;
    const char *s = NULL;
    SCARD_READERSTATE *states = NULL;
    LONG rv;

    /* Get size of string */
    rv = SCardListReaders(context, NULL, NULL, &size);
    if (rv != SCARD_S_SUCCESS)
    {
        printf("SCardListReaders() failed: 0x%0lX\n", rv);
        goto FINISH;
    }

    /* Allocate array to hold reader names */
    if ((string = malloc(sizeof(char) * size)) == NULL)
    {
        syslog(LOG_DEBUG, "[%s] failed to allocate reader names string", 
               __FUNCTION__);
        goto FINISH;
    }

    /* Get reader names string */
    rv = SCardListReaders(context, NULL, string, &size);
    if (rv != SCARD_S_SUCCESS)
    {
        printf("SCardListReaders() failed: 0x%0lX\n", rv);
        goto FINISH;
    }

    /* Get number of readers */
    n = 0;
    for (s = string; s[0] != 0; s += strlen(s))
    {
        n++;
    }

    printf("## there are %d readers available\n",n);

    /* Allocate array of reader states */
    states = calloc(n,  sizeof(states[0]));
    for (s = string; s[0] != 0; s += strlen(s))
    {
        states[0].szReader = strdup(s);
    }
    
    /* Wait for status change or time out */
    rv = SCardGetStatusChange(context, 1000, states, n);
    if (rv != SCARD_S_SUCCESS)
    {
        printf("SCardGetStatusChange() failed: 0x%0lX\n", rv);
        goto FINISH;
    }

    /* Print readers */
    for (i = 0; i < n; i++) 
    {
        const SCARD_READERSTATE *state = &states[i];
        printf("Reader '%s': current state = 0x%0lX, event state = 0x%0lX\n", 
               state->szReader, state->dwCurrentState, state->dwEventState);
    }

FINISH:
    /* Cleanup on error */
    if (rv != SCARD_S_SUCCESS && string != NULL)
    {
        free(string);
    }

    return rv;
}

int main(int argc, char **argv)
{
    SCARDCONTEXT context;
    LONG rv;

    /* Create card context */
    rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 
                               NULL, 
                               NULL, 
                               &context);
    if (rv != SCARD_S_SUCCESS)
    {
        printf("failed: 0x%0lX\n", rv);
        goto FINISH;
    }

    /* Keep getting status change, until non-timeout error */
    while (rv == SCARD_S_SUCCESS || rv == SCARD_E_TIMEOUT)
    {
        rv = get_status_change(context);
        if (rv == SCARD_S_SUCCESS)
        {
            sleep(1);
        } 
    } 

    /* Release card context */
    SCardReleaseContext(context);

FINISH:
    return rv;
}

Attachment: reader_loop.out
Description: reader_loop.out

Attachment: pcscd.out
Description: pcscd.out

_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle

Reply via email to