summaryrefslogtreecommitdiffstats
path: root/src/knot/zone/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/knot/zone/serial.c')
-rw-r--r--src/knot/zone/serial.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/knot/zone/serial.c b/src/knot/zone/serial.c
new file mode 100644
index 0000000..0be5cbe
--- /dev/null
+++ b/src/knot/zone/serial.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 2019 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <time.h>
+
+#include "knot/conf/conf.h"
+#include "knot/zone/serial.h"
+
+static const serial_cmp_result_t diffbrief2result[4] = {
+ [0] = SERIAL_EQUAL,
+ [1] = SERIAL_GREATER,
+ [2] = SERIAL_INCOMPARABLE,
+ [3] = SERIAL_LOWER,
+};
+
+serial_cmp_result_t serial_compare(uint32_t s1, uint32_t s2)
+{
+ uint64_t diff = ((uint64_t)s1 + ((uint64_t)1 << 32) - s2) & 0xffffffff;
+ int diffbrief = (diff >> 31 << 1) | ((diff & 0x7fffffff) ? 1 : 0);
+ assert(diffbrief > -1 && diffbrief < 4);
+ return diffbrief2result[diffbrief];
+}
+
+static uint32_t serial_dateserial(uint32_t current)
+{
+ struct tm now;
+ time_t current_time = time(NULL);
+ struct tm *gmtime_result = gmtime_r(&current_time, &now);
+ if (gmtime_result == NULL) {
+ return current;
+ }
+ return (1900 + now.tm_year) * 1000000 +
+ ( 1 + now.tm_mon ) * 10000 +
+ ( now.tm_mday) * 100;
+}
+
+uint32_t serial_next(uint32_t current, int policy, uint32_t must_increment)
+{
+ uint32_t minimum;
+ switch (policy) {
+ case SERIAL_POLICY_INCREMENT:
+ minimum = current;
+ break;
+ case SERIAL_POLICY_UNIXTIME:
+ minimum = time(NULL);
+ break;
+ case SERIAL_POLICY_DATESERIAL:
+ minimum = serial_dateserial(current);
+ break;
+ default:
+ assert(0);
+ return 0;
+ }
+ if (serial_compare(minimum, current) != SERIAL_GREATER) {
+ return current + must_increment;
+ } else {
+ return minimum;
+ }
+}
+
+serial_cmp_result_t kserial_cmp(kserial_t a, kserial_t b)
+{
+ return ((a.valid && b.valid) ? serial_compare(a.serial, b.serial) : SERIAL_INCOMPARABLE);
+}