dirmngr: Resurrect hosts in the HKP hosttable.
authorWerner Koch <wk@gnupg.org>
Tue, 18 Mar 2014 10:07:05 +0000 (11:07 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 18 Mar 2014 10:07:05 +0000 (11:07 +0100)
* dirmngr/dirmngr.c (HOUSEKEEPING_INTERVAL): New.
(housekeeping_thread): New.
(handle_tick): Call new function.
* dirmngr/ks-engine-hkp.c (RESURRECT_INTERVAL): New.
(struct hostinfo_s): Add field died_at and set it along with the dead
flag.
(ks_hkp_print_hosttable): Print that info.
(ks_hkp_housekeeping): New.
--

The resurrection gives the host a chance to get back to life the next
time a new host is selected.

dirmngr/dirmngr.c
dirmngr/dirmngr.h
dirmngr/ks-engine-hkp.c

index e3f98c0..ab65720 100644 (file)
@@ -1,23 +1,22 @@
 /* dirmngr.c - LDAP access
- *     Copyright (C) 2002 Klarälvdalens Datakonsult AB
- *      Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH
+ * Copyright (C) 2002 Klarälvdalens Datakonsult AB
+ * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH
+ * Copyright (C) 2014 Werner Koch
  *
- * This file is part of DirMngr.
+ * This file is part of GnuPG.
  *
- * DirMngr is free software; you can redistribute it and/or modify
+ * 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 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
- * DirMngr is distributed in the hope that it will be useful,
+ * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -243,9 +242,7 @@ static int active_connections;
 
 /* The timer tick used for housekeeping stuff.  For Windows we use a
    longer period as the SetWaitableTimer seems to signal earlier than
-   the 2 seconds.  CHECK_OWN_SOCKET_INTERVAL defines how often we
-   check our own socket in standard socket mode.  If that value is 0
-   we don't check at all.   All values are in seconds. */
+   the 2 seconds.  All values are in seconds. */
 #if defined(HAVE_W32CE_SYSTEM)
 # define TIMERTICK_INTERVAL         (60)
 #elif defined(HAVE_W32_SYSTEM)
@@ -254,6 +251,9 @@ static int active_connections;
 # define TIMERTICK_INTERVAL          (2)
 #endif
 
+#define HOUSEKEEPING_INTERVAL      (600)
+
+
 /* This union is used to avoid compiler warnings in case a pointer is
    64 bit and an int 32 bit.  We store an integer in a pointer and get
    it back later (npth_getspecific et al.).  */
@@ -1657,14 +1657,49 @@ handle_signal (int signo)
 #endif /*!HAVE_W32_SYSTEM*/
 
 
+/* Thread to do the housekeeping.  */
+static void *
+housekeeping_thread (void *arg)
+{
+  static int sentinel;
+  time_t curtime;
+
+  (void)arg;
+
+  curtime = gnupg_get_time ();
+  if (sentinel)
+    {
+      log_info ("housekeeping is already going on\n");
+      return NULL;
+    }
+  sentinel++;
+  if (opt.verbose)
+    log_info ("starting housekeeping\n");
+
+  ks_hkp_housekeeping (curtime);
+
+  if (opt.verbose)
+    log_info ("ready with housekeeping\n");
+  sentinel--;
+  return NULL;
+
+}
+
+
 /* This is the worker for the ticker.  It is called every few seconds
    and may only do fast operations. */
 static void
 handle_tick (void)
 {
-  /* Nothing real to do right now.  Actually we need the timeout only
-     for W32 where we don't use signals and need a way for the loop to
-     check for the shutdown flag. */
+  static time_t last_housekeeping;
+  time_t curtime;
+
+  curtime = gnupg_get_time ();
+  if (!last_housekeeping)
+    last_housekeeping = curtime;
+
+  /* Under Windows we don't use signals and need a way for the loop to
+     check for the shutdown flag.  */
 #ifdef HAVE_W32_SYSTEM
   if (shutdown_pending)
     log_info (_("SIGTERM received - shutting down ...\n"));
@@ -1676,6 +1711,30 @@ handle_tick (void)
       dirmngr_exit (0);
     }
 #endif /*HAVE_W32_SYSTEM*/
+
+  /* Start a housekeeping thread every 10 minutes  */
+  if (last_housekeeping + HOUSEKEEPING_INTERVAL <= curtime
+      || last_housekeeping > curtime /*(be prepared for y2038)*/)
+    {
+      npth_t thread;
+      npth_attr_t tattr;
+      int err;
+
+      last_housekeeping = curtime;
+
+      err = npth_attr_init (&tattr);
+      if (err)
+        log_error ("error preparing housekeeping thread: %s\n", strerror (err));
+      else
+        {
+          npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
+          err = npth_create (&thread, &tattr, housekeeping_thread, NULL);
+          if (err)
+            log_error ("error spawning housekeeping thread: %s\n",
+                       strerror (err));
+          npth_attr_destroy (&tattr);
+        }
+    }
 }
 
 
