]>
git.ipfire.org Git - people/ms/libloc.git/blob - src/network.c
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.
17 #include <arpa/inet.h>
28 #include <loc/libloc.h>
29 #include <loc/compat.h>
30 #include <loc/country.h>
31 #include <loc/network.h>
32 #include <loc/network-list.h>
33 #include <loc/private.h>
40 struct in6_addr first_address
;
41 struct in6_addr last_address
;
46 enum loc_network_flags flags
;
49 static int valid_prefix(struct in6_addr
* address
, unsigned int prefix
) {
50 // The prefix cannot be larger than 128 bits
54 // And the prefix cannot be zero
58 // For IPv4-mapped addresses the prefix has to be 96 or lager
59 if (IN6_IS_ADDR_V4MAPPED(address
) && prefix
<= 96)
65 static struct in6_addr
prefix_to_bitmask(unsigned int prefix
) {
66 struct in6_addr bitmask
;
68 for (unsigned int i
= 0; i
< 16; i
++)
69 bitmask
.s6_addr
[i
] = 0;
71 for (int i
= prefix
, j
= 0; i
> 0; i
-= 8, j
++) {
73 bitmask
.s6_addr
[j
] = 0xff;
75 bitmask
.s6_addr
[j
] = 0xff << (8 - i
);
81 static struct in6_addr
make_first_address(const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
84 // Perform bitwise AND
85 for (unsigned int i
= 0; i
< 4; i
++)
86 a
.s6_addr32
[i
] = address
->s6_addr32
[i
] & bitmask
->s6_addr32
[i
];
91 static struct in6_addr
make_last_address(const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
95 for (unsigned int i
= 0; i
< 4; i
++)
96 a
.s6_addr32
[i
] = address
->s6_addr32
[i
] | ~bitmask
->s6_addr32
[i
];
101 static struct in6_addr
address_increment(const struct in6_addr
* address
) {
102 struct in6_addr a
= *address
;
104 for (int octet
= 15; octet
>= 0; octet
--) {
105 if (a
.s6_addr
[octet
] < 255) {
109 a
.s6_addr
[octet
] = 0;
116 LOC_EXPORT
int loc_network_new(struct loc_ctx
* ctx
, struct loc_network
** network
,
117 struct in6_addr
* address
, unsigned int prefix
) {
118 // Address cannot be unspecified
119 if (IN6_IS_ADDR_UNSPECIFIED(address
)) {
120 DEBUG(ctx
, "Start address is unspecified\n");
124 // Address cannot be loopback
125 if (IN6_IS_ADDR_LOOPBACK(address
)) {
126 DEBUG(ctx
, "Start address is loopback address\n");
130 // Address cannot be link-local
131 if (IN6_IS_ADDR_LINKLOCAL(address
)) {
132 DEBUG(ctx
, "Start address cannot be link-local\n");
136 // Address cannot be site-local
137 if (IN6_IS_ADDR_SITELOCAL(address
)) {
138 DEBUG(ctx
, "Start address cannot be site-local\n");
142 // Validate the prefix
143 if (valid_prefix(address
, prefix
) != 0) {
144 DEBUG(ctx
, "Invalid prefix: %u\n", prefix
);
148 struct loc_network
* n
= calloc(1, sizeof(*n
));
152 n
->ctx
= loc_ref(ctx
);
158 // Convert the prefix into a bitmask
159 struct in6_addr bitmask
= prefix_to_bitmask(n
->prefix
);
161 // Store the first and last address in the network
162 n
->first_address
= make_first_address(address
, &bitmask
);
163 n
->last_address
= make_last_address(&n
->first_address
, &bitmask
);
166 if (IN6_IS_ADDR_V4MAPPED(&n
->first_address
))
169 n
->family
= AF_INET6
;
171 DEBUG(n
->ctx
, "Network allocated at %p\n", n
);
176 LOC_EXPORT
int loc_network_new_from_string(struct loc_ctx
* ctx
, struct loc_network
** network
,
177 const char* address_string
) {
178 struct in6_addr first_address
;
180 unsigned int prefix
= 128;
183 DEBUG(ctx
, "Attempting to parse network %s\n", address_string
);
185 // Make a copy of the string to work on it
186 char* buffer
= strdup(address_string
);
187 address_string
= prefix_string
= buffer
;
189 // Split address and prefix
190 address_string
= strsep(&prefix_string
, "/");
192 DEBUG(ctx
, " Split into address = %s, prefix = %s\n", address_string
, prefix_string
);
195 r
= loc_parse_address(ctx
, address_string
, &first_address
);
197 DEBUG(ctx
, "The address could not be parsed\n");
201 // If a prefix was given, we will try to parse it
203 // Convert prefix to integer
204 prefix
= strtol(prefix_string
, NULL
, 10);
207 DEBUG(ctx
, "The prefix was not parsable: %s\n", prefix_string
);
211 // Map the prefix to IPv6 if needed
212 if (IN6_IS_ADDR_V4MAPPED(&first_address
))
217 // Free temporary buffer
220 // Exit if the parsing was unsuccessful
224 // Create a new network
225 return loc_network_new(ctx
, network
, &first_address
, prefix
);
228 LOC_EXPORT
struct loc_network
* loc_network_ref(struct loc_network
* network
) {
234 static void loc_network_free(struct loc_network
* network
) {
235 DEBUG(network
->ctx
, "Releasing network at %p\n", network
);
237 loc_unref(network
->ctx
);
241 LOC_EXPORT
struct loc_network
* loc_network_unref(struct loc_network
* network
) {
245 if (--network
->refcount
> 0)
248 loc_network_free(network
);
252 static int format_ipv6_address(const struct in6_addr
* address
, char* string
, size_t length
) {
253 const char* ret
= inet_ntop(AF_INET6
, address
, string
, length
);
260 static int format_ipv4_address(const struct in6_addr
* address
, char* string
, size_t length
) {
261 struct in_addr ipv4_address
;
262 ipv4_address
.s_addr
= address
->s6_addr32
[3];
264 const char* ret
= inet_ntop(AF_INET
, &ipv4_address
, string
, length
);
271 LOC_EXPORT
char* loc_network_str(struct loc_network
* network
) {
273 const size_t length
= INET6_ADDRSTRLEN
+ 4;
275 char* string
= malloc(length
);
279 unsigned int prefix
= network
->prefix
;
281 switch (network
->family
) {
283 r
= format_ipv6_address(&network
->first_address
, string
, length
);
287 r
= format_ipv4_address(&network
->first_address
, string
, length
);
297 ERROR(network
->ctx
, "Could not convert network to string: %s\n", strerror(errno
));
304 sprintf(string
+ strlen(string
), "/%u", prefix
);
309 LOC_EXPORT
int loc_network_address_family(struct loc_network
* network
) {
310 return network
->family
;
313 static char* loc_network_format_address(struct loc_network
* network
, const struct in6_addr
* address
) {
314 const size_t length
= INET6_ADDRSTRLEN
;
316 char* string
= malloc(length
);
322 switch (network
->family
) {
324 r
= format_ipv6_address(address
, string
, length
);
328 r
= format_ipv4_address(address
, string
, length
);
337 ERROR(network
->ctx
, "Could not format IP address to string: %s\n", strerror(errno
));
346 LOC_EXPORT
const struct in6_addr
* loc_network_get_first_address(struct loc_network
* network
) {
347 return &network
->first_address
;
350 LOC_EXPORT
char* loc_network_format_first_address(struct loc_network
* network
) {
351 return loc_network_format_address(network
, &network
->first_address
);
354 LOC_EXPORT
const struct in6_addr
* loc_network_get_last_address(struct loc_network
* network
) {
355 return &network
->last_address
;
358 LOC_EXPORT
char* loc_network_format_last_address(struct loc_network
* network
) {
359 return loc_network_format_address(network
, &network
->last_address
);
362 LOC_EXPORT
int loc_network_match_address(struct loc_network
* network
, const struct in6_addr
* address
) {
363 // Address must be larger than the start address
364 if (in6_addr_cmp(&network
->first_address
, address
) > 0)
367 // Address must be smaller than the last address
368 if (in6_addr_cmp(&network
->last_address
, address
) < 0)
371 // The address is inside this network
375 LOC_EXPORT
const char* loc_network_get_country_code(struct loc_network
* network
) {
376 return network
->country_code
;
379 LOC_EXPORT
int loc_network_set_country_code(struct loc_network
* network
, const char* country_code
) {
380 // Set empty country code
381 if (!country_code
|| !*country_code
) {
382 *network
->country_code
= '\0';
386 // Check country code
387 if (!loc_country_code_is_valid(country_code
))
390 loc_country_code_copy(network
->country_code
, country_code
);
395 LOC_EXPORT
int loc_network_match_country_code(struct loc_network
* network
, const char* country_code
) {
396 // Check country code
397 if (!loc_country_code_is_valid(country_code
))
400 return (network
->country_code
[0] == country_code
[0])
401 && (network
->country_code
[1] == country_code
[1]);
404 LOC_EXPORT
uint32_t loc_network_get_asn(struct loc_network
* network
) {
408 LOC_EXPORT
int loc_network_set_asn(struct loc_network
* network
, uint32_t asn
) {
414 LOC_EXPORT
int loc_network_match_asn(struct loc_network
* network
, uint32_t asn
) {
415 return network
->asn
== asn
;
418 LOC_EXPORT
int loc_network_has_flag(struct loc_network
* network
, uint32_t flag
) {
419 return network
->flags
& flag
;
422 LOC_EXPORT
int loc_network_set_flag(struct loc_network
* network
, uint32_t flag
) {
423 network
->flags
|= flag
;
428 LOC_EXPORT
int loc_network_match_flag(struct loc_network
* network
, uint32_t flag
) {
429 return loc_network_has_flag(network
, flag
);
432 LOC_EXPORT
int loc_network_eq(struct loc_network
* self
, struct loc_network
* other
) {
433 // Family must be the same
434 if (self
->family
!= other
->family
)
437 // The start address must be the same
438 if (in6_addr_cmp(&self
->first_address
, &other
->first_address
) != 0)
441 // The prefix length must be the same
442 if (self
->prefix
!= other
->prefix
)
448 LOC_EXPORT
int loc_network_gt(struct loc_network
* self
, struct loc_network
* other
) {
449 // Families must match
450 if (self
->family
!= other
->family
)
453 int r
= in6_addr_cmp(&self
->first_address
, &other
->first_address
);
468 if (self
->prefix
> other
->prefix
)
475 LOC_EXPORT
int loc_network_overlaps(struct loc_network
* self
, struct loc_network
* other
) {
476 if (loc_network_match_address(self
, &other
->first_address
) == 0)
479 if (loc_network_match_address(self
, &other
->last_address
) == 0)
482 if (loc_network_match_address(other
, &self
->first_address
) == 0)
485 if (loc_network_match_address(other
, &self
->last_address
) == 0)
491 LOC_EXPORT
int loc_network_is_subnet(struct loc_network
* self
, struct loc_network
* other
) {
492 // If the start address of the other network is smaller than this network,
493 // it cannot be a subnet.
494 if (in6_addr_cmp(&self
->first_address
, &other
->first_address
) < 0)
497 // If the end address of the other network is greater than this network,
498 // it cannot be a subnet.
499 if (in6_addr_cmp(&self
->last_address
, &other
->last_address
) > 0)
505 // XXX DEPRECATED - I find this too difficult to use
506 LOC_EXPORT
int loc_network_is_subnet_of(struct loc_network
* self
, struct loc_network
* other
) {
507 // If the start address of the other network is smaller than this network,
508 // it cannot be a subnet.
509 if (in6_addr_cmp(&self
->first_address
, &other
->first_address
) < 0)
512 // If the end address of the other network is greater than this network,
513 // it cannot be a subnet.
514 if (in6_addr_cmp(&self
->last_address
, &other
->last_address
) > 0)
520 LOC_EXPORT
struct loc_network_list
* loc_network_subnets(struct loc_network
* network
) {
521 struct loc_network_list
* list
;
524 unsigned int prefix
= network
->prefix
+ 1;
526 // Check if the new prefix is valid
527 if (valid_prefix(&network
->first_address
, prefix
))
530 // Create a new list with the result
531 int r
= loc_network_list_new(network
->ctx
, &list
);
533 ERROR(network
->ctx
, "Could not create network list: %d\n", r
);
537 struct loc_network
* subnet1
= NULL
;
538 struct loc_network
* subnet2
= NULL
;
540 // Create the first half of the network
541 r
= loc_network_new(network
->ctx
, &subnet1
, &network
->first_address
, prefix
);
545 // The next subnet starts after the first one
546 struct in6_addr first_address
= address_increment(&subnet1
->last_address
);
548 // Create the second half of the network
549 r
= loc_network_new(network
->ctx
, &subnet2
, &first_address
, prefix
);
553 // Push the both onto the stack (in reverse order)
554 r
= loc_network_list_push(list
, subnet2
);
558 r
= loc_network_list_push(list
, subnet1
);
563 const char* country_code
= loc_network_get_country_code(network
);
565 loc_network_set_country_code(subnet1
, country_code
);
566 loc_network_set_country_code(subnet2
, country_code
);
570 uint32_t asn
= loc_network_get_asn(network
);
572 loc_network_set_asn(subnet1
, asn
);
573 loc_network_set_asn(subnet2
, asn
);
576 loc_network_unref(subnet1
);
577 loc_network_unref(subnet2
);
583 loc_network_unref(subnet1
);
586 loc_network_unref(subnet2
);
589 loc_network_list_unref(list
);
594 LOC_EXPORT
struct loc_network_list
* loc_network_exclude(
595 struct loc_network
* self
, struct loc_network
* other
) {
596 struct loc_network_list
* list
;
599 char* n1
= loc_network_str(self
);
600 char* n2
= loc_network_str(other
);
602 DEBUG(self
->ctx
, "Returning %s excluding %s...\n", n1
, n2
);
609 if (self
->family
!= other
->family
) {
610 DEBUG(self
->ctx
, "Family mismatch\n");
615 // Other must be a subnet of self
616 if (!loc_network_is_subnet_of(other
, self
)) {
617 DEBUG(self
->ctx
, "Network %p is not contained in network %p\n", other
, self
);
622 // We cannot perform this operation if both networks equal
623 if (loc_network_eq(self
, other
)) {
624 DEBUG(self
->ctx
, "Networks %p and %p are equal\n", self
, other
);
629 // Create a new list with the result
630 int r
= loc_network_list_new(self
->ctx
, &list
);
632 ERROR(self
->ctx
, "Could not create network list: %d\n", r
);
636 struct loc_network_list
* subnets
= loc_network_subnets(self
);
638 struct loc_network
* subnet1
= NULL
;
639 struct loc_network
* subnet2
= NULL
;
642 // Fetch both subnets
643 subnet1
= loc_network_list_get(subnets
, 0);
644 subnet2
= loc_network_list_get(subnets
, 1);
647 loc_network_list_unref(subnets
);
650 if (loc_network_eq(other
, subnet1
)) {
651 r
= loc_network_list_push(list
, subnet2
);
655 } else if (loc_network_eq(other
, subnet2
)) {
656 r
= loc_network_list_push(list
, subnet1
);
660 } else if (loc_network_is_subnet_of(other
, subnet1
)) {
661 r
= loc_network_list_push(list
, subnet2
);
665 subnets
= loc_network_subnets(subnet1
);
667 } else if (loc_network_is_subnet_of(other
, subnet2
)) {
668 r
= loc_network_list_push(list
, subnet1
);
672 subnets
= loc_network_subnets(subnet2
);
675 ERROR(self
->ctx
, "We should never get here\n");
679 loc_network_unref(subnet1
);
680 loc_network_unref(subnet2
);
684 loc_network_list_dump(list
);
692 loc_network_unref(subnet1
);
695 loc_network_unref(subnet2
);
698 loc_network_list_unref(list
);
703 LOC_EXPORT
struct loc_network_list
* loc_network_exclude_list(
704 struct loc_network
* network
, struct loc_network_list
* list
) {
705 struct loc_network_list
* to_check
;
707 // Create a new list with all networks to look at
708 int r
= loc_network_list_new(network
->ctx
, &to_check
);
712 struct loc_network
* subnet
= NULL
;
713 struct loc_network_list
* subnets
= NULL
;
715 for (unsigned int i
= 0; i
< loc_network_list_size(list
); i
++) {
716 subnet
= loc_network_list_get(list
, i
);
718 // Find all excluded networks
719 struct loc_network_list
* excluded
= loc_network_exclude(network
, subnet
);
721 // Add them all to the "to check" list
722 loc_network_list_merge(to_check
, excluded
);
723 loc_network_list_unref(excluded
);
727 loc_network_unref(subnet
);
730 r
= loc_network_list_new(network
->ctx
, &subnets
);
732 loc_network_list_unref(to_check
);
736 while (!loc_network_list_empty(to_check
)) {
737 struct loc_network
* subnet_to_check
= loc_network_list_pop(to_check
);
739 // Marks whether this subnet passed all checks
742 for (unsigned int i
= 0; i
< loc_network_list_size(list
); i
++) {
743 subnet
= loc_network_list_get(list
, i
);
745 // Drop this subnet if is is already in list
746 if (loc_network_eq(subnet_to_check
, subnet
)) {
748 loc_network_unref(subnet
);
752 // Drop this subnet if is a subnet of another subnet
753 if (loc_network_is_subnet_of(subnet
, subnet_to_check
)) {
755 loc_network_unref(subnet
);
759 // Break it down if it overlaps
760 if (loc_network_overlaps(subnet_to_check
, subnet
)) {
763 struct loc_network_list
* excluded
= loc_network_exclude(subnet_to_check
, subnet
);
765 loc_network_list_merge(to_check
, excluded
);
766 loc_network_list_unref(excluded
);
769 loc_network_unref(subnet
);
773 loc_network_unref(subnet
);
777 r
= loc_network_list_push(subnets
, subnet_to_check
);
780 loc_network_unref(subnet_to_check
);
783 loc_network_list_unref(to_check
);
786 loc_network_list_sort(subnets
);
791 LOC_EXPORT
int loc_network_to_database_v1(struct loc_network
* network
, struct loc_database_network_v1
* dbobj
) {
793 loc_country_code_copy(dbobj
->country_code
, network
->country_code
);
796 dbobj
->asn
= htobe32(network
->asn
);
799 dbobj
->flags
= htobe16(network
->flags
);
804 LOC_EXPORT
int loc_network_new_from_database_v1(struct loc_ctx
* ctx
, struct loc_network
** network
,
805 struct in6_addr
* address
, unsigned int prefix
, const struct loc_database_network_v1
* dbobj
) {
806 char country_code
[3] = "\0\0";
808 int r
= loc_network_new(ctx
, network
, address
, prefix
);
810 ERROR(ctx
, "Could not allocate a new network: %s", strerror(-r
));
814 // Import country code
815 loc_country_code_copy(country_code
, dbobj
->country_code
);
817 r
= loc_network_set_country_code(*network
, country_code
);
819 ERROR(ctx
, "Could not set country code: %s\n", country_code
);
824 uint32_t asn
= be32toh(dbobj
->asn
);
825 r
= loc_network_set_asn(*network
, asn
);
827 ERROR(ctx
, "Could not set ASN: %d\n", asn
);
832 int flags
= be16toh(dbobj
->flags
);
833 r
= loc_network_set_flag(*network
, flags
);
835 ERROR(ctx
, "Could not set flags: %d\n", flags
);
842 struct loc_network_tree
{
846 struct loc_network_tree_node
* root
;
849 struct loc_network_tree_node
{
853 struct loc_network_tree_node
* zero
;
854 struct loc_network_tree_node
* one
;
856 struct loc_network
* network
;
859 int loc_network_tree_new(struct loc_ctx
* ctx
, struct loc_network_tree
** tree
) {
860 struct loc_network_tree
* t
= calloc(1, sizeof(*t
));
864 t
->ctx
= loc_ref(ctx
);
867 // Create the root node
868 int r
= loc_network_tree_node_new(ctx
, &t
->root
);
870 loc_network_tree_unref(t
);
874 DEBUG(t
->ctx
, "Network tree allocated at %p\n", t
);
879 struct loc_network_tree_node
* loc_network_tree_get_root(struct loc_network_tree
* tree
) {
880 return loc_network_tree_node_ref(tree
->root
);
883 static struct loc_network_tree_node
* loc_network_tree_get_node(struct loc_network_tree_node
* node
, int path
) {
884 struct loc_network_tree_node
** n
;
891 // If the desired node doesn't exist, yet, we will create it
893 int r
= loc_network_tree_node_new(node
->ctx
, n
);
901 static struct loc_network_tree_node
* loc_network_tree_get_path(struct loc_network_tree
* tree
, const struct in6_addr
* address
, unsigned int prefix
) {
902 struct loc_network_tree_node
* node
= tree
->root
;
904 for (unsigned int i
= 0; i
< prefix
; i
++) {
905 // Check if the ith bit is one or zero
906 node
= loc_network_tree_get_node(node
, in6_addr_get_bit(address
, i
));
912 static int __loc_network_tree_walk(struct loc_ctx
* ctx
, struct loc_network_tree_node
* node
,
913 int(*filter_callback
)(struct loc_network
* network
, void* data
),
914 int(*callback
)(struct loc_network
* network
, void* data
), void* data
) {
917 // Finding a network ends the walk here
919 if (filter_callback
) {
920 int f
= filter_callback(node
->network
, data
);
924 // Skip network if filter function returns value greater than zero
929 r
= callback(node
->network
, data
);
934 // Walk down on the left side of the tree first
936 r
= __loc_network_tree_walk(ctx
, node
->zero
, filter_callback
, callback
, data
);
941 // Then walk on the other side
943 r
= __loc_network_tree_walk(ctx
, node
->one
, filter_callback
, callback
, data
);
951 int loc_network_tree_walk(struct loc_network_tree
* tree
,
952 int(*filter_callback
)(struct loc_network
* network
, void* data
),
953 int(*callback
)(struct loc_network
* network
, void* data
), void* data
) {
954 return __loc_network_tree_walk(tree
->ctx
, tree
->root
, filter_callback
, callback
, data
);
957 static void loc_network_tree_free(struct loc_network_tree
* tree
) {
958 DEBUG(tree
->ctx
, "Releasing network tree at %p\n", tree
);
960 loc_network_tree_node_unref(tree
->root
);
962 loc_unref(tree
->ctx
);
966 struct loc_network_tree
* loc_network_tree_unref(struct loc_network_tree
* tree
) {
967 if (--tree
->refcount
> 0)
970 loc_network_tree_free(tree
);
974 static int __loc_network_tree_dump(struct loc_network
* network
, void* data
) {
975 DEBUG(network
->ctx
, "Dumping network at %p\n", network
);
977 char* s
= loc_network_str(network
);
981 INFO(network
->ctx
, "%s\n", s
);
987 int loc_network_tree_dump(struct loc_network_tree
* tree
) {
988 DEBUG(tree
->ctx
, "Dumping network tree at %p\n", tree
);
990 return loc_network_tree_walk(tree
, NULL
, __loc_network_tree_dump
, NULL
);
993 int loc_network_tree_add_network(struct loc_network_tree
* tree
, struct loc_network
* network
) {
994 DEBUG(tree
->ctx
, "Adding network %p to tree %p\n", network
, tree
);
996 struct loc_network_tree_node
* node
= loc_network_tree_get_path(tree
,
997 &network
->first_address
, network
->prefix
);
999 ERROR(tree
->ctx
, "Could not find a node\n");
1003 // Check if node has not been set before
1004 if (node
->network
) {
1005 DEBUG(tree
->ctx
, "There is already a network at this path\n");
1009 // Point node to the network
1010 node
->network
= loc_network_ref(network
);
1015 static int __loc_network_tree_count(struct loc_network
* network
, void* data
) {
1016 size_t* counter
= (size_t*)data
;
1018 // Increase the counter for each network
1024 size_t loc_network_tree_count_networks(struct loc_network_tree
* tree
) {
1027 int r
= loc_network_tree_walk(tree
, NULL
, __loc_network_tree_count
, &counter
);
1034 static size_t __loc_network_tree_count_nodes(struct loc_network_tree_node
* node
) {
1038 counter
+= __loc_network_tree_count_nodes(node
->zero
);
1041 counter
+= __loc_network_tree_count_nodes(node
->one
);
1046 size_t loc_network_tree_count_nodes(struct loc_network_tree
* tree
) {
1047 return __loc_network_tree_count_nodes(tree
->root
);
1050 int loc_network_tree_node_new(struct loc_ctx
* ctx
, struct loc_network_tree_node
** node
) {
1051 struct loc_network_tree_node
* n
= calloc(1, sizeof(*n
));
1055 n
->ctx
= loc_ref(ctx
);
1058 n
->zero
= n
->one
= NULL
;
1060 DEBUG(n
->ctx
, "Network node allocated at %p\n", n
);
1065 struct loc_network_tree_node
* loc_network_tree_node_ref(struct loc_network_tree_node
* node
) {
1072 static void loc_network_tree_node_free(struct loc_network_tree_node
* node
) {
1073 DEBUG(node
->ctx
, "Releasing network node at %p\n", node
);
1076 loc_network_unref(node
->network
);
1079 loc_network_tree_node_unref(node
->zero
);
1082 loc_network_tree_node_unref(node
->one
);
1084 loc_unref(node
->ctx
);
1088 struct loc_network_tree_node
* loc_network_tree_node_unref(struct loc_network_tree_node
* node
) {
1092 if (--node
->refcount
> 0)
1095 loc_network_tree_node_free(node
);
1099 struct loc_network_tree_node
* loc_network_tree_node_get(struct loc_network_tree_node
* node
, unsigned int index
) {
1108 return loc_network_tree_node_ref(node
);
1111 int loc_network_tree_node_is_leaf(struct loc_network_tree_node
* node
) {
1112 return (!!node
->network
);
1115 struct loc_network
* loc_network_tree_node_get_network(struct loc_network_tree_node
* node
) {
1116 return loc_network_ref(node
->network
);