diff options
author | Libor Peltan <libor.peltan@nic.cz> | 2017-06-09 19:54:06 +0200 |
---|---|---|
committer | Daniel Salzman <daniel.salzman@nic.cz> | 2017-06-16 13:22:39 +0200 |
commit | 1e77544e11108da4a1f9daacaaa1b37e0d1ca143 (patch) | |
tree | b6a4e086242b731147ffacc96ad19e0e938cabce | |
parent | conf: improve error messages with a special message for module error (diff) | |
download | knot-1e77544e11108da4a1f9daacaaa1b37e0d1ca143.tar.xz knot-1e77544e11108da4a1f9daacaaa1b37e0d1ca143.zip |
dnssec: timestamps always 64bit and zero==infinity
-rw-r--r-- | src/contrib/time.h | 93 | ||||
-rw-r--r-- | src/knot/dnssec/context.c | 2 | ||||
-rw-r--r-- | src/knot/dnssec/context.h | 2 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/kasp_db.c | 22 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/kasp_db.h | 5 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/kasp_zone.c | 10 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/kasp_zone.h | 2 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/keystate.c | 12 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/keystate.h | 3 | ||||
-rw-r--r-- | src/knot/dnssec/kasp/policy.h | 14 | ||||
-rw-r--r-- | src/knot/dnssec/key-events.c | 95 | ||||
-rw-r--r-- | src/knot/dnssec/policy.h | 1 | ||||
-rw-r--r-- | src/knot/dnssec/zone-events.c | 21 | ||||
-rw-r--r-- | src/knot/dnssec/zone-events.h | 6 | ||||
-rw-r--r-- | src/knot/dnssec/zone-keys.c | 32 | ||||
-rw-r--r-- | src/knot/dnssec/zone-keys.h | 6 | ||||
-rw-r--r-- | src/knot/dnssec/zone-sign.c | 35 | ||||
-rw-r--r-- | src/knot/dnssec/zone-sign.h | 2 | ||||
-rw-r--r-- | src/knot/events/handlers/dnssec.c | 14 | ||||
-rw-r--r-- | src/knot/events/handlers/nsec3resalt.c | 2 | ||||
-rw-r--r-- | src/knot/zone/zone-load.c | 2 | ||||
-rw-r--r-- | src/utils/keymgr/bind_privkey.c | 10 | ||||
-rw-r--r-- | src/utils/keymgr/functions.c | 16 | ||||
-rw-r--r-- | tests/contrib/test_time.c | 65 |
24 files changed, 307 insertions, 165 deletions
diff --git a/src/contrib/time.h b/src/contrib/time.h index 6d7998800..4ce1ec878 100644 --- a/src/contrib/time.h +++ b/src/contrib/time.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2017 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 @@ -13,17 +13,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/*! - * \file - * - * \brief Universal time getter. - * - * \addtogroup contrib - * @{ - */ #pragma once +#include <stdint.h> #include <time.h> /*! @@ -41,4 +34,84 @@ struct timespec time_diff(const struct timespec *begin, const struct timespec *e */ double time_diff_ms(const struct timespec *begin, const struct timespec *end); -/*! @} */ +/*! + * \brief Data type for keeping UNIX timestamps. + * + * This is because time_t can be 32-bit on some systems, which is bad. + * Zero value represents infinity. + */ +typedef uint64_t knot_time_t; + +/*! + * \brief Data type for keeping time differences. + */ +typedef int64_t knot_timediff_t; + +#define KNOT_TIMEDIFF_MIN INT64_MIN +#define KNOT_TIMEDIFF_MAX INT64_MAX + +/*! + * \brief Returns current time sice epoch. + */ +inline static knot_time_t knot_time(void) +{ + return (knot_time_t)time(NULL); +} + +/*! + * \brief Compare two timestamps. + * + * \return 0 if equal, -1 if the former is smaller (=earlier), 1 else. + */ +inline static int knot_time_cmp(knot_time_t a, knot_time_t b) +{ + return (a == b ? 0 : 1) * ((a && b) == 0 ? -1 : 1) * (a < b ? -1 : 1); +} + +/*! + * \brief Return the smaller (=earlier) from given two timestamps. + */ +inline static knot_time_t knot_time_min(knot_time_t a, knot_time_t b) +{ + if ((a && b) == 0) { + return a + b; + } else { + return (a < b ? a : b); + } +} + +/*! + * \brief Return the difference between two timestamps (to "minus" from). + * + * \note If both are zero (=infinity), KNOT_TIMEDIFF_MAX is returned. + */ +inline static knot_timediff_t knot_time_diff(knot_time_t to, knot_time_t from) +{ + if ((to && from) == 0) { + return (to > from ? KNOT_TIMEDIFF_MIN : KNOT_TIMEDIFF_MAX); + } else { + return (knot_timediff_t)to - (knot_timediff_t)from; + } +} + +/*! + * \brief Add a time difference to timestamp. + */ +inline static knot_time_t knot_time_add(knot_time_t since, knot_timediff_t howlong) +{ + return (since != 0 ? since + howlong : since); +} + +/*! + * \brief Convert uint32_t-encoded timestamp to knot_time_t. + * + * In RRSIG rdata, there are inception and expiration timestamps in uint32_t format. + * One shall use 'serial arithmetics' to decode them. + * + * \todo However it needs time(now) context which is slow to obtain, so we don't do it + * for now. Please fix this in next 100 years. + */ +inline static knot_time_t knot_time_from_u32(uint32_t u32time) +{ + return (knot_time_t)u32time; +} diff --git a/src/knot/dnssec/context.c b/src/knot/dnssec/context.c index a1369078d..ebbc4858c 100644 --- a/src/knot/dnssec/context.c +++ b/src/knot/dnssec/context.c @@ -158,7 +158,7 @@ int kdnssec_ctx_init(conf_t *conf, kdnssec_ctx_t *ctx, const knot_dname_t *zone_ goto init_error; } - ctx->now = time(NULL); + ctx->now = knot_time(); return KNOT_EOK; init_error: diff --git a/src/knot/dnssec/context.h b/src/knot/dnssec/context.h index f4e3ad7aa..54072ae60 100644 --- a/src/knot/dnssec/context.h +++ b/src/knot/dnssec/context.h @@ -28,7 +28,7 @@ * \brief DNSSEC signing context. */ typedef struct { - time_t now; + knot_time_t now; kasp_db_t **kasp_db; knot_kasp_zone_t *zone; diff --git a/src/knot/dnssec/kasp/kasp_db.c b/src/knot/dnssec/kasp/kasp_db.c index b213c4431..7f148959f 100644 --- a/src/knot/dnssec/kasp/kasp_db.c +++ b/src/knot/dnssec/kasp/kasp_db.c @@ -253,12 +253,12 @@ static int deserialize_key_params(key_params_t *params, const knot_db_val_t *key params->keytag = wire_ctx_read_u16(&wire); params->algorithm = wire_ctx_read_u8(&wire); params->is_ksk = (wire_ctx_read_u8(&wire) != (uint8_t)0x00); - params->timing.created = (time_t)wire_ctx_read_u64(&wire); - params->timing.publish = (time_t)wire_ctx_read_u64(&wire); - params->timing.ready = (time_t)wire_ctx_read_u64(&wire); - params->timing.active = (time_t)wire_ctx_read_u64(&wire); - params->timing.retire = (time_t)wire_ctx_read_u64(&wire); - params->timing.remove = (time_t)wire_ctx_read_u64(&wire); + params->timing.created = (knot_time_t)wire_ctx_read_u64(&wire); + params->timing.publish = (knot_time_t)wire_ctx_read_u64(&wire); + params->timing.ready = (knot_time_t)wire_ctx_read_u64(&wire); + params->timing.active = (knot_time_t)wire_ctx_read_u64(&wire); + params->timing.retire = (knot_time_t)wire_ctx_read_u64(&wire); + params->timing.remove = (knot_time_t)wire_ctx_read_u64(&wire); if (wire.error != KNOT_EOK) { return KNOT_ERROR; } @@ -494,10 +494,10 @@ int kasp_db_share_key(kasp_db_t *db, const knot_dname_t *zone_from, const knot_d } int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, - const dnssec_binary_t *nsec3salt, time_t salt_created) + const dnssec_binary_t *nsec3salt, knot_time_t salt_created) { if (db == NULL || db->keys_db == NULL || - zone_name == NULL || nsec3salt == NULL) { + zone_name == NULL || nsec3salt == NULL || salt_created <= 0) { return KNOT_EINVAL; } @@ -508,7 +508,7 @@ int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, free_key(&key); txn_check(NULL); key = make_key(KASPDBKEY_NSEC3TIME, zone_name, NULL); - uint64_t tmp = htobe64(salt_created); + uint64_t tmp = htobe64((uint64_t)salt_created); val.len = sizeof(tmp); val.data = &tmp; ret = db_api->insert(txn, &key, &val, 0); @@ -518,7 +518,7 @@ int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, } int kasp_db_load_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, - dnssec_binary_t *nsec3salt, time_t *salt_created) + dnssec_binary_t *nsec3salt, knot_time_t *salt_created) { if (db == NULL || db->keys_db == NULL || zone_name == NULL || nsec3salt == NULL || salt_created == NULL) { @@ -531,7 +531,7 @@ int kasp_db_load_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, free_key(&key); if (ret == KNOT_EOK) { if (val.len == sizeof(uint64_t)) { - *salt_created = be64toh(*(uint64_t *)val.data); + *salt_created = (knot_time_t)be64toh(*(uint64_t *)val.data); } else { ret = KNOT_EMALF; diff --git a/src/knot/dnssec/kasp/kasp_db.h b/src/knot/dnssec/kasp/kasp_db.h index 2bf2fce2c..7877f3107 100644 --- a/src/knot/dnssec/kasp/kasp_db.h +++ b/src/knot/dnssec/kasp/kasp_db.h @@ -18,6 +18,7 @@ #include <time.h> +#include "contrib/time.h" #include "contrib/ucw/lists.h" #include "libknot/db/db_lmdb.h" #include "libknot/dname.h" @@ -138,7 +139,7 @@ int kasp_db_share_key(kasp_db_t *db, const knot_dname_t *zone_from, const knot_d * \return KNOT_E* */ int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, - const dnssec_binary_t *nsec3salt, time_t salt_created); + const dnssec_binary_t *nsec3salt, knot_time_t salt_created); /*! * \brief Load NSEC3 salt for given zone. @@ -151,7 +152,7 @@ int kasp_db_store_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, * \return KNOT_E* (KNOT_ENOENT if not stored before) */ int kasp_db_load_nsec3salt(kasp_db_t *db, const knot_dname_t *zone_name, - dnssec_binary_t *nsec3salt, time_t *salt_created); + dnssec_binary_t *nsec3salt, knot_time_t *salt_created); /*! * \brief For given policy name, obtain last generated key. diff --git a/src/knot/dnssec/kasp/kasp_zone.c b/src/knot/dnssec/kasp/kasp_zone.c index da5386ca3..c44663a2e 100644 --- a/src/knot/dnssec/kasp/kasp_zone.c +++ b/src/knot/dnssec/kasp/kasp_zone.c @@ -124,7 +124,7 @@ int kasp_zone_load(knot_kasp_zone_t *zone, knot_kasp_key_t *dkeys = NULL; size_t num_dkeys = 0; dnssec_binary_t salt = { 0 }; - time_t sc = 0; + knot_time_t sc = 0; list_t key_params; init_list(&key_params); @@ -217,9 +217,11 @@ int kasp_zone_save(const knot_kasp_zone_t *zone, } } - ret = kasp_db_store_nsec3salt(kdb, zone_name, &zone->nsec3_salt, zone->nsec3_salt_created); - if (ret != KNOT_EOK) { - goto kzs_end; + if (zone->nsec3_salt.size > 0) { + ret = kasp_db_store_nsec3salt(kdb, zone_name, &zone->nsec3_salt, zone->nsec3_salt_created); + if (ret != KNOT_EOK) { + goto kzs_end; + } } kzs_end: diff --git a/src/knot/dnssec/kasp/kasp_zone.h b/src/knot/dnssec/kasp/kasp_zone.h index 855c4ff22..83eaea2d9 100644 --- a/src/knot/dnssec/kasp/kasp_zone.h +++ b/src/knot/dnssec/kasp/kasp_zone.h @@ -25,7 +25,7 @@ typedef struct { size_t num_keys; dnssec_binary_t nsec3_salt; - time_t nsec3_salt_created; + knot_time_t nsec3_salt_created; } knot_kasp_zone_t; int kasp_zone_load(knot_kasp_zone_t *zone, diff --git a/src/knot/dnssec/kasp/keystate.c b/src/knot/dnssec/kasp/keystate.c index 54c30b49b..9038dcb2a 100644 --- a/src/knot/dnssec/kasp/keystate.c +++ b/src/knot/dnssec/kasp/keystate.c @@ -21,7 +21,7 @@ #include "knot/dnssec/kasp/policy.h" #include "knot/dnssec/kasp/keystate.h" -key_state_t get_key_state(const knot_kasp_key_t *key, time_t moment) +key_state_t get_key_state(const knot_kasp_key_t *key, knot_time_t moment) { if (!key || moment <= 0) { @@ -40,12 +40,12 @@ key_state_t get_key_state(const knot_kasp_key_t *key, time_t moment) const knot_kasp_key_timing_t *t = &key->timing; - bool removed = t->remove != 0 && t->remove <= moment; - bool retired = t->retire != 0 && t->retire <= moment; + bool removed = (knot_time_cmp(t->remove, moment) <= 0); + bool retired = (knot_time_cmp(t->retire, moment) <= 0); - bool published = !removed && (t->publish == 0 || t->publish <= moment); - bool ready = !retired && (t->ready == 0 || t->ready <= moment); - bool activated = !retired && (t->active == 0 || t->active <= moment); + bool published = !removed && (knot_time_cmp(t->publish, moment) <= 0); + bool ready = !retired && (knot_time_cmp(t->ready, moment) <= 0); + bool activated = !retired && (knot_time_cmp(t->active, moment) <= 0); /* * Evaluate special transition states as invalid. E.g., when signatures diff --git a/src/knot/dnssec/kasp/keystate.h b/src/knot/dnssec/kasp/keystate.h index 1aa9e677d..e376ab351 100644 --- a/src/knot/dnssec/kasp/keystate.h +++ b/src/knot/dnssec/kasp/keystate.h @@ -18,6 +18,7 @@ #include <time.h> +#include "contrib/time.h" #include "knot/dnssec/kasp/policy.h" enum key_state { @@ -31,4 +32,4 @@ enum key_state { typedef enum key_state key_state_t; -key_state_t get_key_state(const knot_kasp_key_t *key, time_t moment); +key_state_t get_key_state(const knot_kasp_key_t *key, knot_time_t moment); diff --git a/src/knot/dnssec/kasp/policy.h b/src/knot/dnssec/kasp/policy.h index 63d1bee8d..75a7eedb0 100644 --- a/src/knot/dnssec/kasp/policy.h +++ b/src/knot/dnssec/kasp/policy.h @@ -19,18 +19,19 @@ #include <stdbool.h> #include <time.h> +#include "contrib/time.h" #include "dnssec/lib/dnssec/key.h" /*! * KASP key timing information. */ typedef struct { - time_t created; /*!< Time the key was generated/imported. */ - time_t publish; /*!< Time of DNSKEY record publication. */ - time_t ready; /*!< Start of RRSIG generation, waiting for parent zone. */ - time_t active; /*!< RRSIG records generating, other keys can be retired */ - time_t retire; /*!< End of RRSIG records generating. */ - time_t remove; /*!< Time of DNSKEY record removal. */ + knot_time_t created; /*!< Time the key was generated/imported. */ + knot_time_t publish; /*!< Time of DNSKEY record publication. */ + knot_time_t ready; /*!< Start of RRSIG generation, waiting for parent zone. */ + knot_time_t active; /*!< RRSIG records generating, other keys can be retired */ + knot_time_t retire; /*!< End of RRSIG records generating. */ + knot_time_t remove; /*!< Time of DNSKEY record removal. */ } knot_kasp_key_timing_t; /*! @@ -87,3 +88,4 @@ typedef struct { uint32_t ksk_sbm_timeout; uint32_t ksk_sbm_check_interval; } knot_kasp_policy_t; +// TODO make the time parameters knot_timediff_t ?? diff --git a/src/knot/dnssec/key-events.c b/src/knot/dnssec/key-events.c index cde6fa6c6..bb94a08ff 100644 --- a/src/knot/dnssec/key-events.c +++ b/src/knot/dnssec/key-events.c @@ -16,15 +16,12 @@ #include <assert.h> -#include "contrib/macros.h" #include "knot/common/log.h" #include "knot/dnssec/kasp/keystate.h" #include "knot/dnssec/key-events.h" #include "knot/dnssec/policy.h" #include "knot/dnssec/zone-keys.h" -#define TIME_INFINITY ((time_t)0x00ffffffffffff00LLU) - static bool key_present(kdnssec_ctx_t *ctx, uint16_t flag) { assert(ctx); @@ -65,7 +62,7 @@ static knot_kasp_key_t *key_get_by_id(kdnssec_ctx_t *ctx, const char *keyid) return NULL; } -static int generate_key(kdnssec_ctx_t *ctx, bool ksk, time_t when_active) +static int generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_time_t when_active) { knot_kasp_key_t *key = NULL; int ret = kdnssec_generate_key(ctx, ksk, &key); @@ -73,8 +70,8 @@ static int generate_key(kdnssec_ctx_t *ctx, bool ksk, time_t when_active) return ret; } - key->timing.remove = TIME_INFINITY; - key->timing.retire = TIME_INFINITY; + key->timing.remove = 0; + key->timing.retire = 0; key->timing.active = when_active; key->timing.ready = when_active; key->timing.publish = ctx->now; @@ -82,7 +79,7 @@ static int generate_key(kdnssec_ctx_t *ctx, bool ksk, time_t when_active) return KNOT_EOK; } -static int share_or_generate_key(kdnssec_ctx_t *ctx, bool ksk, time_t when_active) +static int share_or_generate_key(kdnssec_ctx_t *ctx, bool ksk, knot_time_t when_active) { knot_dname_t *borrow_zone = NULL; char *borrow_key = NULL; @@ -104,8 +101,8 @@ static int share_or_generate_key(kdnssec_ctx_t *ctx, bool ksk, time_t when_activ if (ret != KNOT_EOK) { return ret; } - key->timing.remove = TIME_INFINITY; - key->timing.retire = TIME_INFINITY; + key->timing.remove = 0; + key->timing.retire = 0; key->timing.active = when_active; key->timing.ready = when_active; key->timing.publish = ctx->now; @@ -165,70 +162,70 @@ typedef enum { typedef struct { roll_action_type type; bool ksk; - time_t time; + knot_time_t time; knot_kasp_key_t *key; } roll_action; -static time_t zsk_publish_time(time_t active_time, const kdnssec_ctx_t *ctx) +static knot_time_t zsk_publish_time(knot_time_t active_time, const kdnssec_ctx_t *ctx) { - if (active_time <= 0 || active_time >= TIME_INFINITY) { - return TIME_INFINITY; + if (active_time <= 0) { + return 0; } - return active_time + ctx->policy->zsk_lifetime; + return knot_time_add(active_time, ctx->policy->zsk_lifetime); } -static time_t zsk_active_time(time_t publish_time, const kdnssec_ctx_t *ctx) +static knot_time_t zsk_active_time(knot_time_t publish_time, const kdnssec_ctx_t *ctx) { - if (publish_time <= 0 || publish_time >= TIME_INFINITY) { - return TIME_INFINITY; + if (publish_time <= 0) { + return 0; } - return publish_time + ctx->policy->propagation_delay + ctx->policy->dnskey_ttl; + return knot_time_add(publish_time, ctx->policy->propagation_delay + ctx->policy->dnskey_ttl); } -static time_t zsk_remove_time(time_t retire_time, const kdnssec_ctx_t *ctx) +static knot_time_t zsk_remove_time(knot_time_t retire_time, const kdnssec_ctx_t *ctx) { - if (retire_time <= 0 || retire_time >= TIME_INFINITY) { - return TIME_INFINITY; + if (retire_time <= 0) { + return 0; } - return retire_time + ctx->policy->propagation_delay + ctx->policy->zone_maximal_ttl; + return knot_time_add(retire_time, ctx->policy->propagation_delay + ctx->policy->zone_maximal_ttl); } -static time_t ksk_publish_time(time_t created_time, const kdnssec_ctx_t *ctx) +static knot_time_t ksk_publish_time(knot_time_t created_time, const kdnssec_ctx_t *ctx) { - if (created_time <= 0 || created_time >= TIME_INFINITY || ctx->policy->ksk_lifetime == 0) { - return TIME_INFINITY; + if (created_time <= 0 || ctx->policy->ksk_lifetime == 0) { + return 0; } - return created_time + ctx->policy->ksk_lifetime; + return knot_time_add(created_time, ctx->policy->ksk_lifetime); } -static time_t ksk_ready_time(time_t publish_time, const kdnssec_ctx_t *ctx) +static knot_time_t ksk_ready_time(knot_time_t publish_time, const kdnssec_ctx_t *ctx) { - if (publish_time <= 0 || publish_time >= TIME_INFINITY) { - return TIME_INFINITY; + if (publish_time <= 0) { + return 0; } - return publish_time + ctx->policy->propagation_delay + ctx->policy->dnskey_ttl; + return knot_time_add(publish_time, ctx->policy->propagation_delay + ctx->policy->dnskey_ttl); } -static time_t ksk_sbm_max_time(time_t ready_time, const kdnssec_ctx_t *ctx) +static knot_time_t ksk_sbm_max_time(knot_time_t ready_time, const kdnssec_ctx_t *ctx) { - if (ready_time <= 0 || ready_time >= TIME_INFINITY || ctx->policy->ksk_sbm_timeout == 0) { - return TIME_INFINITY; + if (ready_time <= 0 || ctx->policy->ksk_sbm_timeout == 0) { + return 0; } - return ready_time + ctx->policy->ksk_sbm_timeout; + return knot_time_add(ready_time, ctx->policy->ksk_sbm_timeout); } -static time_t ksk_remove_time(time_t retire_time, const kdnssec_ctx_t *ctx) +static knot_time_t ksk_remove_time(knot_time_t retire_time, const kdnssec_ctx_t *ctx) { - if (retire_time <= 0 || retire_time >= TIME_INFINITY) { - return TIME_INFINITY; + if (retire_time <= 0) { + return 0; } - return retire_time + ctx->policy->propagation_delay + ctx->policy->dnskey_ttl; + return knot_time_add(retire_time, ctx->policy->propagation_delay + ctx->policy->dnskey_ttl); } static roll_action next_action(kdnssec_ctx_t *ctx) { roll_action res = { 0 }; - res.time = TIME_INFINITY; + res.time = 0; bool is_zsk_published = false; bool is_ksk_published = false; @@ -247,7 +244,7 @@ static roll_action next_action(kdnssec_ctx_t *ctx) for (size_t i = 0; i < ctx->zone->num_keys; i++) { knot_kasp_key_t *key = &ctx->zone->keys[i]; - time_t keytime = TIME_INFINITY; + knot_time_t keytime = 0; roll_action_type restype = INVALID; bool isksk = (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK); if (isksk) { @@ -300,7 +297,7 @@ static roll_action next_action(kdnssec_ctx_t *ctx) assert(0); } } - if (keytime < res.time) { + if (knot_time_cmp(keytime, res.time) < 0) { res.key = key; res.ksk = isksk; res.time = keytime; @@ -323,7 +320,7 @@ static int exec_new_signatures(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey) // A delay to avoid left-behind of behind-a-loadbalancer parent NSs // for now we use (incorrectly) ksk_sbm_check_interval, to avoid too many conf options - time_t delay = 0; + knot_timediff_t delay = 0; if (kskflag == DNSKEY_FLAGS_KSK && ctx->policy->ksk_sbm_check_interval != 0) { delay = ctx->policy->ksk_sbm_check_interval; } @@ -332,7 +329,7 @@ static int exec_new_signatures(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey) knot_kasp_key_t *key = &ctx->zone->keys[i]; if (dnssec_key_get_flags(key->key) == kskflag && get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_ACTIVE) { - key->timing.retire = MIN(ctx->now + delay, key->timing.retire); + key->timing.retire = knot_time_min(knot_time_add(ctx->now, delay), key->timing.retire); } } @@ -341,9 +338,9 @@ static int exec_new_signatures(kdnssec_ctx_t *ctx, knot_kasp_key_t *newkey) } else { assert(get_key_state(newkey, ctx->now) == DNSSEC_KEY_STATE_PUBLISHED); assert(delay == 0); - newkey->timing.ready = MIN(ctx->now + delay, newkey->timing.ready); + newkey->timing.ready = knot_time_min(knot_time_add(ctx->now, delay), newkey->timing.ready); } - newkey->timing.active = MIN(ctx->now + delay, newkey->timing.active); + newkey->timing.active = knot_time_min(knot_time_add(ctx->now, delay), newkey->timing.active); return KNOT_EOK; } @@ -390,13 +387,13 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *resched reschedule->next_rollover = next.time; - if (!ctx->policy->singe_type_signing && reschedule->next_rollover <= ctx->now) { + if (!ctx->policy->singe_type_signing && knot_time_cmp(reschedule->next_rollover, ctx->now) <= 0) { switch (next.type) { case PUBLISH: if (next.ksk && ctx->policy->ksk_shared) { - ret = share_or_generate_key(ctx, next.ksk, TIME_INFINITY); + ret = share_or_generate_key(ctx, next.ksk, 0); } else { - ret = generate_key(ctx, next.ksk, TIME_INFINITY); + ret = generate_key(ctx, next.ksk, 0); } if (ret == KNOT_EOK) { log_zone_info(ctx->zone->dname, "DNSSEC, %cSK rollover started", (next.ksk ? 'K' : 'Z')); @@ -421,7 +418,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_reschedule_t *resched next = next_action(ctx); reschedule->next_rollover = next.time; } else { - reschedule->next_rollover = time(NULL) + 10; // fail => try in 10seconds #TODO better? + reschedule->next_rollover = knot_time_add(knot_time(), 10); // fail => try in 10seconds #TODO better? } } diff --git a/src/knot/dnssec/policy.h b/src/knot/dnssec/policy.h index 7c0e4c1d5..7a45b6b7b 100644 --- a/src/knot/dnssec/policy.h +++ b/src/knot/dnssec/policy.h @@ -16,6 +16,7 @@ #pragma once +#include "contrib/time.h" #include "knot/dnssec/context.h" #include "knot/zone/contents.h" diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c index 9f20ad07f..bc92763f9 100644 --- a/src/knot/dnssec/zone-events.c +++ b/src/knot/dnssec/zone-events.c @@ -83,15 +83,14 @@ static int sign_update_soa(const zone_contents_t *zone, changeset_t *chset, return knot_zone_sign_update_soa(&soa, &rrsigs, keyset, ctx, chset); } -static uint32_t schedule_next(kdnssec_ctx_t *kctx, const zone_keyset_t *keyset, - uint32_t zone_expire) +static knot_time_t schedule_next(kdnssec_ctx_t *kctx, const zone_keyset_t *keyset, + knot_time_t zone_expire) { - uint32_t zone_refresh = zone_expire - kctx->policy->rrsig_refresh_before; + knot_time_t zone_refresh = knot_time_add(zone_expire, -(knot_timediff_t)kctx->policy->rrsig_refresh_before); assert(zone_refresh > 0); - uint32_t dnskey_update = MIN(MAX(knot_get_next_zone_key_event(keyset), 0), - UINT32_MAX); - uint32_t next = MIN(zone_refresh, dnskey_update); + knot_time_t dnskey_update = knot_get_next_zone_key_event(keyset); + knot_time_t next = knot_time_min(zone_refresh, dnskey_update); return next; } @@ -122,7 +121,7 @@ static int generate_salt(dnssec_binary_t *salt, uint16_t length) // TODO preserve the resalt timeout in timers-db instead of kasp_db -int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, time_t *when_resalt) +int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, knot_time_t *when_resalt) { int ret = KNOT_EOK; @@ -136,13 +135,13 @@ int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, time_t *when if (ctx->zone->nsec3_salt.size != ctx->policy->nsec3_salt_length) { *when_resalt = ctx->now; - } else if (ctx->now < ctx->zone->nsec3_salt_created) { + } else if (knot_time_cmp(ctx->now, ctx->zone->nsec3_salt_created) < 0) { return KNOT_EINVAL; } else { *when_resalt = ctx->zone->nsec3_salt_created + ctx->policy->nsec3_salt_lifetime; } - if (*when_resalt <= ctx->now) { + if (knot_time_cmp(*when_resalt, ctx->now) <= 0) { ret = generate_salt(&ctx->zone->nsec3_salt, ctx->policy->nsec3_salt_length); if (ret == KNOT_EOK) { ctx->zone->nsec3_salt_created = ctx->now; @@ -150,7 +149,7 @@ int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, time_t *when *salt_changed = true; } // continue to planning next resalt even if NOK - *when_resalt = ctx->now + ctx->policy->nsec3_salt_lifetime; + *when_resalt = knot_time_add(ctx->now, ctx->policy->nsec3_salt_lifetime); } return ret; @@ -195,7 +194,7 @@ int knot_dnssec_zone_sign(zone_contents_t *zone, changeset_t *out_ch, goto done; } - uint32_t zone_expire = 0; + knot_time_t zone_expire = 0; result = knot_zone_sign(zone, &keyset, &ctx, out_ch, &zone_expire); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to sign zone content (%s)", diff --git a/src/knot/dnssec/zone-events.h b/src/knot/dnssec/zone-events.h index ee4bed3cb..95899684b 100644 --- a/src/knot/dnssec/zone-events.h +++ b/src/knot/dnssec/zone-events.h @@ -31,8 +31,8 @@ enum zone_sign_flags { typedef enum zone_sign_flags zone_sign_flags_t; typedef struct { - time_t next_sign; - time_t next_rollover; + knot_time_t next_sign; + knot_time_t next_rollover; bool keys_changed; bool plan_ds_query; bool allow_rollover; // this one is set by the caller @@ -94,4 +94,4 @@ int knot_dnssec_sign_changeset(const zone_contents_t *zone, * * \return KNOT_E* */ -int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, time_t *when_resalt); +int knot_dnssec_nsec3resalt(kdnssec_ctx_t *ctx, bool *salt_changed, knot_time_t *when_resalt); diff --git a/src/knot/dnssec/zone-keys.c b/src/knot/dnssec/zone-keys.c index 7d641d460..82c6d7cbe 100644 --- a/src/knot/dnssec/zone-keys.c +++ b/src/knot/dnssec/zone-keys.c @@ -177,7 +177,7 @@ int kdnssec_delete_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key_ptr) /*! * \brief Get key feature flags from key parameters. */ -static int set_key(knot_kasp_key_t *kasp_key, time_t now, zone_key_t *zone_key) +static int set_key(knot_kasp_key_t *kasp_key, knot_time_t now, zone_key_t *zone_key) { assert(kasp_key); assert(zone_key); @@ -198,18 +198,18 @@ static int set_key(knot_kasp_key_t *kasp_key, time_t now, zone_key_t *zone_key) // next event computation - time_t next = LONG_MAX; - time_t timestamps[5] = { + knot_time_t next = 0; + knot_time_t timestamps[5] = { timing->active, - timing->publish, + timing->publish, timing->remove, timing->retire, timing->ready, }; for (int i = 0; i < 5; i++) { - time_t ts = timestamps[i]; - if (ts != 0 && now < ts && ts < next) { + knot_time_t ts = timestamps[i]; + if (knot_time_cmp(now, ts) < 0 && knot_time_cmp(ts, next) < 0) { next = ts; } } @@ -222,12 +222,12 @@ static int set_key(knot_kasp_key_t *kasp_key, time_t now, zone_key_t *zone_key) zone_key->is_ksk = flags & KNOT_RDATA_DNSKEY_FLAG_KSK; zone_key->is_zsk = !zone_key->is_ksk; - zone_key->is_active = timing->active <= now && - (timing->retire == 0 || now < timing->retire); - zone_key->is_public = timing->publish <= now && - (timing->remove == 0 || now < timing->remove); - zone_key->is_ready = timing->ready <= now && - (timing->retire == 0 || now < timing->retire); + zone_key->is_active = (knot_time_cmp(timing->active, now) <= 0 && + knot_time_cmp(timing->retire, now) > 0); + zone_key->is_public = (knot_time_cmp(timing->publish, now) <= 0 && + knot_time_cmp(timing->remove, now) > 0); + zone_key->is_ready = (knot_time_cmp(timing->ready, now) <= 0 && + knot_time_cmp(timing->retire, now) > 0); return KNOT_EOK; } @@ -401,7 +401,7 @@ static void log_key_info(const zone_key_t *key, const knot_dname_t *zone_name) * \brief Load zone keys and init cryptographic context. */ int load_zone_keys(knot_kasp_zone_t *zone, dnssec_keystore_t *store, - bool nsec3_enabled, time_t now, zone_keyset_t *keyset_ptr) + bool nsec3_enabled, knot_time_t now, zone_keyset_t *keyset_ptr) { if (!zone || !store || !keyset_ptr) { return KNOT_EINVAL; @@ -488,15 +488,15 @@ struct keyptr_dynarray get_zone_keys(const zone_keyset_t *keyset, uint16_t searc /*! * \brief Get timestamp of next key event. */ -time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset) +knot_time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset) { assert(keyset); - time_t result = LONG_MAX; + knot_time_t result = 0; for (size_t i = 0; i < keyset->count; i++) { zone_key_t *key = &keyset->keys[i]; - if (key->next_event < result) { + if (knot_time_cmp(key->next_event, result) < 0) { result = key->next_event; } } diff --git a/src/knot/dnssec/zone-keys.h b/src/knot/dnssec/zone-keys.h index efa81a52e..3de3fedc9 100644 --- a/src/knot/dnssec/zone-keys.h +++ b/src/knot/dnssec/zone-keys.h @@ -46,7 +46,7 @@ struct zone_key { dnssec_binary_t precomputed_ds; - time_t next_event; + knot_time_t next_event; bool is_ksk; bool is_zsk; @@ -121,7 +121,7 @@ int kdnssec_delete_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key_ptr); * \return Error code, KNOT_EOK if successful. */ int load_zone_keys(knot_kasp_zone_t *zone, dnssec_keystore_t *store, - bool nsec3_enabled, time_t now, zone_keyset_t *keyset_ptr); + bool nsec3_enabled, knot_time_t now, zone_keyset_t *keyset_ptr); /*! * \brief Get zone keys by a keytag. @@ -147,7 +147,7 @@ void free_zone_keys(zone_keyset_t *keyset); * * \return Timestamp of next key event. */ -time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset); +knot_time_t knot_get_next_zone_key_event(const zone_keyset_t *keyset); /*! * \brief Returns DS record rdata for given key. diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c index d5bb8d122..b31ded39d 100644 --- a/src/knot/dnssec/zone-sign.c +++ b/src/knot/dnssec/zone-sign.c @@ -202,15 +202,14 @@ static keyptr_dynarray_t get_matching_zone_keys(const knot_rrset_t *rrsigs, * \param expires_at Current earliest expiration, will be updated. */ static void note_earliest_expiration(const knot_rrset_t *rrsigs, size_t pos, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(rrsigs); assert(expires_at); - uint32_t current = knot_rrsig_sig_expiration(&rrsigs->rrs, pos); - if (current < *expires_at) { - *expires_at = current; - } + uint32_t curr_rdata = knot_rrsig_sig_expiration(&rrsigs->rrs, pos); + knot_time_t current = knot_time_from_u32(curr_rdata); + *expires_at = knot_time_min(current, *expires_at); } /*! @@ -230,7 +229,7 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered, const zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, changeset_t *changeset, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(changeset); @@ -433,7 +432,7 @@ static int resign_rrset(const knot_rrset_t *covered, const zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, changeset_t *changeset, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(!knot_rrset_empty(covered)); @@ -494,7 +493,7 @@ static int sign_node_rrsets(const zone_node_t *node, const zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, changeset_t *changeset, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(node); assert(dnssec_ctx); @@ -535,7 +534,7 @@ typedef struct node_sign_args { const zone_keyset_t *zone_keys; const kdnssec_ctx_t *dnssec_ctx; changeset_t *changeset; - uint32_t expires_at; + knot_time_t expires_at; } node_sign_args_t; /*! @@ -581,7 +580,7 @@ static int zone_tree_sign(zone_tree_t *tree, const zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, changeset_t *changeset, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(zone_keys); assert(dnssec_ctx); @@ -591,7 +590,7 @@ static int zone_tree_sign(zone_tree_t *tree, .zone_keys = zone_keys, .dnssec_ctx = dnssec_ctx, .changeset = changeset, - .expires_at = dnssec_ctx->now + dnssec_ctx->policy->rrsig_lifetime + .expires_at = knot_time_add(dnssec_ctx->now, dnssec_ctx->policy->rrsig_lifetime), }; int result = zone_tree_apply(tree, sign_node, &args); @@ -939,7 +938,7 @@ static int update_record_rrsigs(const knot_rrset_t *rrsigs, const kdnssec_ctx_t *dnssec_ctx, uint16_t rrtype, changeset_t *changeset, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(zone_keys); assert(changeset); @@ -998,7 +997,7 @@ static int update_dnskeys(const zone_contents_t *zone, zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, changeset_t *changeset, - uint32_t *expires_at) + knot_time_t *expires_at) { assert(zone); assert(zone->apex); @@ -1269,7 +1268,7 @@ int knot_zone_sign(const zone_contents_t *zone, zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, changeset_t *changeset, - uint32_t *expire_at) + knot_time_t *expire_at) { if (!zone || !zone_keys || !dnssec_ctx || !changeset || !expire_at) { return KNOT_EINVAL; @@ -1277,28 +1276,28 @@ int knot_zone_sign(const zone_contents_t *zone, int result; - uint32_t dnskey_expire = UINT32_MAX; + knot_time_t dnskey_expire = 0; result = update_dnskeys(zone, zone_keys, dnssec_ctx, changeset, &dnskey_expire); if (result != KNOT_EOK) { return result; } - uint32_t normal_expire = UINT32_MAX; + knot_time_t normal_expire = 0; result = zone_tree_sign(zone->nodes, zone_keys, dnssec_ctx, changeset, &normal_expire); if (result != KNOT_EOK) { return result; } - uint32_t nsec3_expire = UINT32_MAX; + knot_time_t nsec3_expire = 0; result = zone_tree_sign(zone->nsec3_nodes, zone_keys, dnssec_ctx, changeset, &nsec3_expire); if (result != KNOT_EOK) { return result; } - *expire_at = MIN(dnskey_expire, MIN(normal_expire, nsec3_expire)); + *expire_at = knot_time_min(dnskey_expire, knot_time_min(normal_expire, nsec3_expire)); return KNOT_EOK; } diff --git a/src/knot/dnssec/zone-sign.h b/src/knot/dnssec/zone-sign.h index 8e5899965..21412416a 100644 --- a/src/knot/dnssec/zone-sign.h +++ b/src/knot/dnssec/zone-sign.h @@ -50,7 +50,7 @@ int knot_zone_sign(const zone_contents_t *zone, zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, - changeset_t *out_ch, uint32_t *expire_at); + changeset_t *out_ch, knot_time_t *expire_at); /*! * \brief Update and sign SOA and store performed changes in changeset. diff --git a/src/knot/events/handlers/dnssec.c b/src/knot/events/handlers/dnssec.c index 0271d3c51..273c8766c 100644 --- a/src/knot/events/handlers/dnssec.c +++ b/src/knot/events/handlers/dnssec.c @@ -30,24 +30,28 @@ void event_dnssec_reschedule(conf_t *conf, zone_t *zone, { time_t now = time(NULL); time_t ignore = -1; - time_t refresh_at = refresh->next_sign; + knot_time_t refresh_at = refresh->next_sign; - if (refresh->next_rollover < refresh_at && refresh->next_rollover > 0) { + if (knot_time_cmp(refresh->next_rollover, refresh_at) < 0) { refresh_at = refresh->next_rollover; } + if (refresh_at <= 0) { + return; + } + conf_val_t val = conf_zone_get(conf, C_ZONEFILE_SYNC, zone->name); - log_dnssec_next(zone->name, refresh_at); + log_dnssec_next(zone->name, (time_t)refresh_at); if (refresh->plan_ds_query) { log_zone_notice(zone->name, "DNSSEC, published CDS, CDNSKEY for submission"); } zone_events_schedule_at(zone, - ZONE_EVENT_DNSSEC, refresh_at, + ZONE_EVENT_DNSSEC, (time_t)refresh_at, ZONE_EVENT_PARENT_DS_Q, refresh->plan_ds_query ? now : ignore, - ZONE_EVENT_NOTIFY, zone_changed ? now : ignore, + ZONE_EVENT_NOTIFY, zone_changed ? now : ignore, ZONE_EVENT_FLUSH, zone_changed && conf_int(&val) == 0 ? now : ignore ); } diff --git a/src/knot/events/handlers/nsec3resalt.c b/src/knot/events/handlers/nsec3resalt.c index 78313c764..d222c30f0 100644 --- a/src/knot/events/handlers/nsec3resalt.c +++ b/src/knot/events/handlers/nsec3resalt.c @@ -20,7 +20,7 @@ int event_nsec3resalt(conf_t *conf, zone_t *zone) { bool salt_changed = false; - time_t next_resalt = 0; + knot_time_t next_resalt = 0; kdnssec_ctx_t kctx = { 0 }; diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index ea857e6cd..ef96a91ba 100644 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -235,7 +235,7 @@ int zone_load_post(conf_t *conf, zone_t *zone, zone_contents_t *contents, return ret; } - bool ignore1 = false; time_t ignore2 = 0; + bool ignore1 = false; knot_time_t ignore2 = 0; ret = knot_dnssec_nsec3resalt(&kctx, &ignore1, &ignore2); if (ret != KNOT_EOK) { kdnssec_ctx_deinit(&kctx); diff --git a/src/utils/keymgr/bind_privkey.c b/src/utils/keymgr/bind_privkey.c index 3ae9b9750..d0381a3af 100644 --- a/src/utils/keymgr/bind_privkey.c +++ b/src/utils/keymgr/bind_privkey.c @@ -374,9 +374,9 @@ void bind_privkey_to_timing(bind_privkey_t *params, knot_kasp_key_timing_t *timi { // unsupported: time_created, time_revoke - timing->publish = params->time_publish; - timing->ready = params->time_activate; - timing->active = params->time_activate; - timing->retire = params->time_inactive; - timing->remove = params->time_delete; + timing->publish = (knot_time_t)params->time_publish; + timing->ready = (knot_time_t)params->time_activate; + timing->active = (knot_time_t)params->time_activate; + timing->retire = (knot_time_t)params->time_inactive; + timing->remove = (knot_time_t)params->time_delete; } diff --git a/src/utils/keymgr/functions.c b/src/utils/keymgr/functions.c index 9c71922a8..663d8fd0a 100644 --- a/src/utils/keymgr/functions.c +++ b/src/utils/keymgr/functions.c @@ -141,22 +141,22 @@ static bool genkeyargs(int argc, char *argv[], bool just_timing, } switch ((argv[i][0] == 'r') ? argv[i][3] : argv[i][0]) { case 'c': - timing->created = stamp; + timing->created = (knot_time_t)stamp; break; case 'a': - timing->active = stamp; + timing->active = (knot_time_t)stamp; break; case 'd': - timing->ready = stamp; + timing->ready = (knot_time_t)stamp; break; case 'p': - timing->publish = stamp; + timing->publish = (knot_time_t)stamp; break; case 'i': - timing->retire = stamp; + timing->retire = (knot_time_t)stamp; break; case 'o': - timing->remove = stamp; + timing->remove = (knot_time_t)stamp; break; } } else { @@ -169,7 +169,7 @@ static bool genkeyargs(int argc, char *argv[], bool just_timing, // modifies ctx->policy options, so don't do anything afterwards ! int keymgr_generate_key(kdnssec_ctx_t *ctx, int argc, char *argv[]) { - time_t now = time(NULL), infty = 0x0fffffffffffff00LLU; + knot_time_t now = knot_time(), infty = 0; knot_kasp_key_timing_t gen_timing = { now, now, now, now, infty, infty }; bool isksk = false; uint16_t keysize = 0; @@ -358,7 +358,7 @@ cleanup: int keymgr_import_pem(kdnssec_ctx_t *ctx, const char *import_file, int argc, char *argv[]) { // parse params - time_t now = time(NULL), infty = 0x0fffffffffffff00LLU; + knot_time_t now = knot_time(), infty = 0; knot_kasp_key_timing_t gen_timing = { now, now, now, now, infty, infty }; bool isksk = false; uint16_t keysize = 0; diff --git a/tests/contrib/test_time.c b/tests/contrib/test_time.c index cd11c8fe6..a8bf51573 100644 --- a/tests/contrib/test_time.c +++ b/tests/contrib/test_time.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2017 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 @@ -59,6 +59,68 @@ static void test_diff_ms(void) ok(-40010.0 < ms && ms < -39990.0, "time_diff_ms() negative"); } +static void test_knot_time(void) +{ + knot_time_t a = knot_time(); + knot_time_t inf = 0; + knot_time_t c; + knot_timediff_t d; + int ret; + + ok(a != 0, "knot time not zero"); + + ret = knot_time_cmp(a, a); + ok(ret == 0, "compare same times"); + + ret = knot_time_cmp(a - 1, a + 1); + ok(ret == -1, "compare smaller time"); + + ret = knot_time_cmp(a + 10, a - 10); + ok(ret == 1, "compare bigger time"); + + ret = knot_time_cmp(inf, inf); + ok(ret == 0, "compare two infinities"); + + ret = knot_time_cmp(a, inf); + ok(ret == -1, "compare time and infty"); + + ret = knot_time_cmp(inf, a); + ok(ret == 1, "compare infty and time"); + + c = knot_time_min(a, a); + ok(c == a, "take same time"); + + c = knot_time_min(a, a + 1); + ok(c == a, "take first smaller"); + + c = knot_time_min(a + 1, a); + ok(c == a, "take second smaller"); + + c = knot_time_min(inf, inf); + ok(c == inf, "take same infty"); + + c = knot_time_min(a, inf); + ok(c == a, "take first finite"); + + c = knot_time_min(inf, a); + ok(c == a, "take second finite"); + + d = knot_time_diff(a + 1, a); + ok(d == 1, "positive diff"); + + d = knot_time_diff(a, a + 1); + ok(d == -1, "negative diff"); + + d = knot_time_diff(inf, inf); + ok(d == KNOT_TIMEDIFF_MAX, "positive double infty diff"); + + d = knot_time_diff(inf, a); + ok(d == KNOT_TIMEDIFF_MAX, "positive infty diff"); + + d = knot_time_diff(a, inf); + ok(d == KNOT_TIMEDIFF_MIN, "negative infty diff"); +} + int main(int argc, char *argv[]) { plan_lazy(); @@ -66,6 +128,7 @@ int main(int argc, char *argv[]) test_now(); test_diff(); test_diff_ms(); + test_knot_time(); return 0; } |