Commit f173089b authored by Jan Včelák's avatar Jan Včelák 🚀

serial arithmetic, separate module

parent fedfa106
......@@ -150,6 +150,8 @@ src/knot/zone/node.c
src/knot/zone/node.h
src/knot/zone/semantic-check.c
src/knot/zone/semantic-check.h
src/knot/zone/serial.c
src/knot/zone/serial.h
src/knot/zone/timers.c
src/knot/zone/timers.h
src/knot/zone/zone-diff.c
......@@ -348,6 +350,7 @@ tests/wire.c
tests/worker_pool.c
tests/worker_queue.c
tests/zone_events.c
tests/zone_serial.c
tests/zone_timers.c
tests/zone_update.c
tests/zonedb.c
......
......@@ -302,6 +302,8 @@ libknotd_la_SOURCES = \
knot/zone/node.h \
knot/zone/semantic-check.c \
knot/zone/semantic-check.h \
knot/zone/serial.c \
knot/zone/serial.h \
knot/zone/timers.c \
knot/zone/timers.h \
knot/zone/zone-diff.c \
......
......@@ -23,6 +23,7 @@
#include "knot/nameserver/nsec_proofs.h"
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/process_answer.h"
#include "knot/zone/serial.h"
#include "knot/zone/zonedb.h"
/*! \brief Check if given node was already visited. */
......
......@@ -21,6 +21,7 @@
#include "knot/nameserver/process_answer.h"
#include "knot/updates/apply.h"
#include "knot/common/debug.h"
#include "knot/zone/serial.h"
#include "libknot/descriptor.h"
#include "libknot/internal/utils.h"
#include "libknot/rrtype/soa.h"
......
......@@ -21,6 +21,7 @@
#include "knot/updates/ddns.h"
#include "knot/updates/changesets.h"
#include "knot/updates/zone-update.h"
#include "knot/zone/serial.h"
#include "libknot/packet/pkt.h"
#include "libknot/consts.h"
#include "libknot/rrtype/soa.h"
......@@ -969,9 +970,14 @@ int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
return KNOT_ENOMEM;
}
uint32_t new_serial =
zone_contents_next_serial(zone->contents,
zone->conf->serial_policy);
uint32_t old_serial = knot_soa_serial(&soa_cpy->rrs);
uint32_t new_serial = serial_next(old_serial, zone->conf->serial_policy);
if (serial_compare(old_serial, new_serial) >= 0) {
log_zone_warning(zone->name, "updated serial is lower "
"than current, serial %u -> %u",
old_serial, new_serial);
}
knot_soa_serial_set(&soa_cpy->rrs, new_serial);
changeset->soa_to = soa_cpy;
}
......
......@@ -1347,34 +1347,6 @@ uint32_t zone_contents_serial(const zone_contents_t *zone)
return knot_soa_serial(soa);
}
uint32_t zone_contents_next_serial(const zone_contents_t *zone, int policy)
{
assert(zone);
uint32_t old_serial = zone_contents_serial(zone);
uint32_t new_serial = 0;
switch (policy) {
case CONF_SERIAL_INCREMENT:
new_serial = (uint32_t)old_serial + 1;
break;
case CONF_SERIAL_UNIXTIME:
new_serial = (uint32_t)time(NULL);
break;
default:
assert(0);
}
/* If the new serial is 'lower' or equal than the new one, warn the user.*/
if (serial_compare(old_serial, new_serial) >= 0) {
log_zone_warning(zone->apex->owner, "updated serial is lower "
"than current, serial %u -> %u",
old_serial, new_serial);
}
return new_serial;
}
bool zone_contents_is_signed(const zone_contents_t *zone)
{
return node_rrtype_is_signed(zone->apex, KNOT_RRTYPE_SOA);
......
......@@ -273,10 +273,6 @@ const knot_rdataset_t *zone_contents_soa(const zone_contents_t *zone);
*/
uint32_t zone_contents_serial(const zone_contents_t *zone);
/*! \brief Calculate next serial. */
uint32_t zone_contents_next_serial(const zone_contents_t *zone, int policy);
/*!
* \brief Return true if zone is signed.
*/
......
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program 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.
This program 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 <http://www.gnu.org/licenses/>.
*/
#include "knot/zone/serial.h"
#include "knot/conf/conf.h"
#include <assert.h>
#include <time.h>
static int32_t serial_difference(uint32_t s1, uint32_t s2)
{
return (((int64_t)s1 - s2) % ((int64_t)1 << 32));
}
int serial_compare(uint32_t s1, uint32_t s2)
{
int32_t diff = serial_difference(s1, s2);
return (s1 == s2) /* s1 equal to s2 */
? 0
:((diff >= 1 && diff < ((uint32_t)1 << 31))
? 1 /* s1 larger than s2 */
: -1); /* s1 less than s2 */
}
int serial_next(uint32_t current, int policy)
{
switch (policy) {
case CONF_SERIAL_INCREMENT:
return current + 1;
case CONF_SERIAL_UNIXTIME:
return time(NULL);
default:
assert(0);
return 0;
}
}
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program 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.
This program 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
/*!
* \brief Compares two zone serials.
*
* \retval < 0 if s1 is less than s2.
* \retval > 0 if s1 is larger than s2.
* \retval == 0 if s1 is equal to s2.
*/
int serial_compare(uint32_t s1, uint32_t s2);
/*!
* \brief Get next serial for given serial update policy.
*
* \param current Current SOA serial.
* \param policy CONF_SERIAL_INCREMENT or CONF_SERIAL_UNIXTIME.
*
* \return New serial.
*/
int serial_next(uint32_t current, int policy);
......@@ -21,6 +21,7 @@
#include "knot/common/debug.h"
#include "libknot/errcode.h"
#include "knot/zone/zone-diff.h"
#include "knot/zone/serial.h"
#include "libknot/descriptor.h"
#include "libknot/internal/utils.h"
#include "libknot/rrtype/soa.h"
......
......@@ -25,6 +25,7 @@
#include "libknot/internal/lists.h"
#include "knot/common/trim.h"
#include "knot/zone/node.h"
#include "knot/zone/serial.h"
#include "knot/zone/zone.h"
#include "knot/zone/zonefile.h"
#include "knot/zone/contents.h"
......
......@@ -61,22 +61,6 @@ lookup_table_t *lookup_by_id(lookup_table_t *table, int id)
/*----------------------------------------------------------------------------*/
static int32_t serial_difference(uint32_t s1, uint32_t s2)
{
return (((int64_t)s1 - s2) % ((int64_t)1 << 32));
}
_public_
int serial_compare(uint32_t s1, uint32_t s2)
{
int32_t diff = serial_difference(s1, s2);
return (s1 == s2) /* s1 equal to s2 */
? 0
:((diff >= 1 && diff < ((uint32_t)1 << 31))
? 1 /* s1 larger than s2 */
: -1); /* s1 less than s2 */
}
_public_
uint16_t wire_read_u16(const uint8_t *pos)
{
......
......@@ -142,13 +142,4 @@ void wire_write_u48(uint8_t *pos, uint64_t data);
*/
void wire_write_u64(uint8_t *pos, uint64_t data);
/*!
* \brief Compares two zone serials.
*
* \retval < 0 if s1 is less than s2.
* \retval > 0 if s1 is larger than s2.
* \retval == 0 if s1 is equal to s2.
*/
int serial_compare(uint32_t s1, uint32_t s2);
/*! @} */
......@@ -41,6 +41,7 @@ wire
worker_pool
worker_queue
zone_events
zone_serial
zone_timers
zone_update
zonedb
......
......@@ -45,6 +45,7 @@ check_PROGRAMS = \
worker_pool \
worker_queue \
zone_events \
zone_serial \
zone_timers \
zone_update \
zonedb \
......
......@@ -16,11 +16,6 @@
#include <tap/basic.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "libknot/internal/utils.h"
lookup_table_t test_table[] = {
......@@ -31,28 +26,9 @@ lookup_table_t test_table[] = {
{ 0, NULL }
};
enum serials {
S_LOWEST = 0, // lowest value
S_2LOWEST = 1, // second lowest value
S_BELOW_MIDDLE = 0x7fffffff, // one below middle
S_ABOVE_MIDDLE = 0x80000000, // one above middle
S_2HIGHEST = 0xffffffff - 1, // second highest value
S_HIGHEST = 0xffffffff // highest value
};
static uint32_t random_serial()
{
uint32_t s = rand() & 0xff;
s |= (rand() & 0xff) << 8;
s |= (rand() & 0xff) << 16;
s |= (rand() & 0xff) << 24;
return s;
}
int main(int argc, char *argv[])
{
plan(9 + 20);
plan(9);
/* Lookup by ID. */
lookup_table_t *found = lookup_by_id(test_table, 3);
......@@ -86,62 +62,5 @@ int main(int argc, char *argv[])
found = lookup_by_name(test_table, "non existent name");
ok(found == NULL, "lookup table: find by name - non-existent name");
/* Serial compare test. */
ok(serial_compare(S_LOWEST, S_BELOW_MIDDLE) < 0,
"serial compare: lowest < below middle");
ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) > 0,
"serial compare: below middle > lowest");
/* Corner-case: these serials' distance is exactly 2^31. */
ok(serial_compare(S_LOWEST, S_ABOVE_MIDDLE) < 0,
"serial compare: lowest < above_middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) < 0,
"serial compare: above_middle < lowest");
ok(serial_compare(S_LOWEST, S_HIGHEST) > 0,
"serial compare: lowest > highest");
ok(serial_compare(S_HIGHEST, S_LOWEST) < 0,
"serial compare: highest < lowest");
ok(serial_compare(S_2LOWEST, S_ABOVE_MIDDLE) < 0,
"serial compare: 2nd lowest < above middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_2LOWEST) > 0,
"serial compare: above middle > 2nd lowest");
/* Corner-case: these serials' distance is exactly 2^31. */
ok(serial_compare(S_BELOW_MIDDLE, S_HIGHEST) < 0,
"serial compare: below middle < highest");
ok(serial_compare(S_HIGHEST, S_BELOW_MIDDLE) < 0,
"serial compare: highest < below middle");
ok(serial_compare(S_BELOW_MIDDLE, S_2HIGHEST) < 0,
"serial compare: below middle < 2nd highest");
ok(serial_compare(S_2HIGHEST, S_BELOW_MIDDLE) > 0,
"serial compare: 2nd highest > below middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_HIGHEST) < 0,
"serial compare: above middle < highest");
ok(serial_compare(S_HIGHEST, S_ABOVE_MIDDLE) > 0,
"serial compare: highest > above middle");
ok(serial_compare(S_LOWEST, S_LOWEST) == 0,
"serial compare: lowest == lowest");
ok(serial_compare(S_HIGHEST, S_HIGHEST) == 0,
"serial compare: highest == highest");
ok(serial_compare(S_LOWEST - 1, S_HIGHEST) == 0,
"serial compare: lowest - 1 == highest");
ok(serial_compare(S_LOWEST, S_HIGHEST + 1) == 0,
"serial compare: lowest== highest + 1");
/* Corner-case: these serials' distance is exactly 2^31. */
uint32_t s1 = random_serial();
uint32_t s2 = s1 + S_ABOVE_MIDDLE; // exactly the 'oposite' number
ok(serial_compare(s1, s2) < 0,
"serial compare: random oposites (s1 < s2)");
ok(serial_compare(s2, s1) < 0,
"serial compare: random oposites (s2 < s1)");
return 0;
}
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program 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.
This program 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 <http://www.gnu.org/licenses/>.
*/
#include <tap/basic.h>
#include <stdlib.h>
#include "knot/zone/serial.h"
enum serials {
S_LOWEST = 0, // lowest value
S_2LOWEST = 1, // second lowest value
S_BELOW_MIDDLE = 0x7fffffff, // one below middle
S_ABOVE_MIDDLE = 0x80000000, // one above middle
S_2HIGHEST = 0xffffffff - 1, // second highest value
S_HIGHEST = 0xffffffff // highest value
};
static uint32_t random_serial()
{
uint32_t s = rand() & 0xff;
s |= (rand() & 0xff) << 8;
s |= (rand() & 0xff) << 16;
s |= (rand() & 0xff) << 24;
return s;
}
int main(int argc, char *argv[])
{
plan(20);
/* Serial compare test. */
ok(serial_compare(S_LOWEST, S_BELOW_MIDDLE) < 0,
"serial compare: lowest < below middle");
ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) > 0,
"serial compare: below middle > lowest");
/* Corner-case: these serials' distance is exactly 2^31. */
ok(serial_compare(S_LOWEST, S_ABOVE_MIDDLE) < 0,
"serial compare: lowest < above_middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) < 0,
"serial compare: above_middle < lowest");
ok(serial_compare(S_LOWEST, S_HIGHEST) > 0,
"serial compare: lowest > highest");
ok(serial_compare(S_HIGHEST, S_LOWEST) < 0,
"serial compare: highest < lowest");
ok(serial_compare(S_2LOWEST, S_ABOVE_MIDDLE) < 0,
"serial compare: 2nd lowest < above middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_2LOWEST) > 0,
"serial compare: above middle > 2nd lowest");
/* Corner-case: these serials' distance is exactly 2^31. */
ok(serial_compare(S_BELOW_MIDDLE, S_HIGHEST) < 0,
"serial compare: below middle < highest");
ok(serial_compare(S_HIGHEST, S_BELOW_MIDDLE) < 0,
"serial compare: highest < below middle");
ok(serial_compare(S_BELOW_MIDDLE, S_2HIGHEST) < 0,
"serial compare: below middle < 2nd highest");
ok(serial_compare(S_2HIGHEST, S_BELOW_MIDDLE) > 0,
"serial compare: 2nd highest > below middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_HIGHEST) < 0,
"serial compare: above middle < highest");
ok(serial_compare(S_HIGHEST, S_ABOVE_MIDDLE) > 0,
"serial compare: highest > above middle");
ok(serial_compare(S_LOWEST, S_LOWEST) == 0,
"serial compare: lowest == lowest");
ok(serial_compare(S_HIGHEST, S_HIGHEST) == 0,
"serial compare: highest == highest");
ok(serial_compare(S_LOWEST - 1, S_HIGHEST) == 0,
"serial compare: lowest - 1 == highest");
ok(serial_compare(S_LOWEST, S_HIGHEST + 1) == 0,
"serial compare: lowest== highest + 1");
/* Corner-case: these serials' distance is exactly 2^31. */
uint32_t s1 = random_serial();
uint32_t s2 = s1 + S_ABOVE_MIDDLE; // exactly the 'oposite' number
ok(serial_compare(s1, s2) < 0,
"serial compare: random oposites (s1 < s2)");
ok(serial_compare(s2, s1) < 0,
"serial compare: random oposites (s2 < s1)");
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment