#include <stdlib.h>
#include <time.h>
-#include <loc/libloc.h>
-#include <loc/network.h>
-#include <loc/private.h>
+#include <libloc/address.h>
+#include <libloc/libloc.h>
+#include <libloc/network.h>
+#include <libloc/private.h>
struct loc_network_list {
struct loc_ctx* ctx;
size_t size;
};
-static int loc_network_list_grow(struct loc_network_list* list, size_t size) {
+static int loc_network_list_grow(struct loc_network_list* list) {
+ size_t size = list->elements_size * 2;
+ if (size < 1024)
+ size = 1024;
+
DEBUG(list->ctx, "Growing network list %p by %zu to %zu\n",
list, size, list->elements_size + size);
struct loc_network** elements = reallocarray(list->elements,
list->elements_size + size, sizeof(*list->elements));
if (!elements)
- return -errno;
+ return 1;
list->elements = elements;
list->elements_size += size;
}
LOC_EXPORT struct loc_network_list* loc_network_list_unref(struct loc_network_list* list) {
- if (!list)
- return NULL;
-
if (--list->refcount > 0)
return list;
LOC_EXPORT void loc_network_list_dump(struct loc_network_list* list) {
struct loc_network* network;
- char* s;
for (unsigned int i = 0; i < list->size; i++) {
network = list->elements[i];
- s = loc_network_str(network);
-
- INFO(list->ctx, "%4d: %s\n", i, s);
- free(s);
+ INFO(list->ctx, "%4d: %s\n",
+ i, loc_network_str(network));
}
}
// Check if we have space left
if (list->size >= list->elements_size) {
- int r = loc_network_list_grow(list, 64);
+ int r = loc_network_list_grow(list);
if (r)
return r;
}
return network;
}
+int loc_network_list_remove(struct loc_network_list* list, struct loc_network* network) {
+ int found = 0;
+
+ // Find the network on the list
+ off_t index = loc_network_list_find(list, network, &found);
+
+ // Nothing to do if the network wasn't found
+ if (!found)
+ return 0;
+
+ // Dereference the network at the position
+ loc_network_unref(list->elements[index]);
+
+ // Move all other elements back
+ for (unsigned int i = index; i < list->size - 1; i++)
+ list->elements[i] = list->elements[i+1];
+
+ // The list is shorter now
+ --list->size;
+
+ return 0;
+}
+
LOC_EXPORT int loc_network_list_contains(struct loc_network_list* list, struct loc_network* network) {
int found = 0;
return 1;
}
- int family = loc_address_family(first);
+ DEBUG(ctx, "Summarizing %s - %s\n", loc_address_str(first), loc_address_str(last));
+
+ const int family1 = loc_address_family(first);
+ const int family2 = loc_address_family(last);
- // Families must match
- if (family != loc_address_family(last)) {
+ // Check if address families match
+ if (family1 != family2) {
ERROR(ctx, "Address families do not match\n");
errno = EINVAL;
return 1;
}
// Check if the last address is larger than the first address
- if (in6_addr_cmp(first, last) >= 0) {
+ if (loc_address_cmp(first, last) >= 0) {
ERROR(ctx, "The first address must be smaller than the last address\n");
errno = EINVAL;
return 1;
}
struct loc_network* network = NULL;
-
struct in6_addr start = *first;
- const struct in6_addr* end = NULL;
-
- while (in6_addr_cmp(&start, last) <= 0) {
- // Guess the prefix
- int prefix = 128 - loc_address_count_trailing_zero_bits(&start);
- while (1) {
- // Create a new network object
- r = loc_network_new(ctx, &network, &start, prefix);
- if (r)
- return r;
+ const int family_bit_length = loc_address_family_bit_length(family1);
- // Is this network within bounds?
- end = loc_network_get_last_address(network);
- if (in6_addr_cmp(last, end) <= 0)
- break;
+ while (loc_address_cmp(&start, last) <= 0) {
+ struct in6_addr num;
+ int bits1;
- // Drop network and decrease prefix
- loc_network_unref(network);
- prefix--;
+ // Find the number of trailing zeroes of the start address
+ if (loc_address_all_zeroes(&start))
+ bits1 = family_bit_length;
+ else {
+ bits1 = loc_address_count_trailing_zero_bits(&start);
+ if (bits1 > family_bit_length)
+ bits1 = family_bit_length;
}
- // Push it on the list
+ // Subtract the start address from the last address and add one
+ // (i.e. how many addresses are in this network?)
+ r = loc_address_sub(&num, last, &start);
+ if (r)
+ return r;
+
+ loc_address_increment(&num);
+
+ // How many bits do we need to represent this address?
+ int bits2 = loc_address_bit_length(&num) - 1;
+
+ // Select the smaller one
+ int bits = (bits1 > bits2) ? bits2 : bits1;
+
+ // Create a network
+ r = loc_network_new(ctx, &network, &start, family_bit_length - bits);
+ if (r)
+ return r;
+
+ DEBUG(ctx, "Found network %s\n", loc_network_str(network));
+
+ // Push network on the list
r = loc_network_list_push(*list, network);
if (r) {
loc_network_unref(network);
return r;
}
- // Reset addr to the next start address
- start = address_increment(end);
+ // The next network starts right after this one
+ start = *loc_network_get_last_address(network);
+
+ // If we have reached the end of possible IP addresses, we stop
+ if (loc_address_all_ones(&start))
+ break;
- // Cleanup
- loc_network_unref(network);
+ loc_address_increment(&start);
}
return 0;
}
+
+void loc_network_list_remove_with_prefix_smaller_than(
+ struct loc_network_list* list, const unsigned int prefix) {
+ unsigned int p = 0;
+
+ // Count how many networks were removed
+ unsigned int removed = 0;
+
+ for (unsigned int i = 0; i < list->size; i++) {
+ // Fetch the prefix
+ p = loc_network_prefix(list->elements[i]);
+
+ if (p > prefix) {
+ // Drop this network
+ loc_network_unref(list->elements[i]);
+
+ // Increment counter
+ removed++;
+
+ continue;
+ }
+
+ // Move pointers backwards to keep the list filled
+ list->elements[i - removed] = list->elements[i];
+ }
+
+ // Adjust size
+ list->size -= removed;
+
+ return;
+}