#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;
static void loc_network_list_free(struct loc_network_list* list) {
DEBUG(list->ctx, "Releasing network list at %p\n", list);
- for (unsigned int i = 0; i < list->size; i++)
- loc_network_unref(list->elements[i]);
+ // Remove all content
+ loc_network_list_clear(list);
loc_unref(list->ctx);
free(list);
}
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_network_unref(list->elements[i]);
free(list->elements);
+ list->elements = NULL;
list->elements_size = 0;
list->size = 0;
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, "%s\n", s);
- free(s);
+ INFO(list->ctx, "%4d: %s\n",
+ i, loc_network_str(network));
}
}
return loc_network_ref(list->elements[index]);
}
-//MOVE FUNCTION GOES HERE
-
static off_t loc_network_list_find(struct loc_network_list* list,
struct loc_network* network, int* found) {
+ // Insert at the beginning for an empty list
+ if (loc_network_list_empty(list))
+ return 0;
+
off_t lo = 0;
off_t hi = list->size - 1;
int result;
return i;
}
- if (result > 0)
+ if (result > 0) {
lo = i + 1;
- else
+ i++;
+ } else {
hi = i - 1;
+ }
}
*found = 0;
// 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;
}
struct loc_network* network = list->elements[0];
// Move all elements to the top of the stack
- for (unsigned int i = 0; i < --list->size; i++) {
+ for (unsigned int i = 0; i < list->size - 1; i++) {
list->elements[i] = list->elements[i+1];
}
+ // The list is shorter now
+ --list->size;
+
DEBUG(list->ctx, "%p: Popping network %p from stack\n", list, network);
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 0;
}
+
+int loc_network_list_summarize(struct loc_ctx* ctx,
+ const struct in6_addr* first, const struct in6_addr* last, struct loc_network_list** list) {
+ int r;
+
+ if (!list) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ 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);
+
+ // 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 (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 int family_bit_length = loc_address_family_bit_length(family1);
+
+ while (loc_address_cmp(&start, last) <= 0) {
+ struct in6_addr num;
+ int bits1;
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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;
+
+ 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;
+}