]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Optimize the ROA code
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Wed, 10 Apr 2019 21:58:11 +0000 (16:58 -0500)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Mon, 22 Apr 2019 22:59:25 +0000 (17:59 -0500)
Changed a bunch of arraylists into a tree. Helps with substantially
reducing comparisons needed to compute deltas.

55 files changed:
src/Makefile.am
src/address.c
src/address.h
src/asn1/signed_data.c
src/asn1/signed_data.h
src/clients.c
src/console_handler.c [new file with mode: 0644]
src/console_handler.h [new file with mode: 0644]
src/data_structure/array_list.h [moved from src/array_list.h with 66% similarity]
src/data_structure/circular_indexer.c [new file with mode: 0644]
src/data_structure/circular_indexer.h [new file with mode: 0644]
src/data_structure/common.h [new file with mode: 0644]
src/main.c
src/notify.c
src/object/certificate.c
src/object/certificate.h
src/object/name.c
src/object/name.h
src/object/roa.c
src/object/roa.h
src/object/tal.c
src/object/tal.h
src/rpp.c
src/rtr/db/delta.c [new file with mode: 0644]
src/rtr/db/delta.h [new file with mode: 0644]
src/rtr/db/roa.c [new file with mode: 0644]
src/rtr/db/roa.h [new file with mode: 0644]
src/rtr/db/roa_tree.c [new file with mode: 0644]
src/rtr/db/roa_tree.h [new file with mode: 0644]
src/rtr/db/vrp.h [new file with mode: 0644]
src/rtr/db/vrps.c [new file with mode: 0644]
src/rtr/db/vrps.h [new file with mode: 0644]
src/rtr/pdu.h
src/rtr/pdu_handler.c
src/rtr/pdu_sender.c
src/rtr/pdu_sender.h
src/rtr/pdu_serializer.h
src/rtr/primitive_reader.h
src/rtr/primitive_writer.h
src/rtr/rtr.h
src/state.c
src/state.h
src/thread_var.c
src/thread_var.h
src/updates_daemon.c
src/validation_handler.c [new file with mode: 0644]
src/validation_handler.h [new file with mode: 0644]
src/vrps.c [deleted file]
src/vrps.h [deleted file]
test/Makefile.am
test/address_test.c
test/data_structure/circular_indexer_test.c [new file with mode: 0644]
test/impersonator.c
test/rtr/pdu_test.c
test/rtr/stream.h

index c6b56a885802d0033442af8fb3881812806d779d..fd901afc29c5f0b4d2f6aa9aaaacbb1d211cb1e6 100644 (file)
@@ -1,6 +1,6 @@
 # Comment these out during releases.
 # Also increase optimization I guess (-O0 -> -On)
-CFLAGS_DEBUG  = -DDEBUG
+#CFLAGS_DEBUG  = -DDEBUG
 LDFLAGS_DEBUG = -rdynamic
 
 bin_PROGRAMS = fort
@@ -9,8 +9,8 @@ fort_SOURCES  = main.c
 
 fort_SOURCES += address.h address.c
 fort_SOURCES += algorithm.h algorithm.c
-fort_SOURCES += array_list.h
 fort_SOURCES += certificate_refs.h certificate_refs.c
+fort_SOURCES += console_handler.h console_handler.c
 fort_SOURCES += common.h
 fort_SOURCES += config.h config.c
 fort_SOURCES += debug.h debug.c
@@ -28,6 +28,7 @@ fort_SOURCES += str.h str.c
 fort_SOURCES += thread_var.h thread_var.c
 fort_SOURCES += uri.h uri.c
 fort_SOURCES += json_handler.h json_handler.c
+fort_SOURCES += validation_handler.h validation_handler.c
 
 fort_SOURCES += rsync/rsync.h rsync/rsync.c
 
@@ -45,9 +46,14 @@ fort_SOURCES += config/types.h
 fort_SOURCES += config/uint.c config/uint.h
 fort_SOURCES += config/uint32.c config/uint32.h
 
+fort_SOURCES += data_structure/array_list.h
+
 fort_SOURCES += crypto/base64.h crypto/base64.c
 fort_SOURCES += crypto/hash.h crypto/hash.c
 
+fort_SOURCES += data_structure/circular_indexer.h
+fort_SOURCES += data_structure/circular_indexer.c
+
 fort_SOURCES += object/certificate.h object/certificate.c
 fort_SOURCES += object/crl.h object/crl.c
 fort_SOURCES += object/ghostbusters.h object/ghostbusters.c
@@ -67,7 +73,6 @@ fort_SOURCES += clients.c clients.h
 fort_SOURCES += common.c common.h
 fort_SOURCES += notify.c notify.h
 fort_SOURCES += updates_daemon.c updates_daemon.h
-fort_SOURCES += vrps.c vrps.h
 
 fort_SOURCES += rtr/err_pdu.c rtr/err_pdu.h
 fort_SOURCES += rtr/pdu_handler.c rtr/pdu_handler.h
@@ -78,20 +83,25 @@ fort_SOURCES += rtr/primitive_reader.c rtr/primitive_reader.h
 fort_SOURCES += rtr/primitive_writer.c rtr/primitive_writer.h
 fort_SOURCES += rtr/rtr.c rtr/rtr.h
 
+fort_SOURCES += rtr/db/delta.c rtr/db/delta.h
+fort_SOURCES += rtr/db/roa_tree.c rtr/db/roa_tree.h
+fort_SOURCES += rtr/db/roa.c rtr/db/roa.h
+fort_SOURCES += rtr/db/vrps.c rtr/db/vrps.h
+
 fort_CFLAGS  = -Wall
 # Feel free to temporarily remove this one if you're not using gcc 7.3.0.
-fort_CFLAGS += $(GCC_WARNS)
+#fort_CFLAGS += $(GCC_WARNS)
 fort_CFLAGS += -std=gnu99 -O0 -g $(CFLAGS_DEBUG)
 fort_LDFLAGS = $(LDFLAGS_DEBUG)
 fort_LDADD   = ${JANSSON_LIBS}
 
 # I'm tired of scrolling up, but feel free to comment this out.
-#GCC_WARNS  = -fmax-errors=1
+GCC_WARNS  = -fmax-errors=1
 
 # Please ready some arguments if you want to permanently remove some of these
 # flags. I gave a quick read to the documentation of all of these warnings, and
 # generally liked each of them.
-GCC_WARNS = -Wpedantic -pedantic-errors -Waddress -Walloc-zero -Walloca
+GCC_WARNS += -Wpedantic -pedantic-errors -Waddress -Walloc-zero -Walloca
 GCC_WARNS += -Wno-aggressive-loop-optimizations -Warray-bounds=2 -Wbool-compare
 GCC_WARNS += -Wbool-operation -Wno-builtin-declaration-mismatch -Wcast-align
 GCC_WARNS += -Wcast-qual -Wchar-subscripts -Wchkp -Wclobbered -Wcomment
index c37e583cc2e674015922bf79a34565afa633b36c..cdde1ec63781d295286cf7dbdd3a85f37a60d617 100644 (file)
@@ -112,11 +112,34 @@ ipv6_suffix_mask(unsigned int prefix_len, struct in6_addr *result)
        }
 }
 
+bool
+prefix4_equals(struct ipv4_prefix const *a, struct ipv4_prefix const *b)
+{
+       return (a->addr.s_addr == b->addr.s_addr) && (a->len == b->len);
+}
+
+bool
+prefix6_equals(struct ipv6_prefix const *a, struct ipv6_prefix const *b)
+{
+       unsigned int i;
+
+       /*
+        * Not sure if I can use a memcmp() instead.
+        * I feel like in6_addr's union could cause padding in weird
+        * implementations.
+        */
+       for (i = 0; i < 16; i++)
+               if (a->addr.s6_addr[i] != b->addr.s6_addr[i])
+                       return false;
+
+       return a->len == b->len;
+}
+
 /**
  * Translates an `IPAddress_t` to its equivalent `struct ipv4_prefix`.
  */
 int
