time_t current = events->time[i];
if ((next == 0 || current < next) && (current != 0) &&
- (events->forced[i] || !events->ufrozen || !ufreeze_applies(i))) {
+ (events->forced[i] || !events->ufrozen || !ufreeze_applies(i)) &&
+ (events->answering || !only_started(i))) {
next = current;
next_type = i;
}
pthread_cond_destroy(&cond);
}
+void zone_events_start_answering(zone_t *zone)
+{
+ pthread_mutex_lock(&zone->events.mx);
+ zone->events.answering = true;
+ reschedule(&zone->events, true); // unlocks events->mx
+}
+
void zone_events_start(zone_t *zone)
{
if (!zone) {
pthread_mutex_lock(&events->mx);
events->frozen = false;
- reschedule(events, true); //unlocks events->mx
+ reschedule(events, true); // unlocks events->mx
}
time_t zone_events_get_time(const struct zone *zone, zone_event_type_t type)
bool frozen; //!< Terminated, don't schedule new events.
bool ufrozen; //!< Updates to the zone temporarily frozen by user.
+ bool answering; //!< Server is answering.
event_t *event; //!< Scheduler event.
worker_pool_t *pool; //!< Server worker pool.
*/
void zone_events_freeze_blocking(struct zone *zone);
+/*!
+ * \brief Set "answering" bit to true.
+ */
+void zone_events_start_answering(struct zone *zone);
+
/*!
* \brief ufreeze_applies
* \param type Type of event to be checked
*/
bool ufreeze_applies(zone_event_type_t type);
+/*!
+ * \brief Events that require answering server.
+ */
+inline static bool only_started(zone_event_type_t type)
+{
+ return type == ZONE_EVENT_NOTIFY;
+}
+
/*!
* \brief Start the events processing.
*
}
}
+ knot_zonedb_foreach(server->zone_db, zone_events_start_answering);
+
return KNOT_EOK;
}
zone_free(&zone);
return NULL;
}
+ zone->events.answering = (server->state & ServerAnswering);
return zone;
}
--- /dev/null
+#!/usr/bin/env python3
+
+'''Test that NOTIFY is not sent before server is answering (on XFR).'''
+
+from dnstest.test import Test
+
+t = Test()
+
+master = t.server("knot")
+slave = t.server("knot")
+
+zones = t.zone_rnd(1, records=1200, names=["zzzzzzzzz."]) + t.zone("example.")
+
+t.link(zones, master, slave)
+
+master.dnssec(zones[0]).enable = True
+slave.conf_zone(zones).retry_min_interval = 300
+
+t.generate_conf()
+slave.start()
+master.start()
+
+serials = master.zones_wait(zones)
+slave.zones_wait(zones)
+
+t.end()
return [zone]
def zone_rnd(self, number, dnssec=None, nsec3=None, records=None, serial=None,
- ttl=None, exists=True):
+ ttl=None, exists=True, names=None):
zones = list()
# Generate unique zone names.
- names = zone_generate.main(["-n", number]).split()
+ if names is None:
+ names = zone_generate.main(["-n", number]).split()
for name in names:
zone = dnstest.zonefile.ZoneFile(self.zones_dir)
zone.set_name(name)