1*e386eeb1Sclaudio /* $OpenBSD: rde_sets.c,v 1.13 2024/09/10 09:38:45 claudio Exp $ */ 2a8e18e82Sclaudio 3a8e18e82Sclaudio /* 4a8e18e82Sclaudio * Copyright (c) 2018 Claudio Jeker <claudio@openbsd.org> 5a8e18e82Sclaudio * 6a8e18e82Sclaudio * Permission to use, copy, modify, and distribute this software for any 7a8e18e82Sclaudio * purpose with or without fee is hereby granted, provided that the above 8a8e18e82Sclaudio * copyright notice and this permission notice appear in all copies. 9a8e18e82Sclaudio * 10a8e18e82Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a8e18e82Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a8e18e82Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a8e18e82Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a8e18e82Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a8e18e82Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a8e18e82Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a8e18e82Sclaudio */ 18a8e18e82Sclaudio #include <sys/types.h> 19a8e18e82Sclaudio #include <sys/queue.h> 20a8e18e82Sclaudio 21a8e18e82Sclaudio #include <assert.h> 22a8e18e82Sclaudio #include <errno.h> 23a8e18e82Sclaudio #include <limits.h> 24a8e18e82Sclaudio #include <stdlib.h> 25a8e18e82Sclaudio #include <stdio.h> 26a8e18e82Sclaudio #include <string.h> 27a8e18e82Sclaudio 28a8e18e82Sclaudio #include "rde.h" 29a8e18e82Sclaudio 3059e404fbSclaudio struct set_table { 3178355a53Sclaudio void *set; 32a8e18e82Sclaudio size_t nmemb; 3378355a53Sclaudio size_t size; 34a8e18e82Sclaudio size_t max; 35a8e18e82Sclaudio }; 36a8e18e82Sclaudio 3759e404fbSclaudio struct as_set * 3859e404fbSclaudio as_sets_new(struct as_set_head *as_sets, const char *name, size_t nmemb, 3959e404fbSclaudio size_t size) 40a8e18e82Sclaudio { 4159e404fbSclaudio struct as_set *aset; 4259e404fbSclaudio size_t len; 4359e404fbSclaudio 4459e404fbSclaudio aset = calloc(1, sizeof(*aset)); 4559e404fbSclaudio if (aset == NULL) 4659e404fbSclaudio return NULL; 4759e404fbSclaudio 4859e404fbSclaudio len = strlcpy(aset->name, name, sizeof(aset->name)); 4959e404fbSclaudio assert(len < sizeof(aset->name)); 5059e404fbSclaudio 5159e404fbSclaudio aset->set = set_new(nmemb, size); 5259e404fbSclaudio if (aset->set == NULL) { 5359e404fbSclaudio free(aset); 5459e404fbSclaudio return NULL; 5559e404fbSclaudio } 5659e404fbSclaudio 57a8e18e82Sclaudio SIMPLEQ_INSERT_TAIL(as_sets, aset, entry); 5859e404fbSclaudio return aset; 59a8e18e82Sclaudio } 60a8e18e82Sclaudio 61a8e18e82Sclaudio struct as_set * 62a8e18e82Sclaudio as_sets_lookup(struct as_set_head *as_sets, const char *name) 63a8e18e82Sclaudio { 64a8e18e82Sclaudio struct as_set *aset; 65a8e18e82Sclaudio 66a8e18e82Sclaudio SIMPLEQ_FOREACH(aset, as_sets, entry) { 67a8e18e82Sclaudio if (strcmp(aset->name, name) == 0) 68a8e18e82Sclaudio return aset; 69a8e18e82Sclaudio } 70a8e18e82Sclaudio return NULL; 71a8e18e82Sclaudio } 72a8e18e82Sclaudio 73a8e18e82Sclaudio 74a8e18e82Sclaudio void 75a8e18e82Sclaudio as_sets_free(struct as_set_head *as_sets) 76a8e18e82Sclaudio { 77a8e18e82Sclaudio struct as_set *aset; 78a8e18e82Sclaudio 79a8e18e82Sclaudio if (as_sets == NULL) 80a8e18e82Sclaudio return; 81a8e18e82Sclaudio while (!SIMPLEQ_EMPTY(as_sets)) { 82a8e18e82Sclaudio aset = SIMPLEQ_FIRST(as_sets); 83a8e18e82Sclaudio SIMPLEQ_REMOVE_HEAD(as_sets, entry); 8459e404fbSclaudio set_free(aset->set); 8559e404fbSclaudio free(aset); 86a8e18e82Sclaudio } 87a8e18e82Sclaudio } 88a8e18e82Sclaudio 89a8e18e82Sclaudio void 90a8e18e82Sclaudio as_sets_mark_dirty(struct as_set_head *old, struct as_set_head *new) 91a8e18e82Sclaudio { 92a8e18e82Sclaudio struct as_set *n, *o; 93a8e18e82Sclaudio 94a8e18e82Sclaudio SIMPLEQ_FOREACH(n, new, entry) { 95a8e18e82Sclaudio if (old == NULL || (o = as_sets_lookup(old, n->name)) == NULL || 967ff9bf35Sclaudio !set_equal(n->set, o->set)) { 97a8e18e82Sclaudio n->dirty = 1; 987ff9bf35Sclaudio n->lastchange = getmonotime(); 997ff9bf35Sclaudio } else 1007ff9bf35Sclaudio n->lastchange = o->lastchange; 101a8e18e82Sclaudio } 102a8e18e82Sclaudio } 103a8e18e82Sclaudio 10459e404fbSclaudio int 10539386878Sclaudio as_set_match(const struct as_set *aset, uint32_t asnum) 106a8e18e82Sclaudio { 10759e404fbSclaudio return set_match(aset->set, asnum) != NULL; 10859e404fbSclaudio } 109a8e18e82Sclaudio 11059e404fbSclaudio struct set_table * 11159e404fbSclaudio set_new(size_t nmemb, size_t size) 11259e404fbSclaudio { 11359e404fbSclaudio struct set_table *set; 11459e404fbSclaudio 11559e404fbSclaudio set = calloc(1, sizeof(*set)); 11659e404fbSclaudio if (set == NULL) 117a8e18e82Sclaudio return NULL; 118a8e18e82Sclaudio 119a8e18e82Sclaudio if (nmemb == 0) 12078355a53Sclaudio nmemb = 4; 121a8e18e82Sclaudio 12259e404fbSclaudio set->size = size; 12359e404fbSclaudio set->max = nmemb; 12459e404fbSclaudio set->set = calloc(nmemb, set->size); 12559e404fbSclaudio if (set->set == NULL) { 12659e404fbSclaudio free(set); 127a8e18e82Sclaudio return NULL; 128a8e18e82Sclaudio } 129a8e18e82Sclaudio 130e5b62a74Sclaudio rdemem.aset_cnt++; 131e5b62a74Sclaudio rdemem.aset_size += sizeof(*set); 1322762ea3aSclaudio rdemem.aset_size += set->size * set->max; 13359e404fbSclaudio return set; 134a8e18e82Sclaudio } 135a8e18e82Sclaudio 13678355a53Sclaudio void 13759e404fbSclaudio set_free(struct set_table *set) 13878355a53Sclaudio { 13959e404fbSclaudio if (set == NULL) 14078355a53Sclaudio return; 141e5b62a74Sclaudio rdemem.aset_cnt--; 142e5b62a74Sclaudio rdemem.aset_size -= sizeof(*set); 143e5b62a74Sclaudio rdemem.aset_size -= set->size * set->max; 144e5b62a74Sclaudio rdemem.aset_nmemb -= set->nmemb; 14559e404fbSclaudio free(set->set); 14659e404fbSclaudio free(set); 14778355a53Sclaudio } 14878355a53Sclaudio 149a8e18e82Sclaudio int 15059e404fbSclaudio set_add(struct set_table *set, void *elms, size_t nelms) 151a8e18e82Sclaudio { 152*e386eeb1Sclaudio if (nelms == 0) /* nothing todo */ 153*e386eeb1Sclaudio return 0; 154*e386eeb1Sclaudio 15559e404fbSclaudio if (set->max < nelms || set->max - nelms < set->nmemb) { 15639386878Sclaudio uint32_t *s; 157a8e18e82Sclaudio size_t new_size; 158a8e18e82Sclaudio 159a985ac10Sclaudio if (set->nmemb >= SIZE_MAX - 4096 - nelms) { 160a8e18e82Sclaudio errno = ENOMEM; 161a8e18e82Sclaudio return -1; 162a8e18e82Sclaudio } 16359e404fbSclaudio for (new_size = set->max; new_size < set->nmemb + nelms; ) 164a8e18e82Sclaudio new_size += (new_size < 4096 ? new_size : 4096); 165a8e18e82Sclaudio 16659e404fbSclaudio s = reallocarray(set->set, new_size, set->size); 167a8e18e82Sclaudio if (s == NULL) 168a8e18e82Sclaudio return -1; 169e5b62a74Sclaudio rdemem.aset_size += set->size * (new_size - set->max); 17059e404fbSclaudio set->set = s; 17159e404fbSclaudio set->max = new_size; 172a8e18e82Sclaudio } 173a8e18e82Sclaudio 17439386878Sclaudio memcpy((uint8_t *)set->set + set->nmemb * set->size, elms, 17559e404fbSclaudio nelms * set->size); 17659e404fbSclaudio set->nmemb += nelms; 177e5b62a74Sclaudio rdemem.aset_nmemb += nelms; 178a8e18e82Sclaudio 179a8e18e82Sclaudio return 0; 180a8e18e82Sclaudio } 181a8e18e82Sclaudio 18259e404fbSclaudio void * 18359e404fbSclaudio set_get(struct set_table *set, size_t *nelms) 18459e404fbSclaudio { 18559e404fbSclaudio *nelms = set->nmemb; 18659e404fbSclaudio return set->set; 18759e404fbSclaudio } 18859e404fbSclaudio 189a8e18e82Sclaudio static int 19059e404fbSclaudio set_cmp(const void *ap, const void *bp) 191a8e18e82Sclaudio { 19239386878Sclaudio const uint32_t *a = ap; 19339386878Sclaudio const uint32_t *b = bp; 194a8e18e82Sclaudio 195a8e18e82Sclaudio if (*a > *b) 196a8e18e82Sclaudio return 1; 197a8e18e82Sclaudio else if (*a < *b) 198a8e18e82Sclaudio return -1; 199a8e18e82Sclaudio return 0; 200a8e18e82Sclaudio } 201a8e18e82Sclaudio 202a8e18e82Sclaudio void 20359e404fbSclaudio set_prep(struct set_table *set) 204a8e18e82Sclaudio { 20559e404fbSclaudio if (set == NULL) 20678355a53Sclaudio return; 20759e404fbSclaudio qsort(set->set, set->nmemb, set->size, set_cmp); 208a8e18e82Sclaudio } 209a8e18e82Sclaudio 21078355a53Sclaudio void * 21139386878Sclaudio set_match(const struct set_table *a, uint32_t asnum) 212a8e18e82Sclaudio { 21378355a53Sclaudio if (a == NULL) 21478355a53Sclaudio return NULL; 21559e404fbSclaudio return bsearch(&asnum, a->set, a->nmemb, a->size, set_cmp); 216a8e18e82Sclaudio } 217a8e18e82Sclaudio 218a8e18e82Sclaudio int 21959e404fbSclaudio set_equal(const struct set_table *a, const struct set_table *b) 220a8e18e82Sclaudio { 22159e404fbSclaudio /* allow NULL pointers to be passed */ 22259e404fbSclaudio if (a == NULL && b == NULL) 22359e404fbSclaudio return 1; 22459e404fbSclaudio if (a == NULL || b == NULL) 22559e404fbSclaudio return 0; 22659e404fbSclaudio 227a8e18e82Sclaudio if (a->nmemb != b->nmemb) 228a8e18e82Sclaudio return 0; 22978355a53Sclaudio if (memcmp(a->set, b->set, a->nmemb * a->size) != 0) 230a8e18e82Sclaudio return 0; 231a8e18e82Sclaudio return 1; 232a8e18e82Sclaudio } 2337ff9bf35Sclaudio 2347ff9bf35Sclaudio size_t 2357ff9bf35Sclaudio set_nmemb(const struct set_table *set) 2367ff9bf35Sclaudio { 2377ff9bf35Sclaudio return set->nmemb; 2387ff9bf35Sclaudio } 239