[git] GnuPG - branch, master, updated. gnupg-2.2.1-82-gd4e2302

by Werner Koch cvs at cvs.gnupg.org
Tue Nov 14 16:30:02 CET 2017


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  d4e2302d8f4a1ff52d56da4f8e3a5d1c6303822d (commit)
       via  96a4fbecd1acf946dcde20bef4752c539dae196b (commit)
       via  26f08343fbccdbaa177c3507a3c5e24a5cf94a2d (commit)
      from  65038e6852185c20413d8f6602218ee636413b77 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit d4e2302d8f4a1ff52d56da4f8e3a5d1c6303822d
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Nov 14 16:24:12 2017 +0100

    dirmngr: Check for WKD support at session end
    
    * dirmngr/domaininfo.c (insert_or_update): Copy the name.
    * dirmngr/misc.c (copy_stream): Allow arg OUT to be NULL.
    * dirmngr/server.c (set_error): Protect CTX.
    (dirmngr_status): Protect against missing ASSUAN_CTX.
    (dirmngr_status_help): Ditto.
    (dirmngr_status_printf): Ditto.
    (cmd_wkd_get): Factor code out to ...
    (proc_wkd_get): new func.  Support silent operation with no CTX.
    (task_check_wkd_support): New.
    --
    
    This finalizes the feature to efficiently cache WKD checks.  If a
    standard WKD query returns no data, we queue a test to be run after
    the end of the session (so that we do not delay the calling client).
    This check tests whether the server responsible for the queried
    address has WKD at all enabled.  The test is done by checking whether
    the "policy" file exists.  We do not check the "submission-address"
    file because that is not necessary for the web key operation.  The
    policy file is now required.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c
index 90cdb85..a2effff 100644
--- a/dirmngr/domaininfo.c
+++ b/dirmngr/domaininfo.c
@@ -158,6 +158,7 @@ insert_or_update (const char *domain,
   di_new = xtrycalloc (1, sizeof *di + strlen (domain));
   if (!di_new)
     return;  /* Out of core - we ignore this.  */
+  strcpy (di_new->name, domain);
 
   /* Need to do another lookup because the malloc is a system call and
    * thus the hash array may have been changed by another thread.  */
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
index 857aab1..38cd02f 100644
--- a/dirmngr/ks-action.c
+++ b/dirmngr/ks-action.c
@@ -296,7 +296,8 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
 
 
 /* Retrieve keys from URL and write the result to the provided output
-   stream OUTFP.  */
+ * stream OUTFP.  If OUTFP is NULL the data is written to the bit
+ * bucket. */
 gpg_error_t
 ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
 {
diff --git a/dirmngr/misc.c b/dirmngr/misc.c
index 1716141..6291a9a 100644
--- a/dirmngr/misc.c
+++ b/dirmngr/misc.c
@@ -636,7 +636,9 @@ armor_data (char **r_string, const void *data, size_t datalen)
   return 0;
 }
 
-/* Copy all data from IN to OUT.  */
+
+/* Copy all data from IN to OUT.  OUT may be NULL to use this fucntion
+ * as a dummy reader.  */
 gpg_error_t
 copy_stream (estream_t in, estream_t out)
 {
@@ -647,9 +649,8 @@ copy_stream (estream_t in, estream_t out)
     {
       if (!nread)
         return 0; /* EOF */
-      if (es_write (out, buffer, nread, NULL))
+      if (out && es_write (out, buffer, nread, NULL))
         break;
-
     }
   return gpg_error_from_syserror ();
 }
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 1fbd007..3d0768b 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -80,7 +80,8 @@
 
 #define PARM_ERROR(t) assuan_set_error (ctx, \
                                         gpg_error (GPG_ERR_ASS_PARAMETER), (t))
-#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
+#define set_error(e,t) (ctx ? assuan_set_error (ctx, gpg_error (e), (t)) \
+                        /**/: gpg_error (e))
 
 
 
@@ -828,15 +829,11 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
 
 
 

-static const char hlp_wkd_get[] =
-  "WKD_GET [--submission-address|--policy-flags] <user_id>\n"
-  "\n"
-  "Return the key or other info for <user_id>\n"
-  "from the Web Key Directory.";
+/* Core of cmd_wkd_get and task_check_wkd_support.  If CTX is NULL
+ * this function will not write anything to the assuan output.  */
 static gpg_error_t
