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 /scd/scdaemon.c | |
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]>
Diffstat (limited to 'scd/scdaemon.c')
-rw-r--r-- | scd/scdaemon.c | 157 |
1 files changed, 121 insertions, 36 deletions
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 (); |