Was missing from the previous refactor.
- **Type:** Integer
- **Availability:** `argv` and JSON
-- **Default:** 2
-- **Range:** [0, [`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)]
+- **Default:** 21600 (6 hours)
+- **Range:** [1, [`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)]
+
+RTR delta lifetime, measured in validation cycles.
-When routers first connect to Fort, they request a _snapshot_ of the validation results. (ROAs and Router Keys.) Because they need to keep their validated objects updated, and snapshots tend to be relatively large amounts of information, they request _deltas_ afterwards over configurable intervals. ("Deltas" being the differences between snapshots.)
+When routers first connect to Fort, they request a _snapshot_ of the validation results. (ROAs, Router Keys and ASPAs.) Because they need to keep their validated objects updated, and snapshots tend to be relatively large amounts of information, they request _deltas_ afterwards over configurable intervals. ("Deltas" being the differences between snapshots.)
-During each validation cycle, Fort generates a new snapshot, as well as the deltas needed to build the new snapshot from the previous one. These are all stored in RAM. `--server.deltas.lifetime` is the number of iterations a set of deltas will be kept before being deallocated. (Recall that every iteration lasts [`--server.interval.validation`](#--serverintervalvalidation) seconds, plus however long the validation takes.)
+Fort stores the information necessary to serve these deltas in the cache. `--server.deltas.lifetime` is the number of validation cycles a delta will be preserved before being expired.
If a router lags behind, to the point Fort has already deleted the deltas it needs to update the router's snapshot, Fort will have to fall back to fetch the entire latest snapshot instead.
* minute.
*/
.min = 60,
- .max = UINT_MAX,
+ /*
+ * 7 days.
+ * Must not overflow when multiplied by deltas.lifetime.
+ */
+ .max = 604800,
}, {
.id = 5004,
.name = "server.interval.refresh",
/*
* It's a serial, which means the technical maximum is about
* 2^31 - 1. But that's too much.
+ * Must not overflow when multiplied by interval.validation.
*/
.max = 1000,
},
rpki_config.server.interval.refresh = 3600;
rpki_config.server.interval.retry = 600;
rpki_config.server.interval.expire = 7200;
- rpki_config.server.deltas_lifetime = 2;
+ rpki_config.server.deltas_lifetime = 6;
rpki_config.prometheus.port = 0;
static int
rm(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
- pr_op_debug("Deleting %s.", fpath);
+ pr_op_debug("Deleting %s", fpath);
return (remove(fpath) != 0) ? errno : 0;
}
int
file_rm_rf(char const *path)
{
+ pr_op_debug("rm -rf %s", path);
/* TODO (performance) optimize that 32 */
return nftw(path, rm, 32, FTW_DEPTH | FTW_PHYS);
}
unsigned int total_roas_v4;
unsigned int total_roas_v6;
- struct rtr_metadata rtr;
+ struct rtr_index rtr;
};
struct db_table *
free(aspa);
}
+ rtridx_cleanup(&table->rtr);
+
free(table);
}
}
static int
-cache_vrps(struct db_table *table)
+cache_vrps(struct db_table *table, serial_t serial)
{
FILE *f4 = NULL;
FILE *f6 = NULL;
struct vrp *vrp;
int err;
- err = rtr_open_file(table->rtr.serial, "vrp4", "w", &f4);
+ err = rtr_open_file(serial, "vrp4", "w", &f4);
if (err)
return err;
- err = rtr_open_file(table->rtr.serial, "vrp6", "w", &f6);
+ err = rtr_open_file(serial, "vrp6", "w", &f6);
if (err)
goto end;
}
static int
-cache_rks(struct db_table *table)
+cache_rks(struct db_table *table, serial_t serial)
{
FILE *file = NULL;
struct hashable_key *rk, *tmpr;
int err;
- err = rtr_open_file(table->rtr.serial, "rk", "w", &file);
+ err = rtr_open_file(serial, "rk", "w", &file);
if (err)
return err;
}
static int
-cache_aspas(struct db_table *table)
+cache_aspas(struct db_table *table, serial_t serial)
{
FILE *file = NULL;
struct hashable_aspa *aspa, *tmpa;
array_index i;
int err;
- err = rtr_open_file(table->rtr.serial, "aspa", "w", &file);
+ err = rtr_open_file(serial, "aspa", "w", &file);
if (err)
return err;
char *dir;
int error;
- error = rtr_save_metadata(&table->rtr);
+ error = rtridx_save(&table->rtr);
if (error) {
pr_op_err("Could not save RTR metadata; RTR can no longer be served.");
dir = rtr_filename(NULL, NULL);
return error;
}
-static bool
-is_number(char const *str)
-{
- if (*str == 0)
- return false;
-
- for (; *str != 0; str++)
- if (*str < '0' || '9' < *str)
- return false;
-
- return true;
-}
-
-static void
-delete_old_serials(serial_t current)
-{
- char *path;
- serial_t lowest;
- DIR *dir;
- struct dirent *file;
- unsigned long serial;
- int ret;
-
- lowest = current - ((serial_t)config_get_deltas_lifetime());
-
- path = rtr_filename(NULL, NULL);
- dir = opendir(path);
- free(path);
- if (!dir) {
- if (errno != ENOENT)
- pr_op_warn("Cannot clean rtr directory: %s",
- strerror(errno));
- return;
- }
-
- FOREACH_DIR_FILE(dir, file) {
- if (!is_number(file->d_name))
- continue;
-
- errno = 0;
- serial = strtoul(file->d_name, NULL, 10);
- if (errno) {
- pr_op_warn("Cannot delete rtr/%s: %s",
- file->d_name, strerror(errno));
- continue;
- }
- if (serial > UINT32_MAX) {
- pr_op_warn("Cannot delete rtr/%s: Serial too big",
- file->d_name);
- continue;
- }
-
- if (!serial_lt(serial, lowest))
- continue;
-
- path = rtr_filename2(serial, NULL);
- ret = file_rm_rf(path);
- free(path);
- if (ret < 0)
- pr_op_warn("Cannot delete rtr/%s: nftw returned %d",
- file->d_name, ret);
- else if (ret)
- pr_op_warn("Cannot delete rtr/%s: %s",
- file->d_name, strerror(ret));
- }
- if (errno)
- pr_op_warn("Cleanup rtr directory traversal interrupted: %s",
- strerror(errno));
-
- closedir(dir);
-}
-
int
db_table_cache(struct db_table *table)
{
char *path;
+ serial_t serial;
int ret;
- if (rtr_load_metadata(&table->rtr) != 0)
- rtr_new_metadata(&table->rtr);
- table->rtr.serial++;
+ ret = rtridx_load(&table->rtr, true);
+ if (ret == ENOENT)
+ rtridx_init(&table->rtr);
+ else if (ret) {
+ pr_op_err("Cannot access RTR index file: %s", strerror(ret));
+ return ret;
+ }
+
+ serial = rtridx_add_serial(&table->rtr);
- path = rtr_filename(NULL, NULL);
+ path = rtr_filename(NULL, NULL); /* cache/rtr */
ret = mkdir_f(path);
free(path);
if (ret)
return ret;
- path = rtr_filename2(table->rtr.serial, NULL);
+ path = rtr_filename2(serial, NULL); /* cache/rtr/1234 */
ret = mkdir_f(path);
free(path);
if (ret)
return ret;
- ret = cache_vrps(table);
+ ret = cache_vrps(table, serial);
if (ret)
goto fail;
- ret = cache_rks(table);
+ ret = cache_rks(table, serial);
if (ret)
goto fail;
- ret = cache_aspas(table);
+ ret = cache_aspas(table, serial);
if (ret)
goto fail;
ret = cache_metadata(table);
if (ret)
goto fail;
- delete_old_serials(table->rtr.serial);
+ rtridx_clean(&table->rtr);
return 0;
-fail: path = rtr_filename2(table->rtr.serial, NULL);
+fail: path = rtr_filename2(serial, NULL);
file_rm_rf(path);
free(path);
return ret;
serial_t
db_table_serial(struct db_table *table)
{
- return table ? table->rtr.serial : 0;
+ return (table && table->rtr.serials) ? table->rtr.serials->serial : 0;
}
void
#include "alloc.h"
#include "common.h"
#include "config.h"
+#include "data_structure/common.h"
#include "log.h"
#include "file.h"
}
void
-rtr_new_metadata(struct rtr_metadata *rtr)
+rtridx_init(struct rtr_index *idx)
{
- time_t now = 0x1234u;
- get_current_time(&now);
- rtr->session = now & 0xFFFFu;
- rtr->serial = 0;
+ time_t now;
+
+ now = time(NULL);
+ if (now == (time_t)-1)
+ pr_crit("time(NULL) returned (time_t) -1.");
+
+ idx->session = now & 0xFFFF;
+ idx->serials = NULL;
}
int
-rtr_save_metadata(struct rtr_metadata *rtr)
+rtridx_save(struct rtr_index *idx)
{
- char *filepath;
+ char *path;
FILE *file;
- int error = 0;
+ struct rtr_serial *srl;
+ int error;
- filepath = rtr_filename("metadata", NULL);
+ path = rtr_filename("index", NULL);
- file = fopen(filepath, "w");
+ file = fopen(path, "w");
if (!file) {
error = errno;
pr_op_err("Cannot open '%s' for writing: %s",
- filepath, strerror(error));
- free(filepath);
+ path, strerror(error));
+ free(path);
return error;
}
- free(filepath);
+ free(path);
+
+ if (fprintf(file, "session:%u\n", idx->session) < 0) {
+ error = pr_op_err("fprintf(session) failed.");
+ goto end;
+ }
- if (fprintf(file, "session:%u serial:%u", rtr->session, rtr->serial) < 0)
- error = pr_op_err("fprintf(serial) failed.");
+ for (srl = idx->serials; srl; srl = srl->next) {
+ if (fprintf(file, "serial:%u date:%04d-%02d-%02dT%02d:%02d:%02dZ\n",
+ srl->serial, srl->date.tm_year + 1900, srl->date.tm_mon + 1,
+ srl->date.tm_mday, srl->date.tm_hour, srl->date.tm_min,
+ srl->date.tm_sec) < 0) {
+ error = pr_op_err("fprintf(serial) failed.");
+ goto end;
+ }
+ }
- fclose(file);
+ error = 0;
+
+end: fclose(file);
return error;
}
+/*
+ * If @all is true, loads all the serials from the index.
+ * Otherwise loads only the most recent one.
+ */
int
-rtr_load_metadata(struct rtr_metadata *rtr)
+rtridx_load(struct rtr_index *idx, bool all)
{
char *filepath;
FILE *file;
- unsigned int session;
- unsigned int serial;
- int error = 0;
+ char buf[64];
+ unsigned int se;
+ struct rtr_serial *srl, *prev;
+ int error;
+
+ idx->serials = NULL;
- filepath = rtr_filename("metadata", NULL);
+ filepath = rtr_filename("index", NULL); /* cache/rtr/index */
file = fopen(filepath, "r");
if (!file) {
+ error = errno;
+ if (error != ENOENT)
+ pr_op_warn("Cannot open RTR index: %s", strerror(error));
free(filepath);
- return errno;
+ return error;
}
free(filepath);
- if (fscanf(file, "session:%u serial:%u", &session, &serial) >= 2) {
- rtr->session = session;
- rtr->serial = serial;
- } else {
- error = EINVAL;
+ if (!fgets(buf, sizeof(buf), file)) {
+ pr_op_debug("RTR index seems empty.");
+ goto fail;
+ }
+ if (sscanf(buf, "session:%u", &se) < 1 || se > UINT16_MAX) {
+ pr_op_debug("First line of RTR index is not a session.");
+ goto fail;
+ }
+
+ idx->session = se;
+ prev = NULL;
+
+ while (fgets(buf, sizeof(buf), file) != NULL) {
+ srl = pzalloc(sizeof(struct rtr_serial));
+
+ if (sscanf(buf, "serial:%u date:%d-%d-%dT%d:%d:%dZ",
+ &se, &srl->date.tm_year, &srl->date.tm_mon,
+ &srl->date.tm_mday, &srl->date.tm_hour, &srl->date.tm_min,
+ &srl->date.tm_sec) < 1 || se > UINT32_MAX) {
+ pr_op_debug("Malformed serial in RTR index.");
+ goto fail;
+ }
+ srl->serial = se;
+
+ if (idx->serials) {
+ if (serial_le(idx->serials->serial, srl->serial)) {
+ pr_op_debug("RTR index serials are not sorted.");
+ goto fail;
+ }
+ }
+
+ srl->date.tm_year -= 1900;
+ srl->date.tm_mon -= 1;
+ if (prev)
+ prev->next = srl;
+ else
+ idx->serials = srl;
+ prev = srl;
+
+ if (!all)
+ break;
}
fclose(file);
- return error;
+ return 0;
+
+fail: fclose(file);
+ rtridx_cleanup(idx);
+ return ENOENT;
+}
+
+serial_t
+rtridx_add_serial(struct rtr_index *idx)
+{
+ struct rtr_serial *srl;
+ time_t now;
+
+ srl = pmalloc(sizeof(struct rtr_serial));
+
+ srl->serial = idx->serials ? (idx->serials->serial + 1) : 1;
+
+ now = time(NULL);
+ if (now == (time_t)-1)
+ pr_crit("time(NULL) returned (time_t) -1.");
+ if (gmtime_r(&now, &srl->date) == NULL)
+ pr_crit("gmtime_r(now) failed: %s", strerror(errno));
+
+ srl->next = idx->serials;
+ idx->serials = srl;
+
+ return srl->serial;
+}
+
+void
+rtridx_cleanup(struct rtr_index *idx)
+{
+ struct rtr_serial *srl;
+
+ while (idx->serials) {
+ srl = idx->serials;
+ idx->serials = srl->next;
+ free(srl);
+ }
+}
+
+void
+rtridx_print(struct rtr_index *idx)
+{
+ struct rtr_serial *srl;
+
+ printf("==== RTR index ====\n");
+
+ if (!idx) {
+ printf("<Empty>\n");
+ return;
+ }
+
+ printf("session:%u\n", idx->session);
+ printf("serials:\n");
+
+ for (srl = idx->serials; srl; srl = srl->next)
+ printf(" serial:%u date:%04d-%02d-%02dT%02d:%02d:%02dZ\n",
+ srl->serial,
+ srl->date.tm_year + 1900, srl->date.tm_mon + 1, srl->date.tm_mday,
+ srl->date.tm_hour, srl->date.tm_min + 1, srl->date.tm_sec);
+}
+
+static bool
+is_number(char const *str)
+{
+ if (*str == 0)
+ return false;
+
+ for (; *str != 0; str++)
+ if (*str < '0' || '9' < *str)
+ return false;
+
+ return true;
+}
+
+static void
+rm_rf(char *path)
+{
+ int error;
+
+ error = file_rm_rf(path);
+ if (error < 0)
+ pr_op_warn("Cannot delete %s: nftw returned %d", path, error);
+ else if (error)
+ pr_op_warn("Cannot delete %s: %s", path, strerror(error));
+
+ free(path);
+}
+
+static void
+delete_unindexed_serials(serial_t min, serial_t max)
+{
+ char *path;
+ DIR *dir;
+ struct dirent *file;
+ serial_t serial;
+
+ path = rtr_filename(NULL, NULL);
+ dir = opendir(path);
+ free(path);
+ if (!dir) {
+ if (errno != ENOENT)
+ pr_op_warn("Cannot clean rtr directory: %s",
+ strerror(errno));
+ return;
+ }
+
+ FOREACH_DIR_FILE(dir, file) {
+ if (S_ISDOTS(file) || strcmp(file->d_name, "index") == 0)
+ continue;
+ if (!is_number(file->d_name))
+ goto rm;
+
+ errno = 0;
+ serial = strtoul(file->d_name, NULL, 10);
+ if (errno || serial > UINT32_MAX)
+ goto rm;
+
+ if (serial_le(min, serial) && serial_le(serial, max))
+ continue;
+
+rm: pr_op_warn("Deleting stray filesystem entry rtr/%s", file->d_name);
+ rm_rf(rtr_filename(file->d_name, NULL));
+ }
+ if (errno)
+ pr_op_warn("Cleanup rtr directory traversal interrupted: %s",
+ strerror(errno));
+
+ closedir(dir);
+}
+
+/*
+ * Cleans cache/rtr.
+ * This means dropping serials that exceed the threshold
+ * (config_get_deltas_lifetime()) and unknown files or directories
+ * directly in cache/rtr.
+ */
+void
+rtridx_clean(struct rtr_index *idx)
+{
+ struct rtr_serial *srl, **prev;
+ serial_t min, max;
+
+ max = idx->serials[0].serial;
+ min = max - config_get_deltas_lifetime();
+
+ for (srl = idx->serials, prev = &idx->serials; srl; srl = *prev) {
+ if (serial_lt(srl->serial, min) || serial_lt(max, srl->serial)) {
+ pr_op_debug("Dropping serial by FIFO: %u", srl->serial);
+ rm_rf(rtr_filename2(srl->serial, NULL));
+ *prev = srl->next;
+ free(srl);
+ } else {
+ prev = &srl->next;
+ }
+ }
+
+ if (!idx->serials) {
+ /* The session died; we'll create a new one later. */
+ pr_op_debug("All serials expired; clearing RTR cache.");
+ rm_rf(rtr_filename(NULL, NULL));
+ return;
+ }
+
+ rtridx_save(idx);
+
+ /* Clean up unindexed serials for paranoia */
+ delete_unindexed_serials(min, max);
+}
+
+static bool
+too_old(struct rtr_serial *srl, time_t now)
+{
+ time_t serial_date;
+ double diff;
+ unsigned int lifetime;
+
+ serial_date = timegm(&srl->date);
+ if (serial_date == (time_t)-1)
+ return true; /* Dunno; delete it */
+
+ diff = difftime(serial_date, now);
+ if (diff > 0)
+ return true; /* Dunno; delete it */
+
+ /*
+ * This is an estimate. In reality, I'd like deltas_lifetime to be the
+ * timestamp, but I can't because of historical reasons, and also
+ * because it's a lot easier to test as a cycle count.
+ */
+ lifetime = config_get_deltas_lifetime() * config_get_validation_interval();
+
+ return (-diff) > lifetime;
+}
+
+/* Deletes serials that are too old, based on time. */
+void
+rtridx_expire(void)
+{
+ time_t now;
+ struct rtr_index idx;
+ struct rtr_serial *srl, **prev;
+ int error;
+
+ now = time(NULL);
+ if (now == (time_t)-1) {
+ pr_op_warn("Can't ditch old RTR: time() returned -1.");
+ return;
+ }
+
+ error = rtridx_load(&idx, true);
+ if (error == ENOENT)
+ return;
+ if (error) {
+ pr_op_warn("Can't ditch old RTR: %s", strerror(error));
+ return;
+ }
+
+ for (srl = idx.serials, prev = &idx.serials; srl; srl = *prev) {
+ if (too_old(srl, now)) {
+ pr_op_debug("Dropping expired serial: %u", srl->serial);
+ rm_rf(rtr_filename2(srl->serial, NULL));
+ *prev = srl->next;
+ free(srl);
+ } else {
+ prev = &srl->next;
+ }
+ }
+
+ if (!idx.serials) {
+ /* The session died; we'll create a new one later. */
+ pr_op_debug("All serials expired; clearing RTR cache.");
+ rm_rf(rtr_filename(NULL, NULL));
+ goto end;
+ }
+
+ rtridx_save(&idx);
+end: rtridx_cleanup(&idx);
}
int
#define SRC_RTR_META_H_
#include <stdio.h>
+#include <time.h>
+#include <sys/queue.h>
#include "types/serial.h"
struct rtr_metadata {
serial_t serial;
};
+struct rtr_serial {
+ serial_t serial;
+ struct tm date;
+ struct rtr_serial *next;
+};
+
+struct rtr_index {
+ uint16_t session;
+ /*
+ * Linked list; sorted from newest to oldest.
+ *
+ * Can't use SLIST because clean() and expire() want safe traversal
+ * with cursor removals.
+ */
+ struct rtr_serial *serials;
+};
+
char *rtr_filename(char const *, char const *);
char *rtr_filename2(serial_t, char const *);
-void rtr_new_metadata(struct rtr_metadata *);
-int rtr_save_metadata(struct rtr_metadata *);
-int rtr_load_metadata(struct rtr_metadata *);
+void rtridx_init(struct rtr_index *);
+int rtridx_save(struct rtr_index *);
+int rtridx_load(struct rtr_index *, bool);
+serial_t rtridx_add_serial(struct rtr_index *);
+void rtridx_cleanup(struct rtr_index *);
+void rtridx_print(struct rtr_index *);
+
+void rtridx_clean(struct rtr_index *);
+void rtridx_expire(void);
int rtr_serial_stat(serial_t serial);
return error;
}
+static int
+load_rtr_metadata(struct rtr_metadata *rtr)
+{
+ struct rtr_index idx;
+ int error;
+
+ error = rtridx_load(&idx, false);
+ if (error)
+ return error;
+ if (idx.serials == NULL) {
+ error = ENOENT;
+ goto end;
+ }
+
+ rtr->session = idx.session;
+ rtr->serial = idx.serials->serial;
+
+end: rtridx_cleanup(&idx);
+ return error;
+}
+
int
handle_reset_query_pdu(struct rtr_request *request)
{
stream.fd = request->fd;
stream.ver = request->pdu.rtr_version;
- error = rtr_load_metadata(&rtr);
+ error = load_rtr_metadata(&rtr);
switch (error) {
case 0:
break;
stream.fd = request->fd;
stream.ver = request->pdu.rtr_version;
- error = rtr_load_metadata(&rtr);
+ error = load_rtr_metadata(&rtr);
switch (error) {
case 0: break;
case ENOENT: return err_pdu_send_no_data_available(stream.fd, stream.ver);
default: goto internal_error;
}
+ pr_op_debug("Sending RTR delta: %u-%u", oserial, nserial);
+
error = send_cache_response_pdu(stream.fd, stream.ver, rtr.session);
if (error)
return error;
unsigned char data[RTRPDU_SERIAL_NOTIFY_LEN];
unsigned char *buf;
+ pr_op_debug("Sending Serial Notify PDU.");
+
buf = serialize_hdr(data, version, type, meta->session, len);
buf = write_uint32(buf, meta->serial);
static const uint32_t len = RTRPDU_CACHE_RESET_LEN;
unsigned char data[RTRPDU_CACHE_RESET_LEN];
+ pr_op_debug("Sending Cache Reset PDU.");
serialize_hdr(data, version, type, 0, len);
-
return send_response(fd, type, data, len);
}
static const uint32_t len = RTRPDU_CACHE_RESPONSE_LEN;
unsigned char data[RTRPDU_CACHE_RESPONSE_LEN];
+ pr_op_debug("Sending Cache Response PDU.");
serialize_hdr(data, version, type, session, len);
-
return send_response(fd, type, data, len);
}
int
send_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp, uint8_t flags)
{
+ pr_op_debug("Sending Prefix PDU.");
+
switch (vrp->addr_fam) {
case AF_INET:
return send_ipv4_prefix_pdu(fd, version, vrp, flags);
if (version < RTR_V1)
return 0;
+ pr_op_debug("Sending RK PDU.");
+
buf = serialize_hdr(data, version, type, flags << 8, len);
memcpy(buf, router_key->ski, sizeof(router_key->ski));
buf += sizeof(router_key->ski);
if (version < RTR_V2)
return 0;
+ pr_op_debug("Sending ASPA announcement PDU.");
+
bufsize = 12 + 4 * aspa->providers.count;
if (bufsize > 1024)
bufsize = 1024;
unsigned char data[12];
unsigned char *buf;
+ pr_op_debug("Sending ASPA withdraw PDU.");
+
buf = serialize_hdr(data, version, type, FLAG_WITHDRAWAL << 8, 12);
write_uint32(buf, customer);
unsigned char *buf;
uint32_t len;
+ pr_op_debug("Sending End of Data PDU.");
+
switch (version) {
case RTR_V0:
len = RTRPDU_END_OF_DATA_V0_LEN;
size_t len;
int error;
+ pr_op_debug("Sending error PDU: %s", message);
+
error_pdu_len = compute_error_pdu_len(request);
error_msg_len = (message != NULL) ? strlen(message) : 0;
len = rtrpdu_error_report_len(error_pdu_len, error_msg_len);
{
int error;
+ rtridx_expire();
+
server_arraylist_init(&servers);
client_arraylist_init(&clients);
return ((s1 < s2) && ((s2 - s1) < 0x80000000u)) ||
((s1 > s2) && ((s1 - s2) > 0x80000000u));
}
+
+bool
+serial_le(serial_t s1, serial_t s2)
+{
+ return (s1 == s2) ? true : serial_lt(s1, s2);
+}
typedef uint32_t serial_t;
bool serial_lt(serial_t s1, serial_t s2);
+bool serial_le(serial_t s1, serial_t s2);
#endif /* SRC_TYPES_SERIAL_H_ */
__MOCK_ABORT(config_get_deltas_lifetime, unsigned int, 0, void)
__MOCK_ABORT(config_get_local_repository, char const *, "tmp/dbt", void)
MOCK_UINT(config_get_max_aspa_providers, 10, void)
-MOCK_ABORT_VOID(rtr_new_metadata, struct rtr_metadata *m)
-MOCK_ABORT_INT(rtr_save_metadata, struct rtr_metadata *m)
-MOCK_ABORT_INT(rtr_load_metadata, struct rtr_metadata *m)
+MOCK_ABORT_VOID(rtridx_init, struct rtr_index *i)
+MOCK_ABORT_INT(rtridx_save, struct rtr_index *i)
+MOCK_ABORT_INT(rtridx_load, struct rtr_index *i, bool b)
MOCK_ABORT_INT(rtr_open_file, serial_t serial, char const *basename,
char const *mode, FILE **result)
__MOCK_ABORT(rtr_filename, char *, NULL, char const *a, char const *b)