-cmd_wkd_get (assuan_context_t ctx, char *line)
+proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
 {
-  ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
   char *mbox = NULL;
   char *domainbuf = NULL;
@@ -895,7 +892,8 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
       domainlen = strlen (domain);
       for (i = 0; i < srvscount; i++)
         {
-          log_debug ("srv: trying '%s:%hu'\n", srvs[i].target, srvs[i].port);
+          if (DBG_DNS)
+            log_debug ("srv: trying '%s:%hu'\n", srvs[i].target, srvs[i].port);
           targetlen = strlen (srvs[i].target);
           if ((targetlen > domainlen + 1
                && srvs[i].target[targetlen - domainlen - 1] == '.'
@@ -972,19 +970,24 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
   {
     estream_t outfp;
 
-    outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
-    if (!outfp)
+    outfp = ctx? es_fopencookie (ctx, "w", data_line_cookie_functions) : NULL;
+    if (!outfp && ctx)
       err = set_error (GPG_ERR_ASS_GENERAL,
                        "error setting up a data stream");
     else
       {
-        if (no_log)
-          ctrl->server_local->inhibit_data_logging = 1;
-        ctrl->server_local->inhibit_data_logging_now = 0;
-        ctrl->server_local->inhibit_data_logging_count = 0;
+        if (ctrl->server_local)
+          {
+            if (no_log)
+              ctrl->server_local->inhibit_data_logging = 1;
+            ctrl->server_local->inhibit_data_logging_now = 0;
+            ctrl->server_local->inhibit_data_logging_count = 0;
+          }
         err = ks_action_fetch (ctrl, uri, outfp);
         es_fclose (outfp);
-        ctrl->server_local->inhibit_data_logging = 0;
+        if (ctrl->server_local)
+          ctrl->server_local->inhibit_data_logging = 0;
+
         /* Register the result under the domain name of MBOX. */
         switch (gpg_err_code (err))
           {
@@ -998,8 +1001,9 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
             break;
 
           case GPG_ERR_NO_DATA:
-            if (is_wkd_query) /* Mark that and schedule a check.  */
+            if (is_wkd_query && ctrl->server_local)
               {
+                /* Mark that and schedule a check.  */
                 domaininfo_set_wkd_not_found (domain_orig);
                 workqueue_add_task (task_check_wkd_support, domain_orig,
                                     ctrl->server_local->session_id, 1);
@@ -1020,6 +1024,23 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
   xfree (encodedhash);
   xfree (mbox);
   xfree (domainbuf);
+  return err;
+}
+
+
+static const char hlp_wkd_get[] =
+  "WKD_GET [--submission-address|--policy-flags] <user_id>\n"
+  "\n"
+  "Return the key or other info for <user_id>\n"
+  "from the Web Key Directory.";
+static gpg_error_t
+cmd_wkd_get (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  err = proc_wkd_get (ctrl, ctx, line);
+
   return leave_cmd (ctx, err);
 }
 
@@ -1029,10 +1050,19 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
 static const char *
 task_check_wkd_support (ctrl_t ctrl, const char *domain)
 {
+  char *string;
+
   if (!ctrl || !domain)
     return "check_wkd_support";
 
-  log_debug ("FIXME: Implement %s\n", __func__);
+  string = strconcat ("--policy-flags foo@", domain, NULL);
+  if (!string)
+    log_error ("%s: %s\n", __func__, gpg_strerror (gpg_error_from_syserror ()));
+  else
+    {
+      proc_wkd_get (ctrl, NULL, string);
+      xfree (string);
+    }
 
   return NULL;
 }
@@ -2800,12 +2830,12 @@ dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
   gpg_error_t err = 0;
   va_list arg_ptr;
   const char *text;
+  assuan_context_t ctx;
 
   va_start (arg_ptr, keyword);
 
-  if (ctrl->server_local)
+  if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx))
     {
-      assuan_context_t ctx = ctrl->server_local->assuan_ctx;
       char buf[950], *p;
       size_t n;
 
@@ -2835,10 +2865,10 @@ gpg_error_t
 dirmngr_status_help (ctrl_t ctrl, const char *text)
 {
   gpg_error_t err = 0;
+  assuan_context_t ctx;
 
-  if (ctrl->server_local)
+  if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx))
     {
-      assuan_context_t ctx = ctrl->server_local->assuan_ctx;
       char buf[950], *p;
       size_t n;
 
@@ -2888,7 +2918,10 @@ dirmngr_status_printf (ctrl_t ctrl, const char *keyword,
 {
   gpg_error_t err;
   va_list arg_ptr;
-  assuan_context_t ctx = ctrl->server_local->assuan_ctx;
+  assuan_context_t ctx;
+
+  if (!ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx))
+    return 0;
 
   va_start (arg_ptr, format);
   err = vprint_assuan_status (ctx, keyword, format, arg_ptr);

commit 96a4fbecd1acf946dcde20bef4752c539dae196b
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Nov 14 13:42:18 2017 +0100

    dirmngr: Add a background task framework.
    
    * dirmngr/workqueue.c: New.
    * dirmngr/Makefile.am (dirmngr_SOURCES): Add new file.
    * dirmngr/server.c (server_local_s): New field session_id.
    (cmd_wkd_get): Add a task.
    (task_check_wkd_support): New stub function.
    (cmd_getinfo): New sub-commands "session_id" and "workqueue".
    (start_command_handler): Add arg session_id and store it in
    SERVER_LOCAL.
    (dirmngr_status_helpf): New.
    * dirmngr/dirmngr.h (wqtask_t): New type.
    * dirmngr/dirmngr.c (main): Pass 0 as session_id to
    start_command_handler.
    (start_connection_thread): Introduce a session_id and pass it to
    start_command_handler.  Run post session tasks.
    (housekeeping_thread): Run global workqueue tasks.
    --
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am
index 421a325..43f59bd 100644
--- a/dirmngr/Makefile.am
+++ b/dirmngr/Makefile.am
@@ -60,6 +60,7 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
 dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c	\
 	certcache.c certcache.h \
 	domaininfo.c \
+	workqueue.c \
 	loadswdb.c \
 	cdb.h cdblib.c misc.c dirmngr-err.h  \
 	ocsp.c ocsp.h validate.c validate.h  \
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 2b64655..9cb0203 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -1134,7 +1134,7 @@ main (int argc, char **argv)
       cert_cache_init (hkp_cacert_filenames);
       crl_cache_init ();
       http_register_netactivity_cb (netactivity_action);
-      start_command_handler (ASSUAN_INVALID_FD);
+      start_command_handler (ASSUAN_INVALID_FD, 0);
       shutdown_reaper ();
     }
 #ifndef HAVE_W32_SYSTEM
@@ -1939,7 +1939,10 @@ housekeeping_thread (void *arg)
       network_activity_seen = 0;
       if (opt.allow_version_check)
         dirmngr_load_swdb (&ctrlbuf, 0);
+      workqueue_run_global_tasks (&ctrlbuf, 1);
     }
+  else
+    workqueue_run_global_tasks (&ctrlbuf, 0);
 
   dirmngr_deinit_default_ctrl (&ctrlbuf);
 
@@ -2034,6 +2037,8 @@ check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 static void *
 start_connection_thread (void *arg)
 {
+  static unsigned int last_session_id;
+  unsigned int session_id;
   union int_and_ptr_u argval;
   gnupg_fd_t fd;
 
@@ -2055,12 +2060,17 @@ start_connection_thread (void *arg)
   if (opt.verbose)
     log_info (_("handler for fd %d started\n"), FD2INT (fd));
 
-  start_command_handler (fd);
+  session_id = ++last_session_id;
+  if (!session_id)
+    session_id = ++last_session_id;
+  start_command_handler (fd, session_id);
 
   if (opt.verbose)
     log_info (_("handler for fd %d terminated\n"), FD2INT (fd));
   active_connections--;
 
+  workqueue_run_post_session_tasks (session_id);
+
 #ifndef HAVE_W32_SYSTEM
   argval.afd = ASSUAN_INVALID_FD;
   npth_setspecific (my_tlskey_current_fd, argval.aptr);
diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h
index b08e4fe..5189f93 100644
--- a/dirmngr/dirmngr.h
+++ b/dirmngr/dirmngr.h
@@ -228,9 +228,11 @@ ksba_cert_t get_cert_local_ski (ctrl_t ctrl,
 gpg_error_t get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr);
 int dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
                                 const char *msg);
-void start_command_handler (gnupg_fd_t fd);
+void start_command_handler (gnupg_fd_t fd, unsigned int session_id);
 gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...);
 gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text);
+gpg_error_t dirmngr_status_helpf (ctrl_t ctrl, const char *format,
+                                  ...) GPGRT_ATTR_PRINTF(2,3);
 gpg_error_t dirmngr_status_printf (ctrl_t ctrl, const char *keyword,
                                    const char *format,
                                    ...) GPGRT_ATTR_PRINTF(3,4);
@@ -258,6 +260,15 @@ void domaininfo_set_wkd_supported (const char *domain);
 void domaininfo_set_wkd_not_supported (const char *domain);
 void domaininfo_set_wkd_not_found (const char *domain);
 
+/*-- workqueue.c --*/
+typedef const char *(*wqtask_t)(ctrl_t ctrl, const char *args);
+
+void workqueue_dump_queue (ctrl_t ctrl);
+gpg_error_t workqueue_add_task (wqtask_t func, const char *args,
+                                unsigned int session_id, int need_network);
+void workqueue_run_global_tasks (ctrl_t ctrl, int with_network);
+void workqueue_run_post_session_tasks (unsigned int session_id);
+
 
 
 #endif /*DIRMNGR_H*/
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 18a5f72..1fbd007 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -90,6 +90,9 @@ struct server_local_s
   /* Data used to associate an Assuan context with local server data */
   assuan_context_t assuan_ctx;
 
+  /* The session id (a counter).  */
+  unsigned int session_id;
+
   /* Per-session LDAP servers.  */
   ldap_server_t ldapservers;
 
@@ -125,6 +128,9 @@ static es_cookie_io_functions_t data_line_cookie_functions =
   };
 
 
+/* Local prototypes */
+static const char *task_check_wkd_support (ctrl_t ctrl, const char *domain);
+
 
 
 

@@ -992,8 +998,12 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
             break;
 
           case GPG_ERR_NO_DATA:
-            if (is_wkd_query) /* Mark that - we will latter do a check.  */
-              domaininfo_set_wkd_not_found (domain_orig);
+            if (is_wkd_query) /* Mark that and schedule a check.  */
+              {
+                domaininfo_set_wkd_not_found (domain_orig);
+                workqueue_add_task (task_check_wkd_support, domain_orig,
+                                    ctrl->server_local->session_id, 1);
+              }
             else if (opt_policy_flags) /* No policy file - no support.  */
               domaininfo_set_wkd_not_supported (domain_orig);
             break;
@@ -1014,6 +1024,20 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
 }
 
 
+/* A task to check whether DOMAIN supports WKD.  This is done by
+ * checking whether the policy flags file can be read.  */
+static const char *
+task_check_wkd_support (ctrl_t ctrl, const char *domain)
+{
+  if (!ctrl || !domain)
+    return "check_wkd_support";
+
+  log_debug ("FIXME: Implement %s\n", __func__);
+
+  return NULL;
+}
+
+
 

 static const char hlp_ldapserver[] =
   "LDAPSERVER <data>\n"
@@ -2428,12 +2452,15 @@ static const char hlp_getinfo[] =
   "pid         - Return the process id of the server.\n"
   "tor         - Return OK if running in Tor mode\n"
   "dnsinfo     - Return info about the DNS resolver\n"
-  "socket_name - Return the name of the socket.\n";
+  "socket_name - Return the name of the socket.\n"
+  "session_id  - Return the current session_id.\n"
+  "workqueue   - Inspect the work queue\n";
 static gpg_error_t
 cmd_getinfo (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
+  char numbuf[50];
 
   if (!strcmp (line, "version"))
     {
@@ -2442,8 +2469,6 @@ cmd_getinfo (assuan_context_t ctx, char *line)
     }
   else if (!strcmp (line, "pid"))
     {
-      char numbuf[50];
-
       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
       err = assuan_send_data (ctx, numbuf, strlen (numbuf));
     }
@@ -2452,6 +2477,11 @@ cmd_getinfo (assuan_context_t ctx, char *line)
       const char *s = dirmngr_get_current_socket_name ();
       err = assuan_send_data (ctx, s, strlen (s));
     }
+  else if (!strcmp (line, "session_id"))
+    {
+      snprintf (numbuf, sizeof numbuf, "%u", ctrl->server_local->session_id);
+      err = assuan_send_data (ctx, numbuf, strlen (numbuf));
+    }
   else if (!strcmp (line, "tor"))
     {
       int use_tor;
@@ -2487,6 +2517,11 @@ cmd_getinfo (assuan_context_t ctx, char *line)
         }
       err = 0;
     }
