const char *apptype;
unsigned int card_version;
unsigned int card_status;
+ unsigned int reset_requested:1;
unsigned int require_get_status:1;
unsigned int did_chv1:1;
unsigned int force_chv1:1; /* True if the card does not cache CHV1. */
int scan, const unsigned char *serialno_bin,
size_t serialno_bin_len);
char *get_supported_applications (void);
-void release_application (app_t app);
+void release_application (app_t app, int locked_already);
gpg_error_t app_munge_serialno (app_t app);
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl,
unsigned int flags);
}
-static void
-release_application_internal (app_t app)
-{
- if (!app->ref_count)
- log_bug ("trying to release an already released context\n");
-
- --app->ref_count;
-}
-
gpg_error_t
app_reset (app_t app, ctrl_t ctrl, int send_reset)
{
- gpg_error_t err;
-
- err = lock_app (app, ctrl);
- if (err)
- return err;
+ gpg_error_t err = 0;
if (send_reset)
{
- int sw = apdu_reset (app->slot);
+ int sw;
+
+ lock_app (app, ctrl);
+ sw = apdu_reset (app->slot);
if (sw)
err = gpg_error (GPG_ERR_CARD_RESET);
- /* Release the same application which is used by other sessions. */
- send_client_notifications (app, 1);
+ app->reset_requested = 1;
+ unlock_app (app);
+
+ scd_kick_the_loop ();
+ gnupg_sleep (1);
}
else
{
ctrl->app_ctx = NULL;
- release_application_internal (app);
+ release_application (app, 0);
}
- unlock_app (app);
return err;
}
}
apdu_dev_list_finish (l);
+ scd_kick_the_loop ();
}
npth_mutex_lock (&app_list_lock);
}
xfree (app->serialno);
+
+ unlock_app (app);
xfree (app);
}
actually deferring the deallocation to allow for a later reuse by
a new connection. */
void
-release_application (app_t app)
+release_application (app_t app, int locked_already)
{
if (!app)
return;
is using the card - this way the PIN cache and other cached data
are preserved. */
- lock_app (app, NULL);
- release_application_internal (app);
- unlock_app (app);
+ if (!locked_already)
+ lock_app (app, NULL);
+
+ if (!app->ref_count)
+ log_bug ("trying to release an already released context\n");
+
+ --app->ref_count;
+ if (!locked_already)
+ unlock_app (app);
}
npth_mutex_lock (&app_list_lock);
for (a = app_top; a; a = app_next)
{
+ unsigned int status;
+
+ lock_app (a, NULL);
app_next = a->next;
- if (a->require_get_status)
+
+ if (a->reset_requested)
+ status = 0;
+ else
{
int sw;
- unsigned int status;
sw = apdu_get_status (a->slot, 0, &status);
if (sw == SW_HOST_NO_READER)
else if (sw)
{
/* Get status failed. Ignore that. */
+ unlock_app (a);
continue;
}
+ }
+
+ if (a->card_status != status)
+ {
+ report_change (a->slot, a->card_status, status);
+ send_client_notifications (a, status == 0);
- if (a->card_status != status)
+ if (status == 0)
{
- report_change (a->slot, a->card_status, status);
- send_client_notifications (a, status == 0);
-
- if (status == 0)
- {
- log_debug ("Removal of a card: %d\n", a->slot);
- apdu_close_reader (a->slot);
- deallocate_app (a);
- }
- else
- a->card_status = status;
+ log_debug ("Removal of a card: %d\n", a->slot);
+ apdu_close_reader (a->slot);
+ deallocate_app (a);
+ }
+ else
+ {
+ a->card_status = status;
+ unlock_app (a);
}
}
+ else
+ unlock_app (a);
}
npth_mutex_unlock (&app_list_lock);
}
/* Re-scan USB devices. Release APP, before the scan. */
ctrl->app_ctx = NULL;
- release_application (app);
+ release_application (app, 0);
if (serialno)
serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
if (app)
{
ctrl->app_ctx = NULL;
- release_application (app);
+ release_application (app, 0);
}
if (locked_session && ctrl->server_local == locked_session)
{
{
sl->ctrl_backlink->app_ctx = NULL;
sl->card_removed = 1;
- release_application (app);
+ release_application (app, 1);
}
if (!sl->event_signal || !sl->assuan_ctx)
#include "ccid-driver.h"
#include "gc-opt-flags.h"
#include "asshelp.h"
+#include "exechelp.h"
#include "../common/init.h"
#ifndef ENAMETOOLONG
disabled but it won't perform any ticker specific actions. */
static int ticker_disabled;
-
+/* FD to notify update of usb devices. */
+static int notify_fd;
\f
static char *create_socket_name (char *standard_name);
static gnupg_fd_t create_server_socket (const char *name,
}
+void
+scd_kick_the_loop (void)
+{
+ int ret;
+
+ /* Kick the select loop. */
+ ret = write (notify_fd, "", 1);
+ (void)ret;
+}
+
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. LISTEN_FD is allowed to be -1
in which case this code will only do regular timeouts and handle
#ifndef HAVE_W32_SYSTEM
int signo;
#endif
+ int pipe_fd[2];
+
+ ret = gnupg_create_pipe (pipe_fd);
+ if (ret)
+ {
+ log_error ("pipe creation failed: %s\n", gpg_strerror (ret));
+ return;
+ }
+ notify_fd = pipe_fd[1];
ret = npth_attr_init(&tattr);
- /* FIXME: Check error. */
+ if (ret)
+ {
+ log_error ("npth_attr_init failed: %s\n", strerror (ret));
+ return;
+ }
+
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
#ifndef HAVE_W32_SYSTEM
for (;;)
{
+ int max_fd;
+
if (shutdown_pending)
{
if (active_connections == 0)
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
+ FD_SET (pipe_fd[0], &read_fdset);
+ if (nfd < pipe_fd[0])
+ max_fd = pipe_fd[0];
+ else
+ max_fd = nfd;
+
#ifndef HAVE_W32_SYSTEM
- ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
+ ret = npth_pselect (max_fd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
saved_errno = errno;
while (npth_sigev_get_pending(&signo))
handle_signal (signo);
#else
- ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL);
+ ret = npth_eselect (max_fd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL);
saved_errno = errno;
#endif
/* Timeout. Will be handled when calculating the next timeout. */
continue;
+ if (FD_ISSET (pipe_fd[0], &read_fdset))
+ {
+ char buf[256];
+
+ ret = read (pipe_fd[0], buf, sizeof buf);
+ }
+
if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset))
{
ctrl_t ctrl;
}
}
+ close (pipe_fd[0]);
+ close (pipe_fd[1]);
cleanup ();
log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
npth_attr_destroy (&tattr);
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
void scd_update_reader_status_file (void);
void send_client_notifications (app_t app, int removal);
+void scd_kick_the_loop (void);
#endif /*SCDAEMON_H*/