summaryrefslogtreecommitdiffstats
path: root/bin/tests/optional/rbt_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/tests/optional/rbt_test.c')
-rw-r--r--bin/tests/optional/rbt_test.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/bin/tests/optional/rbt_test.c b/bin/tests/optional/rbt_test.c
new file mode 100644
index 0000000..735c229
--- /dev/null
+++ b/bin/tests/optional/rbt_test.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+const char *progname;
+isc_mem_t *mctx;
+
+#define DNSNAMELEN 255
+
+static dns_name_t *
+create_name(char *s) {
+ int length;
+ isc_result_t result;
+ isc_buffer_t source, target;
+ static dns_name_t *name;
+
+ if (s == NULL || *s == '\0') {
+ printf("missing name argument\n");
+ return (NULL);
+ }
+
+ length = strlen(s);
+
+ isc_buffer_init(&source, s, length);
+ isc_buffer_add(&source, length);
+
+ /*
+ * It isn't really necessary in this program to create individual
+ * memory spaces for each name structure and its associated character
+ * string. It is done here to provide a relatively easy way to test
+ * the callback from dns_rbt_deletename that is supposed to free the
+ * data associated with a node.
+ *
+ * The buffer for the actual name will immediately follow the
+ * name structure.
+ */
+ name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN);
+
+ dns_name_init(name, NULL);
+ isc_buffer_init(&target, name + 1, DNSNAMELEN);
+
+ result = dns_name_fromtext(name, &source, dns_rootname, 0, &target);
+
+ if (result != ISC_R_SUCCESS) {
+ printf("dns_name_fromtext(%s) failed: %s\n", s,
+ dns_result_totext(result));
+ return (NULL);
+ }
+
+ return (name);
+}
+
+static void
+delete_name(void *data, void *arg) {
+ dns_name_t *name;
+
+ UNUSED(arg);
+ name = data;
+ isc_mem_put(mctx, name, sizeof(*name) + DNSNAMELEN);
+}
+
+static void
+print_name(dns_name_t *name) {
+ isc_buffer_t target;
+ char buffer[1024];
+
+ isc_buffer_init(&target, buffer, sizeof(buffer));
+
+ /*
+ * false means absolute names have the final dot added.
+ */
+ dns_name_totext(name, false, &target);
+
+ printf("%.*s", (int)target.used, (char *)target.base);
+}
+
+static void
+detail(dns_rbt_t *rbt, dns_name_t *name) {
+ dns_name_t *foundname, *origin, *fullname;
+ dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
+ dns_rbtnode_t *node1, *node2;
+ dns_rbtnodechain_t chain;
+ isc_result_t result;
+ bool nodes_should_match = false;
+
+ dns_rbtnodechain_init(&chain);
+
+ origin = dns_fixedname_initname(&fixedorigin);
+ fullname = dns_fixedname_initname(&fixedfullname);
+ foundname = dns_fixedname_initname(&fixedfoundname);
+
+ node1 = node2 = NULL;
+
+ printf("checking chain information for ");
+ print_name(name);
+ printf("\n");
+
+ result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+
+ switch (result) {
+ case ISC_R_SUCCESS:
+ printf(" found exact.");
+ nodes_should_match = true;
+ break;
+ case DNS_R_PARTIALMATCH:
+ printf(" found parent.");
+ break;
+ case ISC_R_NOTFOUND:
+ printf(" name not found.");
+ break;
+ default:
+ printf(" unexpected result: %s\n", dns_result_totext(result));
+ return;
+ }
+
+ if (node1 != NULL && node1->data != NULL) {
+ printf(" data at node: ");
+ print_name(node1->data);
+ } else {
+ printf(" no data at node.");
+ }
+
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ printf("\n name from dns_rbt_findnode: ");
+ print_name(foundname);
+ }
+
+ result = dns_rbtnodechain_current(&chain, foundname, origin, &node2);
+
+ if (result == ISC_R_SUCCESS) {
+ printf("\n name from dns_rbtnodechain_current: ");
+
+ result = dns_name_concatenate(foundname, origin, fullname,
+ NULL);
+ if (result == ISC_R_SUCCESS) {
+ print_name(fullname);
+ } else {
+ printf("%s\n", dns_result_totext(result));
+ }
+ printf("\n (foundname = ");
+ print_name(foundname);
+ printf(", origin = ");
+ print_name(origin);
+ printf(")\n");
+ if (nodes_should_match && node1 != node2) {
+ printf(" nodes returned from each function "
+ "DO NOT match!\n");
+ }
+ } else {
+ printf("\n result from dns_rbtnodechain_current: %s\n",
+ dns_result_totext(result));
+ }
+
+ printf(" level_matches = %u, level_count = %u\n", chain.level_matches,
+ chain.level_count);
+}
+
+static void
+iterate(dns_rbt_t *rbt, bool forward) {
+ dns_name_t foundname, *origin;
+ dns_rbtnodechain_t chain;
+ dns_fixedname_t fixedorigin;
+ isc_result_t result;
+ isc_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin);
+
+ dns_rbtnodechain_init(&chain);
+
+ dns_name_init(&foundname, NULL);
+ origin = dns_fixedname_initname(&fixedorigin);
+
+ if (forward) {
+ printf("iterating forward\n");
+ move = dns_rbtnodechain_next;
+
+ result = dns_rbtnodechain_first(&chain, rbt, &foundname,
+ origin);
+ } else {
+ printf("iterating backward\n");
+ move = dns_rbtnodechain_prev;
+
+ result = dns_rbtnodechain_last(&chain, rbt, &foundname, origin);
+ }
+
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ printf("start not found!\n");
+ } else {
+ for (;;) {
+ if (result == DNS_R_NEWORIGIN) {
+ printf(" new origin: ");
+ print_name(origin);
+ printf("\n");
+ }
+
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NEWORIGIN)
+ {
+ print_name(&foundname);
+ printf("\n");
+ } else {
+ if (result != ISC_R_NOMORE) {
+ printf("UNEXPECTED ITERATION ERROR: %s",
+ dns_result_totext(result));
+ }
+ break;
+ }
+
+ result = move(&chain, &foundname, origin);
+ }
+ }
+}
+
+#define CMDCHECK(s) (strncasecmp(command, (s), length) == 0)
+#define PRINTERR(r) \
+ if (r != ISC_R_SUCCESS) \
+ printf("... %s\n", dns_result_totext(r));
+
+int
+main(int argc, char **argv) {
+ char *command, *arg, buffer[1024];
+ const char *whitespace;
+ dns_name_t *name, *foundname;
+ dns_fixedname_t fixedname;
+ dns_rbt_t *rbt = NULL;
+ int length, ch;
+ bool show_final_mem = false;
+ isc_result_t result;
+ void *data;
+
+ progname = strrchr(*argv, '/');
+ if (progname != NULL) {
+ progname++;
+ } else {
+ progname = *argv;
+ }
+
+ while ((ch = isc_commandline_parse(argc, argv, "m")) != -1) {
+ switch (ch) {
+ case 'm':
+ show_final_mem = true;
+ break;
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+ POST(argv);
+
+ if (argc > 1) {
+ printf("Usage: %s [-m]\n", progname);
+ exit(1);
+ }
+
+ setbuf(stdout, NULL);
+
+ /*
+ * So isc_mem_stats() can report any allocation leaks.
+ */
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ isc_mem_create(&mctx);
+
+ result = dns_rbt_create(mctx, delete_name, NULL, &rbt);
+ if (result != ISC_R_SUCCESS) {
+ printf("dns_rbt_create: %s: exiting\n",
+ dns_result_totext(result));
+ exit(1);
+ }
+
+ whitespace = " \t";
+
+ while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
+ length = strlen(buffer);
+
+ if (buffer[length - 1] != '\n') {
+ printf("line to long (%lu max), ignored\n",
+ (unsigned long)sizeof(buffer) - 2);
+ continue;
+ }
+
+ buffer[length - 1] = '\0';
+
+ command = buffer + strspn(buffer, whitespace);
+
+ if (*command == '#') {
+ continue;
+ }
+
+ arg = strpbrk(command, whitespace);
+ if (arg != NULL) {
+ *arg++ = '\0';
+ arg += strspn(arg, whitespace);
+ }
+
+ length = strlen(command);
+ if (*command != '\0') {
+ if (CMDCHECK("add")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("adding name %s\n", arg);
+ result = dns_rbt_addname(rbt, name,
+ name);
+ PRINTERR(result);
+ }
+ } else if (CMDCHECK("delete")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("deleting name %s\n", arg);
+ result = dns_rbt_deletename(rbt, name,
+ false);
+ PRINTERR(result);
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("nuke")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("nuking name %s "
+ "and its descendants\n",
+ arg);
+ result = dns_rbt_deletename(rbt, name,
+ true);
+ PRINTERR(result);
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("search")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("searching for name %s ... ",
+ arg);
+
+ foundname = dns_fixedname_initname(
+ &fixedname);
+ data = NULL;
+
+ result = dns_rbt_findname(
+ rbt, name, 0, foundname, &data);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ printf("found exact: ");
+ print_name(data);
+ putchar('\n');
+ break;
+ case DNS_R_PARTIALMATCH:
+ printf("found parent: ");
+ print_name(data);
+ printf("\n\t(foundname: ");
+ print_name(foundname);
+ printf(")\n");
+ break;
+ case ISC_R_NOTFOUND:
+ printf("NOT FOUND!\n");
+ break;
+ case ISC_R_NOMEMORY:
+ printf("OUT OF MEMORY!\n");
+ break;
+ default:
+ printf("UNEXPECTED RESULT\n");
+ }
+
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("check")) {
+ /*
+ * Or "chain". I know, I know. Lame name.
+ * I was having a hard time thinking of a
+ * name (especially one that did not have
+ * a conflicting first letter with another
+ * command) that would differentiate this
+ * from the search command.
+ *
+ * But it is just a test program, eh?
+ */
+ name = create_name(arg);
+ if (name != NULL) {
+ detail(rbt, name);
+
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("forward")) {
+ iterate(rbt, true);
+ } else if (CMDCHECK("backward")) {
+ iterate(rbt, false);
+ } else if (CMDCHECK("print")) {
+ if (arg == NULL || *arg == '\0') {
+ dns_rbt_printtext(rbt, NULL, stdout);
+ } else {
+ printf("usage: print\n");
+ }
+ } else if (CMDCHECK("quit")) {
+ if (arg == NULL || *arg == '\0') {
+ break;
+ } else {
+ printf("usage: quit\n");
+ }
+ } else {
+ printf("a(dd) NAME, d(elete) NAME, "
+ "s(earch) NAME, p(rint), or q(uit)\n");
+ }
+ }
+ }
+
+ dns_rbt_destroy(&rbt);
+
+ if (show_final_mem) {
+ isc_mem_stats(mctx, stderr);
+ }
+
+ return (0);
+}