From 6c058fac65c7e9d1ffb72686f0f02644f172da22 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 18 Mar 2014 11:07:05 +0100 Subject: [PATCH] dirmngr: Resurrect hosts in the HKP hosttable. * 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 | 89 ++++++++++++++++++++++++++++++++++------- dirmngr/dirmngr.h | 19 ++++++--- dirmngr/ks-engine-hkp.c | 62 ++++++++++++++++++++++++++-- 3 files changed, 145 insertions(+), 25 deletions(-) diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index e3f98c04e..ab657202c 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -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 . */ #include @@ -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); + } + } } diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 4f5cbd1d7..bb368f252 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -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*/ diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index e485e6288..fa616a0c0 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -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