Introduce object to store an AS
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 12 Dec 2017 11:40:47 +0000 (11:40 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 12 Dec 2017 11:40:47 +0000 (11:40 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
configure.ac
src/.gitignore
src/as.c [new file with mode: 0644]
src/as.h [new file with mode: 0644]
src/database.c
src/database.h
src/libloc.sym
src/loc/format.h [new file with mode: 0644]
src/stringpool.h
src/test-as.c [new file with mode: 0644]

index a47cdae..6f4875d 100644 (file)
@@ -36,6 +36,7 @@ pkgconfigdir = $(libdir)/pkgconfig
        $(SED_PROCESS)
 
 pkginclude_HEADERS = \
+       src/loc/format.h \
        src/loc/libloc.h
 
 lib_LTLIBRARIES = \
@@ -44,6 +45,8 @@ lib_LTLIBRARIES = \
 src_libloc_la_SOURCES =\
        src/libloc-private.h \
        src/libloc.c \
+       src/as.c \
+       src/as.h \
        src/database.c \
        src/database.h \
        src/stringpool.c \
@@ -71,12 +74,14 @@ CLEANFILES += \
 TESTS = \
        src/test-libloc \
        src/test-stringpool \
-       src/test-database
+       src/test-database \
+       src/test-as
 
 check_PROGRAMS = \
        src/test-libloc \
        src/test-stringpool \
-       src/test-database
+       src/test-database \
+       src/test-as
 
 src_test_libloc_SOURCES = \
        src/test-libloc.c
@@ -84,6 +89,12 @@ src_test_libloc_SOURCES = \
 src_test_libloc_LDADD = \
        src/libloc.la
 
+src_test_as_SOURCES = \
+       src/test-as.c
+
+src_test_as_LDADD = \
+       src/libloc.la
+
 src_test_stringpool_SOURCES = \
        src/test-stringpool.c
 
index 0c9b22a..ace67d3 100644 (file)
@@ -41,7 +41,8 @@ AS_IF([test "x$enable_debug" = "xyes"], [
 
 AC_CHECK_FUNCS([ \
        __secure_getenv \
-       secure_getenv\
+       secure_getenv \
+        qsort \
 ])
 
 my_CFLAGS="\
index 15e9181..8c2a12c 100644 (file)
@@ -5,6 +5,7 @@
 *.lo
 *.trs
 libloc.pc
+test-as
 test-libloc
 test-database
 test-stringpool
diff --git a/src/as.c b/src/as.c
new file mode 100644 (file)
index 0000000..654ab26
--- /dev/null
+++ b/src/as.c
@@ -0,0 +1,126 @@
+/*
+       libloc - A library to determine the location of someone on the Internet
+
+       Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+*/
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <loc/libloc.h>
+#include <loc/format.h>
+
+#include "libloc-private.h"
+#include "as.h"
+#include "stringpool.h"
+
+struct loc_as {
+       struct loc_ctx* ctx;
+       int refcount;
+
+       struct loc_stringpool* pool;
+
+       uint32_t number;
+       off_t name;
+};
+
+LOC_EXPORT int loc_as_new(struct loc_ctx* ctx, struct loc_stringpool* pool, struct loc_as** as, uint32_t number) {
+       struct loc_as* a = calloc(1, sizeof(*a));
+       if (!a)
+               return -ENOMEM;
+
+       a->ctx = loc_ref(ctx);
+       a->refcount = 1;
+       a->pool = loc_stringpool_ref(pool);
+
+       a->number = number;
+
+       DEBUG(a->ctx, "AS%u allocated at %p\n", a->number, a);
+       *as = a;
+
+       return 0;
+}
+
+LOC_EXPORT struct loc_as* loc_as_ref(struct loc_as* as) {
+       as->refcount++;
+
+       return as;
+}
+
+static void loc_as_free(struct loc_as* as) {
+       DEBUG(as->ctx, "Releasing AS%u %p\n", as->number, as);
+
+       loc_stringpool_unref(as->pool);
+       loc_unref(as->ctx);
+
+       free(as);
+}
+
+LOC_EXPORT struct loc_as* loc_as_unref(struct loc_as* as) {
+       if (--as->refcount > 0)
+               return NULL;
+
+       loc_as_free(as);
+
+       return NULL;
+}
+
+LOC_EXPORT uint32_t loc_as_get_number(struct loc_as* as) {
+       return as->number;
+}
+
+LOC_EXPORT const char* loc_as_get_name(struct loc_as* as) {
+       return loc_stringpool_get(as->pool, as->name);
+}
+
+LOC_EXPORT int loc_as_set_name(struct loc_as* as, const char* name) {
+       // Add the string to the string pool
+       off_t offset = loc_stringpool_add(as->pool, name);
+       if (offset < 0)
+               return offset;
+
+       as->name = offset;
+       return 0;
+}
+
+LOC_EXPORT int loc_as_cmp(struct loc_as* as1, struct loc_as* as2) {
+       if (as1->number > as2->number)
+               return 1;
+
+       if (as1->number < as2->number)
+               return -1;
+
+       return 0;
+}
+
+int loc_as_new_from_database_v0(struct loc_ctx* ctx, struct loc_stringpool* pool,
+               struct loc_as** as, const struct loc_database_as_v0* dbobj) {
+       uint32_t number = ntohl(dbobj->number);
+
+       int r = loc_as_new(ctx, pool, as, number);
+       if (r)
+               return r;
+
+       (*as)->name = ntohl(dbobj->name);
+
+       return 0;
+}
+
+int loc_as_to_database_v0(struct loc_as* as, struct loc_database_as_v0* dbobj) {
+       dbobj->number = htonl(as->number);
+       dbobj->name   = htonl(as->name);
+
+       return 0;
+}
diff --git a/src/as.h b/src/as.h
new file mode 100644 (file)
index 0000000..1aefe30
--- /dev/null
+++ b/src/as.h
@@ -0,0 +1,43 @@
+/*
+       libloc - A library to determine the location of someone on the Internet
+
+       Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+*/
+
+#ifndef LIBLOC_AS_H
+#define LIBLOC_AS_H
+
+#include <stdint.h>
+
+#include <loc/libloc.h>
+#include <loc/format.h>
+
+#include "stringpool.h"
+
+struct loc_as;
+int loc_as_new(struct loc_ctx* ctx, struct loc_stringpool* pool, struct loc_as** as, uint32_t number);
+struct loc_as* loc_as_ref(struct loc_as* as);
+struct loc_as* loc_as_unref(struct loc_as* as);
+
+uint32_t loc_as_get_number(struct loc_as* as);
+
+const char* loc_as_get_name(struct loc_as* as);
+int loc_as_set_name(struct loc_as* as, const char* name);
+
+int loc_as_cmp(struct loc_as* as1, struct loc_as* as2);
+
+int loc_as_new_from_database_v0(struct loc_ctx* ctx, struct loc_stringpool* pool,
+               struct loc_as** as, const struct loc_database_as_v0* dbobj);
+int loc_as_to_database_v0(struct loc_as* as, struct loc_database_as_v0* dbobj);
+
+#endif
index 85e3912..e81ea44 100644 (file)
 #include <sys/types.h>
 
 #include <loc/libloc.h>
+#include <loc/format.h>
 
 #include "libloc-private.h"
+#include "as.h"
 #include "database.h"
 #include "stringpool.h"
 
@@ -37,6 +39,10 @@ struct loc_database {
        off_t vendor;
        off_t description;
 
+       // ASes in the database
+       struct loc_as** as;
+       size_t as_count;
+
        struct loc_stringpool* pool;
 };
 
@@ -50,18 +56,6 @@ struct loc_database_magic {
        uint8_t version;
 };
 
-struct loc_database_header_v0 {
-       // Vendor who created the database
-       uint32_t vendor;
-
-       // Description of the database
-       uint32_t description;
-
-       // Tells us where the pool starts
-       uint32_t pool_offset;
-       uint32_t pool_length;
-};
-
 LOC_EXPORT int loc_database_new(struct loc_ctx* ctx, struct loc_database** database, size_t pool_size) {
        struct loc_database* db = calloc(1, sizeof(*db));
        if (!db)
@@ -102,6 +96,14 @@ LOC_EXPORT struct loc_database* loc_database_ref(struct loc_database* db) {
 static void loc_database_free(struct loc_database* db) {
        DEBUG(db->ctx, "Releasing database %p\n", db);
 
+       // Remove references to all ASes
+       if (db->as) {
+               for (unsigned int i = 0; i < db->as_count; i++) {
+                       loc_as_unref(db->as[i]);
+               }
+               free(db->as);
+       }
+
        loc_stringpool_unref(db->pool);
 
        loc_unref(db->ctx);
@@ -144,6 +146,62 @@ LOC_EXPORT int loc_database_set_description(struct loc_database* db, const char*
        return 0;
 }
 
+LOC_EXPORT size_t loc_database_count_as(struct loc_database* db) {
+       return db->as_count;
+}
+
+static int loc_database_has_as(struct loc_database* db, struct loc_as* as) {
+       for (unsigned int i = 0; i < db->as_count; i++) {
+               if (loc_as_cmp(as, db->as[i]) == 0)
+                       return i;
+       }
+
+       return -1;
+}
+
+static int __loc_as_cmp(const void* as1, const void* as2) {
+       return loc_as_cmp(*(struct loc_as**)as1, *(struct loc_as**)as2);
+}
+
+static void loc_database_sort_ases(struct loc_database* db) {
+       qsort(db->as, db->as_count, sizeof(*db->as), __loc_as_cmp);
+}
+
+static struct loc_as* __loc_database_add_as(struct loc_database* db, struct loc_as* as) {
+       // Check if AS exists already
+       int i = loc_database_has_as(db, as);
+       if (i >= 0) {
+               loc_as_unref(as);
+
+               // Select already existing AS
+               as = db->as[i];
+
+               return loc_as_ref(as);
+       }
+
+       db->as_count++;
+
+       // Make space for the new entry
+       db->as = realloc(db->as, sizeof(*db->as) * db->as_count);
+
+       // Add the new entry at the end
+       db->as[db->as_count - 1] = loc_as_ref(as);
+
+       // Sort everything
+       loc_database_sort_ases(db);
+
+       return as;
+}
+
+LOC_EXPORT struct loc_as* loc_database_add_as(struct loc_database* db, uint32_t number) {
+       struct loc_as* as;
+       int r = loc_as_new(db->ctx, db->pool, &as, number);
+       if (r)
+               return NULL;
+
+       return __loc_database_add_as(db, as);
+}
+
 static int loc_database_read_magic(struct loc_database* db, FILE* f) {
        struct loc_database_magic magic;
 
@@ -174,6 +232,40 @@ static int loc_database_read_magic(struct loc_database* db, FILE* f) {
        return 1;
 }
 
+static int loc_database_read_as_section_v0(struct loc_database* db,
+               off_t as_offset, size_t as_length, FILE* f) {
+       struct loc_database_as_v0 dbobj;
+
+       // Read from the start of the section
+       int r = fseek(f, as_offset, SEEK_SET);
+       if (r)
+               return r;
+
+       // Read all ASes
+       size_t as_count = as_length / sizeof(dbobj);
+       for (unsigned int i = 0; i < as_count; i++) {
+               size_t bytes_read = fread(&dbobj, 1, sizeof(dbobj), f);
+               if (bytes_read < sizeof(dbobj)) {
+                       ERROR(db->ctx, "Could not read an AS object\n");
+                       return -ENOMSG;
+               }
+
+               // Allocate a new AS
+               struct loc_as* as;
+               r = loc_as_new_from_database_v0(db->ctx, db->pool, &as, &dbobj);
+               if (r)
+                       return r;
+
+               // Attach it to the database
+               as = __loc_database_add_as(db, as);
+               loc_as_unref(as);
+       }
+
+       INFO(db->ctx, "Read %zu ASes from the database\n", db->as_count);
+
+       return 0;
+}
+
 static int loc_database_read_header_v0(struct loc_database* db, FILE* f) {
        struct loc_database_header_v0 header;
 
@@ -197,6 +289,14 @@ static int loc_database_read_header_v0(struct loc_database* db, FILE* f) {
        if (r)
                return r;
 
+       // AS section
+       off_t as_offset  = ntohl(header.as_offset);
+       size_t as_length = ntohl(header.as_length);
+
+       r = loc_database_read_as_section_v0(db, as_offset, as_length, f);
+       if (r)
+               return r;
+
        return 0;
 }
 
@@ -266,6 +366,19 @@ LOC_EXPORT int loc_database_write(struct loc_database* db, FILE* f) {
        }
        offset += sizeof(header);
 
+       // Write all ASes
+       header.as_offset = htonl(offset);
+
+       struct loc_database_as_v0 dbas;
+       for (unsigned int i = 0; i < db->as_count; i++) {
+               // Convert AS into database format
+               loc_as_to_database_v0(db->as[i], &dbas);
+
+               // Write to disk
+               offset += fwrite(&dbas, 1, sizeof(dbas), f);
+       }
+       header.as_length = htonl(db->as_count * sizeof(dbas));
+
        // Save the offset of the pool section
        DEBUG(db->ctx, "Pool starts at %jd bytes\n", offset);
        header.pool_offset = htonl(offset);
index 72cda5a..41142ab 100644 (file)
 #define LIBLOC_DATABASE_H
 
 #include <stdio.h>
+#include <stdint.h>
 
 #include <loc/libloc.h>
 
+#include "as.h"
+
 struct loc_database;
 int loc_database_new(struct loc_ctx* ctx, struct loc_database** db, size_t pool_size);
 int loc_database_open(struct loc_ctx* ctx, struct loc_database** database, FILE* f);
@@ -32,6 +35,9 @@ int loc_database_set_vendor(struct loc_database* db, const char* vendor);
 const char* loc_database_get_description(struct loc_database* db);
 int loc_database_set_description(struct loc_database* db, const char* description);
 
+size_t loc_database_count_as(struct loc_database* db);
+struct loc_as* loc_database_add_as(struct loc_database* db, uint32_t number);
+
 int loc_database_read(struct loc_database* db, FILE* f);
 int loc_database_write(struct loc_database* db, FILE* f);
 
index 2a527f1..175c3fa 100644 (file)
@@ -1,6 +1,16 @@
 LIBLOC_PRIVATE {
 global:
+       # AS
+       loc_as_get_name;
+       loc_as_get_number;
+       loc_as_new;
+       loc_as_ref;
+       loc_as_set_name;
+       loc_as_unref;
+
        # Database
+       loc_database_add_as;
+       loc_database_count_as;
        loc_database_get_description;
        loc_database_get_vendor;
        loc_database_new;
diff --git a/src/loc/format.h b/src/loc/format.h
new file mode 100644 (file)
index 0000000..deec7f1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+       libloc - A library to determine the location of someone on the Internet
+
+       Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+*/
+
+#ifndef LIBLOC_FORMAT_H
+#define LIBLOC_FORMAT_H
+
+#include <stdint.h>
+
+struct loc_database_header_v0 {
+       // Vendor who created the database
+       uint32_t vendor;
+
+       // Description of the database
+       uint32_t description;
+
+       // Tells us where the ASes start
+       uint32_t as_offset;
+       uint32_t as_length;
+
+       // Tells us where the pool starts
+       uint32_t pool_offset;
+       uint32_t pool_length;
+};
+
+struct loc_database_as_v0 {
+       // The AS number
+       uint32_t number;
+
+       // Name
+       uint32_t name;
+};
+
+#endif
index dbe82c8..c3dffdd 100644 (file)
@@ -18,6 +18,7 @@
 #define LIBLOC_STRINGPOOL_H
 
 #include <stddef.h>
+#include <stdio.h>
 
 #include <loc/libloc.h>
 
diff --git a/src/test-as.c b/src/test-as.c
new file mode 100644 (file)
index 0000000..1e1c91e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+       libloc - A library to determine the location of someone on the Internet
+
+       Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <loc/libloc.h>
+#include "database.h"
+
+#define TEST_AS_COUNT 100
+
+int main(int argc, char** argv) {
+       int err;
+
+       struct loc_ctx* ctx;
+       err = loc_new(&ctx);
+       if (err < 0)
+               exit(EXIT_FAILURE);
+
+       // Create a database
+       struct loc_database* db;
+       err = loc_database_new(ctx, &db, 1024);
+       if (err < 0)
+               exit(EXIT_FAILURE);
+
+       char name[256];
+       for (unsigned int i = 1; i <= TEST_AS_COUNT; i++) {
+               struct loc_as* as = loc_database_add_as(db, i);
+
+               sprintf(name, "Test AS%u", i);
+               loc_as_set_name(as, name);
+
+               loc_as_unref(as);
+       }
+
+       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_database_write(db, f);
+       if (err) {
+               fprintf(stderr, "Could not write database: %s\n", strerror(-err));
+               exit(EXIT_FAILURE);
+       }
+       fclose(f);
+
+       loc_database_unref(db);
+
+       // And open it again from disk
+       f = fopen("test.db", "r");
+       if (!f) {
+               fprintf(stderr, "Could not open file for reading: %s\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       err = loc_database_open(ctx, &db, f);
+       if (err) {
+               fprintf(stderr, "Could not open database: %s\n", strerror(-err));
+               exit(EXIT_FAILURE);
+       }
+
+       size_t as_count = loc_database_count_as(db);
+       if (as_count != TEST_AS_COUNT) {
+               fprintf(stderr, "Could not read all ASes\n");
+               exit(EXIT_FAILURE);
+       }
+
+       loc_database_unref(db);
+       loc_unref(ctx);
+
+       return EXIT_SUCCESS;
+}