diff options
author | NIIBE Yutaka <[email protected]> | 2017-01-26 13:02:41 +0000 |
---|---|---|
committer | NIIBE Yutaka <[email protected]> | 2017-01-26 13:02:41 +0000 |
commit | 881dcdfd84ebad36bff20c895e629025bed9d94e (patch) | |
tree | 09cd09205463d53951090ea06a943172770c4c00 | |
parent | scd: Fix APP reference counting. (diff) | |
download | gnupg-881dcdfd84ebad36bff20c895e629025bed9d94e.tar.gz gnupg-881dcdfd84ebad36bff20c895e629025bed9d94e.zip |
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 <[email protected]>
-rw-r--r-- | scd/apdu.c | 11 | ||||
-rw-r--r-- | scd/apdu.h | 2 | ||||
-rw-r--r-- | scd/app.c | 6 | ||||
-rw-r--r-- | scd/ccid-driver.c | 8 | ||||
-rw-r--r-- | scd/ccid-driver.h | 2 | ||||
-rw-r--r-- | scd/scdaemon.c | 157 | ||||
-rw-r--r-- | scd/scdaemon.h | 1 |
7 files changed, 145 insertions, 42 deletions
diff --git a/scd/apdu.c b/scd/apdu.c index 38ebd2be5..f88d97035 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -2970,15 +2970,22 @@ apdu_dev_list_start (const char *portstr, struct dev_list **l_p) return 0; } -void +int apdu_dev_list_finish (struct dev_list *dl) { + int all_have_intr_endp; + #ifdef HAVE_LIBUSB 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 xfree (dl); npth_mutex_unlock (&reader_table_lock); + return all_have_intr_endp; } diff --git a/scd/apdu.h b/scd/apdu.h index 473def518..d71c8dd5d 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -88,7 +88,7 @@ struct dev_list; gpg_error_t apdu_init (void); 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. */ 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->card_status = (unsigned int)-1; 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) { struct dev_list *l; + int all_have_intr_endp; err = apdu_dev_list_start (opt.reader_port, &l); 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); @@ -1050,6 +1053,7 @@ scd_update_reader_status_file (void) log_debug ("Removal of a card: %d\n", a->slot); apdu_close_reader (a->slot); deallocate_app (a); + update_fdset_for_usb (0, 0); } else a->card_status = status; diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index ce5539385..8ca8e9646 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1699,13 +1699,17 @@ ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p) return err; } -void +int ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max) { + int all_have_intr_endp = 1; int i; for (i = 0; i < max; i++) { + if (tbl[i].ep_intr == -1) + all_have_intr_endp = 0; + free (tbl[i].ifcdesc_extra); tbl[i].transport = 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); ccid_usb_dev_list = NULL; + + return all_have_intr_endp; } unsigned int diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 9e71f5eb1..8e9f9e251 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -115,7 +115,7 @@ int ccid_set_debug_level (int level); char *ccid_get_reader_list (void); 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); int ccid_compare_BAI (ccid_driver_t handle, unsigned int); int ccid_open_reader (const char *spec_reader_name, diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 74fed4454..8e1f69847 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -44,6 +44,10 @@ #include <assuan.h> /* malloc hooks */ +#ifdef HAVE_LIBUSB +#include <libusb.h> +#endif + #include "i18n.h" #include "sysutils.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. */ 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 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); static void *start_connection_thread (void *arg); -static void handle_connections (int listen_fd); +static void handle_connections (void); /* Pth wrapper function definitions. */ ASSUAN_SYSTEM_NPTH_IMPL; @@ -780,7 +794,8 @@ main (int argc, char **argv ) /* We run handle_connection to wait for the shutdown signal and to run the ticker stuff. */ - handle_connections (fd); + listen_fd = fd; + handle_connections (); if (fd != -1) close (fd); } @@ -912,7 +927,8 @@ main (int argc, char **argv ) #endif /*!HAVE_W32_SYSTEM*/ - handle_connections (fd); + listen_fd = fd; + handle_connections (); 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 thread after accepting a connection. LISTEN_FD is allowed to be -1 in which case this code will only do regular timeouts and handle signals. */ static void -handle_connections (int listen_fd) +handle_connections (void) { npth_attr_t tattr; struct sockaddr_un paddr; socklen_t plen; - fd_set fdset, read_fdset; + fd_set read_fdset; int ret; int fd; - int nfd; struct timespec abstime; struct timespec curtime; struct timespec timeout; + struct timespec *t; int saved_errno; #ifndef HAVE_W32_SYSTEM int signo; @@ -1244,56 +1313,63 @@ handle_connections (int listen_fd) used to just wait on a signal or timeout event. */ FD_ZERO (&fdset); listen_fd = -1; - } + } - npth_clock_gettime (&curtime); - if (!(npth_timercmp (&curtime, &abstime, <))) - { - /* Timeout. */ - handle_tick (); - timeout.tv_sec = TIMERTICK_INTERVAL_SEC; - timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000; - npth_timeradd (&curtime, &timeout, &abstime); - } - npth_timersub (&abstime, &curtime, &timeout); + if (need_tick ()) + { + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) + { + /* Timeout. */ + timeout.tv_sec = TIMERTICK_INTERVAL_SEC; + timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000; + npth_timeradd (&curtime, &timeout, &abstime); + } + npth_timersub (&abstime, &curtime, &timeout); + t = &timeout; + } + else + t = NULL; + + handle_tick (); /* POSIX says that fd_set should be implemented as a structure, thus a simple assignment is fine to copy the entire set. */ read_fdset = fdset; #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; while (npth_sigev_get_pending(&signo)) - handle_signal (signo); + handle_signal (signo); #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; #endif if (ret == -1 && saved_errno != EINTR) - { + { log_error (_("npth_pselect failed: %s - waiting 1s\n"), strerror (saved_errno)); npth_sleep (1); - continue; - } + continue; + } if (ret <= 0) - /* Timeout. Will be handled when calculating the next timeout. */ - continue; + /* Timeout. Will be handled when calculating the next timeout. */ + continue; if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset)) - { + { ctrl_t ctrl; plen = sizeof paddr; - fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen); - if (fd == -1) - { - log_error ("accept failed: %s\n", strerror (errno)); - } + fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen); + if (fd == -1) + { + log_error ("accept failed: %s\n", strerror (errno)); + } else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) ) { log_error ("error allocating connection control data: %s\n", @@ -1303,12 +1379,12 @@ handle_connections (int listen_fd) else { char threadname[50]; - npth_t thread; + npth_t thread; snprintf (threadname, sizeof threadname, "conn fd=%d", fd); ctrl->thread_startup.fd = INT2FD (fd); ret = npth_create (&thread, &tattr, start_connection_thread, ctrl); - if (ret) + if (ret) { log_error ("error spawning connection handler: %s\n", strerror (ret)); @@ -1316,10 +1392,19 @@ handle_connections (int listen_fd) close (fd); } 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 (); diff --git a/scd/scdaemon.h b/scd/scdaemon.h index d0bc98efe..9d92ff2c3 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -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 scd_update_reader_status_file (void); void send_client_notifications (app_t app, int removal); +void update_fdset_for_usb (int scanned, int all_have_intr_endp); #endif /*SCDAEMON_H*/ |