23 RCSID(
"$Id: 344a24564536764b47335f1d1158506b1711c981 $")
25 #include <freeradius-devel/util/dict.h>
26 #include <freeradius-devel/util/misc.h>
27 #include <freeradius-devel/util/syserror.h>
28 #include <freeradius-devel/util/trie.h>
73 #if !defined(NO_PATH_COMPRESSION) && !defined(WITH_PATH_COMPRESSION)
74 #define WITH_PATH_COMPRESSION
79 #ifdef WITH_NODE_COMPRESSION
80 #ifndef WITH_PATH_COMPRESSION
81 #define WITH_PATH_COMPRESSION
85 #define MAX_COMP_BITS (8)
88 #ifndef MAX_COMP_EDGES
89 #define MAX_COMP_EDGES (4)
94 #define MAX_KEY_BYTES (256)
95 #define MAX_KEY_BITS (MAX_KEY_BYTES * 8)
98 #define MAX_NODE_BITS (4)
111 #define WITH_TRIE_VERIFY (1)
112 # define MPRINT(...) fprintf(stderr, ## __VA_ARGS__)
115 # define MPRINT2(...)
116 # define MPRINT3(...)
120 # define MPRINT2(...)
121 # define MPRINT3(...)
122 #define trie_sprint(_trie, _key, _start_bit, _lineno)
125 #ifdef WITH_TRIE_VERIFY
128 #define VERIFY(_x) if (trie_verify((fr_trie_t *) _x) < 0) do { fprintf(stderr, "FAIL VERIFY at %d - %s\n", __LINE__, fr_strerror()); fr_cond_assert(0); } while (0)
136 #define BITSOF(_x) ((_x) * 8)
137 #define BYTEOF(_x) ((_x) >> 3)
138 #define BYTES(_x) (((_x) + 0x07) >> 3)
151 0xff, 0x7f, 0x3f, 0x1f,
152 0x0f, 0x07, 0x03, 0x01
156 0x80, 0xc0, 0xe0, 0xf0,
157 0xf8, 0xfc, 0xfe, 0xff,
164 static char const *
spaces =
" ";
168 #if defined(WITH_PATH_COMPRESSION) || defined(TESTING)
231 if (!keylen1 || !keylen2)
return 0;
235 if (end_bit > keylen2) end_bit = keylen2;
236 end_bit += start_bit;
238 MPRINT2(
"%.*sLCP %02x%02x %02x%02x start %d length %d, %d\n",
239 start_bit,
spaces, key1[0], key1[1], key2[0], key2[1], start_bit, keylen1, keylen2);
243 while (end_bit > 0) {
271 if ((start_bit & 0x07) != 0) {
274 num_bits -= start_bit;
275 end_bit -= start_bit;
321 static void hex_dump(FILE *fp,
char const *
msg,
uint8_t const *key,
int start_bit,
int end_bit)
325 fprintf(fp,
"%s\ts=%zd e=%zd\t\t",
msg, start_bit, end_bit);
327 for (i = 0; i <
BYTES(end_bit); i++) {
328 fprintf(fp,
"%02x ", key[i]);
357 chunk = key[0] >> (7 - start_bit);
365 if (start_bit == 0) {
366 if (num_bits < 7)
return key[0] >> (8 - num_bits);
367 if (num_bits == 8)
return key[0];
369 chunk = (key[0] << 8) | key[1];
370 if (num_bits < 16) chunk >>= (16 - num_bits);
383 if (
BYTEOF(start_bit + num_bits - 1) != 0) {
395 end_bit = (start_bit + num_bits) & 0x07;
396 if (end_bit != 0) chunk >>= 8 - end_bit;
425 out[0] &= ~((1 << (7 - start_bit)) - 1);
426 out[0] |= chunk << (7 - start_bit);
440 if ((start_bit + num_bits) < 16) chunk <<= (16 - (start_bit + num_bits));
447 out[0] |= chunk >> 8;
449 if ((start_bit + num_bits) > 8) {
450 out[1] = chunk & 0xff;
457 #ifdef WITH_PATH_COMPRESSION
460 #ifdef WITH_NODE_COMPRESSION
466 #define FR_TRIE_MAX (FR_TRIE_NODE + 1)
469 static int trie_number = 0;
471 #define TRIE_HEADER uint8_t type; uint8_t bits; int number
472 #define TRIE_TYPE_CHECK(_x, _r) do { if ((trie->type == FR_TRIE_INVALID) || \
473 (trie->type >= FR_TRIE_MAX) || \
474 !trie_ ## _x ##_table [trie->type]) { \
475 fr_strerror_printf("unknown trie type %d", trie->type); \
480 #define TRIE_HEADER uint8_t type; uint8_t bits
481 #define TRIE_TYPE_CHECK(_x, _r)
504 #ifdef WITH_PATH_COMPRESSION
515 #ifdef WITH_NODE_COMPRESSION
533 if ((bits <= 0) || (bits > 8)) {
546 talloc_set_name_const(node,
"fr_trie_node_t");
551 node->number = trie_number++;
578 for (i = 0; i < (1 << node->bits); i++) {
579 if (!node->
trie[i])
continue;
588 #ifdef WITH_PATH_COMPRESSION
598 #ifdef WITH_NODE_COMPRESSION
599 if (trie->type == FR_TRIE_COMP) {
600 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
603 for (i = 0; i <
comp->used; i++) {
627 user->number = trie_number++;
633 #ifdef WITH_PATH_COMPRESSION
638 if (end_bit <= start_bit) {
647 key += (start_bit >> 3);
648 end_bit -= 8 * (start_bit >> 3);
649 start_bit -= 8 * (start_bit >> 3);
652 if ((end_bit - start_bit) > 16) {
673 path->bits = end_bit - start_bit;
682 fprintf(stderr,
"PATH ALLOC key %02x%02x start %d end %d bits %d == chunk %04x key %02x%02x\n",
684 start_bit, end_bit, path->bits,
689 path->number = trie_number++;
696 #ifdef WITH_NODE_COMPRESSION
697 static fr_trie_comp_t *fr_trie_comp_alloc(TALLOC_CTX *ctx,
int bits)
699 fr_trie_comp_t *
comp;
704 if ((bits <= 2) || (bits > MAX_COMP_BITS)) {
709 comp = talloc_zero(ctx, fr_trie_comp_t);
715 comp->type = FR_TRIE_COMP;
720 comp->number = trie_number++;
751 if (!user)
return NULL;
762 uctx->get_key = get_key;
763 uctx->free_data = free_data;
776 int i, remaining_bits;
782 if ((bits == 0) || (bits >= node->bits) || (node->bits == 1)) {
788 if (!
split)
return NULL;
790 remaining_bits = node->bits - bits;
796 for (i = 0; i < (1 << bits); i++) {
806 for (j = 0; j < (1 << remaining_bits); j++) {
807 if (!node->trie[(i << remaining_bits) + j])
continue;
809 child->
trie[j] = node->
trie[(i << remaining_bits) + j];
810 node->
trie[(i << remaining_bits) + j] = NULL;
830 #ifdef WITH_PATH_COMPRESSION
838 if ((lcp <= 0) || (lcp > path->bits) || (start_bit < 0)) {
843 MPRINT3(
"%.*sSPLIT start %d\n", start_bit,
spaces, start_bit);
847 if (!
split)
return NULL;
849 child =
fr_trie_path_alloc(ctx, &path->key[0], start_bit + lcp, start_bit + path->bits);
850 if (!child)
return NULL;
876 MPRINT3(
"%.*ssplit %02x%02x start %d split %d -> %02x%02x %02x%02x\n",
878 path->key[0], path->key[1],
879 start_bit,
split->bits,
881 child->
key[0], child->
key[1]);
894 if (start_bit > end_bit) {
902 next_bit = start_bit + 16 - (start_bit & 0x07);
904 if (next_bit >= end_bit) {
906 if (!path)
return NULL;
914 if (!path)
return NULL;
931 if (start_bit == end_bit) {
935 bits = end_bit - start_bit;
942 if (!node)
return NULL;
944 chunk =
get_chunk(key, start_bit, node->bits);
946 if (!node->
trie[chunk]) {
961 #ifdef WITH_NODE_COMPRESSION
962 static fr_trie_t *trie_comp_split(TALLOC_CTX *ctx, fr_trie_comp_t *
comp,
int start_bit,
int bits)
965 fr_trie_comp_t *
split;
971 if ((bits == 0) || (bits >=
comp->bits)) {
976 split = fr_trie_comp_alloc(ctx, bits);
977 if (!
split)
return NULL;
979 if (start_bit > 7) start_bit &= 0x07;
990 for (i = 0; i <
comp->used; i++) {
996 before = i >> (
comp->bits - bits);
997 after = i & ((1 << bits) - 1);
1005 for (j = 0; j <
split->used; j++) {
1006 if (before ==
split->index[j]) {
1012 if (
split->index[where]) {
1019 if (!path)
goto fail;
1029 for (i = 0; i <
split->used; i++) {
1040 #ifdef WITH_PATH_COMPRESSION
1050 #ifdef WITH_NODE_COMPRESSION
1051 if (trie->type == FR_TRIE_COMP) {
1052 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
1055 if (chunk >= (1 <<
comp->bits))
return -1;
1057 if (
comp->used >= MAX_COMP_EDGES)
return -1;
1060 for (i = 0; i <
comp->used; i++) {
1061 if (
comp->index[i] < chunk)
continue;
1063 if (
comp->index[edge] == chunk)
return -1;
1069 if (edge == MAX_COMP_EDGES)
return -1;
1075 for (i = edge; i <
comp->used; i++) {
1076 comp->index[i + 1] =
comp->index[i];
1080 comp->index[edge] = chunk;
1081 comp->trie[edge] = child;
1093 if (chunk >= (1 << node->bits))
return -1;
1095 if (node->
trie[chunk] != NULL)
return -1;
1098 node->
trie[chunk] = child;
1106 typedef void *(*trie_key_match_t)(
fr_trie_t *trie,
uint8_t const *key,
int start_bit,
int end_bit,
bool exact);
1119 if (start_bit == end_bit)
return user->
data;
1135 MPRINT2(
"no exact match at %d\n", __LINE__);
1150 chunk =
get_chunk(key, start_bit, node->bits);
1151 if (!node->
trie[chunk]) {
1152 MPRINT2(
"no match for node chunk %02x at %d\n", chunk, __LINE__);
1156 return trie_key_match(node->
trie[chunk], key, start_bit + node->bits, end_bit, exact);
1159 #ifdef WITH_PATH_COMPRESSION
1165 chunk =
get_chunk(key, start_bit, path->bits);
1166 if (chunk != path->
chunk)
return NULL;
1172 #ifdef WITH_NODE_COMPRESSION
1173 static void *trie_comp_match(
fr_trie_t *trie,
uint8_t const *key,
int start_bit,
int end_bit,
bool exact)
1177 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
1181 for (i = 0; i <
comp->used; i++) {
1182 if (
comp->index[i] < chunk)
continue;
1184 if (
comp->index[i] == chunk) {
1203 #ifdef WITH_PATH_COMPRESSION
1206 #ifdef WITH_NODE_COMPRESSION
1207 [ FR_TRIE_COMP ] = trie_comp_match,
1228 if (!trie)
return NULL;
1233 if ((start_bit + trie->bits) > end_bit) {
1234 MPRINT2(
"%d + %d = %d > %d\n",
1235 start_bit, trie->bits, start_bit + trie->bits, end_bit);
1237 MPRINT2(
"no match for key too short for trie NODE-%d at %d\n", trie->number, __LINE__);
1268 if (!ft->
trie)
return NULL;
1292 if (!ft->
trie)
return NULL;
1313 MPRINT3(
"%.*sFailed to find user data %s from start %d end %d at %d\n", start_bit,
spaces,
data,
1314 start_bit, end_bit, lineno);
1318 if (answer !=
data) {
1321 MPRINT3(
"%.*sFound wrong user data %s != %s, from start %d end %d at %d\n", start_bit,
spaces,
1322 answer,
data, start_bit, end_bit, lineno);
1327 #define trie_check(_trie, _key, _start_bit, _end_bit, _data, _lineno)
1339 MPRINT3(
"user insert to start %d end %d with data %s\n", start_bit, end_bit, (
char *)
data);
1344 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1355 MPRINT3(
"%.*snode insert end %d with data %s\n",
1364 if ((start_bit + node->bits) > end_bit) {
1367 MPRINT3(
"%.*snode insert splitting %d at %d start %d end %d with data %s\n",
1369 node->bits, start_bit - end_bit,
1370 start_bit, end_bit, (
char *)
data);
1382 chunk =
get_chunk(key, start_bit, node->bits);
1388 if (!node->
trie[chunk]) {
1390 if (!node->
trie[chunk]) {
1392 if (trie_to_free)
trie_free(trie_to_free);
1402 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1404 MPRINT(
"Failed recursing at %d\n", __LINE__);
1405 if (trie_to_free)
trie_free(trie_to_free);
1412 MPRINT3(
"%.*snode insert returning at %d\n",
1413 start_bit,
spaces, __LINE__);
1415 if (trie_to_free)
trie_free(trie_to_free);
1421 #ifdef WITH_PATH_COMPRESSION
1433 MPRINT3(
"%.*spath insert start %d end %d with key %02x%02x data %s\n",
1434 start_bit,
spaces, start_bit, end_bit, key[0], key[1], (
char *)
data);
1442 if (start_bit + path->bits <= end_bit) {
1443 chunk =
get_chunk(key, start_bit, path->bits);
1449 if (chunk == path->
chunk) {
1450 MPRINT3(
"%.*spath chunk matches %04x bits of %d\n",
1451 start_bit,
spaces, chunk, path->bits);
1452 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1459 MPRINT3(
"%.*spath returning at %d\n", start_bit,
spaces, __LINE__);
1465 MPRINT3(
"%.*spath using %d\n", start_bit,
spaces, path->bits);
1472 bits = end_bit - start_bit;
1473 MPRINT3(
"%.*spath limiting %d to %d\n", start_bit,
spaces, path->bits, bits);
1481 start_bit2 = start_bit;
1482 if (start_bit2 > 7) {
1483 key2 += (start_bit2 >> 3);
1484 start_bit2 -= 8 * (start_bit2 >> 3);
1499 if (lcp == path->bits) {
1512 MPRINT3(
"%.*spath split depth %d bits %d at lcp %d with data %s\n",
1513 start_bit,
spaces, start_bit, path->bits, lcp, (
char *)
data);
1515 MPRINT3(
"%.*spath key %02x%02x input key %02x%02x, offset %d\n",
1517 path->
key[0],path->
key[1],
1536 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1552 MPRINT3(
"%.*spath returning at %d\n", start_bit,
spaces, __LINE__);
1567 #ifdef WITH_NODE_COMPRESSION
1569 if (bits > MAX_COMP_BITS) bits = MAX_COMP_BITS;
1571 MPRINT3(
"%.*sFanout to comp %d at depth %d data %s\n", start_bit,
spaces, bits, start_bit, (
char *)
data);
1572 node = (
fr_trie_t *) fr_trie_comp_alloc(ctx, bits);
1582 MPRINT3(
"%.*sFanout to node %d at depth %d data %s\n", start_bit,
spaces, bits, start_bit, (
char *)
data);
1585 if (!node)
return -1;
1591 chunk =
get_chunk(&path->
key[0], start_bit2, node->bits);
1593 if (node->bits == path->bits) {
1624 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1644 chunk =
get_chunk(key, start_bit, node->bits);
1654 MPRINT3(
"%.*spath returning at %d\n", start_bit,
spaces, __LINE__);
1666 #ifdef WITH_NODE_COMPRESSION
1667 static CC_HINT(
nonnull(2,3,6)) int trie_comp_insert(TALLOC_CTX *ctx,
fr_trie_t **trie_p,
uint8_t const *key,
int start_bit,
int end_bit,
void *
data)
1671 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
1675 MPRINT3(
"%.*scomp insert start %d end %d with key %02x%02x data %s\n",
1676 start_bit,
spaces, start_bit, end_bit, key[0], key[1], (
char *)
data);
1678 if ((end_bit - start_bit) <
comp->bits) {
1689 for (i = 0; i <
comp->used; i++) {
1690 if (
comp->index[i] < chunk)
continue;
1695 if (
comp->index[i] == chunk) {
1696 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1698 MPRINT3(
"%.*scomp failed recursing at %d", start_bit,
spaces, __LINE__);
1704 MPRINT3(
"%.*scomp returning at %d", start_bit,
spaces, __LINE__);
1721 if (
comp->used < MAX_COMP_EDGES) {
1722 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1725 MPRINT3(
"%.*scomp failed recursing at %d", start_bit,
spaces, __LINE__);
1751 MPRINT3(
"%.*scomp swapping to node bits %d at %d\n", start_bit,
spaces, bits, __LINE__);
1754 if (!node)
return -1;
1756 for (i = 0; i <
comp->used; i++) {
1761 node->
used += (node->
trie[chunk] == NULL);
1767 MPRINT3(
"%.*srecurse at %d\n", start_bit,
spaces, __LINE__);
1769 MPRINT3(
"%.*scomp failed recursing at %d", start_bit,
spaces, __LINE__);
1776 MPRINT3(
"%.*scomp returning at %d", start_bit,
spaces, __LINE__);
1788 #ifdef WITH_PATH_COMPRESSION
1791 #ifdef WITH_NODE_COMPRESSION
1792 [ FR_TRIE_COMP ] = trie_comp_insert,
1820 if (!*trie_p)
return -1;
1824 MPRINT3(
"%.*sIN recurse at %d\n", start_bit,
spaces, __LINE__);
1832 if (start_bit == end_bit) {
1841 if (!user)
return -1;
1853 MPRINT3(
"%.*srecurse at start %d end %d with data %s\n", start_bit,
spaces, start_bit, end_bit, (
char *)
data);
1900 MPRINT2(
"No match for data, inserting...\n");
1902 MPRINT3(
"%.*srecurse STARTS at %d with %.*s=%s\n", 0,
spaces, __LINE__,
1903 (
int) keylen, key, my_data);
1910 typedef void *(*trie_key_remove_t)(TALLOC_CTX *ctx,
fr_trie_t **trie_p,
uint8_t const *key,
int start_bit,
int end_bit);
1922 if (start_bit == end_bit) {
1925 *trie_p = user->
trie;
1941 chunk =
get_chunk(key, start_bit, node->bits);
1942 if (!node->
trie[chunk])
return NULL;
1945 if (!
data)
return NULL;
1950 if (node->
trie[chunk])
return data;
1973 #ifdef WITH_PATH_COMPRESSION
1981 chunk =
get_chunk(key, start_bit, path->bits);
1986 if (path->
chunk != chunk)
return NULL;
1989 if (!
data)
return NULL;
2005 #ifdef WITH_NODE_COMPRESSION
2006 static void *trie_comp_remove(TALLOC_CTX *ctx,
fr_trie_t **trie_p,
uint8_t const *key,
int start_bit,
int end_bit)
2011 fr_trie_comp_t *
comp = *(fr_trie_comp_t **) trie_p;
2019 for (i = 0; i <
comp->used; i++) {
2020 if (
comp->index[i] < chunk)
continue;
2022 if (
comp->index[i] == chunk) {
2031 if (
comp->index[i] > chunk)
return NULL;
2037 if (i >=
comp->used)
return NULL;
2042 if (!
data)
return NULL;
2047 if (
comp->trie[i]) {
2059 for (j = i; j <
comp->used - 1; j++) {
2060 comp->index[j] =
comp->index[j + 1];
2065 if (
comp->used >= 2) {
2091 if (!path)
return data;
2115 #ifdef WITH_PATH_COMPRESSION
2118 #ifdef WITH_NODE_COMPRESSION
2119 [ FR_TRIE_COMP ] = trie_comp_remove,
2130 if (!trie)
return NULL;
2136 if ((start_bit + trie->bits) > end_bit)
return NULL;
2160 if (!ft->
trie)
return NULL;
2192 if (!user->
trie)
return 0;
2203 for (i = 0; i < (1 << node->bits); i++) {
2204 if (!node->
trie[i])
continue;
2210 more || (used < node->
used)) < 0) {
2218 #ifdef WITH_PATH_COMPRESSION
2230 #ifdef WITH_NODE_COMPRESSION
2234 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
2237 for (i = 0; i <
comp->used; i++) {
2244 more || (used < comp->
used)) < 0) {
2256 #ifdef WITH_PATH_COMPRESSION
2259 #ifdef WITH_NODE_COMPRESSION
2260 [ FR_TRIE_COMP ] = trie_comp_walk,
2286 #ifdef WITH_TRIE_VERIFY
2289 typedef int (*trie_verify_t)(
fr_trie_t *trie);
2291 static int trie_user_verify(
fr_trie_t *trie)
2300 if (!user->
trie)
return 0;
2302 return trie_verify(user->
trie);
2305 static int trie_node_verify(
fr_trie_t *trie)
2316 if ((node->
used == 0) || (node->
used > (1 << node->bits))) {
2318 node->
used, node->bits);
2323 for (i = 0; i < (1 << node->bits); i++) {
2324 if (!node->
trie[i])
continue;
2326 if (trie_verify(node->
trie[i]) < 0)
return -1;
2340 #ifdef WITH_PATH_COMPRESSION
2341 static int trie_path_verify(
fr_trie_t *trie)
2345 if ((path->bits == 0) || (path->bits > 16)) {
2356 return trie_verify(path->
trie);
2360 #ifdef WITH_NODE_COMPRESSION
2361 static int trie_comp_verify(
fr_trie_t *trie)
2364 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
2366 if ((
comp->bits == 0) || (
comp->bits > MAX_COMP_BITS)) {
2373 for (i = 0; i <
comp->used; i++) {
2374 if (!
comp->trie[i]) {
2379 if ((i + 1) <
comp->used) {
2380 if (
comp->index[i] >=
comp->index[i + 1]) {
2382 i,
comp->index[i],
comp->index[i + 1]);
2387 if (trie_verify(
comp->trie[i]) < 0)
return -1;
2401 static trie_verify_t trie_verify_table[
FR_TRIE_MAX] = {
2404 #ifdef WITH_PATH_COMPRESSION
2407 #ifdef WITH_NODE_COMPRESSION
2408 [ FR_TRIE_COMP ] = trie_comp_verify,
2418 if (!trie)
return 0;
2422 return trie_verify_table[trie->type](trie);
2432 static void trie_dump_edge(FILE *fp,
fr_trie_t *trie)
2436 fprintf(fp,
"NODE-%d\n", trie->number);
2441 typedef void (*fr_trie_dump_t)(FILE *fp,
fr_trie_t *trie,
char const *key,
int keylen);
2443 static void trie_user_dump(FILE *fp,
fr_trie_t *trie,
char const *key,
int keylen)
2446 int bytes =
BYTES(keylen);
2448 fprintf(fp,
"{ NODE-%d\n", user->number);
2449 fprintf(fp,
"\ttype\tUSER\n");
2450 fprintf(fp,
"\tinput\t{%d}%.*s\n", keylen, bytes, key);
2452 fprintf(fp,
"\tdata\t\"%s\"\n", (
char const *) user->
data);
2454 fprintf(fp,
"}\n\n");
2458 fprintf(fp,
"\tnext\t");
2459 trie_dump_edge(fp, user->
trie);
2460 fprintf(fp,
"}\n\n");
2463 static void trie_node_dump(FILE *fp,
fr_trie_t *trie,
char const *key,
int keylen)
2467 int bytes =
BYTES(keylen);
2469 fprintf(fp,
"{ NODE-%d\n", node->number);
2470 fprintf(fp,
"\ttype\tNODE\n");
2471 fprintf(fp,
"\tinput\t{%d}%.*s\n", keylen, bytes, key);
2473 fprintf(fp,
"\tbits\t%d\n", node->bits);
2474 fprintf(fp,
"\tused\t%d\n", node->
used);
2476 for (i = 0; i < (1 << node->bits); i++) {
2477 if (!node->
trie[i])
continue;
2479 fprintf(fp,
"\t%02x\t", (
int) i);
2480 trie_dump_edge(fp, node->
trie[i]);
2482 fprintf(fp,
"}\n\n");
2485 #ifdef WITH_PATH_COMPRESSION
2486 static void trie_path_dump(FILE *fp,
fr_trie_t *trie,
char const *key,
int keylen)
2489 int bytes =
BYTES(keylen);
2491 fprintf(fp,
"{ NODE-%d\n", path->number);
2492 fprintf(fp,
"\ttype\tPATH\n");
2493 fprintf(fp,
"\tinput\t{%d}%.*s\n", keylen, bytes, key);
2495 fprintf(fp,
"\tbits\t%d\n", (
int) path->bits);
2496 fprintf(fp,
"\tpath\t");
2498 fprintf(fp,
"%02x %02x", path->
key[0], path->
key[1]);
2502 fprintf(fp,
"\tnext\t");
2503 trie_dump_edge(fp, path->
trie);
2505 fprintf(fp,
"}\n\n");
2509 #ifdef WITH_NODE_COMPRESSION
2510 static void trie_comp_dump(FILE *fp,
fr_trie_t *trie,
char const *key,
int keylen)
2512 fr_trie_comp_t *
comp = (fr_trie_comp_t *) trie;
2514 int bytes =
BYTES(keylen);
2516 fprintf(fp,
"{ NODE-%d\n",
comp->number);
2517 fprintf(fp,
"\ttype\tCOMP\n");
2518 fprintf(fp,
"\tinput\t{%d}%.*s\n", keylen, bytes, key);
2520 fprintf(fp,
"\tbits\t%d\n",
comp->bits);
2521 fprintf(fp,
"\tused\t%d\n",
comp->used);
2523 for (i = 0; i <
comp->used; i++) {
2524 fprintf(fp,
"\t%d = %02x\t", i,
comp->index[i]);
2525 trie_dump_edge(fp,
comp->trie[i]);
2527 fprintf(fp,
"}\n\n");
2532 static fr_trie_dump_t trie_dump_table[
FR_TRIE_MAX] = {
2535 #ifdef WITH_PATH_COMPRESSION
2538 #ifdef WITH_NODE_COMPRESSION
2539 [ FR_TRIE_COMP ] = trie_comp_dump,
2551 if (!trie)
return 0;
2555 trie_dump_table[trie->type](fp, trie, (
char const *) cb->
start, keylen);
2572 bytes =
BYTES(keylen);
2575 if ((keylen & 0x07) != 0) {
2576 fprintf(fp,
"{%d}%.*s\t%s\n", keylen, bytes, cb->
start, (
char const *) user->
data);
2578 fprintf(fp,
"%.*s\t%s\n", bytes, cb->
start, (
char const *) user->
data);
2614 .user_callback = callback,
2649 key = &
uctx->buffer[0];
2650 keylen =
sizeof(
uctx->buffer) * 8;
2652 if (!
uctx->get_key)
return false;
2654 if (
uctx->get_key(&key, &keylen,
data) < 0)
return false;
2675 key = &
uctx->buffer[0];
2676 keylen =
sizeof(
uctx->buffer) * 8;
2678 if (!
uctx->get_key)
return false;
2680 if (
uctx->get_key(&key, &keylen,
data) < 0)
return false;
2701 key = &
uctx->buffer[0];
2702 keylen =
sizeof(
uctx->buffer) * 8;
2704 if (!
uctx->get_key)
return false;
2706 if (
uctx->get_key(&key, &keylen,
data) < 0)
return false;
2735 key = &
uctx->buffer[0];
2736 keylen =
sizeof(
uctx->buffer) * 8;
2738 if (!
uctx->get_key)
return -1;
2740 if (
uctx->get_key(&key, &keylen,
data) < 0)
return -1;
2744 if (old) *old = found;
2747 if (old) *old = NULL;
2755 return found ? 1 : 0;
2774 key = &
uctx->buffer[0];
2775 keylen =
sizeof(
uctx->buffer) * 8;
2777 if (!
uctx->get_key)
return NULL;
2779 if (
uctx->get_key(&key, &keylen,
data) < 0)
return NULL;
2801 key = &
uctx->buffer[0];
2802 keylen =
sizeof(
uctx->buffer) * 8;
2804 if (!
uctx->get_key)
return false;
2806 if (
uctx->get_key(&key, &keylen,
data) < 0)
return false;
2809 if (!found)
return false;
2811 if (!
uctx->free_data)
return true;
2813 uctx->free_data(found);
2828 static bool print_lineno =
false;
2834 } trie_sprint_ctx_t;
2842 trie_sprint_ctx_t *ctx;
2848 len =
snprintf(ctx->buffer, ctx->buflen,
"{}");
2854 bytes =
BYTES(keylen);
2857 if (!user->
trie && !more) {
2858 len =
snprintf(ctx->buffer, ctx->buflen,
"%.*s=%s",
2859 bytes, cb->
start, (
char const *) user->
data);
2861 len =
snprintf(ctx->buffer, ctx->buflen,
"%.*s=%s,",
2862 bytes, cb->
start, (
char const *) user->
data);
2876 trie_sprint_ctx_t my_sprint;
2884 memset(
out, 0,
sizeof(
out));
2892 my_sprint.start =
out;
2893 my_sprint.buffer =
out;
2894 my_sprint.buflen =
sizeof(
out);
2903 my_cb.
ctx = &my_sprint;
2921 static int arg2key(
char *arg,
char **key,
int *length)
2928 *length =
BITSOF(strlen(arg));
2932 p = strchr(arg,
'}');
2934 MPRINT(
"Failed to find end '}' for {bits}\n");
2938 bits =
BITSOF(strlen(p + 1));
2940 MPRINT(
"No key found in in '%s'\n", arg);
2944 size = atoi(arg + 1);
2946 MPRINT(
"Length '%d' is longer than bits in key %s",
2961 static void *data_ctx = NULL;
2972 if (arg2key(argv[0], &key, &bits) < 0) {
2980 data = talloc_strdup(data_ctx, argv[1]);
3008 fprintf(stderr,
"Verify failed: trie is malformed\n");
3012 if (trie_verify(ft->
trie) < 0) {
3013 fprintf(stderr,
"Verify failed: %s\n",
fr_strerror());
3074 if (!ft->
trie)
return 0;
3095 if (strcmp(argv[0],
"true") == 0) {
3096 print_lineno =
true;
3098 print_lineno =
false;
3119 if (arg2key(argv[0], &key, &bits) < 0) {
3139 static int command_lookup(
fr_trie_t *ft,
UNUSED int argc,
char **argv,
char *
out,
size_t outlen)
3145 if (arg2key(argv[0], &key, &bits) < 0) {
3165 static int command_remove(
fr_trie_t *ft,
UNUSED int argc,
char **argv,
char *
out,
size_t outlen)
3171 if (arg2key(argv[0], &key, &bits) < 0) {
3177 MPRINT(
"Could not remove key %s\n", key);
3191 MPRINT(
"Still in trie after 'remove' for key %s, found data %s\n", key, (
char const *) answer);
3203 static int command_try_to_remove(
fr_trie_t *ft,
UNUSED int argc,
char **argv,
char *
out,
size_t outlen)
3209 if (arg2key(argv[0], &key, &bits) < 0) {
3229 MPRINT(
"Still in trie after 'remove' for key %s, found data %s\n", key, (
char const *) answer);
3246 trie_sprint_ctx_t my_sprint;
3252 my_sprint.start =
out;
3253 my_sprint.buffer =
out;
3254 my_sprint.buflen = outlen;
3263 my_cb.
ctx = &my_sprint;
3279 static int command_path(
fr_trie_t *ft,
int argc,
char **argv,
char *
out,
size_t outlen)
3284 data = talloc_strdup(ft, argv[1]);
3297 MPRINT(
"Could not look up key %s\n", argv[0]);
3301 if (answer !=
data) {
3302 MPRINT(
"Expected to find %s, got %s\n", argv[1], (
char const *) answer);
3313 MPRINT(
"Could not remove key %s\n", argv[0]);
3317 if (answer !=
data) {
3318 MPRINT(
"Expected to remove %s, got %s\n", argv[1], (
char const *) answer);
3331 static int command_lcp(
UNUSED fr_trie_t *ft,
int argc,
char **argv,
char *
out,
size_t outlen)
3334 int keylen1, keylen2;
3339 key1 = (
uint8_t const *) argv[0];
3340 keylen1 =
BITSOF(strlen(argv[0]));
3342 key2 = (
uint8_t const *) argv[1];
3343 keylen2 =
BITSOF(strlen(argv[1]));
3346 }
else if (argc == 5) {
3347 key1 = (
uint8_t const *) argv[0];
3348 keylen1 = atoi(argv[1]);
3349 if ((keylen1 < 0) || (keylen1 > (
int)
BITSOF(strlen(argv[0])))) {
3350 MPRINT(
"length of key1 %s is larger than string length %ld\n",
3351 argv[1],
BITSOF(strlen(argv[0])));
3355 key2 = (
uint8_t const *) argv[2];
3356 keylen2 = atoi(argv[3]);
3357 if ((keylen2 < 0) || (keylen2 > (
int)
BITSOF(strlen(argv[2])))) {
3358 MPRINT(
"length of key2 %s is larger than string length %ld\n",
3359 argv[3],
BITSOF(strlen(argv[2])));
3363 start_bit = atoi(argv[4]);
3364 if ((start_bit < 0) || (start_bit > 7)) {
3365 MPRINT(
"start_bit has invalid value %s\n", argv[4]);
3370 MPRINT(
"Invalid number of arguments\n");
3385 int start_bit, num_bits;
3388 start_bit = atoi(argv[1]);
3389 num_bits = atoi(argv[2]);
3400 typedef int (*fr_trie_function_t)(
fr_trie_t *ft,
int argc,
char **argv,
char *
out,
size_t outlen);
3407 fr_trie_function_t
function;
3411 } fr_trie_command_t;
3417 static fr_trie_command_t
commands[] = {
3418 {
"lcp", command_lcp, 2, 5,
true },
3419 {
"chunk", command_chunk, 3, 3,
true },
3420 {
"path", command_path, 2, 2,
true },
3421 {
"insert", command_insert, 2, 2,
false },
3423 {
"lookup", command_lookup, 1, 1,
true },
3424 {
"remove", command_remove, 1, 1,
true },
3425 {
"-remove", command_try_to_remove, 1, 1,
true },
3427 {
"dump", command_dump, 0, 0,
false },
3428 {
"keys", command_keys, 0, 0,
false },
3429 {
"verify", command_verify, 0, 0,
false },
3430 {
"lineno", command_lineno, 1, 1,
false },
3435 #define MAX_ARGC (16)
3436 int main(
int argc,
char **argv)
3443 char *my_argv[MAX_ARGC];
3448 fprintf(stderr,
"Please specify filename\n");
3452 fp = fopen(argv[1],
"r");
3454 fprintf(stderr,
"Failed opening %s: %s\n", argv[1],
fr_syserror(errno));
3461 talloc_enable_null_tracking();
3467 fprintf(stderr,
"Failed creating trie\n");
3480 for (p =
buffer; *p !=
'\0'; p++) {
3502 if (strcmp(my_argv[0],
commands[i].
name) != 0)
continue;
3509 fprintf(stderr,
"Unknown command '%s' at line %d\n",
3510 my_argv[0], lineno);
3521 fprintf(stderr,
"Invalid number of arguments to %s at line %d. Expected %d, got %d\n",
3522 my_argv[0], lineno,
commands[cmd].min_argc + 1, my_argc - 1);
3527 printf(
"%d ", lineno);
3531 MPRINT3(
"[%d] %s\n", lineno, my_argv[0]);
3532 if (
commands[cmd].
function(ft, my_argc - 1 -
commands[cmd].output, &my_argv[1], output,
sizeof(output)) < 0) {
3533 fprintf(stderr,
"Failed running %s at line %d\n",
3534 my_argv[0], lineno);
3538 if (!
commands[cmd].output)
continue;
3540 if (strcmp(output, my_argv[my_argc - 1]) != 0) {
3541 fprintf(stderr,
"Failed running %s at line %d: Expected '%s' got '%s'\n",
3542 my_argv[0], lineno, my_argv[my_argc - 1], output);
3552 talloc_report_full(NULL, stdout);
3553 talloc_disable_null_tracking();
static int const char char buffer[256]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
static int split(char **input, char **output, bool syntax_string)
fr_dcursor_eval_t void const * uctx
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
static char const * spaces
int main(int argc, char **argv)
int fr_dict_str_to_argv(char *str, char **argv, int max_argc)
static uint8_t depth(fr_minmax_heap_index_t i)
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
void(* fr_free_t)(void *)
static int8_t comp(void const *a, void const *b)
static void xor(char *out, char *in1, char *in2, int n)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
size_t strlcpy(char *dst, char const *src, size_t siz)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
fr_table_elem_name_t name
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
int(* fr_trie_key_walk_t)(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
#define MPRINT(...)
Internal sanity checks for debugging.
static trie_key_match_t trie_match_table[FR_TRIE_MAX]
static void * trie_user_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
#define trie_check(_trie, _key, _start_bit, _end_bit, _data, _lineno)
static trie_key_remove_t trie_remove_table[FR_TRIE_MAX]
static void * trie_key_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
Match a key in a trie and return user ctx, if any.
static fr_trie_key_walk_t trie_walk_table[FR_TRIE_MAX]
static fr_trie_node_t * trie_node_alloc(TALLOC_CTX *ctx, int bits)
static fr_trie_path_t * fr_trie_path_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit)
void *(* trie_key_match_t)(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
static void * trie_node_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
static int trie_key_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
static fr_trie_t * trie_key_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit, void *data)
static uint16_t get_chunk(uint8_t const *key, uint32_t start_bit, uint32_t num_bits)
Return a chunk of a key (in the low bits) for use in 2^N node de-indexing.
static void * trie_key_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
Remove a key from a trie, and return the user data.
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
static fr_trie_user_t * fr_trie_user_alloc(TALLOC_CTX *ctx, void const *data)
int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
fr_trie_walk_t user_callback
static int _trie_user_cb(fr_trie_t *trie, fr_trie_callback_t *cb, int keylen, UNUSED bool more)
Implement the user-visible side of the walk callback.
static uint8_t xor2lcp[256]
void *(* trie_key_remove_t)(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
static void * trie_path_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
static int trie_path_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
static int trie_node_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
fr_trie_key_walk_t callback
#define trie_sprint(_trie, _key, _start_bit, _lineno)
static trie_key_insert_t trie_insert_table[FR_TRIE_MAX]
static int trie_node_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
#define TRIE_TYPE_CHECK(_x, _r)
static void write_chunk(uint8_t *out, int start_bit, int num_bits, uint16_t chunk)
Write a chunk to an output buffer.
static int fr_trie_key_lcp(uint8_t const *key1, int keylen1, uint8_t const *key2, int keylen2, int start_bit)
Get the longest prefix of the two keys.
static int trie_user_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
static fr_trie_node_t * trie_node_split(TALLOC_CTX *ctx, fr_trie_node_t *node, int bits)
Split a node at bits.
static int trie_add_edge(fr_trie_t *trie, uint16_t chunk, fr_trie_t *child)
Add an edge to a node.
static int trie_key_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data))
Insert a binary key into the trie.
static fr_trie_path_t * trie_path_split(TALLOC_CTX *ctx, fr_trie_path_t *path, int start_bit, int lcp)
CC_NO_UBSAN(function)
Find an element in the trie, returning the data.
static void * trie_path_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
static void * trie_user_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
static int trie_path_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
static uint8_t start_bit_mask[8]
static int trie_user_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
static uint8_t used_bit_mask[8]
int(* trie_key_insert_t)(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
static void * trie_node_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
static void trie_free(fr_trie_t *trie)
Free a fr_trie_t.
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
bool fr_trie_delete(fr_trie_t *ft, void const *data)
bool fr_trie_insert(fr_trie_t *ft, void const *data)
void * fr_trie_find(fr_trie_t *ft, void const *data)
void * fr_trie_remove(fr_trie_t *ft, void const *data)
void * fr_trie_match(fr_trie_t *ft, void const *data)
unsigned int fr_trie_num_elements(fr_trie_t *ft)
int(* fr_trie_walk_t)(uint8_t const *key, size_t keylen, void *data, void *uctx)
Walk over a trie.
int fr_trie_replace(void **old, fr_trie_t *ft, void const *data))
static fr_table_ptr_sorted_t commands[]
static void command_print(void)
static size_t command_match(command_result_t *result, command_file_ctx_t *cc, char *data, size_t data_used, char *in, size_t inlen)
Compare the data buffer to an expected value.
static size_t command_clear(command_result_t *result, UNUSED command_file_ctx_t *cc, char *data, size_t UNUSED data_used, UNUSED char *in, UNUSED size_t inlen)
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static size_t char ** out