scd: Only submit apdu_get_status when needed.
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 26 Jan 2017 13:02:41 +0000 (22:02 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 26 Jan 2017 13:02:41 +0000 (22:02 +0900)
* 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>
scd/apdu.c
scd/apdu.h
scd/app.c
scd/ccid-driver.c
scd/ccid-driver.h
scd/scdaemon.c
scd/scdaemon.h

index 38ebd2b..f88d970 100644 (file)
@@ -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;
 }
 
 
index 473def5..d71c8dd 100644 (file)
@@ -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);
index b10a452..daff0b7 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -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;
index ce55393..8ca8e96 100644 (file)
@@ -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
index 9e71f5e..8e9f9e2 100644 (file)
@@ -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,
index 74fed44..8e1f698 100644 (file)
 
 #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;
 \f
 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 ();
index d0bc98e..9d92ff2 100644 (file)
@@ -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*/