tests, OKs?

diff --git configlexer.lex configlexer.lex
index e6b26f947e1..42dbd152f16 100644
--- configlexer.lex
+++ configlexer.lex
@@ -66,15 +66,6 @@ static void config_start_include(const char* filename)
                c_error_msg("include %s: malloc failure", filename);
                return;
        }
-       if (cfg_parser->chroot) {
-               int l = strlen(cfg_parser->chroot); /* chroot has trailing 
slash */
-               if (strncmp(cfg_parser->chroot, filename, l) != 0) {
-                       c_error_msg("include file '%s' is not relative to 
chroot '%s'",
-                               filename, cfg_parser->chroot);
-                       return;
-               }
-               filename += l - 1; /* strip chroot without trailing slash */
-       }
        nm = strdup(filename);
        if(!nm) {
                c_error_msg("include %s: strdup failure", filename);
@@ -103,12 +94,23 @@ static void config_start_include(const char* filename)
 
 static void config_start_include_glob(const char* filename)
 {
-        /* check for wildcards */
+       /* check for wildcards */
 #ifdef HAVE_GLOB
-        glob_t g;
-        size_t i;
-        int r, flags;
-        if(!(!strchr(filename, '*') && !strchr(filename, '?') &&
+       glob_t g;
+       size_t i;
+       int r, flags;
+#endif /* HAVE_GLOB */
+       if (cfg_parser->chroot) {
+               int l = strlen(cfg_parser->chroot); /* chroot has trailing 
slash */
+               if (strncmp(cfg_parser->chroot, filename, l) != 0) {
+                       c_error_msg("include file '%s' is not relative to 
chroot '%s'",
+                               filename, cfg_parser->chroot);
+                       return;
+               }
+               filename += l - 1; /* strip chroot without trailing slash */
+       }
+#ifdef HAVE_GLOB
+       if(!(!strchr(filename, '*') && !strchr(filename, '?') &&
                 !strchr(filename, '[') && !strchr(filename, '{') &&
                 !strchr(filename, '~'))) {
                 flags = 0
@@ -141,9 +143,9 @@ static void config_start_include_glob(const char* filename)
                }
                globfree(&g);
                return;
-        }
+       }
 #endif /* HAVE_GLOB */
-        config_start_include(filename);
+       config_start_include(filename);
 }
 
 static void config_end_include(void)
diff --git configure configure
index 41bb666a9fc..7d220882e2f 100644
--- configure
+++ configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for NSD 4.1.13.
+# Generated by GNU Autoconf 2.69 for NSD 4.1.14.
 #
 # Report bugs to <nsd-b...@nlnetlabs.nl>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NSD'
 PACKAGE_TARNAME='nsd'
-PACKAGE_VERSION='4.1.13'
-PACKAGE_STRING='NSD 4.1.13'
+PACKAGE_VERSION='4.1.14'
+PACKAGE_STRING='NSD 4.1.14'
 PACKAGE_BUGREPORT='nsd-b...@nlnetlabs.nl'
 PACKAGE_URL=''
 
@@ -1284,7 +1284,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures NSD 4.1.13 to adapt to many kinds of systems.
+\`configure' configures NSD 4.1.14 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1345,7 +1345,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NSD 4.1.13:";;
+     short | recursive ) echo "Configuration of NSD 4.1.14:";;
    esac
   cat <<\_ACEOF
 
@@ -1491,7 +1491,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NSD configure 4.1.13
+NSD configure 4.1.14
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2200,7 +2200,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by NSD $as_me 4.1.13, which was
+It was created by NSD $as_me 4.1.14, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -9717,7 +9717,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by NSD $as_me 4.1.13, which was
+This file was extended by NSD $as_me 4.1.14, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -9779,7 +9779,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-NSD config.status 4.1.13
+NSD config.status 4.1.14
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git configure.ac configure.ac
index e2aca4d531e..029193574f0 100644
--- configure.ac
+++ configure.ac
@@ -4,7 +4,7 @@ dnl
 
 sinclude(acx_nlnetlabs.m4)
 
-AC_INIT(NSD,4.1.13,nsd-b...@nlnetlabs.nl)
+AC_INIT(NSD,4.1.14,nsd-b...@nlnetlabs.nl)
 AC_CONFIG_HEADER([config.h])
 
 CFLAGS="$CFLAGS"
diff --git radtree.c radtree.c
index 8ca4a5bd5ba..fd003795a4a 100644
--- radtree.c
+++ radtree.c
@@ -636,11 +636,13 @@ radnode_cleanup_onechild(struct region* region, struct 
radnode* n,
                return 0;
        }
        /* we know that .str and join are malloced, thus aligned */
-       memcpy(join, par->array[pidx].str, par->array[pidx].len);
+       if(par->array[pidx].str)
+           memcpy(join, par->array[pidx].str, par->array[pidx].len);
        /* the array lookup is gone, put its character in the lookup string*/
        join[par->array[pidx].len] = child->pidx + n->offset;
        /* but join+len may not be aligned */
-       memmove(join+par->array[pidx].len+1, n->array[0].str, n->array[0].len);
+       if(n->array[0].str)
+           memmove(join+par->array[pidx].len+1, n->array[0].str, 
n->array[0].len);
        region_recycle(region, par->array[pidx].str, par->array[pidx].len);
        par->array[pidx].str = join;
        par->array[pidx].len = joinlen;
diff --git remote.c remote.c
index d961dbf4146..baa9985389a 100644
--- remote.c
+++ remote.c
@@ -1469,7 +1469,7 @@ repat_interrupt_zones(xfrd_state_t* xfrd, nsd_options_t* 
newopt)
                        xz->master = 0;
                        xz->master_num = 0;
                        xz->next_master = -1;
-                       xz->round_num = 0; /* fresh set of retries */
+                       xz->round_num = -1; /* fresh set of retries */
                }
        }
        /* if notify list changed:
diff --git xfrd-disk.c xfrd-disk.c
index c724a2c9cc6..a86240d4a57 100644
--- xfrd-disk.c
+++ xfrd-disk.c
@@ -165,8 +165,15 @@ xfrd_read_state(struct xfrd_state* xfrd)
                region_destroy(tempregion);
                return;
        }
-       if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC) ||
-          !xfrd_read_check_str(in, "filetime:") ||
+       if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) {
+               /* older file version; reset everything */
+               DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: file %s is old version. 
refreshing all zones.",
+                       statefile));
+               fclose(in);
+               region_destroy(tempregion);
+               return;
+       }
+       if(!xfrd_read_check_str(in, "filetime:") ||
           !xfrd_read_i32(in, &filetime) ||
           (time_t)filetime > xfrd_time()+15 ||
           !xfrd_read_check_str(in, "numzones:") ||
@@ -183,7 +190,7 @@ xfrd_read_state(struct xfrd_state* xfrd)
                char *p;
                xfrd_zone_t* zone;
                const dname_type* dname;
-               uint32_t state, masnum, nextmas, round_num, timeout;
+               uint32_t state, masnum, nextmas, round_num, timeout, backoff;
                xfrd_soa_t soa_nsd_read, soa_disk_read, soa_notified_read;
                time_t soa_nsd_acquired_read,
                        soa_disk_acquired_read, soa_notified_acquired_read;
@@ -214,6 +221,8 @@ xfrd_read_state(struct xfrd_state* xfrd)
                   !xfrd_read_i32(in, &round_num) ||
                   !xfrd_read_check_str(in, "next_timeout:") ||
                   !xfrd_read_i32(in, &timeout) ||
+                  !xfrd_read_check_str(in, "backoff:") ||
+                  !xfrd_read_i32(in, &backoff) ||
                   !xfrd_read_state_soa(in, "soa_nsd_acquired:", "soa_nsd:",
                        &soa_nsd_read, &soa_nsd_acquired_read) ||
                   !xfrd_read_state_soa(in, "soa_disk_acquired:", "soa_disk:",
@@ -249,6 +258,7 @@ xfrd_read_state(struct xfrd_state* xfrd)
                zone->round_num = round_num;
                zone->timeout.tv_sec = timeout;
                zone->timeout.tv_usec = 0;
+               zone->fresh_xfr_timeout = backoff*XFRD_TRANSFER_TIMEOUT_START;
 
                /* read the zone OK, now set the master properly */
                zone->master = acl_find_num(zone->zone_options->pattern->
@@ -296,10 +306,14 @@ xfrd_read_state(struct xfrd_state* xfrd)
                        zone->state = state;
                        xfrd_set_timer(zone, timeout);
                }       
-               if(zone->soa_nsd_acquired == 0 && soa_nsd_acquired_read == 0 &&
-                       soa_disk_acquired_read == 0) {
-                       /* continue expon backoff where we were + check now */
-                       zone->fresh_xfr_timeout = timeout;
+               if((zone->soa_nsd_acquired == 0 && soa_nsd_acquired_read == 0 &&
+                       soa_disk_acquired_read == 0) ||
+                       (zone->state != xfrd_zone_ok && timeout != 0)) {
+                       /* but don't check now, because that would mean a
+                        * storm of attempts on some master servers */
+                       xfrd_deactivate_zone(zone);
+                       zone->state = state;
+                       xfrd_set_timer(zone, timeout);
                }
 
                /* handle as an incoming SOA. */
@@ -318,7 +332,8 @@ xfrd_read_state(struct xfrd_state* xfrd)
                {
                        xfrd_send_expire_notification(zone);
                }
-               xfrd_handle_incoming_soa(zone, &incoming_soa, 
incoming_acquired);
+               if(incoming_acquired != 0)
+                       xfrd_handle_incoming_soa(zone, &incoming_soa, 
incoming_acquired);
        }
 
        if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) {
@@ -477,6 +492,7 @@ xfrd_write_state(struct xfrd_state* xfrd)
                        neato_timeout(out, "\t# =", zone->timeout.tv_sec);
                }
                fprintf(out, "\n");
+               fprintf(out, "\tbackoff: %d\n", 
zone->fresh_xfr_timeout/XFRD_TRANSFER_TIMEOUT_START);
                xfrd_write_state_soa(out, "soa_nsd", &zone->soa_nsd,
                        zone->soa_nsd_acquired, zone->apex);
                xfrd_write_state_soa(out, "soa_disk", &zone->soa_disk,
diff --git xfrd-disk.h xfrd-disk.h
index b7e2d10b237..acd4e4c8333 100644
--- xfrd-disk.h
+++ xfrd-disk.h
@@ -14,7 +14,7 @@ struct xfrd_state;
 struct nsd;
 
 /* magic string to identify xfrd state file */
-#define XFRD_FILE_MAGIC "NSDXFRD1"
+#define XFRD_FILE_MAGIC "NSDXFRD2"
 
 /* read from state file as many zones as possible (until error/eof).*/
 void xfrd_read_state(struct xfrd_state* xfrd);
diff --git xfrd-tcp.c xfrd-tcp.c
index a4a7a23fe29..506b2520589 100644
--- xfrd-tcp.c
+++ xfrd-tcp.c
@@ -490,6 +490,14 @@ xfrd_tcp_open(xfrd_tcp_set_t* set, struct 
xfrd_tcp_pipeline* tp,
        int fd, family, conn;
        struct timeval tv;
        assert(zone->tcp_conn != -1);
+
+       /* if there is no next master, fallback to use the first one */
+       /* but there really should be a master set */
+       if(!zone->master) {
+               zone->master = zone->zone_options->pattern->request_xfr;
+               zone->master_num = 0;
+       }
+
        DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s open tcp conn to %s",
                zone->apex_str, zone->master->ip_address_spec));
        tp->tcp_r->is_reading = 1;
@@ -879,7 +887,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
                        assert(zone->round_num == -1);
                        break;
                case xfrd_packet_notimpl:
-                       zone->master->ixfr_disabled = time(NULL);
+                       xfrd_disable_ixfr(zone);
                        xfrd_tcp_release(xfrd->tcp_set, zone);
                        /* query next server */
                        xfrd_make_request(zone);
diff --git xfrd.c xfrd.c
index a0b34446ae5..415602f014b 100644
--- xfrd.c
+++ xfrd.c
@@ -30,13 +30,11 @@
 #include "ipc.h"
 #include "remote.h"
 
-#define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 
2*x seconds */
-#define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */
 #define XFRD_UDP_TIMEOUT 10 /* seconds, before a udp request times out */
 #define XFRD_NO_IXFR_CACHE 172800 /* 48h before retrying ixfr's after notimpl 
*/
 #define XFRD_LOWERBOUND_REFRESH 1 /* seconds, smallest refresh timeout */
 #define XFRD_LOWERBOUND_RETRY 1 /* seconds, smallest retry timeout */
-#define XFRD_MAX_ROUNDS 3 /* max number of rounds along the masters */
+#define XFRD_MAX_ROUNDS 1 /* max number of rounds along the masters */
 #define XFRD_TSIG_MAX_UNSIGNED 103 /* max number of packets without tsig in a 
tcp stream. */
                        /* rfc recommends 100, +3 for offbyone 
errors/interoperability. */
 #define XFRD_CHILD_REAP_TIMEOUT 60 /* seconds to wakeup and reap lost children 
*/
@@ -412,7 +410,7 @@ xfrd_init_slave_zone(xfrd_state_t* xfrd, zone_options_t* 
zone_opt)
        xzone->state = xfrd_zone_refreshing;
        xzone->zone_options = zone_opt;
        /* first retry will use first master */
-       xzone->master = 0;
+       xzone->master = xzone->zone_options->pattern->request_xfr;
        xzone->master_num = 0;
        xzone->next_master = 0;
        xzone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START;
@@ -727,11 +725,24 @@ static void
 xfrd_set_timer_retry(xfrd_zone_t* zone)
 {
        time_t set_retry;
+       int mult;
+       /* perform exponential backoff in all the cases */
+       if(zone->fresh_xfr_timeout == 0)
+               zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START;
+       else {
+               /* exponential backoff - some master data in zones is paid-for
+                  but non-working, and will not get fixed. */
+               zone->fresh_xfr_timeout *= 2;
+               if(zone->fresh_xfr_timeout > XFRD_TRANSFER_TIMEOUT_MAX)
+                       zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_MAX;
+       }
+       /* exponential backoff multiplier, starts at 1, backs off */
+       mult = zone->fresh_xfr_timeout / XFRD_TRANSFER_TIMEOUT_START;
+       if(mult == 0) mult = 1;
+
        /* set timer for next retry or expire timeout if earlier. */
        if(zone->soa_disk_acquired == 0) {
                /* if no information, use reasonable timeout */
-               if(zone->fresh_xfr_timeout == 0)
-                       zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START;
 #ifdef HAVE_ARC4RANDOM_UNIFORM
                xfrd_set_timer(zone, zone->fresh_xfr_timeout
                        + arc4random_uniform(zone->fresh_xfr_timeout));
@@ -742,16 +753,12 @@ xfrd_set_timer_retry(xfrd_zone_t* zone)
                xfrd_set_timer(zone, zone->fresh_xfr_timeout
                        + random()%zone->fresh_xfr_timeout);
 #endif
-               /* exponential backoff - some master data in zones is paid-for
-                  but non-working, and will not get fixed. */
-               zone->fresh_xfr_timeout *= 2;
-               if(zone->fresh_xfr_timeout > XFRD_TRANSFER_TIMEOUT_MAX)
-                       zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_MAX;
        } else if(zone->state == xfrd_zone_expired ||
-               xfrd_time() + (time_t)ntohl(zone->soa_disk.retry) <
+               xfrd_time() + (time_t)ntohl(zone->soa_disk.retry)*mult <
                zone->soa_disk_acquired + (time_t)ntohl(zone->soa_disk.expire))
        {
                set_retry = ntohl(zone->soa_disk.retry);
+               set_retry *= mult;
                if(set_retry > 
(time_t)zone->zone_options->pattern->max_retry_time)
                        set_retry = zone->zone_options->pattern->max_retry_time;
                else if(set_retry < 
(time_t)zone->zone_options->pattern->min_retry_time)
@@ -760,13 +767,14 @@ xfrd_set_timer_retry(xfrd_zone_t* zone)
                        set_retry =  XFRD_LOWERBOUND_RETRY;
                xfrd_set_timer(zone, set_retry);
        } else {
-               if(ntohl(zone->soa_disk.expire) < XFRD_LOWERBOUND_RETRY)
+               set_retry = ntohl(zone->soa_disk.expire);
+               if(set_retry < XFRD_LOWERBOUND_RETRY)
                        xfrd_set_timer(zone, XFRD_LOWERBOUND_RETRY);
                else {
-                       if(zone->soa_disk_acquired + 
(time_t)ntohl(zone->soa_disk.expire) < xfrd_time())
+                       if(zone->soa_disk_acquired + set_retry < xfrd_time())
                                xfrd_set_timer(zone, XFRD_LOWERBOUND_RETRY);
                        else xfrd_set_timer(zone, zone->soa_disk_acquired +
-                               ntohl(zone->soa_disk.expire) - xfrd_time());
+                               set_retry - xfrd_time());
                }
        }
 }
@@ -1130,6 +1138,8 @@ xfrd_handle_incoming_soa(xfrd_zone_t* zone,
                zone->soa_nsd = zone->soa_disk;
                zone->soa_nsd_acquired = zone->soa_disk_acquired;
                xfrd->write_zonefile_needed = 1;
+               /* reset exponential backoff, we got a normal timer now */
+               zone->fresh_xfr_timeout = 0;
                if(xfrd_time() - zone->soa_disk_acquired
                        < (time_t)ntohl(zone->soa_disk.refresh))
                {
@@ -1269,6 +1279,19 @@ xfrd_udp_release(xfrd_zone_t* zone)
                xfrd->udp_use_num--;
 }
 
+/** disable ixfr for master */
+void
+xfrd_disable_ixfr(xfrd_zone_t* zone)
+{
+       if(!(zone->master->ixfr_disabled &&
+               (zone->master->ixfr_disabled + XFRD_NO_IXFR_CACHE) <= 
time(NULL))) {
+               /* start new round, with IXFR disabled */
+               zone->round_num = 0;
+               zone->next_master = zone->master_num;
+       }
+       zone->master->ixfr_disabled = time(NULL);
+}
+
 static void
 xfrd_udp_read(xfrd_zone_t* zone)
 {
@@ -1276,7 +1299,7 @@ xfrd_udp_read(xfrd_zone_t* zone)
        if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd)) {
                zone->master->bad_xfr_count++;
                if (zone->master->bad_xfr_count > 2) {
-                       zone->master->ixfr_disabled = time(NULL);
+                       xfrd_disable_ixfr(zone);
                        zone->master->bad_xfr_count = 0;
                }
                /* drop packet */
@@ -1303,7 +1326,7 @@ xfrd_udp_read(xfrd_zone_t* zone)
                        xfrd_udp_release(zone);
                        break;
                case xfrd_packet_notimpl:
-                       zone->master->ixfr_disabled = time(NULL);
+                       xfrd_disable_ixfr(zone);
                        /* drop packet */
                        xfrd_udp_release(zone);
                        /* query next server */
@@ -1320,7 +1343,7 @@ xfrd_udp_read(xfrd_zone_t* zone)
                default:
                        zone->master->bad_xfr_count++;
                        if (zone->master->bad_xfr_count > 2) {
-                               zone->master->ixfr_disabled = time(NULL);
+                               xfrd_disable_ixfr(zone);
                                zone->master->bad_xfr_count = 0;
                        }
                        /* drop packet */
diff --git xfrd.h xfrd.h
index 24541dbfc44..b601c2aae3e 100644
--- xfrd.h
+++ xfrd.h
@@ -244,6 +244,9 @@ enum xfrd_packet_result {
 #define XFRD_MAX_UDP 64 /* max number of UDP sockets at a time for IXFR */
 #define XFRD_MAX_UDP_NOTIFY 64 /* max concurrent UDP sockets for NOTIFY */
 
+#define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 
2*x seconds */
+#define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */
+
 extern xfrd_state_t* xfrd;
 
 /* start xfrd, new start. Pass socket to server_main. */
@@ -256,6 +259,9 @@ void xfrd_init_slave_zone(xfrd_state_t* xfrd, 
zone_options_t* zone_opt);
 /* delete slave zone */
 void xfrd_del_slave_zone(xfrd_state_t* xfrd, const dname_type* dname);
 
+/* disable ixfr for a while for zone->master */
+void xfrd_disable_ixfr(xfrd_zone_t* zone);
+
 /* get the current time epoch. Cached for speed. */
 time_t xfrd_time(void);
 


-- 
I'm not entirely sure you are real.

Reply via email to