+  else if (!strcmp (line, "workqueue"))
+    {
+      workqueue_dump_queue (ctrl);
+      err = 0;
+    }
   else
     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
 
@@ -2614,9 +2649,10 @@ dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
 
 
 /* Startup the server and run the main command loop.  With FD = -1,
-   use stdin/stdout. */
+ * use stdin/stdout.  SESSION_ID is either 0 or a unique number
+ * identifying a session.  */
 void
-start_command_handler (assuan_fd_t fd)
+start_command_handler (assuan_fd_t fd, unsigned int session_id)
 {
   static const char hello[] = "Dirmngr " VERSION " at your service";
   static char *hello_line;
@@ -2693,6 +2729,8 @@ start_command_handler (assuan_fd_t fd)
   assuan_register_option_handler (ctx, option_handler);
   assuan_register_reset_notify (ctx, reset_notify);
 
+  ctrl->server_local->session_id = session_id;
+
   for (;;)
     {
       rc = assuan_accept (ctx);
@@ -2792,8 +2830,7 @@ dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
 }
 
 
-/* Print a help status line.  TEXTLEN gives the length of the text
-   from TEXT to be printed.  The function splits text at LFs.  */
+/* Print a help status line.  The function splits text at LFs.  */
 gpg_error_t
 dirmngr_status_help (ctrl_t ctrl, const char *text)
 {
@@ -2823,6 +2860,26 @@ dirmngr_status_help (ctrl_t ctrl, const char *text)
 }
 
 
+/* Print a help status line using a printf like format.  The function
+ * splits text at LFs.  */
+gpg_error_t
+dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
+{
+  va_list arg_ptr;
+  gpg_error_t err;
+  char *buf;
+
+  va_start (arg_ptr, format);
+  buf = es_vbsprintf (format, arg_ptr);
+  err = buf? 0 : gpg_error_from_syserror ();
+  va_end (arg_ptr);
+  if (!err)
+    err = dirmngr_status_help (ctrl, buf);
+  es_free (buf);
+  return err;
+}
+
+
 /* This function is similar to print_assuan_status but takes a CTRL
  * arg instead of an assuan context as first argument.  */
 gpg_error_t
diff --git a/dirmngr/workqueue.c b/dirmngr/workqueue.c
new file mode 100644
index 0000000..2cb8573
--- /dev/null
+++ b/dirmngr/workqueue.c
@@ -0,0 +1,214 @@
+/* workqueue.c - Maintain a queue of background tasks
+ * Copyright (C) 2017 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0+
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dirmngr.h"
+
+
+/* An object for one item in the workqueue.  */
+struct wqitem_s
+{
+  struct wqitem_s *next;
+
+  /* This flag is set if the task requires network access.  */
+  unsigned int need_network:1;
+
+  /* The id of the session which created this task.  If this is 0 the
+   * task is not associated with a specific session.  */
+  unsigned int session_id;
+
+  /* The function to perform the backgrount task.  */
+  wqtask_t func;
+
+  /* A string with the string argument for that task.  */
+  char args[1];
+};
+typedef struct wqitem_s *wqitem_t;
+
+
+/* The workque is a simple linked list.  */
+static wqitem_t workqueue;
+
+
+/* Dump the queue using Assuan status comments.  */
+void
+workqueue_dump_queue (ctrl_t ctrl)
+{
+  wqitem_t saved_workqueue;
+  wqitem_t item;
+  unsigned int count;
+
+  /* Temporay detach the entiere workqueue so that other threads don't
+   * get into our way.  */
+  saved_workqueue = workqueue;
+  workqueue = NULL;
+
+  for (count=0, item = saved_workqueue; item; item = item->next)
+    count++;
+
+  dirmngr_status_helpf (ctrl, "wq: number of entries: %u", count);
+  for (item = saved_workqueue; item; item = item->next)
+    dirmngr_status_helpf (ctrl, "wq: sess=%u net=%d %s(\"%.100s%s\")",
+                          item->session_id, item->need_network,
+                          item->func? item->func (NULL, NULL): "nop",
+                          item->args, strlen (item->args) > 100? "[...]":"");
+
+  /* Restore then workqueue.  Actually we append the saved queue do a
+   * possibly updated workqueue.  */
+  if (!(item=workqueue))
+    workqueue = saved_workqueue;
+  else
+    {
+      while (item->next)
+        item = item->next;
+      item->next = saved_workqueue;
+    }
+}
+
+
+/* Append the task (FUNC,ARGS) to the work queue.  FUNC shall return
+ * its name when called with (NULL, NULL).  */
+gpg_error_t
+workqueue_add_task (wqtask_t func, const char *args, unsigned int session_id,
+                    int need_network)
+{
+  wqitem_t item, wi;
+
+  item = xtrycalloc (1, sizeof *item + strlen (args));
+  if (!item)
+    return gpg_error_from_syserror ();
+  strcpy (item->args, args);
+  item->func = func;
+  item->session_id = session_id;
+  item->need_network = !!need_network;
+
+  if (!(wi=workqueue))
+    workqueue = item;
+  else
+    {
+      while (wi->next)
+        wi = wi->next;
+      wi->next = item;
+    }
+  return 0;
+}
+
+
+/* Run the task described by ITEM.  ITEM must have been detached from
+ * the workqueue; its ownership is transferred to this fucntion.  */
+static void
+run_a_task (ctrl_t ctrl, wqitem_t item)
+{
+  log_assert (!item->next);
+
+  if (opt.verbose)
+    log_info ("session %u: running %s(\"%s%s\")\n",
+              item->session_id,
+              item->func? item->func (NULL, NULL): "nop",
+              item->args, strlen (item->args) > 100? "[...]":"");
+  if (item->func)
+    item->func (ctrl, item->args);
+
+  xfree (item);
+}
+
+
+/* Run tasks not associated with a session.  This is called from the
+ * ticker every few minutes.  If WITH_NETWORK is not set tasks which
+ * require the network are not run.  */
+void
+workqueue_run_global_tasks (ctrl_t ctrl, int with_network)
+{
+  wqitem_t item, prev;
+
+  with_network = !!with_network;
+
+  if (opt.verbose)
+    log_info ("running scheduled tasks%s\n", with_network?" (with network)":"");
+
+  for (;;)
+    {
+      prev = NULL;
+      for (item = workqueue; item; prev = item, item = item->next)
+        if (!item->session_id
+            && (!item->need_network || (item->need_network && with_network)))
+          break;
+      if (!item)
+        break;  /* No more tasks to run.  */
+
+      /* Detach that item from the workqueue.  */
+      if (!prev)
+        workqueue = item->next;
+      else
+        prev->next = item->next;
+      item->next = NULL;
+
+      /* Run the task.  */
+      run_a_task (ctrl, item);
+    }
+}
+
+
+/* Run tasks scheduled for running after a session.  Those tasks are
+ * identified by the SESSION_ID.  */
+void
+workqueue_run_post_session_tasks (unsigned int session_id)
+{
+  struct server_control_s ctrlbuf;
+  ctrl_t ctrl = NULL;
+  wqitem_t item, prev;
+
+  if (!session_id)
+    return;
+
+  for (;;)
+    {
+      prev = NULL;
+      for (item = workqueue; item; prev = item, item = item->next)
+        if (item->session_id == session_id)
+          break;
+      if (!item)
+        break;  /* No more tasks for this session.  */
+
+      /* Detach that item from the workqueue.  */
+      if (!prev)
+        workqueue = item->next;
+      else
+        prev->next = item->next;
+      item->next = NULL;
+
+      /* Create a CTRL object the first time we need it.  */
+      if (!ctrl)
+        {
+          memset (&ctrlbuf, 0, sizeof ctrlbuf);
+          ctrl = &ctrlbuf;
+          dirmngr_init_default_ctrl (ctrl);
+        }
+
+      /* Run the task.  */
+      run_a_task (ctrl, item);
+    }
+
+  dirmngr_deinit_default_ctrl (ctrl);
+}

commit 26f08343fbccdbaa177c3507a3c5e24a5cf94a2d
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Nov 14 08:37:27 2017 +0100

    dirmngr: Limit the number of cached domains for WKD.
    
    * dirmngr/domaininfo.c (MAX_DOMAINBUCKET_LEN): New.
    (insert_or_update): Limit the length of a bucket chain.
    (domaininfo_print_stats): Print just one summary line.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c
index 393db8c..90cdb85 100644
--- a/dirmngr/domaininfo.c
+++ b/dirmngr/domaininfo.c
@@ -26,7 +26,18 @@
 #include "dirmngr.h"
 
 
-#define NO_OF_DOMAINBUCKETS 103
+/* Number of bucket for the hash array and limit for the length of a
+ * bucket chain.  For debugging values of 13 and 10 are more suitable
+ * and a command like
+ *   for j   in a b c d e f g h i j k l m n o p q r s t u v w z y z; do \
+ *     for i in a b c d e f g h i j k l m n o p q r s t u v w z y z; do \
+ *       gpg-connect-agent --dirmngr "wkd_get foo@$i.$j.gnupg.net" /bye \
+ *       >/dev/null ; done; done
+ * will quickly add a couple of domains.
+ */
+#define NO_OF_DOMAINBUCKETS  103
+#define MAX_DOMAINBUCKET_LEN  20
+
 
 /* Object to keep track of a domain name.  */
 struct domaininfo_s
@@ -74,13 +85,18 @@ domaininfo_print_stats (void)
   int bidx;
   domaininfo_t di;
   int count, no_name, wkd_not_found, wkd_supported, wkd_not_supported;
+  int len, minlen, maxlen;
 
+  count = no_name = wkd_not_found = wkd_supported = wkd_not_supported = 0;
+  maxlen = 0;
+  minlen = -1;
   for (bidx = 0; bidx < NO_OF_DOMAINBUCKETS; bidx++)
     {
-      count = no_name = wkd_not_found = wkd_supported = wkd_not_supported = 0;
+      len = 0;
       for (di = domainbuckets[bidx]; di; di = di->next)
         {
           count++;
+          len++;
           if (di->no_name)
             no_name++;
           if (di->wkd_not_found)
@@ -90,11 +106,16 @@ domaininfo_print_stats (void)
           if (di->wkd_not_supported)
             wkd_not_supported++;
         }
-      if (count)
-        log_info ("domaininfo: chain %3d length=%d nn=%d nf=%d s=%d ns=%d\n",
-                  bidx, count, no_name,
-                  wkd_not_found, wkd_supported, wkd_not_supported);
+      if (len > maxlen)
+        maxlen = len;
+      if (minlen == -1 || len < minlen)
+        minlen = len;
     }
+  log_info ("domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
+            count,
+            minlen > 0? minlen : 0,
+            maxlen,
+            no_name, wkd_not_found, wkd_not_supported, wkd_supported);
 }
 
 
