X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Flibloc.git;a=blobdiff_plain;f=src%2Fdatabase.c;h=9c07590f6cd3e10146e98848bfdc0375c51d8482;hp=85e3912fc0c4d37c4bec76992f342a97204485e6;hb=3f35869aa908b35b296e2694b4f8bf7db8729f6a;hpb=2601e83eca9f5d8447186256c642aef25441f07e diff --git a/src/database.c b/src/database.c index 85e3912..9c07590 100644 --- a/src/database.c +++ b/src/database.c @@ -22,10 +22,13 @@ #include #include #include +#include #include +#include #include "libloc-private.h" +#include "as.h" #include "database.h" #include "stringpool.h" @@ -33,33 +36,16 @@ struct loc_database { struct loc_ctx* ctx; int refcount; + FILE* file; unsigned int version; off_t vendor; off_t description; - struct loc_stringpool* pool; -}; - -const char* LOC_DATABASE_MAGIC = "LOCDBXX"; -unsigned int LOC_DATABASE_VERSION = 0; - -struct loc_database_magic { - char magic[7]; - - // Database version information - uint8_t version; -}; - -struct loc_database_header_v0 { - // Vendor who created the database - uint32_t vendor; - - // Description of the database - uint32_t description; + // ASes in the database + struct loc_as** as; + size_t as_count; - // Tells us where the pool starts - uint32_t pool_offset; - uint32_t pool_length; + struct loc_stringpool* pool; }; LOC_EXPORT int loc_database_new(struct loc_ctx* ctx, struct loc_database** database, size_t pool_size) { @@ -102,8 +88,20 @@ 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); + // Close file + if (db->file) + fclose(db->file); + loc_unref(db->ctx); free(db); } @@ -144,11 +142,67 @@ LOC_EXPORT int loc_database_set_description(struct loc_database* db, const char* return 0; } -static int loc_database_read_magic(struct loc_database* db, FILE* f) { +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) { struct loc_database_magic magic; // Read from file - size_t bytes_read = fread(&magic, 1, sizeof(magic), f); + size_t bytes_read = fread(&magic, 1, sizeof(magic), db->file); // Check if we have been able to read enough data if (bytes_read < sizeof(magic)) { @@ -174,11 +228,45 @@ static int loc_database_read_magic(struct loc_database* db, FILE* f) { return 1; } -static int loc_database_read_header_v0(struct loc_database* db, FILE* f) { +static int loc_database_read_as_section_v0(struct loc_database* db, + off_t as_offset, size_t as_length) { + struct loc_database_as_v0 dbobj; + + // Read from the start of the section + int r = fseek(db->file, 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), db->file); + 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) { struct loc_database_header_v0 header; // Read from file - size_t size = fread(&header, 1, sizeof(header), f); + size_t size = fread(&header, 1, sizeof(header), db->file); if (size < sizeof(header)) { ERROR(db->ctx, "Could not read enough data for header\n"); @@ -193,17 +281,25 @@ static int loc_database_read_header_v0(struct loc_database* db, FILE* f) { off_t pool_offset = ntohl(header.pool_offset); size_t pool_length = ntohl(header.pool_length); - int r = loc_stringpool_read(db->pool, f, pool_offset, pool_length); + int r = loc_stringpool_read(db->pool, db->file, pool_offset, pool_length); + 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); if (r) return r; return 0; } -static int loc_database_read_header(struct loc_database* db, FILE* f) { +static int loc_database_read_header(struct loc_database* db) { switch (db->version) { case 0: - return loc_database_read_header_v0(db, f); + return loc_database_read_header_v0(db); default: ERROR(db->ctx, "Incompatible database version: %u\n", db->version); @@ -212,17 +308,29 @@ static int loc_database_read_header(struct loc_database* db, FILE* f) { } LOC_EXPORT int loc_database_read(struct loc_database* db, FILE* f) { - int r = fseek(f, 0, SEEK_SET); + // Copy the file pointer and work on that so we don't care if + // the calling function closes the file + int fd = fileno(f); + + // Make a copy + fd = dup(fd); + + // Retrieve a file pointer + db->file = fdopen(fd, "r"); + if (!db->file) + return -errno; + + int r = fseek(db->file, 0, SEEK_SET); if (r) return r; // Read magic bytes - r = loc_database_read_magic(db, f); + r = loc_database_read_magic(db); if (r) return r; // Read the header - r = loc_database_read_header(db, f); + r = loc_database_read_header(db); if (r) return r; @@ -266,6 +374,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);