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