as-list.c 3.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
	libloc - A library to determine the location of someone on the Internet

	Copyright (C) 2020 IPFire Development Team <info@ipfire.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
*/

#include <errno.h>
#include <stdlib.h>

#include <loc/as.h>
#include <loc/as-list.h>
#include <loc/private.h>

struct loc_as_list {
	struct loc_ctx* ctx;
	int refcount;

28 29 30
	struct loc_as** elements;
	size_t elements_size;

31 32 33
	size_t size;
};

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
static int loc_as_list_grow(struct loc_as_list* list, size_t size) {
	DEBUG(list->ctx, "Growing AS list %p by %zu to %zu\n",
		list, size, list->elements_size + size);

	struct loc_as** elements = reallocarray(list->elements,
			list->elements_size + size, sizeof(*list->elements));
	if (!elements)
		return -errno;

	list->elements = elements;
	list->elements_size += size;

	return 0;
}

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
LOC_EXPORT int loc_as_list_new(struct loc_ctx* ctx,
		struct loc_as_list** list) {
	struct loc_as_list* l = calloc(1, sizeof(*l));
	if (!l)
		return -ENOMEM;

	l->ctx = loc_ref(ctx);
	l->refcount = 1;

	DEBUG(l->ctx, "AS list allocated at %p\n", l);
	*list = l;

	return 0;
}

LOC_EXPORT struct loc_as_list* loc_as_list_ref(struct loc_as_list* list) {
	list->refcount++;

	return list;
}

static void loc_as_list_free(struct loc_as_list* list) {
	DEBUG(list->ctx, "Releasing AS list at %p\n", list);

	loc_as_list_clear(list);

	loc_unref(list->ctx);
	free(list);
}

LOC_EXPORT struct loc_as_list* loc_as_list_unref(struct loc_as_list* list) {
	if (!list)
		return NULL;

	if (--list->refcount > 0)
		return list;

	loc_as_list_free(list);
	return NULL;
}

LOC_EXPORT size_t loc_as_list_size(struct loc_as_list* list) {
	return list->size;
}

LOC_EXPORT int loc_as_list_empty(struct loc_as_list* list) {
	return list->size == 0;
}

LOC_EXPORT void loc_as_list_clear(struct loc_as_list* list) {
Michael Tremer's avatar
Michael Tremer committed
99 100 101
	if (!list->elements)
		return;

102
	for (unsigned int i = 0; i < list->size; i++)
103
		loc_as_unref(list->elements[i]);
Michael Tremer's avatar
Michael Tremer committed
104 105

	free(list->elements);
106
	list->elements = NULL;
Michael Tremer's avatar
Michael Tremer committed
107 108 109
	list->elements_size = 0;

	list->size = 0;
110 111 112 113 114 115 116
}

LOC_EXPORT struct loc_as* loc_as_list_get(struct loc_as_list* list, size_t index) {
	// Check index
	if (index >= list->size)
		return NULL;

117
	return loc_as_ref(list->elements[index]);
118 119 120 121 122 123 124 125
}

LOC_EXPORT int loc_as_list_append(
		struct loc_as_list* list, struct loc_as* as) {
	if (loc_as_list_contains(list, as))
		return 0;

	// Check if we have space left
126 127 128 129
	if (list->size >= list->elements_size) {
		int r = loc_as_list_grow(list, 64);
		if (r)
			return r;
130 131 132 133
	}

	DEBUG(list->ctx, "%p: Appending AS %p to list\n", list, as);

134
	list->elements[list->size++] = loc_as_ref(as);
135 136 137 138 139 140 141

	return 0;
}

LOC_EXPORT int loc_as_list_contains(
		struct loc_as_list* list, struct loc_as* as) {
	for (unsigned int i = 0; i < list->size; i++) {
142
		if (loc_as_cmp(as, list->elements[i]) == 0)
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
			return 1;
	}

	return 0;
}

LOC_EXPORT int loc_as_list_contains_number(
		struct loc_as_list* list, uint32_t number) {
	struct loc_as* as;

	int r = loc_as_new(list->ctx, &as, number);
	if (r)
		return -1;

	r = loc_as_list_contains(list, as);
	loc_as_unref(as);

	return r;
}