Write networks to the database
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 28 Dec 2017 18:07:11 +0000 (18:07 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 28 Dec 2017 18:07:11 +0000 (18:07 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/loc/format.h
src/loc/network.h
src/network.c
src/test-network.c
src/writer.c

index c4690d5..1f36aae 100644 (file)
@@ -45,17 +45,21 @@ struct loc_database_header_v0 {
        uint32_t as_offset;
        uint32_t as_length;
 
+       // Tells us where the networks start
+       uint32_t networks_offset;
+       uint32_t networks_length;
+
        // Tells us where the pool starts
        uint32_t pool_offset;
        uint32_t pool_length;
 };
 
-struct loc_database_network_v0 {
+struct loc_database_network_node_v0 {
        uint32_t zero;
        uint32_t one;
 };
 
-struct loc_database_network_node_v0 {
+struct loc_database_network_v0 {
        // The start address will be encoded in the tree
        uint8_t prefix;
 
index cb95f1a..daf97d4 100644 (file)
@@ -20,6 +20,7 @@
 #include <netinet/in.h>
 
 #include <loc/libloc.h>
+#include <loc/format.h>
 
 struct loc_network;
 int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
@@ -33,10 +34,16 @@ char* loc_network_str(struct loc_network* network);
 const char* loc_network_get_country_code(struct loc_network* network);
 int loc_network_set_country_code(struct loc_network* network, const char* country_code);
 
+int loc_network_to_database_v0(struct loc_network* network, struct loc_database_network_v0* dbobj);
+
 struct loc_network_tree;
 int loc_network_tree_new(struct loc_ctx* ctx, struct loc_network_tree** tree);
 struct loc_network_tree* loc_network_tree_unref(struct loc_network_tree* tree);
+int loc_network_tree_walk(struct loc_network_tree* tree,
+               int(*filter_callback)(struct loc_network* network, void* data),
+               int(*callback)(struct loc_network* network, void* data), void* data);
 int loc_network_tree_dump(struct loc_network_tree* tree);
 int loc_network_tree_add_network(struct loc_network_tree* tree, struct loc_network* network);
+size_t loc_network_tree_count_networks(struct loc_network_tree* tree);
 
 #endif
index bf11f2a..bc359f6 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <arpa/inet.h>
 #include <assert.h>
+#include <endian.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -168,6 +169,24 @@ LOC_EXPORT int loc_network_set_country_code(struct loc_network* network, const c
        return 0;
 }
 
+LOC_EXPORT int loc_network_to_database_v0(struct loc_network* network, struct loc_database_network_v0* dbobj) {
+       dbobj->prefix = htobe16(network->prefix);
+
+       // Add country code
+       for (unsigned int i = 0; i < 2; i++) {
+               dbobj->country_code[i] = network->country_code ? network->country_code[i] : '\0';
+       }
+
+       // Add ASN
+       uint32_t asn = 0;
+       if (network->as) {
+               asn = loc_as_get_number(network->as);
+       }
+       dbobj->asn = htobe32(asn);
+
+       return 0;
+}
+
 struct loc_network_tree {
        struct loc_ctx* ctx;
        int refcount;
@@ -239,13 +258,14 @@ static struct loc_network_tree_node* loc_network_tree_get_path(struct loc_networ
 }
 
 static int __loc_network_tree_walk(struct loc_ctx* ctx, struct loc_network_tree_node* node,
-               int(*filter_callback)(struct loc_network* network), int(*callback)(struct loc_network* network)) {
+               int(*filter_callback)(struct loc_network* network, void* data),
+               int(*callback)(struct loc_network* network, void* data), void* data) {
        int r;
 
        // Finding a network ends the walk here
        if (node->network) {
                if (filter_callback) {
-                       int f = filter_callback(node->network);
+                       int f = filter_callback(node->network, data);
                        if (f < 0)
                                return f;
 
@@ -254,21 +274,21 @@ static int __loc_network_tree_walk(struct loc_ctx* ctx, struct loc_network_tree_
                                return 0;
                }
 
-               r = callback(node->network);
+               r = callback(node->network, data);
                if (r)
                        return r;
        }
 
        // Walk down on the left side of the tree first
        if (node->zero) {
-               r = __loc_network_tree_walk(ctx, node->zero, filter_callback, callback);
+               r = __loc_network_tree_walk(ctx, node->zero, filter_callback, callback, data);
                if (r)
                        return r;
        }
 
        // Then walk on the other side
        if (node->one) {
-               r = __loc_network_tree_walk(ctx, node->one, filter_callback, callback);
+               r = __loc_network_tree_walk(ctx, node->one, filter_callback, callback, data);
                if (r)
                        return r;
        }
@@ -276,6 +296,12 @@ static int __loc_network_tree_walk(struct loc_ctx* ctx, struct loc_network_tree_
        return 0;
 }
 
+LOC_EXPORT int loc_network_tree_walk(struct loc_network_tree* tree,
+               int(*filter_callback)(struct loc_network* network, void* data),
+               int(*callback)(struct loc_network* network, void* data), void* data) {
+       return __loc_network_tree_walk(tree->ctx, tree->root, filter_callback, callback, data);
+}
+
 static void loc_network_tree_free_subtree(struct loc_network_tree_node* node) {
        if (node->network)
                loc_network_unref(node->network);
@@ -306,7 +332,7 @@ LOC_EXPORT struct loc_network_tree* loc_network_tree_unref(struct loc_network_tr
        return NULL;
 }
 
-int __loc_network_tree_dump(struct loc_network* network) {
+int __loc_network_tree_dump(struct loc_network* network, void* data) {
        DEBUG(network->ctx, "Dumping network at %p\n", network);
 
        char* s = loc_network_str(network);
@@ -322,7 +348,7 @@ int __loc_network_tree_dump(struct loc_network* network) {
 LOC_EXPORT int loc_network_tree_dump(struct loc_network_tree* tree) {
        DEBUG(tree->ctx, "Dumping network tree at %p\n", tree);
 
-       return __loc_network_tree_walk(tree->ctx, tree->root, NULL, __loc_network_tree_dump);
+       return loc_network_tree_walk(tree, NULL, __loc_network_tree_dump, NULL);
 }
 
 LOC_EXPORT int loc_network_tree_add_network(struct loc_network_tree* tree, struct loc_network* network) {
@@ -345,3 +371,22 @@ LOC_EXPORT int loc_network_tree_add_network(struct loc_network_tree* tree, struc
 
        return 0;
 }
+
+static int __loc_network_tree_count(struct loc_network* network, void* data) {
+       size_t* counter = (size_t*)data;
+
+       // Increase the counter for each network
+       counter++;
+
+       return 0;
+}
+
+LOC_EXPORT size_t loc_network_tree_count_networks(struct loc_network_tree* tree) {
+       size_t counter = 0;
+
+       int r = loc_network_tree_walk(tree, NULL, __loc_network_tree_count, &counter);
+       if (r)
+               return r;
+
+       return counter;
+}
index b64c004..b309d45 100644 (file)
@@ -14,6 +14,7 @@
        GNU General Public License for more details.
 */
 
+#include <errno.h>
 #include <stdio.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -21,6 +22,7 @@
 
 #include <loc/libloc.h>
 #include <loc/network.h>
+#include <loc/writer.h>
 
 int main(int argc, char** argv) {
        int err;
@@ -65,6 +67,37 @@ int main(int argc, char** argv) {
                exit(EXIT_FAILURE);
        }
 
+       // Create a database
+       struct loc_writer* writer;
+       err = loc_writer_new(ctx, &writer);
+       if (err < 0)
+               exit(EXIT_FAILURE);
+
+       struct loc_network* network2;
+       err = loc_writer_add_network(writer, &network2, "2001:db8:1::/48");
+       if (err) {
+               fprintf(stderr, "Could not add network\n");
+               exit(EXIT_FAILURE);
+       }
+
+       // Set country code
+       loc_network_set_country_code(network2, "XX");
+
+       FILE* f = fopen("test.db", "w");
+       if (!f) {
+               fprintf(stderr, "Could not open file for writing: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       err = loc_writer_write(writer, f);
+       if (err) {
+               fprintf(stderr, "Could not write database: %s\n", strerror(-err));
+               exit(EXIT_FAILURE);
+       }
+       fclose(f);
+
+       loc_writer_unref(writer);
+
        loc_network_unref(network1);
        loc_network_tree_unref(tree);
        loc_unref(ctx);
index 1e3e360..4c9bcf6 100644 (file)
@@ -221,6 +221,38 @@ static int loc_database_write_as_section(struct loc_writer* writer,
        return 0;
 }
 
+static int loc_database_write_network_section(struct loc_network* network, void* data) {
+       FILE* f = (FILE*)data;
+
+       struct loc_database_network_v0 n;
+
+       int r = loc_network_to_database_v0(network, &n);
+       if (r)
+               return r;
+
+       fwrite(&n, 1, sizeof(n), f);
+
+       return 0;
+}
+
+static int loc_database_write_networks_section(struct loc_writer* writer,
+               struct loc_database_header_v0* header, off_t* offset, FILE* f) {
+       DEBUG(writer->ctx, "Networks section starts at %jd bytes\n", *offset);
+       header->networks_offset = htobe32(*offset);
+
+       size_t networks_length = sizeof(struct loc_database_network_v0)
+               * loc_network_tree_count_networks(writer->networks);
+       offset += networks_length;
+
+       int r = loc_network_tree_walk(writer->networks, NULL, loc_database_write_network_section, f);
+       if (r)
+               return r;
+
+       header->networks_length = htobe32(networks_length);
+
+       return 0;
+}
+
 LOC_EXPORT int loc_writer_write(struct loc_writer* writer, FILE* f) {
        struct loc_database_magic magic;
        make_magic(writer, &magic);
@@ -261,6 +293,13 @@ LOC_EXPORT int loc_writer_write(struct loc_writer* writer, FILE* f) {
 
        align_page_boundary(&offset, f);
 
+       // Write all networks
+       r = loc_database_write_networks_section(writer, &header, &offset, f);
+       if (r)
+               return r;
+
+       align_page_boundary(&offset, f);
+
        // Write pool
        r = loc_database_write_pool(writer, &header, &offset, f);
        if (r)