@@ -122,7 +143,9 @@ insert_or_update (const char *domain,
 {
   domaininfo_t di;
   domaininfo_t di_new;
+  domaininfo_t di_cut;
   u32 hash;
+  int count;
 
   hash = hash_domain (domain);
   for (di = domainbuckets[hash]; di; di = di->next)
@@ -138,7 +161,8 @@ insert_or_update (const char *domain,
 
   /* Need to do another lookup because the malloc is a system call and
    * thus the hash array may have been changed by another thread.  */
-  for (di = domainbuckets[hash]; di; di = di->next)
+  di_cut = NULL;
+  for (count=0, di = domainbuckets[hash]; di; di = di->next, count++)
     if (!strcmp (di->name, domain))
       {
         callback (di, 0);  /* Update */
@@ -146,10 +170,32 @@ insert_or_update (const char *domain,
         return;
       }
 
-  callback (di_new, 1);  /* Insert */
+  /* Before we insert we need to check whether the chain gets too long.  */
+  di_cut = NULL;
+  if (count >= MAX_DOMAINBUCKET_LEN)
+    {
+      for (count=0, di = domainbuckets[hash]; di; di = di->next, count++)
+        if (count >= MAX_DOMAINBUCKET_LEN/2)
+          {
+            di_cut = di->next;
+            di->next = NULL;
+            break;
+          }
+    }
+
+  /* Insert */
+  callback (di_new, 1);
   di = di_new;
   di->next = domainbuckets[hash];
   domainbuckets[hash] = di;
+
+  /* Remove the rest of the cutted chain.  */
+  while (di_cut)
+    {
+      di = di_cut->next;
+      xfree (di_cut);
+      di_cut = di;
+    }
 }
 
 

-----------------------------------------------------------------------

Summary of changes:
 dirmngr/Makefile.am  |   1 +
 dirmngr/dirmngr.c    |  14 +++-
 dirmngr/dirmngr.h    |  13 +++-
 dirmngr/domaininfo.c |  63 +++++++++++++--
 dirmngr/ks-action.c  |   3 +-
 dirmngr/misc.c       |   7 +-
 dirmngr/server.c     | 150 ++++++++++++++++++++++++++++--------
 dirmngr/workqueue.c  | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 420 insertions(+), 45 deletions(-)
 create mode 100644 dirmngr/workqueue.c


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list