mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-10 21:38:50 +01:00
scd: Only submit apdu_get_status when needed.
* scd/apdu.c (apdu_dev_list_finish): Return Boolean value if all device support INTERRUPT transfer. * scd/ccid-driver.c (ccid_dev_scan_finish): Likewise. * scd/app.c (app_new_register): Fix initial value of card_status. (select_application): Call update_fdset_for_usb. (scd_update_reader_status_file): Ditto. * scd/scdaemon.c (update_fdset_for_usb, need_tick): New. (handle_connections): Call handle_tick when select returns. Let select watch USB file descriptors, too. Call libusb_handle_events_timeout_completed for INTERRUPT transfer. Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
parent
9b06633c81
commit
881dcdfd84
11
scd/apdu.c
11
scd/apdu.c
@ -2970,15 +2970,22 @@ apdu_dev_list_start (const char *portstr, struct dev_list **l_p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
apdu_dev_list_finish (struct dev_list *dl)
|
apdu_dev_list_finish (struct dev_list *dl)
|
||||||
{
|
{
|
||||||
|
int all_have_intr_endp;
|
||||||
|
|
||||||
#ifdef HAVE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
if (dl->ccid_table)
|
if (dl->ccid_table)
|
||||||
ccid_dev_scan_finish (dl->ccid_table, dl->idx_max);
|
all_have_intr_endp = ccid_dev_scan_finish (dl->ccid_table, dl->idx_max);
|
||||||
|
else
|
||||||
|
all_have_intr_endp = 0;
|
||||||
|
#else
|
||||||
|
all_have_intr_endp = 0;
|
||||||
#endif
|
#endif
|
||||||
xfree (dl);
|
xfree (dl);
|
||||||
npth_mutex_unlock (&reader_table_lock);
|
npth_mutex_unlock (&reader_table_lock);
|
||||||
|
return all_have_intr_endp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ struct dev_list;
|
|||||||
gpg_error_t apdu_init (void);
|
gpg_error_t apdu_init (void);
|
||||||
|
|
||||||
gpg_error_t apdu_dev_list_start (const char *portstr, struct dev_list **l_p);
|
gpg_error_t apdu_dev_list_start (const char *portstr, struct dev_list **l_p);
|
||||||
void apdu_dev_list_finish (struct dev_list *l);
|
int apdu_dev_list_finish (struct dev_list *l);
|
||||||
|
|
||||||
/* Note, that apdu_open_reader returns no status word but -1 on error. */
|
/* Note, that apdu_open_reader returns no status word but -1 on error. */
|
||||||
int apdu_open_reader (struct dev_list *l);
|
int apdu_open_reader (struct dev_list *l);
|
||||||
|
@ -192,6 +192,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
app->slot = slot;
|
app->slot = slot;
|
||||||
|
app->card_status = (unsigned int)-1;
|
||||||
|
|
||||||
if (npth_mutex_init (&app->lock, NULL))
|
if (npth_mutex_init (&app->lock, NULL))
|
||||||
{
|
{
|
||||||
@ -329,6 +330,7 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app,
|
|||||||
if (scan || !app_top)
|
if (scan || !app_top)
|
||||||
{
|
{
|
||||||
struct dev_list *l;
|
struct dev_list *l;
|
||||||
|
int all_have_intr_endp;
|
||||||
|
|
||||||
err = apdu_dev_list_start (opt.reader_port, &l);
|
err = apdu_dev_list_start (opt.reader_port, &l);
|
||||||
if (err)
|
if (err)
|
||||||
@ -368,7 +370,8 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apdu_dev_list_finish (l);
|
all_have_intr_endp = apdu_dev_list_finish (l);
|
||||||
|
update_fdset_for_usb (1, all_have_intr_endp);
|
||||||
}
|
}
|
||||||
|
|
||||||
npth_mutex_lock (&app_list_lock);
|
npth_mutex_lock (&app_list_lock);
|
||||||
@ -1050,6 +1053,7 @@ scd_update_reader_status_file (void)
|
|||||||
log_debug ("Removal of a card: %d\n", a->slot);
|
log_debug ("Removal of a card: %d\n", a->slot);
|
||||||
apdu_close_reader (a->slot);
|
apdu_close_reader (a->slot);
|
||||||
deallocate_app (a);
|
deallocate_app (a);
|
||||||
|
update_fdset_for_usb (0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
a->card_status = status;
|
a->card_status = status;
|
||||||
|
@ -1699,13 +1699,17 @@ ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max)
|
ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max)
|
||||||
{
|
{
|
||||||
|
int all_have_intr_endp = 1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < max; i++)
|
for (i = 0; i < max; i++)
|
||||||
{
|
{
|
||||||
|
if (tbl[i].ep_intr == -1)
|
||||||
|
all_have_intr_endp = 0;
|
||||||
|
|
||||||
free (tbl[i].ifcdesc_extra);
|
free (tbl[i].ifcdesc_extra);
|
||||||
tbl[i].transport = 0;
|
tbl[i].transport = 0;
|
||||||
tbl[i].n = 0;
|
tbl[i].n = 0;
|
||||||
@ -1719,6 +1723,8 @@ ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max)
|
|||||||
}
|
}
|
||||||
libusb_free_device_list (ccid_usb_dev_list, 1);
|
libusb_free_device_list (ccid_usb_dev_list, 1);
|
||||||
ccid_usb_dev_list = NULL;
|
ccid_usb_dev_list = NULL;
|
||||||
|
|
||||||
|
return all_have_intr_endp;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
|
@ -115,7 +115,7 @@ int ccid_set_debug_level (int level);
|
|||||||
char *ccid_get_reader_list (void);
|
char *ccid_get_reader_list (void);
|
||||||
|
|
||||||
gpg_error_t ccid_dev_scan (int *idx_max, struct ccid_dev_table **t_p);
|
gpg_error_t ccid_dev_scan (int *idx_max, struct ccid_dev_table **t_p);
|
||||||
void ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max);
|
int ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max);
|
||||||
unsigned int ccid_get_BAI (int, struct ccid_dev_table *tbl);
|
unsigned int ccid_get_BAI (int, struct ccid_dev_table *tbl);
|
||||||
int ccid_compare_BAI (ccid_driver_t handle, unsigned int);
|
int ccid_compare_BAI (ccid_driver_t handle, unsigned int);
|
||||||
int ccid_open_reader (const char *spec_reader_name,
|
int ccid_open_reader (const char *spec_reader_name,
|
||||||
|
157
scd/scdaemon.c
157
scd/scdaemon.c
@ -44,6 +44,10 @@
|
|||||||
|
|
||||||
#include <assuan.h> /* malloc hooks */
|
#include <assuan.h> /* malloc hooks */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBUSB
|
||||||
|
#include <libusb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "sysutils.h"
|
#include "sysutils.h"
|
||||||
#include "app-common.h"
|
#include "app-common.h"
|
||||||
@ -224,7 +228,17 @@ static assuan_sock_nonce_t socket_nonce;
|
|||||||
disabled but it won't perform any ticker specific actions. */
|
disabled but it won't perform any ticker specific actions. */
|
||||||
static int ticker_disabled;
|
static int ticker_disabled;
|
||||||
|
|
||||||
|
/* Set of FD to select. */
|
||||||
|
static fd_set fdset;
|
||||||
|
|
||||||
|
/* Max FD to select. */
|
||||||
|
static int nfd;
|
||||||
|
|
||||||
|
/* Set if all usb devices have INTERRUPT endpoints. */
|
||||||
|
static int usb_all_have_intr_endp;
|
||||||
|
|
||||||
|
/* FD to listen incomming connections. */
|
||||||
|
static int listen_fd;
|
||||||
|
|
||||||
static char *create_socket_name (char *standard_name);
|
static char *create_socket_name (char *standard_name);
|
||||||
static gnupg_fd_t create_server_socket (const char *name,
|
static gnupg_fd_t create_server_socket (const char *name,
|
||||||
@ -232,7 +246,7 @@ static gnupg_fd_t create_server_socket (const char *name,
|
|||||||
assuan_sock_nonce_t *nonce);
|
assuan_sock_nonce_t *nonce);
|
||||||
|
|
||||||
static void *start_connection_thread (void *arg);
|
static void *start_connection_thread (void *arg);
|
||||||
static void handle_connections (int listen_fd);
|
static void handle_connections (void);
|
||||||
|
|
||||||
/* Pth wrapper function definitions. */
|
/* Pth wrapper function definitions. */
|
||||||
ASSUAN_SYSTEM_NPTH_IMPL;
|
ASSUAN_SYSTEM_NPTH_IMPL;
|
||||||
@ -780,7 +794,8 @@ main (int argc, char **argv )
|
|||||||
|
|
||||||
/* We run handle_connection to wait for the shutdown signal and
|
/* We run handle_connection to wait for the shutdown signal and
|
||||||
to run the ticker stuff. */
|
to run the ticker stuff. */
|
||||||
handle_connections (fd);
|
listen_fd = fd;
|
||||||
|
handle_connections ();
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
close (fd);
|
close (fd);
|
||||||
}
|
}
|
||||||
@ -912,7 +927,8 @@ main (int argc, char **argv )
|
|||||||
|
|
||||||
#endif /*!HAVE_W32_SYSTEM*/
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
handle_connections (fd);
|
listen_fd = fd;
|
||||||
|
handle_connections ();
|
||||||
|
|
||||||
close (fd);
|
close (fd);
|
||||||
}
|
}
|
||||||
@ -1181,23 +1197,76 @@ start_connection_thread (void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
update_fdset_for_usb (int scanned, int all_have_intr_endp)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBUSB
|
||||||
|
const struct libusb_pollfd **pfd_array = libusb_get_pollfds (NULL);
|
||||||
|
const struct libusb_pollfd **p;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (scanned)
|
||||||
|
usb_all_have_intr_endp = all_have_intr_endp;
|
||||||
|
|
||||||
|
FD_ZERO (&fdset);
|
||||||
|
nfd = 0;
|
||||||
|
|
||||||
|
if (listen_fd != -1)
|
||||||
|
{
|
||||||
|
FD_SET (listen_fd, &fdset);
|
||||||
|
nfd = listen_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBUSB
|
||||||
|
for (p = pfd_array; *p; p++)
|
||||||
|
{
|
||||||
|
int fd = (*p)->fd;
|
||||||
|
|
||||||
|
FD_SET (fd, &fdset);
|
||||||
|
if (nfd < fd)
|
||||||
|
nfd = fd;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_free_pollfds (pfd_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
log_debug ("update_fdset_for_usb (%d, %d): %d\n",
|
||||||
|
scanned, all_have_intr_endp, nfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
need_tick (void)
|
||||||
|
{
|
||||||
|
if (shutdown_pending)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (listen_fd != -1 && nfd == listen_fd)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (usb_all_have_intr_endp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Connection handler loop. Wait for connection requests and spawn a
|
/* Connection handler loop. Wait for connection requests and spawn a
|
||||||
thread after accepting a connection. LISTEN_FD is allowed to be -1
|
thread after accepting a connection. LISTEN_FD is allowed to be -1
|
||||||
in which case this code will only do regular timeouts and handle
|
in which case this code will only do regular timeouts and handle
|
||||||
signals. */
|
signals. */
|
||||||
static void
|
static void
|
||||||
handle_connections (int listen_fd)
|
handle_connections (void)
|
||||||
{
|
{
|
||||||
npth_attr_t tattr;
|
npth_attr_t tattr;
|
||||||
struct sockaddr_un paddr;
|
struct sockaddr_un paddr;
|
||||||
socklen_t plen;
|
socklen_t plen;
|
||||||
fd_set fdset, read_fdset;
|
fd_set read_fdset;
|
||||||
int ret;
|
int ret;
|
||||||
int fd;
|
int fd;
|
||||||
int nfd;
|
|
||||||
struct timespec abstime;
|
struct timespec abstime;
|
||||||
struct timespec curtime;
|
struct timespec curtime;
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
|
struct timespec *t;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
#ifndef HAVE_W32_SYSTEM
|
#ifndef HAVE_W32_SYSTEM
|
||||||
int signo;
|
int signo;
|
||||||
@ -1244,56 +1313,63 @@ handle_connections (int listen_fd)
|
|||||||
used to just wait on a signal or timeout event. */
|
used to just wait on a signal or timeout event. */
|
||||||
FD_ZERO (&fdset);
|
FD_ZERO (&fdset);
|
||||||
listen_fd = -1;
|
listen_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
npth_clock_gettime (&curtime);
|
if (need_tick ())
|
||||||
if (!(npth_timercmp (&curtime, &abstime, <)))
|
{
|
||||||
{
|
npth_clock_gettime (&curtime);
|
||||||
/* Timeout. */
|
if (!(npth_timercmp (&curtime, &abstime, <)))
|
||||||
handle_tick ();
|
{
|
||||||
timeout.tv_sec = TIMERTICK_INTERVAL_SEC;
|
/* Timeout. */
|
||||||
timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000;
|
timeout.tv_sec = TIMERTICK_INTERVAL_SEC;
|
||||||
npth_timeradd (&curtime, &timeout, &abstime);
|
timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000;
|
||||||
}
|
npth_timeradd (&curtime, &timeout, &abstime);
|
||||||
npth_timersub (&abstime, &curtime, &timeout);
|
}
|
||||||
|
npth_timersub (&abstime, &curtime, &timeout);
|
||||||
|
t = &timeout;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
t = NULL;
|
||||||
|
|
||||||
|
handle_tick ();
|
||||||
|
|
||||||
/* POSIX says that fd_set should be implemented as a structure,
|
/* POSIX says that fd_set should be implemented as a structure,
|
||||||
thus a simple assignment is fine to copy the entire set. */
|
thus a simple assignment is fine to copy the entire set. */
|
||||||
read_fdset = fdset;
|
read_fdset = fdset;
|
||||||
|
|
||||||
#ifndef HAVE_W32_SYSTEM
|
#ifndef HAVE_W32_SYSTEM
|
||||||
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
|
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, t, npth_sigev_sigmask());
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
|
|
||||||
while (npth_sigev_get_pending(&signo))
|
while (npth_sigev_get_pending(&signo))
|
||||||
handle_signal (signo);
|
handle_signal (signo);
|
||||||
#else
|
#else
|
||||||
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL);
|
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, t, NULL, NULL);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ret == -1 && saved_errno != EINTR)
|
if (ret == -1 && saved_errno != EINTR)
|
||||||
{
|
{
|
||||||
log_error (_("npth_pselect failed: %s - waiting 1s\n"),
|
log_error (_("npth_pselect failed: %s - waiting 1s\n"),
|
||||||
strerror (saved_errno));
|
strerror (saved_errno));
|
||||||
npth_sleep (1);
|
npth_sleep (1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
/* Timeout. Will be handled when calculating the next timeout. */
|
/* Timeout. Will be handled when calculating the next timeout. */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset))
|
if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset))
|
||||||
{
|
{
|
||||||
ctrl_t ctrl;
|
ctrl_t ctrl;
|
||||||
|
|
||||||
plen = sizeof paddr;
|
plen = sizeof paddr;
|
||||||
fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
|
fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
{
|
{
|
||||||
log_error ("accept failed: %s\n", strerror (errno));
|
log_error ("accept failed: %s\n", strerror (errno));
|
||||||
}
|
}
|
||||||
else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) )
|
else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) )
|
||||||
{
|
{
|
||||||
log_error ("error allocating connection control data: %s\n",
|
log_error ("error allocating connection control data: %s\n",
|
||||||
@ -1303,12 +1379,12 @@ handle_connections (int listen_fd)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
char threadname[50];
|
char threadname[50];
|
||||||
npth_t thread;
|
npth_t thread;
|
||||||
|
|
||||||
snprintf (threadname, sizeof threadname, "conn fd=%d", fd);
|
snprintf (threadname, sizeof threadname, "conn fd=%d", fd);
|
||||||
ctrl->thread_startup.fd = INT2FD (fd);
|
ctrl->thread_startup.fd = INT2FD (fd);
|
||||||
ret = npth_create (&thread, &tattr, start_connection_thread, ctrl);
|
ret = npth_create (&thread, &tattr, start_connection_thread, ctrl);
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
log_error ("error spawning connection handler: %s\n",
|
log_error ("error spawning connection handler: %s\n",
|
||||||
strerror (ret));
|
strerror (ret));
|
||||||
@ -1316,10 +1392,19 @@ handle_connections (int listen_fd)
|
|||||||
close (fd);
|
close (fd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
npth_setname_np (thread, threadname);
|
npth_setname_np (thread, threadname);
|
||||||
}
|
}
|
||||||
fd = -1;
|
|
||||||
}
|
ret--;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBUSB
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
struct timeval tv = {0, 0};
|
||||||
|
libusb_handle_events_timeout_completed (NULL, &tv, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup ();
|
cleanup ();
|
||||||
|
@ -125,6 +125,7 @@ void send_status_info (ctrl_t ctrl, const char *keyword, ...)
|
|||||||
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
|
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
|
||||||
void scd_update_reader_status_file (void);
|
void scd_update_reader_status_file (void);
|
||||||
void send_client_notifications (app_t app, int removal);
|
void send_client_notifications (app_t app, int removal);
|
||||||
|
void update_fdset_for_usb (int scanned, int all_have_intr_endp);
|
||||||
|
|
||||||
|
|
||||||
#endif /*SCDAEMON_H*/
|
#endif /*SCDAEMON_H*/
|
||||||
|
Loading…
Reference in New Issue
Block a user