index 4f5cbd1..bb368f2 100644 (file)
@@ -1,15 +1,16 @@
 /* dirmngr.h - Common definitions for the dirmngr
- *     Copyright (C) 2002 Klarälvdalens Datakonsult AB
- *     Copyright (C) 2004 g10 Code GmbH
+ * Copyright (C) 2002 Klarälvdalens Datakonsult AB
+ * Copyright (C) 2004 g10 Code GmbH
+ * Copyright (C) 2014 Werner Koch
  *
- * This file is part of DirMngr.
+ * This file is part of GnuPG.
  *
- * DirMngr is free software; you can redistribute it and/or modify
+ * 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 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
- * DirMngr is distributed in the hope that it will be useful,
+ * 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.
@@ -183,6 +184,11 @@ void dirmngr_exit( int );  /* Wrapper for exit() */
 void dirmngr_init_default_ctrl (ctrl_t ctrl);
 void dirmngr_sighup_action (void);
 
+
+/*-- Various housekeeping functions.  --*/
+void ks_hkp_housekeeping (time_t curtime);
+
+
 /*-- server.c --*/
 ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl);
 ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer);
@@ -196,4 +202,5 @@ gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text);
 gpg_error_t dirmngr_tick (ctrl_t ctrl);
 
 
+
 #endif /*DIRMNGR_H*/
index e485e62..fa616a0 100644 (file)
@@ -46,6 +46,9 @@
 #endif
 
 
+/* Number of seconds after a host is marked as resurrected.  */
+#define RESURRECT_INTERVAL  (3600*3)  /* 3 hours */
+
 /* To match the behaviour of our old gpgkeys helper code we escape
    more characters than actually needed. */
 #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
@@ -70,6 +73,8 @@ struct hostinfo_s
   unsigned int v4:1; /* Host supports AF_INET.  */
   unsigned int v6:1; /* Host supports AF_INET6.  */
   unsigned int dead:1; /* Host is currently unresponsive.  */
+  time_t died_at;    /* The time the host was marked dead.  IF this is
+                        0 the host has been manually marked dead.  */
   char name[1];      /* The hostname.  */
 };
 
@@ -104,6 +109,7 @@ create_new_hostinfo (const char *name)
   hi->v4 = 0;
   hi->v6 = 0;
   hi->dead = 0;
+  hi->died_at = 0;
 
   /* Add it to the hosttable. */
   for (idx=0; idx < hosttable_size; idx++)
@@ -465,6 +471,9 @@ mark_host_dead (const char *name)
           log_info ("marking host '%s' as dead%s\n",
                     hi->name, hi->dead? " (again)":"");
           hi->dead = 1;
+          hi->died_at = gnupg_get_time ();
+          if (!hi->died_at)
+            hi->died_at = 1;
           done = 1;
         }
     }
@@ -500,6 +509,7 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
   else if (!alive && !hi->dead)
     {
       hi->dead = 1;
+      hi->died_at = 0; /* Manually set dead.  */
       err = ks_printf_help (ctrl, "marking '%s' as dead", name);
     }
 
@@ -538,6 +548,7 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
           else if (!alive && !hi2->dead)
             {
               hi2->dead = 1;
+              hi2->died_at = 0; /* Manually set dead. */
               err = ks_printf_help (ctrl, "marking '%s' as dead",
                                     hi2->name);
             }
@@ -556,18 +567,33 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
   int idx, idx2;
   hostinfo_t hi;
   membuf_t mb;
-  char *p;
+  time_t curtime;
+  char *p, *died;
+  const char *diedstr;
 
-  err = ks_print_help (ctrl, "hosttable (idx, ipv4, ipv6, dead, name):");
+  err = ks_print_help (ctrl, "hosttable (idx, ipv4, ipv6, dead, name, time):");
   if (err)
     return err;
 
+  curtime = gnupg_get_time ();
   for (idx=0; idx < hosttable_size; idx++)
     if ((hi=hosttable[idx]))
       {
-        err = ks_printf_help (ctrl, "%3d %s %s %s %s\n",
+        if (hi->dead && hi->died_at)
+          {
+            died = elapsed_time_string (hi->died_at, curtime);
+            diedstr = died? died : "error";
+          }
+        else
+          diedstr = died = NULL;
+        err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s\n",
                               idx, hi->v4? "4":" ", hi->v6? "6":" ",
-                              hi->dead? "d":" ", hi->name);
+                              hi->dead? "d":" ", hi->name,
+                              diedstr? "  (":"",
+                              diedstr? diedstr:"",
+                              diedstr? ")":""   );
+        xfree (died);
+
         if (err)
           return err;
         if (hi->pool)
@@ -682,6 +708,34 @@ ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
 }
 
 
+/* Housekeeping function called from the housekeeping thread.  It is
+   used to mark dead hosts alive so that they may be tried again after
+   some time.  */
+void
+ks_hkp_housekeeping (time_t curtime)
+{
+  int idx;
+  hostinfo_t hi;
+
+  for (idx=0; idx < hosttable_size; idx++)
+    {
+      hi = hosttable[idx];
+      if (!hi)
+        continue;
+      if (!hi->dead)
+        continue;
+      if (!hi->died_at)
+        continue; /* Do not resurrect manually shot hosts.  */
+      if (hi->died_at + RESURRECT_INTERVAL <= curtime
+          || hi->died_at > curtime)
+        {
+          hi->dead = 0;
+          log_info ("resurrected host '%s'", hi->name);
+        }
+    }
+}
+
+
 /* Send an HTTP request.  On success returns an estream object at
    R_FP.  HOSTPORTSTR is only used for diagnostics.  If POST_CB is not
    NULL a post request is used and that callback is called to allow