2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
24 #include <loc/format.h>
25 #include <loc/network.h>
26 #include <loc/writer.h>
28 #include "libloc-private.h"
35 struct loc_stringpool
* pool
;
42 struct loc_network_tree
* networks
;
45 LOC_EXPORT
int loc_writer_new(struct loc_ctx
* ctx
, struct loc_writer
** writer
) {
46 struct loc_writer
* w
= calloc(1, sizeof(*w
));
50 w
->ctx
= loc_ref(ctx
);
53 int r
= loc_stringpool_new(ctx
, &w
->pool
);
59 // Initialize the network tree
60 r
= loc_network_tree_new(ctx
, &w
->networks
);
70 LOC_EXPORT
struct loc_writer
* loc_writer_ref(struct loc_writer
* writer
) {
76 static void loc_writer_free(struct loc_writer
* writer
) {
77 DEBUG(writer
->ctx
, "Releasing writer at %p\n", writer
);
80 for (unsigned int i
= 0; i
< writer
->as_count
; i
++) {
81 loc_as_unref(writer
->as
[i
]);
84 // Release network tree
86 loc_network_tree_unref(writer
->networks
);
88 // Unref the string pool
89 loc_stringpool_unref(writer
->pool
);
91 loc_unref(writer
->ctx
);
95 LOC_EXPORT
struct loc_writer
* loc_writer_unref(struct loc_writer
* writer
) {
96 if (--writer
->refcount
> 0)
99 loc_writer_free(writer
);
104 LOC_EXPORT
const char* loc_writer_get_vendor(struct loc_writer
* writer
) {
105 return loc_stringpool_get(writer
->pool
, writer
->vendor
);
108 LOC_EXPORT
int loc_writer_set_vendor(struct loc_writer
* writer
, const char* vendor
) {
109 // Add the string to the string pool
110 off_t offset
= loc_stringpool_add(writer
->pool
, vendor
);
114 writer
->vendor
= offset
;
118 LOC_EXPORT
const char* loc_writer_get_description(struct loc_writer
* writer
) {
119 return loc_stringpool_get(writer
->pool
, writer
->description
);
122 LOC_EXPORT
int loc_writer_set_description(struct loc_writer
* writer
, const char* description
) {
123 // Add the string to the string pool
124 off_t offset
= loc_stringpool_add(writer
->pool
, description
);
128 writer
->description
= offset
;
132 static int __loc_as_cmp(const void* as1
, const void* as2
) {
133 return loc_as_cmp(*(struct loc_as
**)as1
, *(struct loc_as
**)as2
);
136 LOC_EXPORT
int loc_writer_add_as(struct loc_writer
* writer
, struct loc_as
** as
, uint32_t number
) {
137 int r
= loc_as_new(writer
->ctx
, writer
->pool
, as
, number
);
141 // We have a new AS to add
145 writer
->as
= realloc(writer
->as
, sizeof(*writer
->as
) * writer
->as_count
);
149 // Add as last element
150 writer
->as
[writer
->as_count
- 1] = loc_as_ref(*as
);
153 qsort(writer
->as
, writer
->as_count
, sizeof(*writer
->as
), __loc_as_cmp
);
158 LOC_EXPORT
int loc_writer_add_network(struct loc_writer
* writer
, struct loc_network
** network
, const char* string
) {
161 // Create a new network object
162 r
= loc_network_new_from_string(writer
->ctx
, network
, string
);
166 // Add it to the local tree
167 return loc_network_tree_add_network(writer
->networks
, *network
);
170 static void make_magic(struct loc_writer
* writer
, struct loc_database_magic
* magic
) {
172 for (unsigned int i
= 0; i
< strlen(LOC_DATABASE_MAGIC
); i
++)
173 magic
->magic
[i
] = LOC_DATABASE_MAGIC
[i
];
176 magic
->version
= htobe16(LOC_DATABASE_VERSION
);
179 static void align_page_boundary(off_t
* offset
, FILE* f
) {
180 // Move to next page boundary
181 while (*offset
% LOC_DATABASE_PAGE_SIZE
> 0)
182 *offset
+= fwrite("", 1, 1, f
);
185 static int loc_database_write_pool(struct loc_writer
* writer
,
186 struct loc_database_header_v0
* header
, off_t
* offset
, FILE* f
) {
187 // Save the offset of the pool section
188 DEBUG(writer
->ctx
, "Pool starts at %jd bytes\n", *offset
);
189 header
->pool_offset
= htobe32(*offset
);
192 size_t pool_length
= loc_stringpool_write(writer
->pool
, f
);
193 *offset
+= pool_length
;
195 DEBUG(writer
->ctx
, "Pool has a length of %zu bytes\n", pool_length
);
196 header
->pool_length
= htobe32(pool_length
);
201 static int loc_database_write_as_section(struct loc_writer
* writer
,
202 struct loc_database_header_v0
* header
, off_t
* offset
, FILE* f
) {
203 DEBUG(writer
->ctx
, "AS section starts at %jd bytes\n", *offset
);
204 header
->as_offset
= htobe32(*offset
);
206 size_t as_length
= 0;
208 struct loc_database_as_v0 as
;
209 for (unsigned int i
= 0; i
< writer
->as_count
; i
++) {
210 // Convert AS into database format
211 loc_as_to_database_v0(writer
->as
[i
], &as
);
214 offset
+= fwrite(&as
, 1, sizeof(as
), f
);
215 as_length
+= sizeof(as
);
218 DEBUG(writer
->ctx
, "AS section has a length of %zu bytes\n", as_length
);
219 header
->as_length
= htobe32(as_length
);
224 static int loc_database_write_network_section(struct loc_network
* network
, void* data
) {
225 FILE* f
= (FILE*)data
;
227 struct loc_database_network_v0 n
;
229 int r
= loc_network_to_database_v0(network
, &n
);
233 fwrite(&n
, 1, sizeof(n
), f
);
238 static int loc_database_write_networks_section(struct loc_writer
* writer
,
239 struct loc_database_header_v0
* header
, off_t
* offset
, FILE* f
) {
240 DEBUG(writer
->ctx
, "Networks section starts at %jd bytes\n", *offset
);
241 header
->networks_offset
= htobe32(*offset
);
243 size_t networks_length
= sizeof(struct loc_database_network_v0
)
244 * loc_network_tree_count_networks(writer
->networks
);
245 offset
+= networks_length
;
247 int r
= loc_network_tree_walk(writer
->networks
, NULL
, loc_database_write_network_section
, f
);
251 header
->networks_length
= htobe32(networks_length
);
256 LOC_EXPORT
int loc_writer_write(struct loc_writer
* writer
, FILE* f
) {
257 struct loc_database_magic magic
;
258 make_magic(writer
, &magic
);
261 struct loc_database_header_v0 header
;
262 header
.vendor
= htobe32(writer
->vendor
);
263 header
.description
= htobe32(writer
->description
);
265 time_t now
= time(NULL
);
266 header
.created_at
= htobe64(now
);
271 // Start writing at the beginning of the file
272 r
= fseek(f
, 0, SEEK_SET
);
277 offset
+= fwrite(&magic
, 1, sizeof(magic
), f
);
279 // Skip the space we need to write the header later
280 r
= fseek(f
, sizeof(header
), SEEK_CUR
);
282 DEBUG(writer
->ctx
, "Could not seek to position after header\n");
285 offset
+= sizeof(header
);
287 align_page_boundary(&offset
, f
);
290 r
= loc_database_write_as_section(writer
, &header
, &offset
, f
);
294 align_page_boundary(&offset
, f
);
296 // Write all networks
297 r
= loc_database_write_networks_section(writer
, &header
, &offset
, f
);
301 align_page_boundary(&offset
, f
);
304 r
= loc_database_write_pool(writer
, &header
, &offset
, f
);
309 r
= fseek(f
, sizeof(magic
), SEEK_SET
);
313 offset
+= fwrite(&header
, 1, sizeof(header
), f
);