]> git.ipfire.org Git - location/libloc.git/blame - src/network.c
network: Export family, first_address and last_address in Python
[location/libloc.git] / src / network.c
CommitLineData
3b5f4af2
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
5
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.
10
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.
15*/
16
17#include <arpa/inet.h>
18#include <assert.h>
19#include <errno.h>
71ff3e69 20#include <stdio.h>
3b5f4af2
MT
21#include <stdlib.h>
22#include <string.h>
23
42f3ccd7
MT
24#ifdef HAVE_ENDIAN_H
25# include <endian.h>
26#endif
27
3b5f4af2 28#include <loc/libloc.h>
42f3ccd7 29#include <loc/compat.h>
57146963 30#include <loc/country.h>
3b5f4af2 31#include <loc/network.h>
9fc7f001 32#include <loc/private.h>
3b5f4af2
MT
33
34struct loc_network {
35 struct loc_ctx* ctx;
36 int refcount;
37
ce4f5752 38 struct in6_addr first_address;
b43edb61 39 struct in6_addr last_address;
3b5f4af2
MT
40 unsigned int prefix;
41
42 char country_code[3];
71ff3e69 43 uint32_t asn;
a293f829 44 enum loc_network_flags flags;
3b5f4af2
MT
45};
46
6183c0f2
MT
47static int valid_prefix(struct in6_addr* address, unsigned int prefix) {
48 // The prefix cannot be larger than 128 bits
49 if (prefix > 128)
50 return 1;
51
52 // And the prefix cannot be zero
53 if (prefix == 0)
54 return 1;
55
aa37232a
MT
56 // For IPv4-mapped addresses the prefix has to be 96 or lager
57 if (IN6_IS_ADDR_V4MAPPED(address) && prefix <= 96)
58 return 1;
59
6183c0f2
MT
60 return 0;
61}
62
a82ce8bc
MT
63static struct in6_addr prefix_to_bitmask(unsigned int prefix) {
64 struct in6_addr bitmask;
65
66 for (unsigned int i = 0; i < 16; i++)
67 bitmask.s6_addr[i] = 0;
68
364a2a37 69 for (int i = prefix, j = 0; i > 0; i -= 8, j++) {
a82ce8bc
MT
70 if (i >= 8)
71 bitmask.s6_addr[j] = 0xff;
72 else
73 bitmask.s6_addr[j] = 0xff << (8 - i);
74 }
75
76 return bitmask;
77}
78
b43edb61 79static struct in6_addr make_first_address(const struct in6_addr* address, const struct in6_addr* bitmask) {
a82ce8bc 80 struct in6_addr a;
a82ce8bc
MT
81
82 // Perform bitwise AND
83 for (unsigned int i = 0; i < 4; i++)
b43edb61 84 a.s6_addr32[i] = address->s6_addr32[i] & bitmask->s6_addr32[i];
a82ce8bc
MT
85
86 return a;
87}
88
b43edb61 89static struct in6_addr make_last_address(const struct in6_addr* address, const struct in6_addr* bitmask) {
2a30e4de 90 struct in6_addr a;
2a30e4de
MT
91
92 // Perform bitwise OR
93 for (unsigned int i = 0; i < 4; i++)
b43edb61 94 a.s6_addr32[i] = address->s6_addr32[i] | ~bitmask->s6_addr32[i];
2a30e4de
MT
95
96 return a;
97}
98
3b5f4af2 99LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
10778041 100 struct in6_addr* address, unsigned int prefix) {
3b5f4af2 101 // Address cannot be unspecified
bca87342 102 if (IN6_IS_ADDR_UNSPECIFIED(address)) {
3b5f4af2
MT
103 DEBUG(ctx, "Start address is unspecified\n");
104 return -EINVAL;
105 }
106
107 // Address cannot be loopback
bca87342 108 if (IN6_IS_ADDR_LOOPBACK(address)) {
3b5f4af2
MT
109 DEBUG(ctx, "Start address is loopback address\n");
110 return -EINVAL;
111 }
112
113 // Address cannot be link-local
bca87342 114 if (IN6_IS_ADDR_LINKLOCAL(address)) {
3b5f4af2
MT
115 DEBUG(ctx, "Start address cannot be link-local\n");
116 return -EINVAL;
117 }
118
119 // Address cannot be site-local
bca87342 120 if (IN6_IS_ADDR_SITELOCAL(address)) {
3b5f4af2
MT
121 DEBUG(ctx, "Start address cannot be site-local\n");
122 return -EINVAL;
123 }
124
6183c0f2 125 // Validate the prefix
10778041 126 if (valid_prefix(address, prefix) != 0) {
6183c0f2
MT
127 DEBUG(ctx, "Invalid prefix: %u\n", prefix);
128 return -EINVAL;
129 }
130
3b5f4af2
MT
131 struct loc_network* n = calloc(1, sizeof(*n));
132 if (!n)
133 return -ENOMEM;
134
135 n->ctx = loc_ref(ctx);
136 n->refcount = 1;
137
b43edb61 138 // Store the prefix
3b5f4af2
MT
139 n->prefix = prefix;
140
b43edb61
MT
141 // Convert the prefix into a bitmask
142 struct in6_addr bitmask = prefix_to_bitmask(n->prefix);
143
144 // Store the first and last address in the network
145 n->first_address = make_first_address(address, &bitmask);
146 n->last_address = make_last_address(&n->first_address, &bitmask);
147
3b5f4af2
MT
148 DEBUG(n->ctx, "Network allocated at %p\n", n);
149 *network = n;
150 return 0;
151}
152
153LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_network** network,
154 const char* address_string) {
ce4f5752 155 struct in6_addr first_address;
b61f14fc 156 unsigned int prefix = 0;
3b5f4af2 157 char* prefix_string;
b61f14fc 158 int r = 1;
3b5f4af2
MT
159
160 // Make a copy of the string to work on it
161 char* buffer = strdup(address_string);
162 address_string = prefix_string = buffer;
163
164 // Split address and prefix
165 address_string = strsep(&prefix_string, "/");
166
b61f14fc
MT
167 // Did we find a prefix?
168 if (prefix_string) {
169 // Convert prefix to integer
170 prefix = strtol(prefix_string, NULL, 10);
3b5f4af2 171
b61f14fc
MT
172 if (prefix) {
173 // Parse the address
ce4f5752 174 r = loc_parse_address(ctx, address_string, &first_address);
aa37232a
MT
175
176 // Map the prefix to IPv6 if needed
ce4f5752 177 if (IN6_IS_ADDR_V4MAPPED(&first_address))
aa37232a 178 prefix += 96;
b61f14fc
MT
179 }
180 }
3b5f4af2
MT
181
182 // Free temporary buffer
183 free(buffer);
184
d3409788 185 if (r == 0) {
ce4f5752 186 r = loc_network_new(ctx, network, &first_address, prefix);
3b5f4af2
MT
187 }
188
189 return r;
190}
191
192LOC_EXPORT struct loc_network* loc_network_ref(struct loc_network* network) {
193 network->refcount++;
194
195 return network;
196}
197
198static void loc_network_free(struct loc_network* network) {
199 DEBUG(network->ctx, "Releasing network at %p\n", network);
200
3b5f4af2
MT
201 loc_unref(network->ctx);
202 free(network);
203}
204
205LOC_EXPORT struct loc_network* loc_network_unref(struct loc_network* network) {
2a30e4de
MT
206 if (!network)
207 return NULL;
208
3b5f4af2
MT
209 if (--network->refcount > 0)
210 return network;
211
212 loc_network_free(network);
213 return NULL;
214}
215
8fb874e9
MT
216static int format_ipv6_address(const struct in6_addr* address, char* string, size_t length) {
217 const char* ret = inet_ntop(AF_INET6, address, string, length);
d3409788
MT
218 if (!ret)
219 return -1;
220
221 return 0;
222}
223
8fb874e9 224static int format_ipv4_address(const struct in6_addr* address, char* string, size_t length) {
d3409788 225 struct in_addr ipv4_address;
8fb874e9 226 ipv4_address.s_addr = address->s6_addr32[3];
d3409788
MT
227
228 const char* ret = inet_ntop(AF_INET, &ipv4_address, string, length);
229 if (!ret)
230 return -1;
231
232 return 0;
233}
234
3b5f4af2 235LOC_EXPORT char* loc_network_str(struct loc_network* network) {
d3409788
MT
236 int r;
237 const size_t length = INET6_ADDRSTRLEN + 4;
3b5f4af2 238
d3409788 239 char* string = malloc(length);
3b5f4af2
MT
240 if (!string)
241 return NULL;
242
aa37232a
MT
243 unsigned int prefix = network->prefix;
244
d3409788
MT
245 int family = loc_network_address_family(network);
246 switch (family) {
247 case AF_INET6:
ce4f5752 248 r = format_ipv6_address(&network->first_address, string, length);
d3409788 249 break;
3b5f4af2 250
d3409788 251 case AF_INET:
ce4f5752 252 r = format_ipv4_address(&network->first_address, string, length);
aa37232a 253 prefix -= 96;
d3409788
MT
254 break;
255
256 default:
257 r = -1;
258 break;
259 }
260
261 if (r) {
262 ERROR(network->ctx, "Could not convert network to string: %s\n", strerror(errno));
3b5f4af2 263 free(string);
d3409788 264
3b5f4af2
MT
265 return NULL;
266 }
267
268 // Append prefix
aa37232a 269 sprintf(string + strlen(string), "/%u", prefix);
3b5f4af2
MT
270
271 return string;
272}
273
44e5ef71 274LOC_EXPORT int loc_network_address_family(struct loc_network* network) {
ce4f5752 275 if (IN6_IS_ADDR_V4MAPPED(&network->first_address))
44e5ef71
MT
276 return AF_INET;
277
278 return AF_INET6;
279}
280
2b9338ea
MT
281static char* loc_network_format_address(struct loc_network* network, const struct in6_addr* address) {
282 const size_t length = INET6_ADDRSTRLEN;
283
284 char* string = malloc(length);
285 if (!string)
286 return NULL;
287
288 int r = 0;
289
290 switch (loc_network_address_family(network)) {
291 case AF_INET6:
292 r = format_ipv6_address(address, string, length);
293 break;
294
295 case AF_INET:
296 r = format_ipv4_address(address, string, length);
297 break;
298
299 default:
300 r = -1;
301 break;
302 }
303
304 if (r) {
305 ERROR(network->ctx, "Could not format IP address to string: %s\n", strerror(errno));
306 free(string);
307
308 return NULL;
309 }
310
311 return string;
312}
313
314LOC_EXPORT char* loc_network_format_first_address(struct loc_network* network) {
315 return loc_network_format_address(network, &network->first_address);
316}
317
318LOC_EXPORT char* loc_network_format_last_address(struct loc_network* network) {
319 return loc_network_format_address(network, &network->last_address);
320}
321
2a30e4de 322LOC_EXPORT int loc_network_match_address(struct loc_network* network, const struct in6_addr* address) {
f50adb09 323 // Address must be larger than the start address
ce4f5752 324 if (in6_addr_cmp(&network->first_address, address) > 0)
2a30e4de
MT
325 return 1;
326
2a30e4de 327 // Address must be smaller than the last address
b43edb61 328 if (in6_addr_cmp(&network->last_address, address) < 0)
2a30e4de
MT
329 return 1;
330
331 // The address is inside this network
332 return 0;
333}
334
3b5f4af2
MT
335LOC_EXPORT const char* loc_network_get_country_code(struct loc_network* network) {
336 return network->country_code;
337}
338
339LOC_EXPORT int loc_network_set_country_code(struct loc_network* network, const char* country_code) {
901ef882
MT
340 // Set empty country code
341 if (!country_code || !*country_code) {
342 *network->country_code = '\0';
343 return 0;
344 }
345
57146963
MT
346 // Check country code
347 if (!loc_country_code_is_valid(country_code))
3b5f4af2
MT
348 return -EINVAL;
349
a7a3d958 350 loc_country_code_copy(network->country_code, country_code);
3b5f4af2
MT
351
352 return 0;
353}
354
e3f696c1 355LOC_EXPORT int loc_network_match_country_code(struct loc_network* network, const char* country_code) {
57146963
MT
356 // Check country code
357 if (!loc_country_code_is_valid(country_code))
e3f696c1
MT
358 return -EINVAL;
359
360 return (network->country_code[0] == country_code[0])
361 && (network->country_code[1] == country_code[1]);
362}
363
71ff3e69
MT
364LOC_EXPORT uint32_t loc_network_get_asn(struct loc_network* network) {
365 return network->asn;
366}
367
368LOC_EXPORT int loc_network_set_asn(struct loc_network* network, uint32_t asn) {
369 network->asn = asn;
370
371 return 0;
372}
373
82910b95
MT
374LOC_EXPORT int loc_network_match_asn(struct loc_network* network, uint32_t asn) {
375 return network->asn == asn;
376}
377
a99e7c2b
MT
378LOC_EXPORT int loc_network_has_flag(struct loc_network* network, uint32_t flag) {
379 return network->flags & flag;
380}
381
382LOC_EXPORT int loc_network_set_flag(struct loc_network* network, uint32_t flag) {
383 network->flags |= flag;
384
385 return 0;
386}
387
388LOC_EXPORT int loc_network_match_flag(struct loc_network* network, uint32_t flag) {
389 return loc_network_has_flag(network, flag);
390}
391
43554dc4
MT
392LOC_EXPORT int loc_network_is_subnet_of(struct loc_network* self, struct loc_network* other) {
393 // If the start address of the other network is smaller than this network,
394 // it cannot be a subnet.
ce4f5752 395 if (in6_addr_cmp(&self->first_address, &other->first_address) < 0)
43554dc4
MT
396 return 0;
397
43554dc4
MT
398 // If the end address of the other network is greater than this network,
399 // it cannot be a subnet.
b43edb61 400 if (in6_addr_cmp(&self->last_address, &other->last_address) > 0)
43554dc4
MT
401 return 0;
402
403 return 1;
404}
405
b904896a 406LOC_EXPORT int loc_network_to_database_v1(struct loc_network* network, struct loc_database_network_v1* dbobj) {
f3e02bc5 407 // Add country code
a7a3d958 408 loc_country_code_copy(dbobj->country_code, network->country_code);
f3e02bc5
MT
409
410 // Add ASN
71ff3e69 411 dbobj->asn = htobe32(network->asn);
f3e02bc5 412
a99e7c2b 413 // Flags
eee6346d 414 dbobj->flags = htobe16(network->flags);
a99e7c2b 415
f3e02bc5
MT
416 return 0;
417}
418
b904896a
MT
419LOC_EXPORT int loc_network_new_from_database_v1(struct loc_ctx* ctx, struct loc_network** network,
420 struct in6_addr* address, unsigned int prefix, const struct loc_database_network_v1* dbobj) {
3dc8adfb 421 char country_code[3] = "\0\0";
a7a3d958 422
39a55353 423 int r = loc_network_new(ctx, network, address, prefix);
94a3f329
MT
424 if (r) {
425 ERROR(ctx, "Could not allocate a new network: %s", strerror(-r));
10778041 426 return r;
94a3f329 427 }
10778041
MT
428
429 // Import country code
a7a3d958 430 loc_country_code_copy(country_code, dbobj->country_code);
10778041
MT
431
432 r = loc_network_set_country_code(*network, country_code);
94a3f329
MT
433 if (r) {
434 ERROR(ctx, "Could not set country code: %s\n", country_code);
10778041 435 return r;
94a3f329 436 }
10778041
MT
437
438 // Import ASN
94a3f329
MT
439 uint32_t asn = be32toh(dbobj->asn);
440 r = loc_network_set_asn(*network, asn);
441 if (r) {
442 ERROR(ctx, "Could not set ASN: %d\n", asn);
10778041 443 return r;
94a3f329 444 }
10778041 445
a99e7c2b 446 // Import flags
94a3f329
MT
447 int flags = be16toh(dbobj->flags);
448 r = loc_network_set_flag(*network, flags);
449 if (r) {
450 ERROR(ctx, "Could not set flags: %d\n", flags);
a99e7c2b 451 return r;
94a3f329 452 }
a99e7c2b 453
10778041
MT
454 return 0;
455}
456
3b5f4af2
MT
457struct loc_network_tree {
458 struct loc_ctx* ctx;
459 int refcount;
460
461 struct loc_network_tree_node* root;
462};
463
464struct loc_network_tree_node {
438db08c
MT
465 struct loc_ctx* ctx;
466 int refcount;
467
3b5f4af2
MT
468 struct loc_network_tree_node* zero;
469 struct loc_network_tree_node* one;
470
471 struct loc_network* network;
472};
473
474LOC_EXPORT int loc_network_tree_new(struct loc_ctx* ctx, struct loc_network_tree** tree) {
475 struct loc_network_tree* t = calloc(1, sizeof(*t));
476 if (!t)
477 return -ENOMEM;
478
479 t->ctx = loc_ref(ctx);
480 t->refcount = 1;
481
482 // Create the root node
438db08c
MT
483 int r = loc_network_tree_node_new(ctx, &t->root);
484 if (r) {
485 loc_network_tree_unref(t);
486 return r;
487 }
3b5f4af2
MT
488
489 DEBUG(t->ctx, "Network tree allocated at %p\n", t);
490 *tree = t;
491 return 0;
492}
493
438db08c
MT
494LOC_EXPORT struct loc_network_tree_node* loc_network_tree_get_root(struct loc_network_tree* tree) {
495 return loc_network_tree_node_ref(tree->root);
3b5f4af2
MT
496}
497
498static struct loc_network_tree_node* loc_network_tree_get_node(struct loc_network_tree_node* node, int path) {
499 struct loc_network_tree_node** n;
500
2a30e4de 501 if (path == 0)
3b5f4af2 502 n = &node->zero;
3eda9cab
MT
503 else
504 n = &node->one;
3b5f4af2
MT
505
506 // If the desired node doesn't exist, yet, we will create it
507 if (*n == NULL) {
438db08c 508 int r = loc_network_tree_node_new(node->ctx, n);
3b5f4af2
MT
509 if (r)
510 return NULL;
511 }
512
513 return *n;
514}
515
39a55353 516static struct loc_network_tree_node* loc_network_tree_get_path(struct loc_network_tree* tree, const struct in6_addr* address, unsigned int prefix) {
3b5f4af2
MT
517 struct loc_network_tree_node* node = tree->root;
518
39a55353 519 for (unsigned int i = 0; i < prefix; i++) {
3b5f4af2 520 // Check if the ith bit is one or zero
2a30e4de 521 node = loc_network_tree_get_node(node, in6_addr_get_bit(address, i));
3b5f4af2
MT
522 }
523
524 return node;
525}
526
527static int __loc_network_tree_walk(struct loc_ctx* ctx, struct loc_network_tree_node* node,
f3e02bc5
MT
528 int(*filter_callback)(struct loc_network* network, void* data),
529 int(*callback)(struct loc_network* network, void* data), void* data) {
3b5f4af2
MT
530 int r;
531
532 // Finding a network ends the walk here
533 if (node->network) {
534 if (filter_callback) {
f3e02bc5 535 int f = filter_callback(node->network, data);
3b5f4af2
MT
536 if (f < 0)
537 return f;
538
539 // Skip network if filter function returns value greater than zero
540 if (f > 0)
541 return 0;
542 }
543
f3e02bc5 544 r = callback(node->network, data);
3b5f4af2
MT
545 if (r)
546 return r;
547 }
548
549 // Walk down on the left side of the tree first
550 if (node->zero) {
f3e02bc5 551 r = __loc_network_tree_walk(ctx, node->zero, filter_callback, callback, data);
3b5f4af2
MT
552 if (r)
553 return r;
554 }
555
556 // Then walk on the other side
557 if (node->one) {
f3e02bc5 558 r = __loc_network_tree_walk(ctx, node->one, filter_callback, callback, data);
3b5f4af2
MT
559 if (r)
560 return r;
561 }
562
563 return 0;
564}
565
f3e02bc5
MT
566LOC_EXPORT int loc_network_tree_walk(struct loc_network_tree* tree,
567 int(*filter_callback)(struct loc_network* network, void* data),
568 int(*callback)(struct loc_network* network, void* data), void* data) {
569 return __loc_network_tree_walk(tree->ctx, tree->root, filter_callback, callback, data);
570}
571
3b5f4af2
MT
572static void loc_network_tree_free(struct loc_network_tree* tree) {
573 DEBUG(tree->ctx, "Releasing network tree at %p\n", tree);
574
438db08c 575 loc_network_tree_node_unref(tree->root);
3b5f4af2
MT
576
577 loc_unref(tree->ctx);
578 free(tree);
579}
580
581LOC_EXPORT struct loc_network_tree* loc_network_tree_unref(struct loc_network_tree* tree) {
582 if (--tree->refcount > 0)
583 return tree;
584
585 loc_network_tree_free(tree);
586 return NULL;
587}
588
e9b4e2a8 589static int __loc_network_tree_dump(struct loc_network* network, void* data) {
3b5f4af2
MT
590 DEBUG(network->ctx, "Dumping network at %p\n", network);
591
592 char* s = loc_network_str(network);
593 if (!s)
594 return 1;
595
596 INFO(network->ctx, "%s\n", s);
597 free(s);
598
599 return 0;
600}
601
602LOC_EXPORT int loc_network_tree_dump(struct loc_network_tree* tree) {
603 DEBUG(tree->ctx, "Dumping network tree at %p\n", tree);
604
f3e02bc5 605 return loc_network_tree_walk(tree, NULL, __loc_network_tree_dump, NULL);
3b5f4af2
MT
606}
607
608LOC_EXPORT int loc_network_tree_add_network(struct loc_network_tree* tree, struct loc_network* network) {
609 DEBUG(tree->ctx, "Adding network %p to tree %p\n", network, tree);
610
39a55353 611 struct loc_network_tree_node* node = loc_network_tree_get_path(tree,
ce4f5752 612 &network->first_address, network->prefix);
3b5f4af2
MT
613 if (!node) {
614 ERROR(tree->ctx, "Could not find a node\n");
615 return -ENOMEM;
616 }
617
618 // Check if node has not been set before
619 if (node->network) {
620 DEBUG(tree->ctx, "There is already a network at this path\n");
c04005bb 621 return -EBUSY;
3b5f4af2
MT
622 }
623
624 // Point node to the network
625 node->network = loc_network_ref(network);
626
627 return 0;
628}
f3e02bc5
MT
629
630static int __loc_network_tree_count(struct loc_network* network, void* data) {
631 size_t* counter = (size_t*)data;
632
633 // Increase the counter for each network
634 counter++;
635
636 return 0;
637}
638
639LOC_EXPORT size_t loc_network_tree_count_networks(struct loc_network_tree* tree) {
640 size_t counter = 0;
641
642 int r = loc_network_tree_walk(tree, NULL, __loc_network_tree_count, &counter);
643 if (r)
644 return r;
645
646 return counter;
647}
940f9c2b
MT
648
649static size_t __loc_network_tree_count_nodes(struct loc_network_tree_node* node) {
650 size_t counter = 1;
651
652 if (node->zero)
653 counter += __loc_network_tree_count_nodes(node->zero);
654
655 if (node->one)
656 counter += __loc_network_tree_count_nodes(node->one);
657
658 return counter;
659}
660
661LOC_EXPORT size_t loc_network_tree_count_nodes(struct loc_network_tree* tree) {
662 return __loc_network_tree_count_nodes(tree->root);
663}
438db08c
MT
664
665LOC_EXPORT int loc_network_tree_node_new(struct loc_ctx* ctx, struct loc_network_tree_node** node) {
666 struct loc_network_tree_node* n = calloc(1, sizeof(*n));
667 if (!n)
668 return -ENOMEM;
669
670 n->ctx = loc_ref(ctx);
671 n->refcount = 1;
672
673 n->zero = n->one = NULL;
674
675 DEBUG(n->ctx, "Network node allocated at %p\n", n);
676 *node = n;
677 return 0;
678}
679
680LOC_EXPORT struct loc_network_tree_node* loc_network_tree_node_ref(struct loc_network_tree_node* node) {
681 if (node)
682 node->refcount++;
683
684 return node;
685}
686
687static void loc_network_tree_node_free(struct loc_network_tree_node* node) {
688 DEBUG(node->ctx, "Releasing network node at %p\n", node);
689
690 if (node->network)
691 loc_network_unref(node->network);
692
693 if (node->zero)
694 loc_network_tree_node_unref(node->zero);
695
696 if (node->one)
697 loc_network_tree_node_unref(node->one);
698
699 loc_unref(node->ctx);
700 free(node);
701}
702
703LOC_EXPORT struct loc_network_tree_node* loc_network_tree_node_unref(struct loc_network_tree_node* node) {
704 if (!node)
705 return NULL;
706
707 if (--node->refcount > 0)
708 return node;
709
710 loc_network_tree_node_free(node);
711 return NULL;
712}
713
714LOC_EXPORT struct loc_network_tree_node* loc_network_tree_node_get(struct loc_network_tree_node* node, unsigned int index) {
715 if (index == 0)
716 node = node->zero;
717 else
718 node = node->one;
719
720 if (!node)
721 return NULL;
722
723 return loc_network_tree_node_ref(node);
724}
725
726LOC_EXPORT int loc_network_tree_node_is_leaf(struct loc_network_tree_node* node) {
727 return (!!node->network);
728}
729
730LOC_EXPORT struct loc_network* loc_network_tree_node_get_network(struct loc_network_tree_node* node) {
731 return loc_network_ref(node->network);
732}