1/* $NetBSD: rbt_test.c,v 1.2.6.1 2012/06/05 21:15:19 bouyer Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2005, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id: rbt_test.c,v 1.52 2011/08/28 23:46:41 tbox Exp */ 21 22#include <config.h> 23 24#include <stdlib.h> 25 26#include <isc/commandline.h> 27#include <isc/mem.h> 28#include <isc/string.h> 29#include <isc/util.h> 30 31#include <dns/rbt.h> 32#include <dns/fixedname.h> 33#include <dns/result.h> 34 35char *progname; 36isc_mem_t *mctx; 37 38#define DNSNAMELEN 255 39 40static dns_name_t * 41create_name(char *s) { 42 int length; 43 isc_result_t result; 44 isc_buffer_t source, target; 45 static dns_name_t *name; 46 47 if (s == NULL || *s == '\0') { 48 printf("missing name argument\n"); 49 return (NULL); 50 } 51 52 length = strlen(s); 53 54 isc_buffer_init(&source, s, length); 55 isc_buffer_add(&source, length); 56 57 /* 58 * It isn't really necessary in this program to create individual 59 * memory spaces for each name structure and its associated character 60 * string. It is done here to provide a relatively easy way to test 61 * the callback from dns_rbt_deletename that is supposed to free the 62 * data associated with a node. 63 * 64 * The buffer for the actual name will immediately follow the 65 * name structure. 66 */ 67 name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN); 68 if (name == NULL) { 69 printf("out of memory!\n"); 70 return (NULL); 71 } 72 73 dns_name_init(name, NULL); 74 isc_buffer_init(&target, name + 1, DNSNAMELEN); 75 76 result = dns_name_fromtext(name, &source, dns_rootname, 0, &target); 77 78 if (result != ISC_R_SUCCESS) { 79 printf("dns_name_fromtext(%s) failed: %s\n", 80 s, dns_result_totext(result)); 81 return (NULL); 82 } 83 84 return (name); 85} 86 87static void 88delete_name(void *data, void *arg) { 89 dns_name_t *name; 90 91 UNUSED(arg); 92 name = data; 93 isc_mem_put(mctx, name, sizeof(*name) + DNSNAMELEN); 94} 95 96static void 97print_name(dns_name_t *name) { 98 isc_buffer_t target; 99 char buffer[1024]; 100 101 isc_buffer_init(&target, buffer, sizeof(buffer)); 102 103 /* 104 * ISC_FALSE means absolute names have the final dot added. 105 */ 106 dns_name_totext(name, ISC_FALSE, &target); 107 108 printf("%.*s", (int)target.used, (char *)target.base); 109} 110 111static void 112detail(dns_rbt_t *rbt, dns_name_t *name) { 113 dns_name_t *foundname, *origin, *fullname; 114 dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname; 115 dns_rbtnode_t *node1, *node2; 116 dns_rbtnodechain_t chain; 117 isc_result_t result; 118 isc_boolean_t nodes_should_match = ISC_FALSE; 119 120 dns_rbtnodechain_init(&chain, mctx); 121 122 dns_fixedname_init(&fixedorigin); 123 dns_fixedname_init(&fixedfullname); 124 dns_fixedname_init(&fixedfoundname); 125 126 origin = dns_fixedname_name(&fixedorigin); 127 fullname = dns_fixedname_name(&fixedfullname); 128 foundname = dns_fixedname_name(&fixedfoundname); 129 130 node1 = node2 = NULL; 131 132 printf("checking chain information for "); 133 print_name(name); 134 printf("\n"); 135 136 result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain, 137 DNS_RBTFIND_EMPTYDATA, NULL, NULL); 138 139 switch (result) { 140 case ISC_R_SUCCESS: 141 printf(" found exact."); 142 nodes_should_match = ISC_TRUE; 143 break; 144 case DNS_R_PARTIALMATCH: 145 printf(" found parent."); 146 break; 147 case ISC_R_NOTFOUND: 148 printf(" name not found."); 149 break; 150 default: 151 printf(" unexpected result: %s\n", dns_result_totext(result)); 152 return; 153 } 154 155 if (node1 != NULL && node1->data != NULL) { 156 printf(" data at node: "); 157 print_name(node1->data); 158 } else 159 printf(" no data at node."); 160 161 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { 162 printf("\n name from dns_rbt_findnode: "); 163 print_name(foundname); 164 } 165 166 result = dns_rbtnodechain_current(&chain, foundname, origin, &node2); 167 168 if (result == ISC_R_SUCCESS) { 169 printf("\n name from dns_rbtnodechain_current: "); 170 171 result = dns_name_concatenate(foundname, origin, 172 fullname, NULL); 173 if (result == ISC_R_SUCCESS) 174 print_name(fullname); 175 else 176 printf("%s\n", dns_result_totext(result)); 177 printf("\n (foundname = "); 178 print_name(foundname); 179 printf(", origin = "); 180 print_name(origin); 181 printf(")\n"); 182 if (nodes_should_match && node1 != node2) 183 printf(" nodes returned from each function " 184 "DO NOT match!\n"); 185 186 } else 187 printf("\n result from dns_rbtnodechain_current: %s\n", 188 dns_result_totext(result)); 189 190 printf(" level_matches = %d, level_count = %d\n", 191 chain.level_matches, chain.level_count); 192} 193 194static void 195iterate(dns_rbt_t *rbt, isc_boolean_t forward) { 196 dns_name_t foundname, *origin; 197 dns_rbtnodechain_t chain; 198 dns_fixedname_t fixedorigin; 199 isc_result_t result; 200 isc_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name, 201 dns_name_t *origin); 202 203 dns_rbtnodechain_init(&chain, mctx); 204 205 dns_name_init(&foundname, NULL); 206 dns_fixedname_init(&fixedorigin); 207 origin = dns_fixedname_name(&fixedorigin); 208 209 if (forward) { 210 printf("iterating forward\n" ); 211 move = dns_rbtnodechain_next; 212 213 result = dns_rbtnodechain_first(&chain, rbt, &foundname, 214 origin); 215 216 } else { 217 printf("iterating backward\n" ); 218 move = dns_rbtnodechain_prev; 219 220 result = dns_rbtnodechain_last(&chain, rbt, &foundname, 221 origin); 222 } 223 224 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) 225 printf("start not found!\n"); 226 227 else { 228 for (;;) { 229 if (result == DNS_R_NEWORIGIN) { 230 printf(" new origin: "); 231 print_name(origin); 232 printf("\n"); 233 } 234 235 if (result == ISC_R_SUCCESS || 236 result == DNS_R_NEWORIGIN) { 237 print_name(&foundname); 238 printf("\n"); 239 240 } else { 241 if (result != ISC_R_NOMORE) 242 printf("UNEXEPCTED ITERATION ERROR: %s", 243 dns_result_totext(result)); 244 break; 245 } 246 247 result = move(&chain, &foundname, origin); 248 } 249 } 250} 251 252 253#define CMDCHECK(s) (strncasecmp(command, (s), length) == 0) 254#define PRINTERR(r) if (r != ISC_R_SUCCESS) \ 255 printf("... %s\n", dns_result_totext(r)); 256 257int 258main(int argc, char **argv) { 259 char *command, *arg, buffer[1024]; 260 const char *whitespace; 261 dns_name_t *name, *foundname; 262 dns_fixedname_t fixedname; 263 dns_rbt_t *rbt = NULL; 264 int length, ch; 265 isc_boolean_t show_final_mem = ISC_FALSE; 266 isc_result_t result; 267 void *data; 268 269 progname = strrchr(*argv, '/'); 270 if (progname != NULL) 271 progname++; 272 else 273 progname = *argv; 274 275 while ((ch = isc_commandline_parse(argc, argv, "m")) != -1) { 276 switch (ch) { 277 case 'm': 278 show_final_mem = ISC_TRUE; 279 break; 280 } 281 } 282 283 argc -= isc_commandline_index; 284 argv += isc_commandline_index; 285 POST(argv); 286 287 if (argc > 1) { 288 printf("Usage: %s [-m]\n", progname); 289 exit(1); 290 } 291 292 setbuf(stdout, NULL); 293 294 /* 295 * So isc_mem_stats() can report any allocation leaks. 296 */ 297 isc_mem_debugging = ISC_MEM_DEBUGRECORD; 298 299 result = isc_mem_create(0, 0, &mctx); 300 if (result != ISC_R_SUCCESS) { 301 printf("isc_mem_create: %s: exiting\n", 302 dns_result_totext(result)); 303 exit(1); 304 } 305 306 result = dns_rbt_create(mctx, delete_name, NULL, &rbt); 307 if (result != ISC_R_SUCCESS) { 308 printf("dns_rbt_create: %s: exiting\n", 309 dns_result_totext(result)); 310 exit(1); 311 } 312 313 whitespace = " \t"; 314 315 while (fgets(buffer, sizeof(buffer), stdin) != NULL) { 316 length = strlen(buffer); 317 318 if (buffer[length - 1] != '\n') { 319 printf("line to long (%lu max), ignored\n", 320 (unsigned long)sizeof(buffer) - 2); 321 continue; 322 } 323 324 buffer[length - 1] = '\0'; 325 326 command = buffer + strspn(buffer, whitespace); 327 328 if (*command == '#') 329 continue; 330 331 arg = strpbrk(command, whitespace); 332 if (arg != NULL) { 333 *arg++ = '\0'; 334 arg += strspn(arg, whitespace); 335 } 336 337 length = strlen(command); 338 if (*command != '\0') { 339 if (CMDCHECK("add")) { 340 name = create_name(arg); 341 if (name != NULL) { 342 printf("adding name %s\n", arg); 343 result = dns_rbt_addname(rbt, 344 name, name); 345 PRINTERR(result); 346 } 347 348 } else if (CMDCHECK("delete")) { 349 name = create_name(arg); 350 if (name != NULL) { 351 printf("deleting name %s\n", arg); 352 result = dns_rbt_deletename(rbt, name, 353 ISC_FALSE); 354 PRINTERR(result); 355 delete_name(name, NULL); 356 } 357 358 } else if (CMDCHECK("nuke")) { 359 name = create_name(arg); 360 if (name != NULL) { 361 printf("nuking name %s " 362 "and its descendants\n", arg); 363 result = dns_rbt_deletename(rbt, name, 364 ISC_TRUE); 365 PRINTERR(result); 366 delete_name(name, NULL); 367 } 368 369 } else if (CMDCHECK("search")) { 370 name = create_name(arg); 371 if (name != NULL) { 372 printf("searching for name %s ... ", 373 arg); 374 375 dns_fixedname_init(&fixedname); 376 foundname = 377 dns_fixedname_name(&fixedname); 378 data = NULL; 379 380 result = dns_rbt_findname(rbt, name, 0, 381 foundname, 382 &data); 383 switch (result) { 384 case ISC_R_SUCCESS: 385 printf("found exact: "); 386 print_name(data); 387 putchar('\n'); 388 break; 389 case DNS_R_PARTIALMATCH: 390 printf("found parent: "); 391 print_name(data); 392 printf("\n\t(foundname: "); 393 print_name(foundname); 394 printf(")\n"); 395 break; 396 case ISC_R_NOTFOUND: 397 printf("NOT FOUND!\n"); 398 break; 399 case ISC_R_NOMEMORY: 400 printf("OUT OF MEMORY!\n"); 401 break; 402 default: 403 printf("UNEXPECTED RESULT\n"); 404 } 405 406 delete_name(name, NULL); 407 } 408 409 } else if (CMDCHECK("check")) { 410 /* 411 * Or "chain". I know, I know. Lame name. 412 * I was having a hard time thinking of a 413 * name (especially one that did not have 414 * a conflicting first letter with another 415 * command) that would differentiate this 416 * from the search command. 417 * 418 * But it is just a test program, eh? 419 */ 420 name = create_name(arg); 421 if (name != NULL) { 422 detail(rbt, name); 423 424 delete_name(name, NULL); 425 } 426 427 } else if (CMDCHECK("forward")) { 428 iterate(rbt, ISC_TRUE); 429 430 } else if (CMDCHECK("backward")) { 431 iterate(rbt, ISC_FALSE); 432 433 } else if (CMDCHECK("print")) { 434 if (arg == NULL || *arg == '\0') 435 dns_rbt_printall(rbt); 436 else 437 printf("usage: print\n"); 438 439 } else if (CMDCHECK("quit")) { 440 if (arg == NULL || *arg == '\0') 441 break; 442 else 443 printf("usage: quit\n"); 444 } else { 445 printf("a(dd) NAME, d(elete) NAME, " 446 "s(earch) NAME, p(rint), or q(uit)\n"); 447 448 } 449 } 450 451 } 452 453 dns_rbt_destroy(&rbt); 454 455 if (show_final_mem) 456 isc_mem_stats(mctx, stderr); 457 458 return (0); 459} 460