-prefix4_decode(IPAddress_t *str, struct ipv4_prefix *result)
+prefix4_decode(IPAddress_t const *str, struct ipv4_prefix *result)
 {
        int len;
 
@@ -152,7 +175,7 @@ prefix4_decode(IPAddress_t *str, struct ipv4_prefix *result)
  * Translates an `IPAddress_t` to its equivalent `struct ipv6_prefix`.
  */
 int
-prefix6_decode(IPAddress_t *str, struct ipv6_prefix *result)
+prefix6_decode(IPAddress_t const *str, struct ipv6_prefix *result)
 {
        struct in6_addr suffix;
        int len;
@@ -226,7 +249,7 @@ check_encoding4(struct ipv4_range *range)
  * Translates an `IPAddressRange_t` to its equivalent `struct ipv4_range`.
  */
 int
-range4_decode(IPAddressRange_t *input, struct ipv4_range *result)
+range4_decode(IPAddressRange_t const *input, struct ipv4_range *result)
 {
        struct ipv4_prefix prefix;
        int error;
@@ -319,7 +342,7 @@ check_encoding6(struct ipv6_range *range)
  * Translates an `IPAddressRange_t` to its equivalent `struct ipv6_range`.
  */
 int
-range6_decode(IPAddressRange_t *input, struct ipv6_range *result)
+range6_decode(IPAddressRange_t const *input, struct ipv6_range *result)
 {
        struct ipv6_prefix prefix;
        int error;
index 75126079131cc44337e7e0188beda6dc193e5ee9..74dba9c3f02492ab443c7832cc5212479092afd3 100644 (file)
@@ -30,9 +30,12 @@ uint32_t u32_suffix_mask(unsigned int);
 uint32_t be32_suffix_mask(unsigned int);
 void ipv6_suffix_mask(unsigned int, struct in6_addr *);
 
-int prefix4_decode(IPAddress_t *, struct ipv4_prefix *);
-int prefix6_decode(IPAddress_t *, struct ipv6_prefix *);
-int range4_decode(IPAddressRange_t *, struct ipv4_range *);
-int range6_decode(IPAddressRange_t *, struct ipv6_range *);
+bool prefix4_equals(struct ipv4_prefix const *, struct ipv4_prefix const *);
+bool prefix6_equals(struct ipv6_prefix const *, struct ipv6_prefix const *);
+
+int prefix4_decode(IPAddress_t const *, struct ipv4_prefix *);
+int prefix6_decode(IPAddress_t const *, struct ipv6_prefix *);
+int range4_decode(IPAddressRange_t const *, struct ipv4_range *);
+int range6_decode(IPAddressRange_t const *, struct ipv6_range *);
 
 #endif /* SRC_ADDRESS_H_ */
index 6967198282907d740c5a9fba731334371f98fc9e..0ad8b3145641b8af11743dafc55094adf9a9f9bc 100644 (file)
@@ -1,4 +1,4 @@
-#include "signed_data.h"
+#include "asn1/signed_data.h"
 
 #include <errno.h>
 #include <libcmscodec/ContentType.h>
@@ -31,6 +31,7 @@ signed_object_args_init(struct signed_object_args *args,
        args->uri = uri;
        args->crls = crls;
        memset(&args->refs, 0, sizeof(args->refs));
+       args->subject_name = NULL;
        return 0;
 }
 
@@ -39,6 +40,8 @@ signed_object_args_cleanup(struct signed_object_args *args)
 {
        resources_destroy(args->res);
        refs_cleanup(&args->refs);
+       if (args->subject_name != NULL)
+               x509_name_put(args->subject_name);
 }
 
 static int
@@ -93,7 +96,7 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct signed_object_args *args,
        error = certificate_validate_chain(cert, args->crls);
        if (error)
                goto end2;
-       error = certificate_validate_rfc6487(cert, false);
+       error = certificate_validate_rfc6487(cert, &args->subject_name, false);
        if (error)
                goto end2;
        error = certificate_validate_extensions_ee(cert, sid, &args->refs,
index 75ca70899b324afb8a6d5186962870419eb58fd9..67ce0ea6548363ea03f483c91159010e5b8f7268 100644 (file)
@@ -23,6 +23,8 @@ struct signed_object_args {
         * recorded for future validation.
         */
        struct certificate_refs refs;
+       /** Certificate's subject name field */
+       struct rfc5280_name *subject_name;
 };
 
 int signed_object_args_init(struct signed_object_args *,
index 53d960a14dbbfbd659e7ddfb8abecfd6f54a6f49..bd072f37f34936a6356a5a5a6d695f7395b21b89 100644 (file)
@@ -1,14 +1,14 @@
 #include "clients.h"
 
-#include "array_list.h"
 #include "common.h"
+#include "data_structure/array_list.h"
 
 #define SADDR_IN(addr) ((struct sockaddr_in *)addr)
 #define SADDR_IN6(addr) ((struct sockaddr_in6 *)addr)
 
 ARRAY_LIST(clientsdb, struct client)
 
-struct clientsdb clients_db;
+static struct clientsdb clients_db;
 
 /* Read and Write locks */
 sem_t rlock, wlock;
diff --git a/src/console_handler.c b/src/console_handler.c
new file mode 100644 (file)
index 0000000..e10a34e
--- /dev/null
@@ -0,0 +1,38 @@
+#include "console_handler.h"
+
+#include "thread_var.h"
+#include "validation_handler.h"
+#include "object/tal.h"
+
+static int
+print_v4_roa(uint32_t as, struct ipv4_prefix const *prefix, uint8_t max_length,
+    void *arg)
+{
+       printf("AS%u,%s/%u,%u\n", as, v4addr2str(&prefix->addr), prefix->len,
+           max_length);
+       return 0;
+}
+
+static int
+print_v6_roa(uint32_t as, struct ipv6_prefix const *prefix, uint8_t max_length,
+    void *arg)
+{
+       printf("AS%u,%s/%u,%u\n", as, v6addr2str(&prefix->addr), prefix->len,
+           max_length);
+       return 0;
+}
+
+int
+validate_into_console(void)
+{
+       struct validation_handler handler;
+
+       handler.reset = NULL;
+       handler.traverse_down = NULL;
+       handler.traverse_up = NULL;
+       handler.handle_roa_v4 = print_v4_roa;
+       handler.handle_roa_v6 = print_v6_roa;
+       handler.arg = NULL;
+
+       return perform_standalone_validation(&handler);
+}
diff --git a/src/console_handler.h b/src/console_handler.h
new file mode 100644 (file)
index 0000000..b712f24
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef SRC_CONSOLE_HANDLER_H_
+#define SRC_CONSOLE_HANDLER_H_
+
+int validate_into_console(void);
+
+#endif /* SRC_CONSOLE_HANDLER_H_ */
similarity index 66%
rename from src/array_list.h
rename to src/data_structure/array_list.h
index 0453c1f1a9dee1dcf57265005bc66b38ba4c4d47..595600c575f4d2cb409810eceeb444334a2cccb8 100644 (file)
@@ -1,25 +1,29 @@
-#ifndef SRC_ARRAY_LIST_H_
-#define SRC_ARRAY_LIST_H_
+#ifndef SRC_DATA_STRUCTURE_ARRAY_LIST_H_
+#define SRC_DATA_STRUCTURE_ARRAY_LIST_H_
 
 #include <errno.h>
 #include <stdlib.h>
 #include "log.h"
+#include "data_structure/common.h"
 
-#define ARRAY_LIST(name, elem_type)                                    \
+/* TODO sizes used to be unsigned ints. Check callers. */
+#define DEFINE_ARRAY_LIST_STRUCT(name, elem_type)                      \
        struct name {                                                   \
                /** Unidimensional array. */                            \
                elem_type *array;                                       \
                /** Number of elements in @array. */                    \
-               unsigned int len;                                       \
+               size_t len;                                             \
                /** Actual allocated slots in @array. */                \
-               unsigned int capacity;                                  \
-       };                                                              \
-                                                                       \
+               size_t capacity;                                        \
+       }
+
+#define DEFINE_ARRAY_LIST_FUNCTIONS(name, elem_type)                   \
        static int                                                      \
        name##_init(struct name *list)                                  \
        {                                                               \
                list->capacity = 8;                                     \
                list->len = 0;                                          \
+               /* TODO I need lazy initialization of this badly */     \
                list->array = malloc(list->capacity                     \
                    * sizeof(elem_type));                               \
                return (list->array != NULL) ? 0 : pr_enomem();         \
        static void                                                     \
        name##_cleanup(struct name *list, void (*cb)(elem_type *))      \
        {                                                               \
-               unsigned int i;                                         \
-               for (i = 0; i < list->len; i++)                         \
-                       cb(&list->array[i]);                            \
+               array_index i;                                          \
+               /* TODO recently added this. Use it more */             \
+               if (cb != NULL)                                         \
+                       for (i = 0; i < list->len; i++)                 \
+                               cb(&list->array[i]);                    \
                free(list->array);                                      \
        }                                                               \
                                                                        \
                return 0;                                               \
        }
 
+#define ARRAY_LIST(name, elem_type)                                    \
+       DEFINE_ARRAY_LIST_STRUCT(name, elem_type);                      \
+       DEFINE_ARRAY_LIST_FUNCTIONS(name, elem_type)
+
 #define ARRAYLIST_FOREACH(list, cursor) for (                          \
        cursor = (list)->array;                                         \
        (cursor - ((typeof(cursor)) ((list)->array))) < (list)->len;    \
        cursor++                                                        \
 )
 
-#endif /* SRC_ARRAY_LIST_H_ */
+#endif /* SRC_DATA_STRUCTURE_ARRAY_LIST_H_ */
diff --git a/src/data_structure/circular_indexer.c b/src/data_structure/circular_indexer.c
new file mode 100644 (file)
index 0000000..f12a3ca
--- /dev/null
@@ -0,0 +1,164 @@
+#include "data_structure/circular_indexer.h"
+
+#include <stdlib.h>
+#include "log.h"
+
+void
+arridx_init(struct circular_indexer *result, size_t len)
+{
+       result->indexes = NULL;
+       result->first = len - 1;
+       result->current = len - 1;
+       result->top = 0;
+       result->len = len;
+       result->allow_another_lap = false;
+}
+
+void
+arridx_cleanup(struct circular_indexer *indexer)
+{
+       if (indexer->indexes != NULL)
+               free(indexer->indexes);
+}
+
+static struct circular_indexer_node *
+get_node(struct circular_indexer *indexer, array_index index)
+{
+       return &indexer->indexes[index - indexer->top];
+}
+
+static struct circular_indexer_node *
+get_current(struct circular_indexer *indexer)
+{
+       return get_node(indexer, indexer->current);
+}
+
+array_index *
+arridx_first(struct circular_indexer *indexer)
+{
+       indexer->allow_another_lap = true;
+
+       if (arridx_next(indexer) == NULL)
+               return NULL;
+
+       indexer->first = indexer->current;
+       indexer->allow_another_lap = false;
+       return &indexer->current;
+}
+
+array_index *
+arridx_next(struct circular_indexer *indexer)
+{
+       array_index result;
+
+       if (indexer->len == 0)
+               return NULL;
+
+       if (indexer->indexes == NULL) {
+               result = indexer->current + 1;
+               if ((result - indexer->top) == indexer->len)
+                       result = indexer->top;
+       } else {
+               result = get_current(indexer)->next;
+       }
+
+       if (result == indexer->first) {
+               if (!indexer->allow_another_lap)
+                       return NULL;
+               indexer->allow_another_lap = false;
+       }
+
+       indexer->current = result;
+       return &indexer->current;
+}
+
+static int
+initialize_indexes(struct circular_indexer *indexer)
+{
+       struct circular_indexer_node *array;
+       size_t len;
+       array_index i;
+
+       len = indexer->len;
+       array = calloc(len, sizeof(struct circular_indexer_node));
+       if (array == NULL)
+               return pr_enomem();
+
+       array[0].previous = len - 1;
+       if (len > 1) {
+               array[0].next = 1;
+               for (i = 1; i < len - 1; i++) {
+                       array[i].previous = i - 1;
+                       array[i].next = i + 1;
+               }
+               array[len - 1].previous = len - 2;
+       }
+       array[len - 1].next = 0;
+
+       indexer->indexes = array;
+       return 0;
+}
+
+int
+arridx_remove(struct circular_indexer *indexer)
+{
+       struct circular_indexer_node *node;
+       int error;
+
+       if (indexer->len == 0) {
+               /*
+                * BTW: This also means that calling code used this function
+                * outside of a loop, so double no cookies.
+                */
+               return pr_crit("Attempting to remove an element from an empty circular array.");
+       }
+
+       if (indexer->indexes == NULL) {
+               if (indexer->top == indexer->current) {
+                       indexer->top++;
+                       if (indexer->first == indexer->current) {
+                               indexer->first++;
+                               indexer->allow_another_lap = true;
+                       }
+                       goto success;
+               }
+
+               error = initialize_indexes(indexer);
+               if (error)
+                       return error;
+       }
+
+       node = get_current(indexer);
+
+       if (indexer->first == indexer->current) {
+               indexer->first = node->next;
+               indexer->allow_another_lap = true;
+       }
+
+       indexer->indexes[node->previous].next = node->next;
+       indexer->indexes[node->next].previous = node->previous;
+
+success:
+       indexer->len--;
+       return 0;
+}
+
+void
+arridx_print(char const *prefix, struct circular_indexer *i)
+{
+       array_index o;
+       array_index p;
+
+       pr_info("%s:", prefix);
+       if (i->indexes != NULL) {
+               pr_info("  indexes:");
+               p = i->first;
+               for (o = 0; o < i->len; o++) {
+                       pr_info("    %zu", p);
+                       p = i->indexes[p].next;
+               }
+       }
+
+       pr_info("  first:%zu current:%zu top:%zu len:%zu allow:%d", i->first,
+           i->current, i->top, i->len, i->allow_another_lap);
+}
diff --git a/src/data_structure/circular_indexer.h b/src/data_structure/circular_indexer.h
new file mode 100644 (file)
index 0000000..f065d8e
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef SRC_DATA_STRUCTURE_CIRCULAR_INDEXER_H_
+#define SRC_DATA_STRUCTURE_CIRCULAR_INDEXER_H_
+
+#include <stdbool.h>
+#include "data_structure/common.h"
+
+/*
+ * What I call a "circular indexer" is a data structure meant to add *temporal*
+ * efficient list-like operations to an already existing array.
+ *
+ * (The operations are O(1) removal and subsequent circular bidirectional
+ * iteration. Of course however, creating the indexer is O(n).)
+ *
+ * In pragmatic terms, a "circular indexer" is an iterator-like thingy which
+ * will keep returning removal-sensitive indexes that can be used to dereference
+ * another array. It's called "circular" because the iteration will wrap
+ * (although each foreach will stop after one lap.)
+ *
+ * It's designed to be used by the ROA tree. While computing deltas, it's useful
+ * to keep removing elements, not only to efficiently prevent re-traversal of
+ * already handled nodes, but also to naturally end up with a list of unused
+ * nodes. At the same time, delta computing is not supposed to destroy the tree.
+ */
+
+struct circular_indexer_node {
+       array_index previous;
+       array_index next;
+};
+
+struct circular_indexer {
+       /*
+        * This is the array where we store the links between the nodes.
+        *
+        * Will be initialized lazily, because most iterations and removals will
+        * actually require nothing more than the variables below, and we don't
+        * want to allocate.
+        *
+        * `indexes[i]` always corresponds to `other_array[i + top]`
+        */
+       struct circular_indexer_node *indexes;
+
+       /*
+        * This is the index of some valid element in @indexes. It's called
+        * "first" because iteration always begins at this element.
+        *
+        * In practice, the code is set up so this points to the successor of
+        * the element in which the last iteration was interrupted. This is
+        * because this element has a high chance of being the element that
+        * calling code is going to be looking up in the next loop.
+        */
+       array_index first;
+       /** Element the iteration is currently traversing. */
+       array_index current;
+       /**
+        * Index of the first element that hasn't been removed.
+        * For example, if @top is 10, then elements 0-9 have been removed,
+        * and 10-* still exist.
+        *
+        * This is a white box optimization. We know that calling code most
+        * often uses the circular indexer to compare two identical arrays, and
+        * that any identical elements need to be removed along.
+        *
+        * So, most of the time, @top is all that is needed, and we can postpone
+        * the initialization of @indexes to never.
+        */
+       array_index top;
+
+       /**
+        * Number of elements remaining. (ie. that haven't been removed.)
+        * (The length of @indexes is not stored because it's never needed.)
+        */
+       size_t len;
+
+       /**
+        * Iteration normally stops when @current reaches @first a second time.
+        * But when the first element is removed, @first now points to the next
+        * one, so @current will need to "touch" @first again.
+        *
+        * This member reminds us that iteration needs to continue the next time
+        * @current reaches @first.
+        */
+       bool allow_another_lap;
+};
+
+/*
+ * Types:
+ * @indexer: pointer to the struct circular_indexer you want to iterate.
+ * @i: pointer to array_index. You will have to dereference it to get the index
+ * cursor.
+ *
+ * Every time you start a foreach, iteration will continue where the last one
+ * stopped. (But will do another full lap.)
+ */
+#define ARRIDX_FOREACH(indexer, i) \
+       for (i = arridx_first(indexer); i != NULL; i = arridx_next(indexer))
+
+void arridx_init(struct circular_indexer *, size_t);
+void arridx_cleanup(struct circular_indexer *);
+
+array_index *arridx_first(struct circular_indexer *);
+array_index *arridx_next(struct circular_indexer *);
+/* Removes the *current* element. (You must be iterating.) */
+int arridx_remove(struct circular_indexer *);
+
+/* TODO remove me */
+void arridx_print(char const *, struct circular_indexer *);
+
+#endif /* SRC_DATA_STRUCTURE_CIRCULAR_INDEXER_H_ */
diff --git a/src/data_structure/common.h b/src/data_structure/common.h
new file mode 100644 (file)
index 0000000..ff5cdc7
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef SRC_DATA_STRUCTURE_COMMON_H_
+#define SRC_DATA_STRUCTURE_COMMON_H_
+
+#include <stddef.h>
+
+typedef size_t array_index;
+
+#endif /* SRC_DATA_STRUCTURE_COMMON_H_ */
index d236e2bc2a9ae2db23b5f6f7a645ddb12234d5a4..909eead71cb16e39f1c73af33d4fdca0b7c40f2e 100644 (file)
@@ -1,19 +1,20 @@
 #include "clients.h"
 #include "config.h"
+#include "console_handler.h"
 #include "debug.h"
 #include "extension.h"
 #include "nid.h"
 #include "thread_var.h"
-#include "vrps.h"
 #include "rsync/rsync.h"
 #include "rtr/rtr.h"
+#include "rtr/db/vrps.h"
 
 static int
 start_rtr_server(void)
 {
        int error;
 
-       error = deltas_db_init();
+       error = vrps_init();
        if (error)
                goto end1;
 
@@ -25,7 +26,7 @@ start_rtr_server(void)
        rtr_cleanup(); /* TODO shouldn't this only happen on !error? */
 
        clients_db_destroy();
-end2:  deltas_db_destroy();
+end2:  vrps_destroy();
 end1:  return error;
 }
 
@@ -54,13 +55,9 @@ main(int argc, char **argv)
        if (error)
                goto revert_rsync;
 
-       error = perform_standalone_validation(NULL);
-       if (error)
-               goto revert_rsync;
-
-       if (config_get_server_address() != NULL)
-               error = start_rtr_server();
-       /* Otherwise, no server requested. */
+       error = (config_get_server_address() != NULL)
+           ? start_rtr_server()
+           : validate_into_console();
 
 revert_rsync:
        rsync_destroy();
index 79a7cd3e3c19d3031945ef06f3ec6fa08ffa4e9a..db19f7e9933cfb2db3ae93a822b0db8892564ad6 100644 (file)
@@ -1,9 +1,9 @@
 #include "notify.h"
 
 #include <err.h>
-#include "rtr/pdu_sender.h"
 #include "clients.h"
-#include "vrps.h"
+#include "rtr/pdu_sender.h"
+#include "rtr/db/vrps.h"
 
 static int
 send_notify(int fd, uint8_t rtr_version)
index 968cfe01d51918da4730e2cfed7b5a997563c534..fe02b76951dfe593812f3c6e634b143ad6e4aed4 100644 (file)
 #include "thread_var.h"
 #include "asn1/decode.h"
 #include "asn1/oid.h"
+#include "asn1/signed_data.h"
 #include "crypto/hash.h"
 #include "object/name.h"
 #include "rsync/rsync.h"
+#include "rtr/db/roa_tree.h"
 
 #include <sys/socket.h>
 
@@ -76,7 +78,7 @@ static int
 validate_issuer(X509 *cert, bool is_ta)
 {
        X509_NAME *issuer;
-       struct rfc5280_name name;
+       struct rfc5280_name *name;
        int error;
 
        issuer = X509_get_issuer_name(cert);
@@ -86,16 +88,16 @@ validate_issuer(X509 *cert, bool is_ta)
 
        error = x509_name_decode(issuer, "issuer", &name);
        if (!error)
-               x509_name_cleanup(&name);
+               x509_name_put(name);
 
        return error;
 }
 
 static int
-validate_subject(X509 *cert)
+validate_subject(X509 *cert, struct rfc5280_name **subject_name)
 {
        struct validation *state;
-       struct rfc5280_name name;
+       struct rfc5280_name *name;
        int error;
 
        state = state_retrieve();
@@ -106,11 +108,14 @@ validate_subject(X509 *cert)
        if (error)
                return error;
 
-       error = validation_store_subject(state, &name);
-       if (error)
-               x509_name_cleanup(&name);
+       error = validation_store_subject(state, name);
+       if (error) {
+               x509_name_put(name);
+               return error;
+       }
 
-       return error;
+       *subject_name = name; /* Transfer ownership */
+       return 0;
 }
 
 static int
@@ -264,7 +269,8 @@ validate_public_key(X509 *cert, bool is_root)
 }
 
 int
-certificate_validate_rfc6487(X509 *cert, bool is_root)
+certificate_validate_rfc6487(X509 *cert, struct rfc5280_name **subject_name,
+    bool is_root)
 {
        int error;
 
@@ -306,7 +312,7 @@ certificate_validate_rfc6487(X509 *cert, bool is_root)
         * "An issuer SHOULD use a different subject name if the subject's
         * key pair has changed" (it's a SHOULD, so [for now] avoid validation)
         */
-       error = validate_subject(cert);
+       error = validate_subject(cert, subject_name);
        if (error)
                return error;
 
@@ -1435,6 +1441,7 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri const *cert_uri,
 {
        struct validation *state;
        X509 *cert;
+       struct rfc5280_name *subject_name;
        struct rpki_uri mft;
        struct certificate_refs refs;
        enum rpki_policy policy;
@@ -1455,46 +1462,57 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri const *cert_uri,
        /* -- Validate the certificate (@cert) -- */
        error = certificate_load(cert_uri, &cert);
        if (error)
-               goto end1;
+               goto revert_fnstack_and_debug;
        if (!is_ta) {
                error = certificate_validate_chain(cert, crls);
                if (error)
-                       goto end2;
+                       goto revert_cert;
        }
-       error = certificate_validate_rfc6487(cert, is_ta);
+       error = certificate_validate_rfc6487(cert, &subject_name, is_ta);
        if (error)
-               goto end2;
+               goto revert_cert;
        error = is_ta
            ? certificate_validate_extensions_ta(cert, &mft, &policy)
            : certificate_validate_extensions_ca(cert, &mft, &refs, &policy);
        if (error)
-               goto end2;
+               goto revert_subject_name;
 
        error = refs_validate_ca(&refs, is_ta, rpp_parent);
        if (error)
-               goto end3;
+               goto revert_uri_and_refs;
 
        /* -- Validate the manifest (@mft) pointed by the certificate -- */
        error = validation_push_cert(state, cert_uri, cert, policy, is_ta);
        if (error)
-               goto end3;
+               goto revert_uri_and_refs;
 
        error = handle_manifest(&mft, crls, &pp);
        if (error)
-               goto end4;
+               goto revert_cert_push;
 
        /* -- Validate & traverse the RPP (@pp) described by the manifest -- */
+       error = vhandler_traverse_down(subject_name);
+       if (error)
+               goto revert_rpp;
+
        error = rpp_traverse(pp);
+       if (error)
+               goto revert_rpp;
+
+       error = vhandler_traverse_up();
 
+revert_rpp:
        rpp_destroy(pp);
-end4:
+revert_cert_push:
        validation_pop_cert(state); /* Error code is useless. */
-end3:
+revert_uri_and_refs:
        uri_cleanup(&mft);
        refs_cleanup(&refs);
-end2:
+revert_subject_name:
+       x509_name_put(subject_name);
+revert_cert:
        X509_free(cert);
-end1:
+revert_fnstack_and_debug:
        fnstack_pop();
        pr_debug_rm("}");
        return error;
index 643425d78945965f0dcfcfe6acea5fcdd42b9e97..2c879d5d929a506d0a86fe210eb3fe76e2c30391 100644 (file)
@@ -9,6 +9,7 @@
 #include "resource.h"
 #include "rpp.h"
 #include "uri.h"
+#include "object/name.h"
 
 int certificate_load(struct rpki_uri const *, X509 **);
 
@@ -21,7 +22,7 @@ int certificate_validate_chain(X509 *, STACK_OF(X509_CRL) *);
  * Validates RFC 6487 compliance.
  * (Except extensions.)
  */
-int certificate_validate_rfc6487(X509 *, bool);
+int certificate_validate_rfc6487(X509 *, struct rfc5280_name **, bool);
 
 int certificate_validate_signature(X509 *, ANY_t *coded, SignatureValue_t *);
 
index 9c07fe5ca0fa47baf58114966600c0f0a0794e72..2aed15708678a8bb2da2a4024e8557256f22ba27 100644 (file)
@@ -7,6 +7,18 @@
 #include "log.h"
 #include "thread_var.h"
 
+/**
+ * It's an RFC5280 name, but from RFC 6487's perspective.
+ * Meaning, only commonName and serialNumbers are allowed, and the latter is
+ * optional.
+ */
+struct rfc5280_name {
+       char *commonName;
+       char *serialNumber;
+       /** Reference counter */
+       unsigned int references;
+};
+
 static int
 name2string(X509_NAME_ENTRY *name, char **_result)
 {
@@ -30,15 +42,21 @@ name2string(X509_NAME_ENTRY *name, char **_result)
 
 int
 x509_name_decode(X509_NAME *name, char const *what,
-    struct rfc5280_name *result)
+    struct rfc5280_name **_result)
 {
+       struct rfc5280_name *result;
        int i;
        X509_NAME_ENTRY *entry;
        int nid;
        int error;
 
+       result = malloc(sizeof(struct rfc5280_name));
+       if (result == NULL)
+               return pr_enomem();
+
        result->commonName = NULL;
        result->serialNumber = NULL;
+       result->references = 1;
 
        for (i = 0; i < X509_NAME_entry_count(name); i++) {
                entry = X509_NAME_get_entry(name, i);
@@ -66,18 +84,41 @@ x509_name_decode(X509_NAME *name, char const *what,
                goto fail;
        }
 
+       *_result = result;
        return 0;
 
 fail:
-       x509_name_cleanup(result);
+       x509_name_put(result);
        return error;
 }
 
 void
-x509_name_cleanup(struct rfc5280_name *name)
+x509_name_get(struct rfc5280_name *name)
+{
+       name->references++;
+}
+
+void
+x509_name_put(struct rfc5280_name *name)
+{
+       name->references--;
+       if (name->references == 0) {
+               free(name->commonName);
+               free(name->serialNumber);
+               free(name);
+       }
+}
+
+char const *
+x509_name_commonName(struct rfc5280_name *name)
 {
-       free(name->commonName);
-       free(name->serialNumber);
+       return name->commonName;
+}
+
+char const *
+x509_name_serialNumber(struct rfc5280_name *name)
+{
+       return name->serialNumber;
 }
 
 /**
@@ -106,8 +147,8 @@ validate_issuer_name(char const *container, X509_NAME *issuer)
 {
        struct validation *state;
        X509 *parent;
-       struct rfc5280_name parent_subject;
-       struct rfc5280_name child_issuer;
+       struct rfc5280_name *parent_subject;
+       struct rfc5280_name *child_issuer;
        int error;
 
        /*
@@ -134,22 +175,24 @@ validate_issuer_name(char const *container, X509_NAME *issuer)
        if (error)
                goto end;
 
-       if (!x509_name_equals(&parent_subject, &child_issuer)) {
+       if (!x509_name_equals(parent_subject, child_issuer)) {
+               char const *parent_serial;
+               char const *child_serial;
+
+               parent_serial = x509_name_serialNumber(parent_subject);
+               child_serial = x509_name_serialNumber(child_issuer);
+
                error = pr_err("%s's issuer name ('%s%s%s') does not equal issuer certificate's name ('%s%s%s').",
                    container,
-                   parent_subject.commonName,
-                   (parent_subject.serialNumber != NULL) ? "/" : "",
-                   (parent_subject.serialNumber != NULL)
-                       ? parent_subject.serialNumber
-                       : "",
-                   child_issuer.commonName,
-                   (child_issuer.serialNumber != NULL) ? "/" : "",
-                   (child_issuer.serialNumber != NULL)
-                       ? child_issuer.serialNumber
-                       : "");
+                   x509_name_commonName(parent_subject),
+                   (parent_serial != NULL) ? "/" : "",
+                   (parent_serial != NULL) ? parent_serial : "",
+                   x509_name_commonName(child_issuer),
+                   (child_serial != NULL) ? "/" : "",
+                   (child_serial != NULL) ? child_serial : "");
        }
 
-       x509_name_cleanup(&child_issuer);
-end:   x509_name_cleanup(&parent_subject);
+       x509_name_put(child_issuer);
+end:   x509_name_put(parent_subject);
        return error;
 }
index c686979bde0335745510deef0c4e3c448b59623c..85d487e073742c2789f7bbc40e66fde011cc67be 100644 (file)
@@ -4,18 +4,17 @@
 #include <stdbool.h>
 #include <openssl/x509.h>
 
-/**
- * It's an RFC5280 name, but from RFC 6487's perspective.
- * Meaning, only commonName and serialNumbers are allowed, and the latter is
- * optional.
- */
-struct rfc5280_name {
-       char *commonName;
-       char *serialNumber;
-};
+struct rfc5280_name;
 
-int x509_name_decode(X509_NAME *, char const *, struct rfc5280_name *);
-void x509_name_cleanup(struct rfc5280_name *);
+/* Constructor */
+int x509_name_decode(X509_NAME *, char const *, struct rfc5280_name **);
+/* Reference counting */
+void x509_name_get(struct rfc5280_name *);
+void x509_name_put(struct rfc5280_name *);
+
+/* Getters */
+char const *x509_name_commonName(struct rfc5280_name *);
+char const *x509_name_serialNumber(struct rfc5280_name *);
 
 bool x509_name_equals(struct rfc5280_name *, struct rfc5280_name *);
 
index 000bea3408b07ee693c1a4ee3a2e74cdb6d8b9ea..7de259aece1b2681a56fb100b797dd749083bb79 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <errno.h>
 #include <arpa/inet.h>
+#include <sys/socket.h>
 #include <libcmscodec/RouteOriginAttestation.h>
 
 #include "config.h"
@@ -10,8 +11,7 @@
 #include "asn1/decode.h"
 #include "asn1/oid.h"
 #include "object/signed_object.h"
-
-#include <sys/socket.h>
+#include "rtr/db/roa_tree.h"
 
 static int
 roa_decode(OCTET_STRING_t *string, void *arg)
@@ -21,7 +21,7 @@ roa_decode(OCTET_STRING_t *string, void *arg)
 }
 
 static int
-print_addr4(struct resources *parent, unsigned long asn,
+____handle_roa_v4(struct resources *parent, unsigned long asn,
     struct ROAIPAddress *roa_addr)
 {
        struct ipv4_prefix prefix;
@@ -59,18 +59,11 @@ print_addr4(struct resources *parent, unsigned long asn,
                    v4addr2str(&prefix.addr), prefix.len);
        }
 
-       /* TODO I think we're not validating asn boundaries */
-       return roa_handle_v4(asn, &prefix, max_length);
-}
-
-int
-roa_handle_v4(uint32_t asn, struct ipv4_prefix *prefix, uint8_t max_length)
-{
-       return -ENOTIMPLEMENTED;
+       return vhandler_handle_roa_v4(asn, &prefix, max_length);
 }
 
 static int
-print_addr6(struct resources *parent, unsigned long asn,
+____handle_roa_v6(struct resources *parent, unsigned long asn,
     struct ROAIPAddress *roa_addr)
 {
        struct ipv6_prefix prefix;
@@ -108,17 +101,11 @@ print_addr6(struct resources *parent, unsigned long asn,
                    v6addr2str(&prefix.addr), prefix.len);
        }
 
-       return roa_handle_v6(asn, &prefix, max_length);
-}
-
-int
-roa_handle_v6(uint32_t asn, struct ipv6_prefix *prefix, uint8_t max_length)
-{
-       return -ENOTIMPLEMENTED;
+       return vhandler_handle_roa_v6(asn, &prefix, max_length);
 }
 
 static int
-print_addr(struct resources *parent, ASID_t *as_id, uint8_t family,
+____handle_roa(struct resources *parent, ASID_t *as_id, uint8_t family,
     struct ROAIPAddress *roa_addr)
 {
        unsigned long asn;
@@ -129,11 +116,14 @@ print_addr(struct resources *parent, ASID_t *as_id, uint8_t family,
                return pr_err("ROA's AS ID couldn't be parsed as unsigned long");
        }
 
+       if (asn > UINT32_MAX)
+               return pr_err("AS value (%lu) is out of range.", asn);
+
        switch (family) {
        case 1: /* IPv4 */
-               return print_addr4(parent, asn, roa_addr);
+               return ____handle_roa_v4(parent, asn, roa_addr);
        case 2: /* IPv6 */
-               return print_addr6(parent, asn, roa_addr);
+               return ____handle_roa_v6(parent, asn, roa_addr);
        }
 
        return pr_err("Unknown family value: %u", family);
@@ -181,7 +171,7 @@ __handle_roa(struct RouteOriginAttestation *roa, struct resources *parent)
                if (block->addresses.list.array == NULL)
                        return pr_err("ROA's address list array is NULL.");
                for (a = 0; a < block->addresses.list.count; a++) {
-                       error = print_addr(parent, &roa->asID,
+                       error = ____handle_roa(parent, &roa->asID,
                            block->addressFamily.buf[1],
                            block->addresses.list.array[a]);
                        if (error)
@@ -216,10 +206,19 @@ roa_traverse(struct rpki_uri const *uri, struct rpp *pp,
        if (error)
                goto end2;
 
+       error = vhandler_traverse_down(sobj_args.subject_name);
+       if (error)
+               goto end3;
+
        error = __handle_roa(roa, sobj_args.res);
        if (error)
                goto end3;
 
+       error = vhandler_traverse_up();
+       if (error)
+               goto end3;
+
+       /* TODO why is this happening so late? */
        error = refs_validate_ee(&sobj_args.refs, pp, sobj_args.uri);
 
 end3:
index ed98a22efcd8bf62942fc1e18bb80733c34cfa70..961ba3f676b79ad4665243147a5a1a8a7534b5db 100644 (file)
@@ -9,7 +9,4 @@
 
 int roa_traverse(struct rpki_uri const *, struct rpp *, STACK_OF(X509_CRL) *);
 
-int roa_handle_v4(uint32_t, struct ipv4_prefix *, uint8_t);
-int roa_handle_v6(uint32_t, struct ipv6_prefix *, uint8_t);
-
 #endif /* SRC_OBJECT_ROA_H_ */
index 11b799fc1ef95a5ab326ef1e103d865157049ebe..16a69aa808edd0282fb7e376b4415e9dda3df1bd 100644 (file)
@@ -210,7 +210,7 @@ void tal_destroy(struct tal *tal)
 }
 
 int
-foreach_uri(struct tal *tal, foreach_uri_cb cb)
+foreach_uri(struct tal *tal, foreach_uri_cb cb, void *arg)
 {
        struct rpki_uri uri;
        unsigned int i;
@@ -227,7 +227,7 @@ foreach_uri(struct tal *tal, foreach_uri_cb cb)
                if (error)
                        return error;
 
-               error = cb(tal, &uri);
+               error = cb(tal, &uri, arg);
                uri_cleanup(&uri);
                if (error)
                        return error;
@@ -273,7 +273,7 @@ tal_get_spki(struct tal *tal, unsigned char const **buffer, size_t *len)
  * have been extracted from a TAL.
  */
 static int
-handle_tal_uri(struct tal *tal, struct rpki_uri const *uri)
+handle_tal_uri(struct tal *tal, struct rpki_uri const *uri, void *arg)
 {
        /*
         * Because of the way the foreach iterates, this function must return
@@ -298,7 +298,11 @@ handle_tal_uri(struct tal *tal, struct rpki_uri const *uri)
                    uri->global);
        }
 
-       error = validation_prepare(&state, tal);
+       error = validation_prepare(&state, tal, arg);
+       if (error)
+               return ENSURE_NEGATIVE(error);
+
+       error = vhandler_reset(arg);
        if (error)
                return ENSURE_NEGATIVE(error);
 
@@ -331,9 +335,8 @@ end:        validation_destroy(state);
        return error;
 }
 
-/* TODO set @updated */
 int
-perform_standalone_validation(bool *updated)
+perform_standalone_validation(struct validation_handler *handler)
 {
        struct tal *tal;
        int error;
@@ -347,7 +350,7 @@ perform_standalone_validation(bool *updated)
 
        if (config_get_shuffle_tal_uris())
                tal_shuffle_uris(tal);
-       error = foreach_uri(tal, handle_tal_uri);
+       error = foreach_uri(tal, handle_tal_uri, handler);
        if (error > 0)
                error = 0;
        else if (error == 0)
index a79ee43ac2b893f0d757ee8f394dc8d66b82823e..06b53263251acd5a5ea4d3f9b74a30a1701cd4e0 100644 (file)
@@ -5,19 +5,20 @@
 
 #include <stddef.h>
 #include "uri.h"
+#include "validation_handler.h"
 
 struct tal;
 
 int tal_load(char const *, struct tal **);
 void tal_destroy(struct tal *);
 
-typedef int (*foreach_uri_cb)(struct tal *, struct rpki_uri const *);
-int foreach_uri(struct tal *, foreach_uri_cb);
+typedef int (*foreach_uri_cb)(struct tal *, struct rpki_uri const *, void *);
+int foreach_uri(struct tal *, foreach_uri_cb, void *);
 void tal_shuffle_uris(struct tal *);
 
 char const *tal_get_file_name(struct tal *);
 void tal_get_spki(struct tal *, unsigned char const **, size_t *);
 
-int perform_standalone_validation(bool *);
+int perform_standalone_validation(struct validation_handler *);
 
 #endif /* TAL_OBJECT_H_ */
index a546b4561aa3e2502d57ab447bfa62a44bc07f2d..1896355e2a649c0127de12a2a99f1d383fa71cb0 100644 (file)
--- a/src/rpp.c
+++ b/src/rpp.c
@@ -1,10 +1,10 @@
 #include "rpp.h"
 
 #include <stdlib.h>
-#include "array_list.h"
 #include "log.h"
 #include "thread_var.h"
 #include "uri.h"
+#include "data_structure/array_list.h"
 #include "object/certificate.h"
 #include "object/crl.h"
 #include "object/ghostbusters.h"
diff --git a/src/rtr/db/delta.c b/src/rtr/db/delta.c
new file mode 100644 (file)
index 0000000..71fa960
--- /dev/null
@@ -0,0 +1,191 @@
+#include "rtr/db/delta.h"
+
+#include "data_structure/array_list.h"
+
+struct delta_v4 {
+       uint32_t as;
+       struct ipv4_prefix prefix;
+       uint8_t max_length;
+};
+
+struct delta_v6 {
+       uint32_t as;
+       struct ipv6_prefix prefix;
+       uint8_t max_length;
+};
+
+ARRAY_LIST(deltas_v6, struct delta_v6)
+ARRAY_LIST(deltas_v4, struct delta_v4)
+
+struct deltas {
+       struct {
+               struct deltas_v4 adds;
+               struct deltas_v4 removes;
+       } v4;
+       struct {
+               struct deltas_v6 adds;
+               struct deltas_v6 removes;
+       } v6;
+};
+
+int
+deltas_create(struct deltas **_result)
+{
+       struct deltas *result;
+       int error;
+
+       result = malloc(sizeof(struct deltas));
+       if (result == NULL)
+               return pr_enomem();
+
+       error = deltas_v4_init(&result->v4.adds);
+       if (error)
+               goto revert_result;
+       error = deltas_v4_init(&result->v4.removes);
+       if (error)
+               goto revert_v4_adds;
+       error = deltas_v6_init(&result->v6.adds);
+       if (error)
+               goto revert_v4_removes;
+       error = deltas_v6_init(&result->v6.removes);
+       if (error)
+               goto revert_v6_adds;
+
+       *_result = result;
+       return 0;
+
+revert_v6_adds:
+       deltas_v6_cleanup(&result->v6.adds, NULL);
+revert_v4_removes:
+       deltas_v4_cleanup(&result->v4.removes, NULL);
+revert_v4_adds:
+       deltas_v4_cleanup(&result->v4.adds, NULL);
+revert_result:
+       free(result);
+       return error;
+}
+
+void
+deltas_destroy(struct deltas *deltas)
+{
+       deltas_v4_cleanup(&deltas->v4.adds, NULL);
+       deltas_v4_cleanup(&deltas->v4.removes, NULL);
+       deltas_v6_cleanup(&deltas->v6.adds, NULL);
+       deltas_v6_cleanup(&deltas->v6.removes, NULL);
+       free(deltas);
+}
+
+int
+deltas_add_roa_v4(struct deltas *deltas, uint32_t as, struct v4_address *addr,
+    enum delta_op op)
+{
+       struct delta_v4 delta = {
+               .as = as,
+               .prefix = addr->prefix,
+               .max_length = addr->max_length,
+       };
+
+       switch (op) {
+       case DELTA_ADD:
+               return deltas_v4_add(&deltas->v4.adds, &delta);
+       case DELTA_RM:
+               return deltas_v4_add(&deltas->v4.removes, &delta);
+       }
+
+       return pr_crit("Unknown delta operation: %u", op);
+}
+
+int
+deltas_add_roa_v6(struct deltas *deltas, uint32_t as, struct v6_address *addr,
+    enum delta_op op)
+{
+       struct delta_v6 delta = {
+               .as = as,
+               .prefix = addr->prefix,
+               .max_length = addr->max_length,
+       };
+
+       switch (op) {
+       case DELTA_ADD:
+               return deltas_v6_add(&deltas->v6.adds, &delta);
+       case DELTA_RM:
+               return deltas_v6_add(&deltas->v6.removes, &delta);
+       }
+
+       return pr_crit("Unknown delta operation: %u", op);
+}
+
+bool
+deltas_is_empty(struct deltas *deltas)
+{
+       return (deltas->v4.adds.len == 0)
+           && (deltas->v4.removes.len == 0)
+           && (deltas->v6.adds.len == 0)
+           && (deltas->v6.removes.len == 0);
+}
+
+static int
+__foreach_v4(struct deltas_v4 *array, vrp_foreach_cb cb, void *arg,
+    uint8_t flags)
+{
+       struct delta_v4 *d;
+       struct vrp vrp;
+       int error;
+
+       vrp.addr_fam = AF_INET;
+       vrp.flags = flags;
+
+       ARRAYLIST_FOREACH(array, d) {
+               vrp.asn = d->as;
+               vrp.prefix.v4 = d->prefix.addr;
+               vrp.prefix_length = d->prefix.len;
+               vrp.max_prefix_length = d->max_length;
+               error = cb(&vrp, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int
+__foreach_v6(struct deltas_v6 *array, vrp_foreach_cb cb, void *arg,
+    uint8_t flags)
+{
+       struct delta_v6 *d;
+       struct vrp vrp;
+       int error;
+
+       vrp.addr_fam = AF_INET6;
+       vrp.flags = flags;
+
+       ARRAYLIST_FOREACH(array, d) {
+               vrp.asn = d->as;
+               vrp.prefix.v6 = d->prefix.addr;
+               vrp.prefix_length = d->prefix.len;
+               vrp.max_prefix_length = d->max_length;
+               error = cb(&vrp, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+int
+deltas_foreach(struct deltas *deltas, vrp_foreach_cb cb, void *arg)
+{
+       int error;
+
+       error = __foreach_v4(&deltas->v4.adds, cb, arg, FLAG_ANNOUNCEMENT);
+       if (error)
+               return error;
+       error = __foreach_v4(&deltas->v4.removes, cb, arg, FLAG_WITHDRAWAL);
+       if (error)
+               return error;
+
+       error = __foreach_v6(&deltas->v6.adds, cb, arg, FLAG_ANNOUNCEMENT);
+       if (error)
+               return error;
+       return __foreach_v6(&deltas->v6.removes, cb, arg, FLAG_WITHDRAWAL);
+}
diff --git a/src/rtr/db/delta.h b/src/rtr/db/delta.h
new file mode 100644 (file)
index 0000000..076b0db
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SRC_DELTA_H_
+#define SRC_DELTA_H_
+
+#include "rtr/db/roa.h"
+#include "rtr/db/vrp.h"
+
+enum delta_op {
+       DELTA_ADD,
+       DELTA_RM,
+};
+
+struct deltas;
+
+int deltas_create(struct deltas **);
+void deltas_destroy(struct deltas *);
+
+int deltas_add_roa_v4(struct deltas *, uint32_t, struct v4_address *,
+    enum delta_op);
+int deltas_add_roa_v6(struct deltas *, uint32_t, struct v6_address *,
+    enum delta_op);
+
+bool deltas_is_empty(struct deltas *);
+int deltas_foreach(struct deltas *, vrp_foreach_cb , void *);
+
+#endif /* SRC_DELTA_H_ */
diff --git a/src/rtr/db/roa.c b/src/rtr/db/roa.c
new file mode 100644 (file)
index 0000000..b40bda2
--- /dev/null
@@ -0,0 +1,83 @@
+#include "rtr/db/roa.h"
+
+DEFINE_ARRAY_LIST_FUNCTIONS(v4_addresses, struct v4_address)
+DEFINE_ARRAY_LIST_FUNCTIONS(v6_addresses, struct v6_address)
+
+static void
+v4_address_destroy(struct v4_address *addr)
+{
+       free(addr);
+}
+
+static void
+v6_address_destroy(struct v6_address *addr)
+{
+       free(addr);
+}
+
+int
+roa_create(u_int32_t as, struct roa **_result)
+{
+       struct roa *result;
+       int error;
+
+       result = malloc(sizeof(struct roa));
+       if (result == NULL)
+               return pr_enomem();
+
+       result->as = as;
+       error = v4_addresses_init(&result->addrs4);
+       if (error)
+               goto revert_result;
+       error = v6_addresses_init(&result->addrs6);
+       if (error)
+               goto revert_addrs4;
+
+       *_result = result;
+       return 0;
+
+revert_addrs4:
+       v4_addresses_cleanup(&result->addrs4, v4_address_destroy);
+revert_result:
+       free(result);
+       return error;
+}
+
+void
+roa_destroy(struct roa *roa)
+{
+       v4_addresses_cleanup(&roa->addrs4, v4_address_destroy);
+       v6_addresses_cleanup(&roa->addrs6, v6_address_destroy);
+}
+
+int
+roa_add_v4(struct roa *roa, uint32_t as, struct ipv4_prefix const *prefix,
+    uint8_t max_length)
+{
+       struct v4_address addr;
+
+       if (roa->as != as) {
+               return pr_err("ROA has more than one ASN. (%u and %u)",
+                   roa->as, as);
+       }
+
+       addr.prefix = *prefix;
+       addr.max_length = max_length;
+       return v4_addresses_add(&roa->addrs4, &addr);
+}
+
+int
+roa_add_v6(struct roa *roa, uint32_t as, struct ipv6_prefix const *prefix,
+    uint8_t max_length)
+{
+       struct v6_address addr;
+
+       if (roa->as != as) {
+               return pr_err("ROA has more than one ASN. (%u and %u)",
+                   roa->as, as);
+       }
+
+       addr.prefix = *prefix;
+       addr.max_length = max_length;
+       return v6_addresses_add(&roa->addrs6, &addr);
+}
diff --git a/src/rtr/db/roa.h b/src/rtr/db/roa.h
new file mode 100644 (file)
index 0000000..8271d9b
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SRC_RTR_DB_ROA_H_
+#define SRC_RTR_DB_ROA_H_
+
+#include "address.h"
+#include "data_structure/array_list.h"
+
+struct v4_address {
+       struct ipv4_prefix prefix;
+       uint8_t max_length;
+};
+
+struct v6_address {
+       struct ipv6_prefix prefix;
+       uint8_t max_length;
+};
+
+DEFINE_ARRAY_LIST_STRUCT(v4_addresses, struct v4_address);
+DEFINE_ARRAY_LIST_STRUCT(v6_addresses, struct v6_address);
+
+struct roa {
+       uint32_t as;
+       struct v4_addresses addrs4;
+       struct v6_addresses addrs6;
+};
+
+int roa_create(u_int32_t, struct roa **);
+void roa_destroy(struct roa *);
+
+int roa_add_v4(struct roa *, uint32_t, struct ipv4_prefix const *, uint8_t);
+int roa_add_v6(struct roa *, uint32_t, struct ipv6_prefix const *, uint8_t);
+
+#endif /* SRC_RTR_DB_ROA_H_ */
diff --git a/src/rtr/db/roa_tree.c b/src/rtr/db/roa_tree.c
new file mode 100644 (file)
index 0000000..86d84df
--- /dev/null
@@ -0,0 +1,525 @@
+#include "rtr/db/roa_tree.h"
+
+#include "common.h"
+#include "data_structure/array_list.h"
+#include "data_structure/circular_indexer.h"
+#include "rtr/db/roa.h"
+
+DEFINE_ARRAY_LIST_STRUCT(nodes, struct node);
+
+struct node {
+       struct rfc5280_name *subject_name;
+       struct node *parent;
+       /*
+        * BTW: There's nothing in this code stopping both children and roa from
+        * being not null, but it should never happen naturally.
+        */
+       struct nodes children;
+       struct roa *roa;
+};
+
+struct roa_tree {
+       struct node *root;
+       struct node *current;
+       unsigned int references;
+};
+
+DEFINE_ARRAY_LIST_FUNCTIONS(nodes, struct node)
+
+static struct node *
+node_create(struct rfc5280_name *subject_name, struct node *parent)
+{
+       struct node *node;
+
+       node = malloc(sizeof(struct node));
+       if (node == NULL)
+               return NULL;
+
+       node->subject_name = subject_name;
+       x509_name_get(subject_name);
+       node->parent = parent;
+       node->children.array = NULL;
+       node->roa = NULL;
+       return node;
+}
+
+static void
+node_destroy(struct node *node)
+{
+       x509_name_put(node->subject_name);
+       if (node->children.array != NULL)
+               nodes_cleanup(&node->children, node_destroy);
+       if (node->roa != NULL)
+               roa_destroy(node->roa);
+       free(node);
+}
+
+static int
+node_add_child(struct node *parent, struct rfc5280_name *subject_name)
+{
+       struct node *child;
+       int error;
+
+       if (parent->children.array == NULL) {
+               error = nodes_init(&parent->children);
+               if (error)
+                       return error;
+       }
+
+       child = node_create(subject_name, parent);
+       if (child == NULL)
+               return pr_enomem();
+
+       error = nodes_add(&parent->children, child);
+       if (error)
+               node_destroy(child);
+
+       return error;
+}
+
+/**
+ * Performs lazy initialization if the root does not exist.
+ */
+static struct node *
+get_root(struct roa_tree *tree, struct rfc5280_name *subject_name)
+{
+       if (tree->root == NULL)
+               tree->root = node_create(subject_name, NULL);
+       return tree->root;
+}
+
+struct roa_tree *
+roa_tree_create(void)
+{
+       struct roa_tree *tree;
+
+       tree = malloc(sizeof(struct roa_tree));
+       if (tree == NULL)
+               return NULL;
+
+       tree->root = NULL;
+       tree->current = NULL;
+       tree->references = 1;
+       return tree;
+}
+
+static void
+roa_tree_cleanup(struct roa_tree *tree)
+{
+       if (tree->root != NULL) {
+               node_destroy(tree->root);
+               tree->root = NULL;
+       }
+       tree->current = NULL;
+}
+
+void
+roa_tree_get(struct roa_tree *tree)
+{
+       tree->references++;
+}
+
+void
+roa_tree_put(struct roa_tree *tree)
+{
+       tree->references--;
+       if (tree->references == 0) {
+               roa_tree_cleanup(tree);
+               free(tree);
+       }
+}
+
+static int
+__foreach_v4(struct roa *roa, vrp_foreach_cb cb, void *arg)
+{
+       struct v4_address *addr;
+       struct vrp vrp;
+       int error;
+
+       vrp.asn = roa->as;
+       vrp.addr_fam = AF_INET;
+       vrp.flags = FLAG_ANNOUNCEMENT;
+
+       ARRAYLIST_FOREACH(&roa->addrs4, addr) {
+               vrp.prefix.v4 = addr->prefix.addr;
+               vrp.prefix_length = addr->prefix.len;
+               vrp.max_prefix_length = addr->max_length;
+               error = cb(&vrp, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int
+__foreach_v6(struct roa *roa, vrp_foreach_cb cb, void *arg)
+{
+       struct v6_address *addr;
+       struct vrp vrp;
+       int error;
+
+       vrp.asn = roa->as;
+       vrp.addr_fam = AF_INET6;
+       vrp.flags = FLAG_ANNOUNCEMENT;
+
+       ARRAYLIST_FOREACH(&roa->addrs6, addr) {
+               vrp.prefix.v6 = addr->prefix.addr;
+               vrp.prefix_length = addr->prefix.len;
+               vrp.max_prefix_length = addr->max_length;
+               error = cb(&vrp, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+int
+__foreach(struct node *node, vrp_foreach_cb cb, void *arg)
+{
+       struct node *child;
+       int error;
+
+       ARRAYLIST_FOREACH(&node->children, child) {
+               error = __foreach(child, cb, arg);
+               if (error)
+                       return error;
+       }
+
+       if (child->roa != NULL) {
+               error = __foreach_v4(child->roa, cb, arg);
+               if (error)
+                       return error;
+               error = __foreach_v6(child->roa, cb, arg);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+int
+roa_tree_foreach_roa(struct roa_tree *tree, vrp_foreach_cb cb, void *arg)
+{
+       return (tree->root != NULL) ? __foreach(tree->root, cb, arg) : 0;
+}
+
+int
+forthandler_reset(struct roa_tree *tree)
+{
+       roa_tree_cleanup(tree);
+       return 0;
+}
+
+int
+forthandler_go_down(struct roa_tree *tree,
+    struct rfc5280_name *subject_name)
+{
+       if (tree->current != NULL)
+               return node_add_child(tree->current, subject_name);
+
+       tree->current = get_root(tree, subject_name);
+       return (tree->current != NULL) ? 0 : pr_enomem();
+}
+
+int
+forthandler_go_up(struct roa_tree *tree)
+{
+       if (tree->current == NULL)
+               return pr_crit("Bad tree traversal: Attempting to move to the parent of a root.");
+
+       tree->current = tree->current->parent;
+       return 0;
+}
+
+static int
+get_current_roa(struct roa_tree *tree, uint32_t asn, struct roa **result)
+{
+       struct roa *roa;
+       int error;
+
+       if (tree->current == NULL)
+               return pr_crit("Validator posted ROA during incorrect context.");
+
+       roa = tree->current->roa;
+       if (roa == NULL) {
+               error = roa_create(asn, &roa);
+               if (error)
+                       return error;
+               tree->current->roa = roa;
+       }
+
+       *result = roa;
+       return 0;
+}
+
+int
+forthandler_handle_roa_v4(struct roa_tree *tree, uint32_t asn,
+    struct ipv4_prefix const *prefix4, uint8_t max_length)
+{
+       struct roa *roa;
+       int error;
+       error = get_current_roa(tree, asn, &roa);
+       return error ? error : roa_add_v4(roa, asn, prefix4, max_length);
+}
+
+int
+forthandler_handle_roa_v6(struct roa_tree *tree, uint32_t asn,
+    struct ipv6_prefix const *prefix6, uint8_t max_length)
+{
+       struct roa *roa;
+       int error;
+       error = get_current_roa(tree, asn, &roa);
+       return error ? error : roa_add_v6(roa, asn, prefix6, max_length);
+}
+
+static bool
+find_subject_name(struct circular_indexer *indexer,
+    struct rfc5280_name *subject_name, struct node *c2array,
+    array_index *result)
+{
+       array_index *i;
+
+       ARRIDX_FOREACH(indexer, i) {
+               if (x509_name_equals(subject_name, c2array[*i].subject_name)) {
+                       *result = *i;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static int
+add_all_roas_v4(struct deltas *deltas, struct roa *roa, enum delta_op op)
+{
+       struct v4_address *addr;
+       int error;
+
+       ARRAYLIST_FOREACH(&roa->addrs4, addr) {
+               error = deltas_add_roa_v4(deltas, roa->as, addr, op);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int
+add_all_roas_v6(struct deltas *deltas, struct roa *roa, enum delta_op op)
+{
+       struct v6_address *addr;
+       int error;
+
+       ARRAYLIST_FOREACH(&roa->addrs6, addr) {
+               error = deltas_add_roa_v6(deltas, roa->as, addr, op);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int
+add_all_deltas(struct node *node, struct deltas *deltas, enum delta_op op)
+{
+       struct node *child;
+       int error;
+
+       ARRAYLIST_FOREACH(&node->children, child) {
+               error = add_all_deltas(child, deltas, op);
+               if (error)
+                       return error;
+       }
+
+       if (child->roa != NULL) {
+               error = add_all_roas_v4(deltas, child->roa, op);
+               if (error)
+                       return error;
+               error = add_all_roas_v6(deltas, child->roa, op);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int compute_deltas_node(struct node *, struct node *, struct deltas *);
+
+static int
+handle_delta_children(struct nodes *children1, struct nodes *children2,
+    struct deltas *deltas)
+{
+       /*
+        * Most of the time, the arrays will be identical.
+        * When they are not, most of the time the arrays will be mostly
+        * identical.
+        *
+        * We will try our hardest to traverse the arrays as sequentially as
+        * possible to exploit these facts.
+        *
+        * Notice that this is the same algorithm as HANDLE_ROAS_FN().
+        * Changes to one function might need to cascade to the other.
+        */
+
+       struct node *c1array;
+       array_index c1; /* counter for c1array */
+
+       struct node *c2array;
+       array_index c2; /* counter for c2array */
+       array_index *c2p; /* counter for c2array, pointer */
+
+       struct circular_indexer c2indexer;
+
+       int error = 0;
+
+       c1array = children1->array;
+       c2array = children2->array;
+       arridx_init(&c2indexer, children2->len);
+
+       for (c1 = 0; c1 < children1->len; c1++) {
+               if (find_subject_name(&c2indexer, c1array[c1].subject_name,
+                   c2array, &c2)) {
+                       error = compute_deltas_node(&c1array[c1], &c2array[c2],
+                           deltas);
+                       if (error)
+                               goto end;
+
+                       error = arridx_remove(&c2indexer);
+               } else {
+                       error = add_all_deltas(&c1array[c1], deltas, DELTA_RM);
+               }
+               if (error)
+                       goto end;
+       }
+
+       ARRIDX_FOREACH(&c2indexer, c2p) {
+               error = add_all_deltas(&c2array[*c2p], deltas, DELTA_ADD);
+               if (error)
+                       goto end;
+       }
+
+end:   arridx_cleanup(&c2indexer);
+       return error;
+}
+
+static bool
+find_addr_v4(struct v4_address *address, struct v4_addresses *array,
+    struct circular_indexer *indexer)
+{
+       array_index *i;
+
+       ARRIDX_FOREACH(indexer, i)
+               if (prefix4_equals(&address->prefix, &array->array[*i].prefix))
+                       return true;
+
+       return false;
+}
+
+static bool
+find_addr_v6(struct v6_address *address, struct v6_addresses *array,
+    struct circular_indexer *indexer)
+{
+       array_index *i;
+
+       ARRIDX_FOREACH(indexer, i)
+               if (prefix6_equals(&address->prefix, &array->array[*i].prefix))
+                       return true;
+
+       return false;
+}
+
+#define HANDLE_ROAS_FN(name, array_type, node_type, field, find_fn,    \
+    add_one_fn, add_all_fn)                                            \
+       static int                                                      \
+       name(struct roa *roa1, struct roa *roa2, struct deltas *deltas) \
+       {                                                               \
+               /* Notice that this is the same algorithm as */         \
+               /* handle_delta_children(). Changes to one function */  \
+               /* might need to cascade to the other. */               \
+                                                                       \
+               struct array_type *addrs1;                              \
+               struct node_type *a1; /* address cursor for addrs1 */   \
+                                                                       \
+               struct array_type *addrs2;                              \
+               array_index *a2p; /* counter for addrs2, pointer */     \
+                                                                       \
+               struct circular_indexer r2indexer;                      \
+               int error = 0;                                          \
+                                                                       \
+               if (roa1->as != roa2->as) {                             \
+                       error = add_all_fn(deltas, roa1, DELTA_RM);     \
+                       if (error)                                      \
+                               return error;                           \
+                       return add_all_fn(deltas, roa2, DELTA_ADD);     \
+               }                                                       \
+                                                                       \
+               addrs1 = &roa1->field;                                  \
+               addrs2 = &roa2->field;                                  \
+               arridx_init(&r2indexer, addrs2->len);                   \
+                                                                       \
+               ARRAYLIST_FOREACH(addrs1, a1) {                         \
+                       if (find_fn(a1, addrs2, &r2indexer))            \
+                               error = arridx_remove(&r2indexer);      \
+                       else                                            \
+                               error = add_one_fn(deltas,              \
+                                   roa1->as, a1, DELTA_RM);            \
+                       if (error)                                      \
+                               goto end;                               \
+               }                                                       \
+                                                                       \
+               ARRIDX_FOREACH(&r2indexer, a2p) {                       \
+                       error = add_one_fn(deltas, roa2->as,            \
+                           &addrs2->array[*a2p], DELTA_ADD);           \
+                       if (error)                                      \
+                               goto end;                               \
+               }                                                       \
+                                                                       \
+       end:    arridx_cleanup(&r2indexer);                             \
+               return error;                                           \
+       }
+
+HANDLE_ROAS_FN(handle_roas_v4, v4_addresses, v4_address, addrs4, find_addr_v4,
+    deltas_add_roa_v4, add_all_roas_v4)
+HANDLE_ROAS_FN(handle_roas_v6, v6_addresses, v6_address, addrs6, find_addr_v6,
+    deltas_add_roa_v6, add_all_roas_v6)
+
+static int
+compute_deltas_node(struct node *n1, struct node *n2, struct deltas *deltas)
+{
+       int error;
+
+       error = handle_delta_children(&n1->children, &n2->children, deltas);
+       if (error)
+               return error;
+
+       error = handle_roas_v4(n1->roa, n2->roa, deltas);
+       if (error)
+               return error;
+
+       return handle_roas_v6(n1->roa, n2->roa, deltas);
+}
+
+int
+compute_deltas(struct roa_tree *t1, struct roa_tree *t2, struct deltas **result)
+{
+       struct deltas *deltas;
+       int error;
+
+       assert(t1->root != NULL);
+       assert(t2->root != NULL);
+
+       error = deltas_create(&deltas);
+       if (error)
+               return error;
+
+       error = compute_deltas_node(t1->root, t2->root, deltas);
+       if (error) {
+               deltas_destroy(deltas);
+               return error;
+       }
+
+       *result = deltas;
+       return 0;
+}
diff --git a/src/rtr/db/roa_tree.h b/src/rtr/db/roa_tree.h
new file mode 100644 (file)
index 0000000..b80c6bc
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SRC_ROA_TREE_H_
+#define SRC_ROA_TREE_H_
+
+#include "address.h"
+#include "object/name.h"
+#include "rtr/db/delta.h"
+#include "rtr/db/vrp.h"
+
+struct roa_tree;
+
+/* Constructor */
+struct roa_tree *roa_tree_create(void);
+/* Reference counting */
+void roa_tree_get(struct roa_tree *);
+void roa_tree_put(struct roa_tree *);
+
+int roa_tree_foreach_roa(struct roa_tree *, vrp_foreach_cb, void *);
+
+/* TODO rename to tree handler or whatever */
+int forthandler_reset(struct roa_tree *);
+int forthandler_go_down(struct roa_tree *, struct rfc5280_name *);
+int forthandler_go_up(struct roa_tree *);
+int forthandler_handle_roa_v4(struct roa_tree *, uint32_t,
+    struct ipv4_prefix const *, uint8_t);
+int forthandler_handle_roa_v6(struct roa_tree *, uint32_t,
+    struct ipv6_prefix const *, uint8_t);
+
+int compute_deltas(struct roa_tree *, struct roa_tree *, struct deltas **);
+
+#endif /* SRC_ROA_TREE_H_ */
diff --git a/src/rtr/db/vrp.h b/src/rtr/db/vrp.h
new file mode 100644 (file)
index 0000000..5b86826
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SRC_RTR_DB_VRP_H_
+#define SRC_RTR_DB_VRP_H_
+
+#define FLAG_WITHDRAWAL                0
+#define FLAG_ANNOUNCEMENT      1
+
+struct vrp {
+       uint32_t        asn;
+       union {
+               struct  in_addr v4;
+               struct  in6_addr v6;
+       } prefix;
+       uint8_t prefix_length;
+       uint8_t max_prefix_length;
+       uint8_t addr_fam;
+       uint8_t flags;
+};
+
+typedef int (*vrp_foreach_cb)(struct vrp *, void *);
+
+#endif /* SRC_RTR_DB_VRP_H_ */
diff --git a/src/rtr/db/vrps.c b/src/rtr/db/vrps.c
new file mode 100644 (file)
index 0000000..b94c076
--- /dev/null
@@ -0,0 +1,234 @@
+#include "vrps.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include "common.h"
+#include "data_structure/array_list.h"
+
+/*
+ * Storage of VRPs (term taken from RFC 6811 "Validated ROA Payload") and
+ * Serials that contain such VRPs
+ */
+
+#define START_SERIAL           0
+
+struct delta {
+       uint32_t serial;
+       struct deltas *deltas;
+};
+
+ARRAY_LIST(deltas_db, struct delta)
+
+struct state {
+       struct roa_tree *base; /** All the current valid ROAs */
+       struct deltas_db deltas; /** ROA changes to @base over time */
+
+       uint32_t current_serial;
+       uint16_t v0_session_id;
+       uint16_t v1_session_id;
+       time_t last_modified_date;
+} state;
+
+/* Read and Write locks */
+static sem_t rlock, wlock;
+
+/* Readers counter */
+static unsigned int rcounter;
+
+static void
+delta_destroy(struct delta *delta)
+{
+       deltas_destroy(delta->deltas);
+}
+
+int
+vrps_init(void)
+{
+       int error;
+
+       state.base = NULL;
+
+       error = deltas_db_init(&state.deltas);
+       if (error)
+               return error;
+
+       /*
+        * Use the same start serial, the session ID will avoid
+        * "desynchronization" (more at RFC 6810 'Glossary' and
+        * 'Fields of a PDU')
+        */
+       state.current_serial = START_SERIAL;
+
+       /* Get the bits that'll fit in session_id */
+       state.v0_session_id = time(NULL) & 0xFFFF;
+       /* Minus 1 to prevent same ID */
+       /*
+        * TODO Assigning an int (and potentially negative) to a uint16_t.
+        * Is this legal?
+        */
+       state.v1_session_id = state.v0_session_id - 1;
+
+       sem_init(&rlock, 0, 1);
+       sem_init(&wlock, 0, 1);
+       rcounter = 0;
+
+       return 0;
+}
+
+void
+vrps_destroy(void)
+{
+       sem_wait(&wlock);
+       roa_tree_put(state.base);
+       deltas_db_cleanup(&state.deltas, delta_destroy);
+       sem_post(&wlock);
+
+       sem_destroy(&wlock);
+       sem_destroy(&rlock);
+}
+
+/*
+ * @new_deltas can be NULL, @new_tree cannot.
+ */
+int
+vrps_update(struct roa_tree *new_tree, struct deltas *new_deltas)
+{
+       struct delta new_delta;
+       int error;
+
+       sem_wait(&wlock);
+
+       if (new_deltas != NULL) {
+               new_delta.serial = state.current_serial + 1;
+               new_delta.deltas = new_deltas;
+               error = deltas_db_add(&state.deltas, &new_delta);
+               if (error) {
+                       sem_post(&wlock);
+                       return error;
+               }
+       }
+
+       if (state.base != NULL)
+               roa_tree_put(state.base);
+       state.base = new_tree;
+       roa_tree_get(new_tree);
+       state.current_serial++;
+
+       sem_post(&wlock);
+       return 0;
+}
+
+/*
+ * Get a status to know the difference between the delta with serial SERIAL and
+ * the last delta at DB.
+ *
+ * If SERIAL is received as NULL, and there's data at DB then the status will
+ * be DIFF_AVAILABLE.
+ */
+enum delta_status
+deltas_db_status(uint32_t *serial)
+{
+       struct delta *delta;
+       enum delta_status result;
+
+       read_lock(&rlock, &wlock, &rcounter);
+       if (state.base == NULL) {
+               result = DS_NO_DATA_AVAILABLE;
+               goto end;
+       }
+
+       /* No serial to match, and there's data at DB */
+       if (serial == NULL) {
+               result = DS_DIFF_AVAILABLE;
+               goto end;
+       }
+
+       /* Is the last version? */
+       if (*serial == state.current_serial) {
+               result = DS_NO_DIFF;
+               goto end;
+       }
+
+       /* Get the delta corresponding to the serial */
+       ARRAYLIST_FOREACH(&state.deltas, delta)
+               if (delta->serial == *serial) {
+                       result = DS_DIFF_AVAILABLE;
+                       goto end;
+               }
+
+       /* No match yet, release lock */
+       read_unlock(&rlock, &wlock, &rcounter);
+
+       /* The first serial isn't at deltas */
+       if (*serial == START_SERIAL)
+               return DS_DIFF_AVAILABLE;
+
+       /* Reached end, diff can't be determined */
+       return DS_DIFF_UNDETERMINED;
+end:
+       read_unlock(&rlock, &wlock, &rcounter);
+       return result;
+}
+
+int
+vrps_foreach_base_roa(vrp_foreach_cb cb, void *arg)
+{
+       int error;
+
+       read_lock(&rlock, &wlock, &rcounter);
+       error = roa_tree_foreach_roa(state.base, cb, arg);
+       read_unlock(&rlock, &wlock, &rcounter);
+
+       return error;
+}
+
+int
+vrps_foreach_delta_roa(uint32_t from, uint32_t to, vrp_foreach_cb cb, void *arg)
+{
+       struct delta *d;
+       bool from_found;
+       int error;
+
+       from_found = false;
+       error = 0;
+
+       read_lock(&rlock, &wlock, &rcounter);
+
+       ARRAYLIST_FOREACH(&state.deltas, d) {
+               if (!from_found) {
+                       if (d->serial >= from)
+                               from_found = true;
+               } else {
+                       if (d->serial > to)
+                               break;
+                       error = deltas_foreach(d->deltas, cb, arg);
+                       if (error)
+                               break;
+               }
+       }
+
+       read_unlock(&rlock, &wlock, &rcounter);
+
+       return error;
+}
+
+uint32_t
+get_last_serial_number(void)
+{
+       uint32_t serial;
+
+       read_lock(&rlock, &wlock, &rcounter);
+       serial = state.current_serial - 1;
+       read_unlock(&rlock, &wlock, &rcounter);
+
+       return serial;
+}
+
+uint16_t
+get_current_session_id(uint8_t rtr_version)
+{
+       /* Semaphore isn't needed since this value is set at initialization */
+       if (rtr_version == 1)
+               return state.v1_session_id;
+       return state.v0_session_id;
+}
diff --git a/src/rtr/db/vrps.h b/src/rtr/db/vrps.h
new file mode 100644 (file)
index 0000000..40cbb6b
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SRC_VRPS_H_
+#define SRC_VRPS_H_
+
+#include <time.h>
+#include <netinet/ip.h>
+#include "rtr/db/delta.h"
+#include "rtr/db/roa_tree.h"
+
+enum delta_status {
+       /** There's no data at the DB */
+       DS_NO_DATA_AVAILABLE,
+       /** The diff can't be determined */
+       DS_DIFF_UNDETERMINED,
+       /** There's no difference */
+       DS_NO_DIFF,
+       /** There are diffs between SERIAL and the last DB serial */
+       DS_DIFF_AVAILABLE,
+};
+
+int vrps_init(void);
+void vrps_destroy(void);
+
+int vrps_update(struct roa_tree *, struct deltas *);
+enum delta_status deltas_db_status(uint32_t *);
+
+int vrps_foreach_base_roa(vrp_foreach_cb, void *);
+int vrps_foreach_delta_roa(uint32_t, uint32_t, vrp_foreach_cb, void *);
+
+uint32_t get_last_serial_number(void);
+uint16_t get_current_session_id(uint8_t);
+
+#endif /* SRC_VRPS_H_ */
index 91071c58b31deda3da13b84b8e534b397381b934..a0f1252dd8f33c266470d1ac3f110dfa3fd476d0 100644 (file)
@@ -93,10 +93,8 @@ struct pdu_metadata {
        void    (*destructor)(void *);
 };
 
-__BEGIN_DECLS
 int pdu_load(int, void **, struct pdu_metadata const **, uint8_t *);
 struct pdu_metadata const *pdu_get_metadata(uint8_t);
 struct pdu_header *pdu_get_header(void *);
-__END_DECLS
 
 #endif /* RTR_PDU_H_ */
index c8ea494af6b80fe08f6008555facbe10b4a6733c..6a5313e9631aeed451d036f02ff34be30c40cdbb 100644 (file)
@@ -8,7 +8,7 @@
 #include "err_pdu.h"
 #include "pdu.h"
 #include "pdu_sender.h"
-#include "vrps.h"
+#include "rtr/db/vrps.h"
 
 static int
 warn_unexpected_pdu(int fd, void *pdu, char const *pdu_name)
@@ -27,7 +27,8 @@ handle_serial_notify_pdu(int fd, void *pdu)
 }
 
 static int
-send_commmon_exchange(struct sender_common *common)
+send_commmon_exchange(struct sender_common *common,
+    int (*pdu_sender)(struct sender_common *))
 {
        int error;
 
@@ -37,7 +38,7 @@ send_commmon_exchange(struct sender_common *common)
                return error;
 
        /* Send Payload PDUs */
-       error = send_payload_pdus(common);
+       error = pdu_sender(common);
        if (error)
                return error;
 
@@ -45,12 +46,20 @@ send_commmon_exchange(struct sender_common *common)
        return send_end_of_data_pdu(common);
 }
 
+/*
+ * TODO The semaphoring is bonkers. The code keeps locking, storing a value,
+ * unlocking, locking again, and using the old value.
+ * It doesn't look like it's a problem for now, but eventually will be, when old
+ * delta forgetting is implemented.
+ * I'm going to defer this because it shouldn't be done during the merge.
+ */
 int
 handle_serial_query_pdu(int fd, void *pdu)
 {
        struct serial_query_pdu *received = pdu;
        struct sender_common common;
-       int error, updates;
+       int error;
+       enum delta_status updates;
        uint32_t current_serial;
        uint16_t session_id;
        uint8_t version;
@@ -74,26 +83,26 @@ handle_serial_query_pdu(int fd, void *pdu)
 
        updates = deltas_db_status(common.start_serial);
        switch (updates) {
-       case NO_DATA_AVAILABLE:
+       case DS_NO_DATA_AVAILABLE:
                /* https://tools.ietf.org/html/rfc8210#section-8.4 */
                return err_pdu_send(fd, version, ERR_PDU_NO_DATA_AVAILABLE,
                    NULL, NULL);
-       case DIFF_UNDETERMINED:
+       case DS_DIFF_UNDETERMINED:
                /* https://tools.ietf.org/html/rfc8210#section-8.3 */
                return send_cache_reset_pdu(&common);
-       case DIFF_AVAILABLE:
+       case DS_DIFF_AVAILABLE:
                /* https://tools.ietf.org/html/rfc8210#section-8.2 */
-               return send_commmon_exchange(&common);
-       case NO_DIFF:
+               return send_commmon_exchange(&common, send_pdus_delta);
+       case DS_NO_DIFF:
                /* Typical exchange with no Payloads */
                error = send_cache_response_pdu(&common);
                if (error)
                        return error;
                return send_end_of_data_pdu(&common);
-       default:
-               warnx("Reached 'unreachable' code");
-               return -EINVAL;
        }
+
+       warnx("Reached 'unreachable' code");
+       return -EINVAL;
 }
 
 int
@@ -104,7 +113,7 @@ handle_reset_query_pdu(int fd, void *pdu)
        uint32_t current_serial;
        uint16_t session_id;
        uint8_t version;
-       int updates;
+       enum delta_status updates;
 
        version = received->header.protocol_version;
        session_id = get_current_session_id(version);
@@ -114,17 +123,20 @@ handle_reset_query_pdu(int fd, void *pdu)
 
        updates = deltas_db_status(NULL);
        switch (updates) {
-       case NO_DATA_AVAILABLE:
+       case DS_NO_DATA_AVAILABLE:
                /* https://tools.ietf.org/html/rfc8210#section-8.4 */
                return err_pdu_send(fd, version, ERR_PDU_NO_DATA_AVAILABLE,
                    NULL, NULL);
-       case DIFF_AVAILABLE:
+       case DS_DIFF_AVAILABLE:
                /* https://tools.ietf.org/html/rfc8210#section-8.1 */
-               return send_commmon_exchange(&common);
-       default:
-               warnx("Reached 'unreachable' code");
-               return -EINVAL;
+               return send_commmon_exchange(&common, send_pdus_base);
+       case DS_DIFF_UNDETERMINED:
+       case DS_NO_DIFF:
+               break;
        }
+
+       warnx("Reached 'unreachable' code");
+       return -EINVAL;
 }
 
 int
index b1c79e40841ef5225aa4d09caa594736132510f4..87baf586119ce26aa1ca134572aee46226394163 100644 (file)
@@ -8,8 +8,8 @@
 #include <unistd.h>
 
 #include "config.h"
-#include "vrps.h"
 #include "rtr/pdu_serializer.h"
+#include "rtr/db/vrps.h"
 
 /* Header length field is always 64 bits long */
 #define HEADER_LENGTH          8
@@ -166,7 +166,7 @@ send_ipv4_prefix_pdu(struct sender_common *common, struct vrp *vrp)
        pdu.prefix_length = vrp->prefix_length;
        pdu.max_length = vrp->max_prefix_length;
        pdu.zero = 0;
-       pdu.ipv4_prefix = vrp->prefix.ipv4;
+       pdu.ipv4_prefix = vrp->prefix.v4;
        pdu.asn = vrp->asn;
        pdu.header.length = length_ipvx_prefix_pdu(true);
 
@@ -189,7 +189,7 @@ send_ipv6_prefix_pdu(struct sender_common *common, struct vrp *vrp)
        pdu.prefix_length = vrp->prefix_length;
        pdu.max_length = vrp->max_prefix_length;
        pdu.zero = 0;
-       pdu.ipv6_prefix = vrp->prefix.ipv6;
+       pdu.ipv6_prefix = vrp->prefix.v6;
        pdu.asn = vrp->asn;
        pdu.header.length = length_ipvx_prefix_pdu(false);
 
@@ -199,37 +199,29 @@ send_ipv6_prefix_pdu(struct sender_common *common, struct vrp *vrp)
 }
 
 int
-send_payload_pdus(struct sender_common *common)
+send_prefix_pdu(struct vrp *vrp, void *arg)
 {
-       struct vrp *vrps, *ptr;
-       unsigned int len;
-       int error;
-
-       vrps = malloc(sizeof(struct vrp));
-       if (vrps == NULL) {
-               warn("Couldn't allocate VRPs to send PDUs");
-               return -ENOMEM;
-       }
-       len = get_vrps_delta(common->start_serial, common->end_serial, &vrps);
-       if (len == 0)
-               goto end;
-
-       for (ptr = vrps; (ptr - vrps) < len; ptr++) {
-               if (ptr->addr_fam == AF_INET)
-                       error = send_ipv4_prefix_pdu(common, ptr);
-               else if (ptr->addr_fam == AF_INET6)
-                       error = send_ipv6_prefix_pdu(common, ptr);
-               else
-                       error = -EINVAL;
-
-               if (error) {
-                       free(vrps);
-                       return error;
-               }
+       switch (vrp->addr_fam) {
+       case AF_INET:
+               return send_ipv4_prefix_pdu(arg, vrp);
+       case AF_INET6:
+               return send_ipv6_prefix_pdu(arg, vrp);
        }
-end:
-       free(vrps);
-       return 0;
+
+       return -EINVAL;
+}
+
+int
+send_pdus_base(struct sender_common *common)
+{
+       return vrps_foreach_base_roa(send_prefix_pdu, common);
+}
+
+int
+send_pdus_delta(struct sender_common *common)
+{
+       return vrps_foreach_delta_roa(*common->start_serial,
+           *common->end_serial, send_prefix_pdu, common);
 }
 
 int
index 43792a21b359ea74eaf66f706a753af1156e3787..94b6f196543b9758e06352a45c44ded09d275215 100644 (file)
@@ -17,7 +17,8 @@ void init_sender_common(struct sender_common *, int, uint8_t, uint16_t *,
 int send_serial_notify_pdu(struct sender_common *);
 int send_cache_reset_pdu(struct sender_common *);
 int send_cache_response_pdu(struct sender_common *);
-int send_payload_pdus(struct sender_common *);
+int send_pdus_base(struct sender_common *);
+int send_pdus_delta(struct sender_common *);
 int send_end_of_data_pdu(struct sender_common *);
 int send_error_report_pdu(int, uint8_t, uint16_t, struct pdu_header *,
     char const *);
index e536ac5d2e126a576e32f57fb2981b4f1e5e3045..9c23dce223ce850ebf3c860c4edaca9063bfb1d2 100644 (file)
@@ -11,7 +11,6 @@ struct data_buffer {
        char *data;
 };
 
-__BEGIN_DECLS
 void init_buffer(struct data_buffer *);
 void free_buffer(struct data_buffer *);
 
@@ -22,6 +21,5 @@ size_t serialize_ipv6_prefix_pdu(struct ipv6_prefix_pdu *, char *);
 size_t serialize_end_of_data_pdu(struct end_of_data_pdu *, char *);
 size_t serialize_cache_reset_pdu(struct cache_reset_pdu *, char *);
 size_t serialize_error_report_pdu(struct error_report_pdu *, char *);
-__END_DECLS
 
 #endif /* SRC_RTR_PDU_SERIALIZER_H_ */
index 49790cfc23d5feaa1b8d4348ff2b0b9e11a79ced..104b1239f0d0de74cc97e19bf26ce5b7debcb23d 100644 (file)
@@ -7,13 +7,11 @@
 
 typedef char rtr_char;
 
-__BEGIN_DECLS
 int read_int8(int, uint8_t *);
 int read_int16(int, uint16_t *);
 int read_int32(int, uint32_t *);
 int read_in_addr(int, struct in_addr *);
 int read_in6_addr(int, struct in6_addr *);
 int read_string(int, rtr_char **);
-__END_DECLS
 
 #endif /* RTR_PRIMITIVE_READER_H_ */
index a271a16e5aa457617818ecb374a408284191371c..8a34ce7d939273447996a29554bb7d28a4773fc9 100644 (file)
@@ -3,12 +3,10 @@
 
 #include <netinet/in.h>
 
-__BEGIN_DECLS
 char *write_int8(char *, uint8_t);
 char *write_int16(char *, uint16_t);
 char *write_int32(char *, uint32_t);
 char *write_in_addr(char *, struct in_addr);
 char *write_in6_addr(char *, struct in6_addr);
-__END_DECLS
 
 #endif /* RTR_PRIMITIVE_WRITER_H_ */
index 0dfc1111455bfea04f3d0655a4af60566bbe578d..2d445c8d01d733ccef526279aae5e1c12af244e6 100644 (file)
@@ -3,9 +3,7 @@
 
 #include "common.h"
 
-__BEGIN_DECLS
 int rtr_listen(void);
 void rtr_cleanup(void);
-__END_DECLS
 
 #endif /* RTR_RTR_H_ */
index 01cdaff523ea32632a1725383f49624c36b237c6..ef0be1794adaf2584be4702e02a6d0580d111c87 100644 (file)
@@ -3,10 +3,10 @@
 #include <sys/queue.h>
 #include <errno.h>
 #include <string.h>
-#include "array_list.h"
 #include "log.h"
 #include "str.h"
 #include "thread_var.h"
+#include "data_structure/array_list.h"
 #include "object/certificate.h"
 
 struct serial_number {
@@ -15,7 +15,7 @@ struct serial_number {
 };
 
 struct subject_name {
-       struct rfc5280_name name;
+       struct rfc5280_name *name;
        char *file; /* File where this subject name was found. */
 };
 
@@ -83,6 +83,8 @@ struct validation {
         */
        char addr_buffer1[INET6_ADDRSTRLEN];
        char addr_buffer2[INET6_ADDRSTRLEN];
+
+       struct validation_handler validation_handler;
 };
 
 /*
@@ -122,7 +124,8 @@ cb(int ok, X509_STORE_CTX *ctx)
 
 /** Creates a struct validation, puts it in thread local, and returns it. */
 int
-validation_prepare(struct validation **out, struct tal *tal)
+validation_prepare(struct validation **out, struct tal *tal,
+    struct validation_handler *validation_handler)
 {
        struct validation *result;
        int error;
@@ -153,6 +156,7 @@ validation_prepare(struct validation **out, struct tal *tal)
 
        SLIST_INIT(&result->certs);
        result->pubkey_state = PKS_UNTESTED;
+       result->validation_handler = *validation_handler;
 
        *out = result;
        return 0;
@@ -174,7 +178,7 @@ serial_cleanup(struct serial_number *serial)
 static void
 subject_cleanup(struct subject_name *subject)
 {
-       x509_name_cleanup(&subject->name);
+       x509_name_put(subject->name);
        free(subject->file);
 }
 
@@ -427,9 +431,6 @@ validation_store_serial_number(struct validation *state, BIGNUM *number)
        return error;
 }
 
-/**
- * This function will steal ownership of @subject on success.
- */
 int
 validation_store_subject(struct validation *state, struct rfc5280_name *subject)
 {
@@ -481,38 +482,40 @@ validation_store_subject(struct validation *state, struct rfc5280_name *subject)
         * fixing.
         */
 
-       /* Remember to free @subject if you return 0 but don't store it. */
-
        cert = SLIST_FIRST(&state->certs);
-       if (cert == NULL) {
-               x509_name_cleanup(subject);
+       if (cert == NULL)
                return 0; /* The TA lacks siblings, so subject is unique. */
-       }
 
        /* See the large comment in validation_store_serial_number(). */
        ARRAYLIST_FOREACH(&cert->subjects, cursor) {
-               if (x509_name_equals(&cursor->name, subject)) {
+               if (x509_name_equals(cursor->name, subject)) {
+                       char const *serial = x509_name_serialNumber(subject);
                        pr_warn("Subject name '%s%s%s' is not unique. (Also found in '%s'.)",
-                           subject->commonName,
-                           (subject->serialNumber != NULL) ? "/" : "",
-                           (subject->serialNumber != NULL)
-                               ? subject->serialNumber
-                               : "",
+                           x509_name_commonName(subject),
+                           (serial != NULL) ? "/" : "",
+                           (serial != NULL) ? serial : "",
                            cursor->file);
-                       x509_name_cleanup(subject);
                        return 0;
                }
        }
 
-       duplicate.name = *subject;
+       duplicate.name = subject;
+       x509_name_get(subject);
+
        error = get_current_file_name(&duplicate.file);
        if (error)
-               return error;
+               goto revert_name;
 
        error = subjects_add(&cert->subjects, &duplicate);
        if (error)
-               free(duplicate.file);
+               goto revert_file;
+
+       return 0;
 
+revert_file:
+       free(duplicate.file);
+revert_name:
+       x509_name_put(subject);
        return error;
 }
 
@@ -527,3 +530,9 @@ validation_get_ip_buffer2(struct validation *state)
 {
        return state->addr_buffer2;
 }
+
+struct validation_handler const *
+validation_get_validation_handler(struct validation *state)
+{
+       return &state->validation_handler;
+}
index 5b1f45c1373092ac43537a7315e096b64d34969e..d7d39517a33cdd3bd3b7917cf97157b7b3532528 100644 (file)
@@ -3,12 +3,14 @@
 
 #include <openssl/x509.h>
 #include "resource.h"
+#include "validation_handler.h"
 #include "object/name.h"
 #include "object/tal.h"
 
 struct validation;
 
-int validation_prepare(struct validation **, struct tal *);
+int validation_prepare(struct validation **, struct tal *,
+    struct validation_handler *);
 void validation_destroy(struct validation *);
 
 struct tal *validation_tal(struct validation *);
@@ -39,4 +41,6 @@ int validation_store_subject(struct validation *, struct rfc5280_name *);
 char *validation_get_ip_buffer1(struct validation *);
 char *validation_get_ip_buffer2(struct validation *);
 
+struct validation_handler const *validation_get_validation_handler(struct validation *);
+
 #endif /* SRC_STATE_H_ */
index d907d85dac8cd91c1379efb80a385477803ccdd9..b61b7cf191a9d58a198b0ba1a9d7df1f985331cb 100644 (file)
@@ -127,18 +127,6 @@ fnstack_cleanup(void)
                fprintf(stderr, "pthread_setspecific() returned %d.", error);
 }
 
-static struct filename_stack *
-get_file_stack(void)
-{
-       struct filename_stack *files;
-
-       files = pthread_getspecific(filenames_key);
-       if (files == NULL)
-               fprintf(stderr, "This thread lacks a files stack.\n");
-
-       return files;
-}
-
 /**
  * Call this function every time you're about to start processing a new file.
  * Any pr_err()s and friends will now include the new file name.
@@ -151,7 +139,7 @@ fnstack_push(char const *file)
        struct filename_stack *files;
        char const **tmp;
 
-       files = get_file_stack();
+       files = pthread_getspecific(filenames_key);
        if (files == NULL || files->filenames == NULL)
                return;
 
@@ -184,7 +172,7 @@ fnstack_peek(void)
 {
        struct filename_stack *files;
 
-       files = get_file_stack();
+       files = pthread_getspecific(filenames_key);
        if (files == NULL || files->filenames == NULL || files->len == 0)
                return NULL;
 
@@ -197,7 +185,7 @@ fnstack_pop(void)
 {
        struct filename_stack *files;
 
-       files = get_file_stack();
+       files = pthread_getspecific(filenames_key);
        if (files == NULL || files->filenames == NULL || files->len == 0)
                return;
 
@@ -205,7 +193,7 @@ fnstack_pop(void)
 }
 
 static char const *
-addr2str(int af, void *addr, char *(*buffer_cb)(struct validation *))
+addr2str(int af, void const *addr, char *(*buffer_cb)(struct validation *))
 {
        struct validation *state;
 
@@ -227,7 +215,7 @@ addr2str(int af, void *addr, char *(*buffer_cb)(struct validation *))
  * The buffer is the same as v6addr2str()'s, so don't mix them either.
  */
 char const *
-v4addr2str(struct in_addr *addr)
+v4addr2str(struct in_addr const *addr)
 {
        return addr2str(AF_INET, addr, validation_get_ip_buffer1);
 }
@@ -236,7 +224,7 @@ v4addr2str(struct in_addr *addr)
  * Same as v4addr2str(), except a different buffer is used.
  */
 char const *
-v4addr2str2(struct in_addr *addr)
+v4addr2str2(struct in_addr const *addr)
 {
        return addr2str(AF_INET, addr, validation_get_ip_buffer2);
 }
@@ -245,7 +233,7 @@ v4addr2str2(struct in_addr *addr)
  * See v4addr2str().
  */
 char const *
-v6addr2str(struct in6_addr *addr)
+v6addr2str(struct in6_addr const *addr)
 {
        return addr2str(AF_INET6, addr, validation_get_ip_buffer1);
 }
@@ -254,7 +242,7 @@ v6addr2str(struct in6_addr *addr)
  * See v4addr2str2().
  */
 char const *
-v6addr2str2(struct in6_addr *addr)
+v6addr2str2(struct in6_addr const *addr)
 {
        return addr2str(AF_INET6, addr, validation_get_ip_buffer2);
 }
index 7dbe18e067f706c5367223163190dbc350fb67c2..a56b88115375d22091d80384f6ec4591bed593f7 100644 (file)
@@ -16,9 +16,9 @@ void fnstack_push_uri(struct rpki_uri const *);
 char const *fnstack_peek(void);
 void fnstack_pop(void);
 
-char const *v4addr2str(struct in_addr *addr);
-char const *v4addr2str2(struct in_addr *addr);
-char const *v6addr2str(struct in6_addr *addr);
-char const *v6addr2str2(struct in6_addr *addr);
+char const *v4addr2str(struct in_addr const *addr);
+char const *v4addr2str2(struct in_addr const *addr);
+char const *v6addr2str(struct in6_addr const *addr);
+char const *v6addr2str2(struct in6_addr const *addr);
 
 #endif /* SRC_THREAD_VAR_H_ */
index cd7d3c8906fc0db8217f7eb2a5ab7c63dce09ebb..9c07a5128b5ae60b1fe7a23711af3e8c029b7da6 100644 (file)
 #include "config.h"
 #include "notify.h"
 #include "object/tal.h"
+#include "rtr/db/vrps.h"
 
 static pthread_t thread;
 
+static int
+__reset(void *arg)
+{
+       return forthandler_reset(arg);
+}
+
+static int
+__traverse_down(struct rfc5280_name *subject_name, void *arg)
+{
+       return forthandler_go_down(arg, subject_name);
+}
+
+static int
+__traverse_up(void *arg)
+{
+       return forthandler_go_up(arg);
+}
+
+int
+__handle_roa_v4(uint32_t as, struct ipv4_prefix const *prefix,
+    uint8_t max_length, void *arg)
+{
+       return forthandler_handle_roa_v4(arg, as, prefix, max_length);
+}
+
+int
+__handle_roa_v6(uint32_t as, struct ipv6_prefix const * prefix,
+    uint8_t max_length, void *arg)
+{
+       return forthandler_handle_roa_v6(arg, as, prefix, max_length);
+}
+
 static void *
 check_vrps_updates(void *param_void)
 {
+       struct validation_handler validation_handler;
+       struct roa_tree *old_tree;
+       struct deltas *deltas;
        int error;
-       bool updated;
+
+       validation_handler.reset = __reset;
+       validation_handler.traverse_down = __traverse_down;
+       validation_handler.traverse_up = __traverse_up;
+       validation_handler.handle_roa_v4 = __handle_roa_v4;
+       validation_handler.handle_roa_v6 = __handle_roa_v6;
+       old_tree = NULL;
 
        do {
-               updated = false;
-               error = perform_standalone_validation(&updated);
+               validation_handler.arg = roa_tree_create();
+               if (validation_handler.arg == NULL) {
+                       pr_err("Memory allocation failed. Cannot validate. Sleeping...");
+                       goto sleep;
+               }
+
+               error = perform_standalone_validation(&validation_handler);
+               if (error) {
+                       roa_tree_put(validation_handler.arg);
+                       pr_err("Validation failed (error code %d). Cannot udpate the ROA database. Sleeping...",
+                           error);
+                       goto sleep;
+               }
+
+               if (old_tree == NULL) {
+                       error = vrps_update(validation_handler.arg, NULL);
+                       if (error) {
+                               roa_tree_put(validation_handler.arg);
+                               pr_err("Error code %d while trying to update the ROA database. Sleeping...",
+                                   error);
+                       } else {
+                               old_tree = validation_handler.arg;
+                       }
+                       goto sleep;
+               }
+
+               error = compute_deltas(old_tree, validation_handler.arg, &deltas);
                if (error) {
-                       warnx("Error '%d' while searching CSV updates, sleeping...",
+                       roa_tree_put(validation_handler.arg);
+                       pr_err("Something went wrong while trying to compute the deltas. (error code %d.) Cannot update the ROA database. Sleeping...",
                            error);
                        goto sleep;
                }
-               if (updated)
-                       notify_clients();
+
+               if (deltas_is_empty(deltas)) {
+                       roa_tree_put(validation_handler.arg);
+                       deltas_destroy(deltas);
+                       pr_debug("No changes. Sleeping...");
+                       goto sleep;
+               }
+
+               error = vrps_update(validation_handler.arg, deltas);
+               if (error) {
+                       roa_tree_put(validation_handler.arg);
+                       deltas_destroy(deltas);
+                       pr_err("Error code %d while trying to store the deltas in the database. Cannot update the ROA database. Sleeping...",
+                           error);
+                       goto sleep;
+               }
+
+               old_tree = validation_handler.arg;
+               notify_clients();
+               pr_debug("Database updated successfully. Sleeping...");
+
 sleep:
                sleep(config_get_vrps_check_interval());
        } while (true);
diff --git a/src/validation_handler.c b/src/validation_handler.c
new file mode 100644 (file)
index 0000000..971af06
--- /dev/null
@@ -0,0 +1,90 @@
+#include "validation_handler.h"
+
+#include <errno.h>
+#include "log.h"
+#include "thread_var.h"
+
+int
+vhandler_reset(struct validation_handler *handler)
+{
+       return (handler->reset != NULL) ? handler->reset(handler->arg) : 0;
+}
+
+static int
+get_current_threads_handler(struct validation_handler const **result)
+{
+       struct validation *state;
+       struct validation_handler const *handler;
+
+       state = state_retrieve();
+       if (state == NULL)
+               return -EINVAL;
+       handler = validation_get_validation_handler(state);
+       if (handler == NULL)
+               return pr_crit("This thread lacks a validation handler.");
+
+       *result = handler;
+       return 0;
+}
+
+int
+vhandler_traverse_down(struct rfc5280_name *subject_name)
+{
+       struct validation_handler const *handler;
+       int error;
+
+       error = get_current_threads_handler(&handler);
+       if (error)
+               return error;
+
+       return (handler->traverse_down != NULL)
+           ? handler->traverse_down(subject_name, handler->arg)
+           : 0;
+}
+
+int
+vhandler_traverse_up(void)
+{
+       struct validation_handler const *handler;
+       int error;
+
+       error = get_current_threads_handler(&handler);
+       if (error)
+               return error;
+
+       return (handler->traverse_up != NULL)
+           ? handler->traverse_up(handler->arg)
+           : 0;
+}
+
+int
+vhandler_handle_roa_v4(uint32_t as, struct ipv4_prefix const *prefix,
+    uint8_t max_length)
+{
+       struct validation_handler const *handler;
+       int error;
+
+       error = get_current_threads_handler(&handler);
+       if (error)
+               return error;
+
+       return (handler->handle_roa_v4 != NULL)
+           ? handler->handle_roa_v4(as, prefix, max_length, handler->arg)
+           : 0;
+}
+
+int
+vhandler_handle_roa_v6(uint32_t as, struct ipv6_prefix const *prefix,
+    uint8_t max_length)
+{
+       struct validation_handler const *handler;
+       int error;
+
+       error = get_current_threads_handler(&handler);
+       if (error)
+               return error;
+
+       return (handler->handle_roa_v6 != NULL)
+           ? handler->handle_roa_v6(as, prefix, max_length, handler->arg)
+           : 0;
+}
diff --git a/src/validation_handler.h b/src/validation_handler.h
new file mode 100644 (file)
index 0000000..72ca426
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef SRC_VALIDATION_HANDLER_H_
+#define SRC_VALIDATION_HANDLER_H_
+
+#include "address.h"
+#include "object/name.h"
+
+struct validation_handler {
+       /* All of these can be NULL. */
+
+       int (*reset)(void *);
+       int (*traverse_down)(struct rfc5280_name *, void *);
+       int (*traverse_up)(void *);
+       int (*handle_roa_v4)(uint32_t, struct ipv4_prefix const *, uint8_t,
+           void *);
+       int (*handle_roa_v6)(uint32_t, struct ipv6_prefix const *, uint8_t,
+           void *);
+       void *arg;
+};
+
+int vhandler_reset(struct validation_handler *);
+int vhandler_traverse_down(struct rfc5280_name *);
+int vhandler_traverse_up(void);
+int vhandler_handle_roa_v4(uint32_t, struct ipv4_prefix const *, uint8_t);
+int vhandler_handle_roa_v6(uint32_t, struct ipv6_prefix const *, uint8_t);
+
+#endif /* SRC_VALIDATION_HANDLER_H_ */
diff --git a/src/vrps.c b/src/vrps.c
deleted file mode 100644 (file)
index b41a10a..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-#include "vrps.h"
-
-#include <stdbool.h>
-#include <string.h>
-#include "array_list.h"
-#include "common.h"
-
-/*
- * Storage of VRPs (term taken from RFC 6811 "Validated ROA Payload") and
- * Serials that contain such VRPs
- */
-
-#define FLAG_WITHDRAWAL                0
-#define FLAG_ANNOUNCEMENT      1
-#define START_SERIAL           0
-
-ARRAY_LIST(vrps, struct vrp)
-
-struct delta {
-       uint32_t serial;
-       struct vrps vrps;
-};
-
-ARRAY_LIST(deltasdb, struct delta)
-
-struct state {
-       /** The current valid ROAs, freshly loaded from the file */
-       struct delta base_db;
-       /** ROA changes over time */
-       struct deltasdb deltas_db;
-       uint32_t current_serial;
-       uint16_t v0_session_id;
-       uint16_t v1_session_id;
-       time_t last_modified_date;
-} state;
-
-/* Read and Write locks */
-sem_t rlock, wlock;
-
-/* Readers counter */
-unsigned int rcounter;
-
-static int
-delta_init(struct delta *delta)
-{
-       return vrps_init(&delta->vrps);
-}
-
-static void
-vrp_destroy(struct vrp *vrp)
-{
-       /* Didn't allocate something, so do nothing */
-}
-
-static void
-delta_destroy(struct delta *delta)
-{
-       vrps_cleanup(&delta->vrps, vrp_destroy);
-}
-
-int
-deltas_db_init(void)
-{
-       int error, shift;
-
-       error = delta_init(&state.base_db);
-       if (error)
-               return error;
-
-       error = deltasdb_init(&state.deltas_db);
-       if (error) {
-               delta_destroy(&state.base_db);
-               return error;
-       }
-
-       /*
-        * Use the same start serial, the session ID will avoid
-        * "desynchronization" (more at RFC 6810 'Glossary' and
-        * 'Fields of a PDU')
-        */
-       state.current_serial = START_SERIAL;
-
-       /* Get the bits that'll fit in session_id */
-       shift = sizeof(time_t) - sizeof(state.v0_session_id);
-       state.v0_session_id = (uint16_t)((time(NULL) << shift) >> shift);
-       /* Minus 1 to prevent same ID */
-       state.v1_session_id = state.v0_session_id - 1;
-
-       sem_init(&rlock, 0, 1);
-       sem_init(&wlock, 0, 1);
-       rcounter = 0;
-
-       return 0;
-}
-
-static void
-init_vrp (struct vrp *vrp, uint32_t asn, uint8_t prefix_length,
-    uint8_t max_prefix_length)
-{
-       vrp->asn = asn;
-       vrp->prefix_length = prefix_length;
-       vrp->max_prefix_length = max_prefix_length;
-       /* Set as ANNOUNCEMENT by default */
-       vrp->flags = FLAG_ANNOUNCEMENT;
-}
-
-struct vrp
-create_vrp4(uint32_t asn, struct in_addr ipv4_prefix, uint8_t prefix_length,
-    uint8_t max_prefix_length)
-{
-       struct vrp result;
-
-       init_vrp(&result, asn, prefix_length, max_prefix_length);
-       result.prefix.ipv4 = ipv4_prefix;
-       result.addr_fam = AF_INET;
-
-       return result;
-}
-
-struct vrp
-create_vrp6(uint32_t asn, struct in6_addr ipv6_prefix, uint8_t prefix_length,
-    uint8_t max_prefix_length)
-{
-       struct vrp result;
-
-       init_vrp(&result, asn, prefix_length, max_prefix_length);
-       result.prefix.ipv6 = ipv6_prefix;
-       result.addr_fam = AF_INET6;
-
-       return result;
-}
-
-static bool
-vrp_equal(struct vrp *left, struct vrp *right)
-{
-       return left->asn == right->asn
-           && left->addr_fam == right->addr_fam
-           && left->prefix_length == right->prefix_length
-           && left->max_prefix_length == right->max_prefix_length
-           && ((left->addr_fam == AF_INET
-               && left->prefix.ipv4.s_addr == right->prefix.ipv4.s_addr)
-           || (left->addr_fam == AF_INET6
-           && IN6_ARE_ADDR_EQUAL(left->prefix.ipv6.s6_addr32,
-               right->prefix.ipv6.s6_addr32)));
-}
-
-static struct vrp *
-vrp_locate(struct vrps *base, struct vrp *vrp)
-{
-       struct vrp *cursor;
-
-       ARRAYLIST_FOREACH(base, cursor)
-               if (vrp_equal(cursor, vrp))
-                       return cursor;
-
-       return NULL;
-}
-
-static bool
-vrp_is_new(struct vrps *base, struct vrp *vrp)
-{
-       return vrp_locate(base, vrp) == NULL;
-}
-
-static int
-delta_add_vrp(struct delta *delta, struct vrp *vrp)
-{
-       return vrps_add(&delta->vrps, vrp);
-}
-
-static int
-delta_summary(struct delta *base_delta, struct delta *result)
-{
-       struct vrps *base, *search_list;
-       struct vrp *cursor;
-       int error;
-
-       /*
-        * Note: Don't fix this function yet.
-        * I realize why you implemented it this way, and I'm trying to come up
-        * with a more efficient algorithm.
-        */
-
-       error = delta_init(result);
-       if (error)
-               return error;
-
-       result->serial = base_delta->serial;
-       read_lock(&rlock, &wlock, &rcounter);
-       /* First check for announcements */
-       base = &base_delta->vrps;
-       search_list = &state.base_db.vrps;
-       ARRAYLIST_FOREACH(base, cursor)
-               if (vrp_is_new(search_list, cursor)) {
-                       cursor->flags = FLAG_ANNOUNCEMENT;
-                       error = delta_add_vrp(result, cursor);
-                       if (error) {
-                               read_unlock(&rlock, &wlock, &rcounter);
-                               return error;
-                       }
-               }
-
-       /* Now for withdrawals */
-       base = &state.base_db.vrps;
-       search_list = &base_delta->vrps;
-       ARRAYLIST_FOREACH(base, cursor)
-               if (vrp_is_new(search_list, cursor)) {
-                       cursor->flags = FLAG_WITHDRAWAL;
-                       error = delta_add_vrp(result, cursor);
-                       if (error) {
-                               read_unlock(&rlock, &wlock, &rcounter);
-                               return error;
-                       }
-               }
-
-       read_unlock(&rlock, &wlock, &rcounter);
-       return 0;
-}
-
-static int
-deltas_db_add_delta(struct delta delta)
-{
-       struct delta summary;
-       int result;
-
-       result = 0;
-       read_lock(&rlock, &wlock, &rcounter);
-       delta.serial = state.current_serial;
-       read_unlock(&rlock, &wlock, &rcounter);
-       /* Store only updates */
-       if (delta.serial != START_SERIAL) {
-               result = delta_summary(&delta, &summary);
-               if (result != 0) {
-                       pr_err("Error summarizing new delta");
-                       return result;
-               }
-               sem_wait(&wlock);
-               result = deltasdb_add(&state.deltas_db, &summary);
-               sem_post(&wlock);
-       }
-       /* Don't set the base in case of error */
-       if (result != 0) {
-               pr_err("Error persisting new delta");
-               return result;
-       }
-
-       sem_wait(&wlock);
-       free(state.base_db.vrps.array);
-       state.base_db = delta;
-       state.current_serial++;
-       sem_post(&wlock);
-       return result;
-}
-
-static void
-copy_vrps(struct vrp **dst, struct vrp *src, unsigned int len)
-{
-       struct vrp *tmp;
-       tmp = realloc(*dst, len * sizeof(struct vrp));
-       if (tmp == NULL) {
-               pr_enomem();
-               return;
-       }
-       *dst = tmp;
-       memcpy(*dst, src, len * sizeof(struct vrp));
-}
-
-int
-deltas_db_create_delta(struct vrp *array, unsigned int len)
-{
-       struct delta new_delta;
-       int error;
-
-       error = delta_init(&new_delta);
-       if (error) {
-               pr_err("New Delta couldn't be initialized");
-               return error;
-       }
-
-       copy_vrps(&new_delta.vrps.array, array, len);
-       new_delta.vrps.len = len;
-       new_delta.vrps.capacity = len * sizeof(struct vrp);
-
-       error = deltas_db_add_delta(new_delta);
-       if (error)
-               return error;
-
-       return 0;
-}
-
-void
-deltas_db_destroy(void)
-{
-       sem_wait(&wlock);
-       delta_destroy(&state.base_db);
-       deltasdb_cleanup(&state.deltas_db, delta_destroy);
-       sem_post(&wlock);
-
-       sem_destroy(&wlock);
-       sem_destroy(&rlock);
-}
-
-/*
- * Get a status to know the difference between the delta with serial SERIAL and
- * the last delta at DB.
- *
- * If SERIAL is received as NULL, and there's data at DB then the status will
- * be DIFF_AVAILABLE.
- *
- * The possible return values are:
- *  NO_DATA_AVAILABLE -> There's no data at the DB
- *  DIFF_UNDETERMINED -> The diff can't be determined
- *  NO_DIFF -> There's no difference
- *  DIFF_AVAILABLE -> There are diffs between SERIAL and the last DB serial
- */
-int
-deltas_db_status(uint32_t *serial)
-{
-       struct delta *delta;
-       int result;
-
-       read_lock(&rlock, &wlock, &rcounter);
-       if (state.base_db.vrps.len == 0) {
-               result = NO_DATA_AVAILABLE;
-               goto end;
-       }
-
-       /* No serial to match, and there's data at DB */
-       if (serial == NULL) {
-               result = DIFF_AVAILABLE;
-               goto end;
-       }
-
-       /* Is the last version? */
-       if (*serial == state.base_db.serial) {
-               result = NO_DIFF;
-               goto end;
-       }
-
-       /* Get the delta corresponding to the serial */
-       ARRAYLIST_FOREACH(&state.deltas_db, delta)
-               if (delta->serial == *serial) {
-                       result = DIFF_AVAILABLE;
-                       goto end;
-               }
-
-       /* No match yet, release lock */
-       read_unlock(&rlock, &wlock, &rcounter);
-
-       /* The first serial isn't at deltas */
-       if (*serial == START_SERIAL)
-               return DIFF_AVAILABLE;
-
-       /* Reached end, diff can't be determined */
-       return DIFF_UNDETERMINED;
-end:
-       read_unlock(&rlock, &wlock, &rcounter);
-       return result;
-}
-
-static void
-add_vrps_filtered(struct vrps *dst, struct vrps *src)
-{
-       struct vrp *ptr;
-       for (ptr = src->array; (ptr - src->array) < src->len; ptr++)
-               if (vrp_is_new(dst, ptr))
-                       vrps_add(dst, ptr);
-}
-
-/*
- * Get the number of updates from serial START_SERIAL to END_SERIAL, set them
- * at RESULT.
- *
- * Return 0 if no updates are available or couldn't be calculated with the
- * received values.
- */
-unsigned int
-get_vrps_delta(uint32_t *start_serial, uint32_t *end_serial,
-    struct vrp **result)
-{
-       struct delta *delta1;
-       struct vrps summary;
-       unsigned int vrps_len;
-
-       read_lock(&rlock, &wlock, &rcounter);
-       /* No data */
-       if (state.base_db.vrps.len == 0) {
-               read_unlock(&rlock, &wlock, &rcounter);
-               return 0;
-       }
-
-       /* NULL start? Send the last version, there's no need to iterate DB */
-       if (start_serial == NULL) {
-               copy_vrps(result, state.base_db.vrps.array,
-                   state.base_db.vrps.len);
-               vrps_len = state.base_db.vrps.len;
-               read_unlock(&rlock, &wlock, &rcounter);
-               return vrps_len;
-       }
-
-       /* Apparently nothing to return */
-       if (*start_serial >= *end_serial) {
-               read_unlock(&rlock, &wlock, &rcounter);
-               return 0;
-       }
-
-       /* Get the delta corresponding to the serials */
-       vrps_init(&summary);
-       ARRAYLIST_FOREACH(&state.deltas_db, delta1) {
-               if (delta1->serial > *start_serial)
-                       add_vrps_filtered(&summary, &delta1->vrps);
-               if (delta1->serial == *end_serial)
-                       break;
-       }
-       read_unlock(&rlock, &wlock, &rcounter);
-
-       copy_vrps(result, summary.array, summary.len);
-       vrps_cleanup(&summary, vrp_destroy);
-       return summary.len;
-}
-
-void
-set_vrps_last_modified_date(time_t new_date)
-{
-       sem_wait(&wlock);
-       state.last_modified_date = new_date;
-       sem_post(&wlock);
-}
-
-uint32_t
-get_last_serial_number(void)
-{
-       uint32_t serial;
-
-       read_lock(&rlock, &wlock, &rcounter);
-       serial = state.current_serial - 1;
-       read_unlock(&rlock, &wlock, &rcounter);
-
-       return serial;
-}
-
-uint16_t
-get_current_session_id(uint8_t rtr_version)
-{
-       /* Semaphore isn't needed since this value is set at initialization */
-       if (rtr_version == 1)
-               return state.v1_session_id;
-       return state.v0_session_id;
-}
-
-time_t
-get_vrps_last_modified_date(void)
-{
-       time_t date;
-
-       read_lock(&rlock, &wlock, &rcounter);
-       date = state.last_modified_date;
-       read_unlock(&rlock, &wlock, &rcounter);
-
-       return date;
-}
diff --git a/src/vrps.h b/src/vrps.h
deleted file mode 100644 (file)
index 11f77d6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef SRC_VRPS_H_
-#define SRC_VRPS_H_
-
-#include <time.h>
-#include <netinet/ip.h>
-
-#define NO_DATA_AVAILABLE      -2
-#define DIFF_UNDETERMINED      -1
-#define NO_DIFF                        0
-#define DIFF_AVAILABLE         1
-
-struct vrp {
-       uint32_t        asn;
-       union {
-               struct  in_addr ipv4;
-               struct  in6_addr ipv6;
-       } prefix;
-       uint8_t prefix_length;
-       uint8_t max_prefix_length;
-       uint8_t addr_fam;
-       uint8_t flags;
-};
-
-int deltas_db_init(void);
-
-struct vrp create_vrp4(uint32_t, struct in_addr, uint8_t, uint8_t);
-struct vrp create_vrp6(uint32_t, struct in6_addr, uint8_t, uint8_t);
-
-int deltas_db_create_delta(struct vrp *, unsigned int);
-int deltas_db_status(uint32_t *);
-
-unsigned int get_vrps_delta(uint32_t *, uint32_t *, struct vrp **);
-
-void deltas_db_destroy(void);
-void set_vrps_last_modified_date(time_t);
-
-uint32_t get_last_serial_number(void);
-uint16_t get_current_session_id(uint8_t);
-time_t get_vrps_last_modified_date(void);
-
-#endif /* SRC_VRPS_H_ */
index b4d456636f32ef9eb53aaae478e9fd59d54b0ac3..c20497c3a2fdbcad7f49f4df6a6ad4b807815aa0 100644 (file)
@@ -20,12 +20,13 @@ BASIC_MODULES  = ../src/log.c ../src/log.h
 BASIC_MODULES += impersonator.c
 
 check_PROGRAMS  = address.test
+check_PROGRAMS += circular_indexer.test
 check_PROGRAMS += vcard.test
 check_PROGRAMS += line_file.test
 check_PROGRAMS += rsync.test
-check_PROGRAMS += tal.test
-check_PROGRAMS += rtr/primitive_reader.test
-check_PROGRAMS += rtr/pdu.test
+#check_PROGRAMS += tal.test
+#check_PROGRAMS += rtr/primitive_reader.test
+#check_PROGRAMS += rtr/pdu.test
 TESTS = ${check_PROGRAMS}
 
 address_test_SOURCES  = ${BASIC_MODULES}
@@ -33,6 +34,11 @@ address_test_SOURCES += ../src/address.h
 address_test_SOURCES += address_test.c
 address_test_LDADD = ${MY_LDADD}
 
+circular_indexer_test_SOURCES  = ${BASIC_MODULES}
+circular_indexer_test_SOURCES += ../src/data_structure/circular_indexer.c
+circular_indexer_test_SOURCES += data_structure/circular_indexer_test.c
+circular_indexer_test_LDADD = ${MY_LDADD}
+
 line_file_test_SOURCES  = ${BASIC_MODULES}
 line_file_test_SOURCES += ../src/file.c ../src/file.h
 line_file_test_SOURCES += ../src/line_file.c ../src/line_file.h
@@ -45,27 +51,27 @@ rsync_test_SOURCES += ../src/uri.c ../src/uri.h
 rsync_test_SOURCES += rsync_test.c
 rsync_test_LDADD = ${MY_LDADD}
 
-rtr_primitive_reader_test_SOURCES  = ${BASIC_MODULES}
-rtr_primitive_reader_test_SOURCES += rtr/primitive_reader_test.c
-rtr_primitive_reader_test_SOURCES += rtr/stream.c
-rtr_primitive_reader_test_LDADD = ${MY_LDADD}
+#rtr_primitive_reader_test_SOURCES  = ${BASIC_MODULES}
+#rtr_primitive_reader_test_SOURCES += rtr/primitive_reader_test.c
+#rtr_primitive_reader_test_SOURCES += rtr/stream.c
+#rtr_primitive_reader_test_LDADD = ${MY_LDADD}
 
-rtr_pdu_test_SOURCES  = ${BASIC_MODULES}
-rtr_pdu_test_SOURCES += rtr/pdu_test.c
-rtr_pdu_test_SOURCES += rtr/stream.c
-rtr_pdu_test_SOURCES += $(top_builddir)/src/rtr/primitive_reader.c
-rtr_pdu_test_SOURCES += $(top_builddir)/src/rtr/pdu_handler.c
-rtr_pdu_test_LDADD = ${MY_LDADD}
+#rtr_pdu_test_SOURCES  = ${BASIC_MODULES}
+#rtr_pdu_test_SOURCES += rtr/pdu_test.c
+#rtr_pdu_test_SOURCES += rtr/stream.c
+#rtr_pdu_test_SOURCES += ../src/rtr/primitive_reader.c
+#rtr_pdu_test_SOURCES += ../src/rtr/pdu_handler.c
+#rtr_pdu_test_LDADD = ${MY_LDADD}
 
-tal_test_SOURCES  = ${BASIC_MODULES}
-tal_test_SOURCES += ../src/file.c ../src/file.h
-tal_test_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h
-tal_test_SOURCES += ../src/random.c ../src/random.h
-tal_test_SOURCES += ../src/str.c ../src/str.h
-tal_test_SOURCES += ../src/uri.c ../src/uri.h
-tal_test_SOURCES += ../src/line_file.c ../src/line_file.h
-tal_test_SOURCES += tal_test.c
-tal_test_LDADD = ${MY_LDADD}
+#tal_test_SOURCES  = ${BASIC_MODULES}
+#tal_test_SOURCES += ../src/file.c ../src/file.h
+#tal_test_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h
+#tal_test_SOURCES += ../src/random.c ../src/random.h
+#tal_test_SOURCES += ../src/str.c ../src/str.h
+#tal_test_SOURCES += ../src/uri.c ../src/uri.h
+#tal_test_SOURCES += ../src/line_file.c ../src/line_file.h
+#tal_test_SOURCES += tal_test.c
+#tal_test_LDADD = ${MY_LDADD}
 
 vcard_test_SOURCES  = ${BASIC_MODULES}
 vcard_test_SOURCES += vcard_test.c
index d829b08ae027467545bb8a174fb21485a03a1215..c31e8d7c0983a41823435f5e84730f0db9dc18c2 100644 (file)
@@ -156,46 +156,15 @@ START_TEST(check_encoding6_test)
 }
 END_TEST
 
-static void
-test_get_address_from_string(char *text_prefix)
-{
-       struct ipv4_prefix prefix;
-       const char *result;
-       int error;
-       char buffer[INET_ADDRSTRLEN];
-
-       error = prefix4_decode(text_prefix, &prefix);
-       if (error)
-               return;
-
-       result = addr2str4(&prefix.addr, buffer);
-
-       ck_assert_str_eq(text_prefix, result);
-}
-
-START_TEST(address_test_get_addr)
-{
-       char *text;
-       text = "198.248.146.0";
-
-       test_get_address_from_string(text);
-
-}
-END_TEST
-
 Suite *address_load_suite(void)
 {
        Suite *suite;
        TCase *core;
-       TCase *string;
 
        core = tcase_create("Core");
        tcase_add_test(core, check_encoding4_test);
        tcase_add_test(core, check_encoding6_test);
 
-       string = tcase_create("Strings");
-       tcase_add_test(string, address_test_get_addr);
-
        suite = suite_create("Encoding checking");
        suite_add_tcase(suite, core);
        return suite;
diff --git a/test/data_structure/circular_indexer_test.c b/test/data_structure/circular_indexer_test.c
new file mode 100644 (file)
index 0000000..6ad87d8
--- /dev/null
@@ -0,0 +1,383 @@
+#include "data_structure/circular_indexer.h"
+
+#include <check.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * These are macros so CHECK will be able to report proper lines on errors.
+ * Functions would ruin that.
+ */
+
+static array_index *tmp;
+#define assert_index(expected, actual)                                 \
+       tmp = actual;                                                   \
+       ck_assert_ptr_ne(NULL, tmp);                                    \
+       ck_assert_int_eq(expected, *tmp);
+
+#define assert_next_is_null(indexer)                                   \
+       /* Twice, to make sure it stays consistent. */                  \
+       ck_assert_ptr_eq(NULL, arridx_next(indexer));                   \
+       ck_assert_ptr_eq(NULL, arridx_next(indexer));
+
+#define assert_first_is_null(indexer)                                  \
+       ck_assert_ptr_eq(NULL, arridx_first(indexer));                  \
+       ck_assert_ptr_eq(NULL, arridx_first(indexer));
+
+START_TEST(no_removes)
+{
+       struct circular_indexer indexer;
+
+       arridx_init(&indexer, 4);
+
+       /* Full traversal from 0 */
+       assert_index(0, arridx_first(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       assert_index(0, arridx_first(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_index(2, arridx_next(&indexer));
+
+       /* Full traversal from 3 */
+       assert_index(3, arridx_first(&indexer));
+       assert_index(0, arridx_next(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       assert_index(3, arridx_first(&indexer));
+       assert_index(0, arridx_next(&indexer));
+       assert_index(1, arridx_next(&indexer));
+
+       /* Full traversal from 2 */
+       assert_index(2, arridx_first(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_index(0, arridx_next(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       assert_index(2, arridx_first(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_index(0, arridx_next(&indexer));
+
+       /* Full traversal from 1 */
+       assert_index(1, arridx_first(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_index(0, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       ck_assert_ptr_eq(NULL, indexer.indexes);
+       arridx_cleanup(&indexer);
+}
+END_TEST
+
+static void
+test_traversal_with_removal(array_index *(*traverser)(struct circular_indexer *))
+{
+       struct circular_indexer indexer;
+
+       arridx_init(&indexer, 5);
+
+       assert_index(0, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(1, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(2, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(3, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(4, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+
+       assert_next_is_null(&indexer);
+       assert_first_is_null(&indexer);
+       assert_next_is_null(&indexer);
+
+       ck_assert_ptr_eq(NULL, indexer.indexes);
+       arridx_cleanup(&indexer);
+}
+
+START_TEST(always_remove_first)
+{
+       test_traversal_with_removal(arridx_first);
+}
+END_TEST
+
+START_TEST(always_remove_next)
+{
+       test_traversal_with_removal(arridx_next);
+}
+END_TEST
+
+START_TEST(remove_only_top)
+{
+       /* This one is also unnecessary. */
+
+       struct circular_indexer indexer;
+
+       arridx_init(&indexer, 5);
+
+       /* 0 1 2 3 4 */
+       assert_index(0, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_index(4, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 2 3 4 (just make sure the indexer was left in a consistent state) */
+       assert_index(2, arridx_first(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_index(4, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 2 3 4 */
+       assert_index(2, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_index(4, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 3 4 */
+       assert_index(3, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(4, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 4 */
+       assert_index(4, arridx_first(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 4 */
+       assert_index(4, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* */
+       assert_first_is_null(&indexer);
+       assert_next_is_null(&indexer);
+
+       ck_assert_ptr_eq(NULL, indexer.indexes);
+       arridx_cleanup(&indexer);
+}
+END_TEST
+
+START_TEST(remove_top_mid_iteration)
+{
+       struct circular_indexer indexer;
+
+       arridx_init(&indexer, 4);
+
+       /* 0 1 2 3 */
+       assert_index(0, arridx_first(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_index(2, arridx_next(&indexer));
+
+       /* 3 0 1 2 */
+       assert_index(3, arridx_first(&indexer));
+       assert_index(0, arridx_next(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 3 1 2 */
+       assert_index(3, arridx_first(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* 3 */
+       assert_index(3, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* */
+       assert_first_is_null(&indexer);
+       assert_next_is_null(&indexer);
+
+       ck_assert_ptr_eq(NULL, indexer.indexes);
+       arridx_cleanup(&indexer);
+}
+END_TEST
+
+static void
+traverse_mallocd_indexer_easy(array_index *(*traverser)(struct circular_indexer *))
+{
+       struct circular_indexer indexer;
+
+       arridx_init(&indexer, 4);
+
+       /* (This iteration is mostly just intended to prepare the array) */
+       /* 0 1 2 3 */
+       assert_index(0, arridx_first(&indexer));
+       assert_index(1, arridx_next(&indexer));
+
+       ck_assert_ptr_eq(NULL, indexer.indexes);
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       ck_assert_ptr_ne(NULL, indexer.indexes);
+
+       assert_index(2, arridx_next(&indexer));
+       assert_index(3, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* (This is the actual test) */
+       /* 0 2 3 */
+       assert_index(0, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(2, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(3, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* */
+       assert_first_is_null(&indexer);
+       assert_next_is_null(&indexer);
+
+       arridx_cleanup(&indexer);
+}
+
+START_TEST(malloc_always_remove_first_simple)
+{
+       traverse_mallocd_indexer_easy(arridx_first);
+}
+END_TEST
+
+START_TEST(malloc_always_remove_next_simple)
+{
+       traverse_mallocd_indexer_easy(arridx_next);
+}
+END_TEST
+
+/*
+ * This is the same as traverse_mallocd_indexer(), except it has the first, last
+ * and two contiguous elements pre-removed, cuz that's trickier.
+ */
+static void
+traverse_mallocd_indexer_hard(array_index *(*traverser)(struct circular_indexer *))
+{
+       struct circular_indexer indexer;
+
+       arridx_init(&indexer, 8);
+
+       /* -- Prepare the array -- */
+       /*
+        * Despite being initialization, this actually manhandles the indexer
+        * quite a bit, which is good.
+        */
+       /* 0 1 2 3 4 5 6 7 */
+       assert_index(0, arridx_first(&indexer));
+       assert_index(1, arridx_next(&indexer));
+       assert_index(2, arridx_next(&indexer));
+
+       assert_index(3, arridx_next(&indexer));
+       ck_assert_ptr_eq(NULL, indexer.indexes);
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       ck_assert_ptr_ne(NULL, indexer.indexes);
+
+       assert_index(4, arridx_next(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+
+       assert_index(5, arridx_next(&indexer));
+       assert_index(6, arridx_next(&indexer));
+
+       assert_index(7, arridx_next(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+
+       assert_next_is_null(&indexer);
+
+       /* 0 1 2 5 6 */
+       assert_index(0, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+
+       /* -- Actual test -- */
+       /* Let's do an innocent traversal first, just for shits and giggles. */
+       /* 1 2 5 6 */
+       assert_index(1, arridx_first(&indexer));
+       assert_index(2, arridx_next(&indexer));
+       assert_index(5, arridx_next(&indexer));
+       assert_index(6, arridx_next(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* Ok, begin. */
+       /* 1 2 5 6 */
+       assert_index(1, arridx_first(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(2, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(5, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_index(6, traverser(&indexer));
+       ck_assert_int_eq(0, arridx_remove(&indexer));
+       assert_next_is_null(&indexer);
+
+       /* */
+       assert_first_is_null(&indexer);
+       assert_next_is_null(&indexer);
+
+       arridx_cleanup(&indexer);
+}
+
+START_TEST(malloc_always_remove_first_complex)
+{
+       traverse_mallocd_indexer_hard(arridx_first);
+}
+END_TEST
+
+START_TEST(malloc_always_remove_next_complex)
+{
+       traverse_mallocd_indexer_hard(arridx_next);
+}
+END_TEST
+
+Suite *address_load_suite(void)
+{
+       Suite *suite;
+       TCase *malloc_no;
+       TCase *malloc_yes;
+
+       /* Tests in which the indexer.indexes array is not allocated. */
+       malloc_no = tcase_create("No malloc tests");
+       tcase_add_test(malloc_no, no_removes);
+       tcase_add_test(malloc_no, always_remove_first);
+       tcase_add_test(malloc_no, always_remove_next);
+       tcase_add_test(malloc_no, remove_only_top);
+       tcase_add_test(malloc_no, remove_top_mid_iteration);
+
+       /* Tests that involve the indexer.indexes array. */
+       malloc_yes = tcase_create("malloc tests");
+       tcase_add_test(malloc_yes, malloc_always_remove_first_simple);
+       tcase_add_test(malloc_yes, malloc_always_remove_next_simple);
+       tcase_add_test(malloc_yes, malloc_always_remove_first_complex);
+       tcase_add_test(malloc_yes, malloc_always_remove_next_complex);
+
+       suite = suite_create("Circular indexer");
+       suite_add_tcase(suite, malloc_no);
+       suite_add_tcase(suite, malloc_yes);
+       return suite;
+}
+
+int main(void)
+{
+       Suite *suite;
+       SRunner *runner;
+       int tests_failed;
+
+       suite = address_load_suite();
+
+       runner = srunner_create(suite);
+       srunner_run_all(runner, CK_NORMAL);
+       tests_failed = srunner_ntests_failed(runner);
+       srunner_free(runner);
+
+       return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index d7c7c1d65d05ec9fe7f202ff77de14b69c6c8e92..41cbbc2172b892c72d72832a92e21227d1b4b076 100644 (file)
@@ -64,7 +64,7 @@ config_get_rsync_program(void)
 }
 
 struct string_array const *
-config_get_rsync_args(void)
+config_get_rsync_args(bool is_ta)
 {
        static const struct string_array array = { 0 };
        return &array;
index 305db91d3df20dd77785ceeef82f4d26bdfa6606..1e4e11b886929834c6d5f246e30aedad854c6275 100644 (file)
@@ -26,7 +26,7 @@ init_pdu_header(struct pdu_header *header)
 {
        header->protocol_version = 0;
        header->pdu_type = 22;
-       header->reserved = 12345;
+       header->m.reserved = 12345;
        header->length = 0xFFAA9955;
 }
 
@@ -35,7 +35,7 @@ assert_pdu_header(struct pdu_header *header)
 {
        ck_assert_uint_eq(header->protocol_version, 0);
        ck_assert_uint_eq(header->pdu_type, 22);
-       ck_assert_uint_eq(header->reserved, 12345);
+       ck_assert_uint_eq(header->m.reserved, 12345);
        ck_assert_uint_eq(header->length, 0xFFAA9955);
 }
 
@@ -54,7 +54,7 @@ START_TEST(test_pdu_header_from_stream)
 
        ck_assert_uint_eq(header.protocol_version, 0);
        ck_assert_uint_eq(header.pdu_type, 1);
-       ck_assert_uint_eq(header.reserved, 0x0203);
+       ck_assert_uint_eq(header.m.reserved, 0x0203);
        ck_assert_uint_eq(header.length, 0x04050607);
 }
 END_TEST
@@ -178,7 +178,7 @@ START_TEST(test_error_report_from_stream)
        sub_pdu = pdu->erroneous_pdu;
        ck_assert_uint_eq(sub_pdu->header.protocol_version, 1);
        ck_assert_uint_eq(sub_pdu->header.pdu_type, 0);
-       ck_assert_uint_eq(sub_pdu->header.reserved, 0x0203);
+       ck_assert_uint_eq(sub_pdu->header.m.reserved, 0x0203);
        ck_assert_uint_eq(sub_pdu->header.length, 12);
        ck_assert_uint_eq(sub_pdu->serial_number, 0x01020304);
        ck_assert_str_eq(pdu->error_message, "hello");
index 84f3212df840e221f0383ef8af2dda9b2852cf46..a3fc2c8fd7f6cfcac044da846bf29153b1f4dea0 100644 (file)
@@ -3,9 +3,7 @@
 
 #include <stddef.h>
 
-__BEGIN_DECLS
 int write_exact(int, unsigned char *, size_t);
 int buffer2fd(unsigned char *, size_t);
-__END_DECLS
 
 #endif /* TEST_RTR_STREAM_H_ */