1 /* $NetBSD: slapd-mtread.c,v 1.1.1.3 2018/02/06 01:53:12 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2017 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 /* ACKNOWLEDGEMENTS: 18 * This work was initially developed by Kurt Spanier for inclusion 19 * in OpenLDAP Software. 20 */ 21 22 /* 23 * This tool is a MT reader. It behaves like slapd-read however 24 * with one or more threads simultaneously using the same connection. 25 * If -M is enabled, then M threads will also perform write operations. 26 */ 27 28 #include <sys/cdefs.h> 29 __RCSID("$NetBSD: slapd-mtread.c,v 1.1.1.3 2018/02/06 01:53:12 christos Exp $"); 30 31 #include "portable.h" 32 33 #include <stdio.h> 34 #include "ldap_pvt_thread.h" 35 36 #include "ac/stdlib.h" 37 38 #include "ac/ctype.h" 39 #include "ac/param.h" 40 #include "ac/socket.h" 41 #include "ac/string.h" 42 #include "ac/unistd.h" 43 #include "ac/wait.h" 44 45 #include "ldap.h" 46 #include "lutil.h" 47 48 #include "ldap_pvt.h" 49 50 #include "slapd-common.h" 51 52 #define MAXCONN 512 53 #define LOOPS 100 54 #define RETRIES 0 55 #define DEFAULT_BASE "ou=people,dc=example,dc=com" 56 57 static void 58 do_conn( char *uri, char *manager, struct berval *passwd, 59 LDAP **ld, int nobind, int maxretries, int conn_num ); 60 61 static void 62 do_read( LDAP *ld, char *entry, 63 char **attrs, int noattrs, int nobind, int maxloop, 64 int maxretries, int delay, int force, int chaserefs, int idx ); 65 66 static void 67 do_random( LDAP *ld, 68 char *sbase, char *filter, char **attrs, int noattrs, int nobind, 69 int innerloop, int maxretries, int delay, int force, int chaserefs, 70 int idx ); 71 72 static void 73 do_random2( LDAP *ld, 74 char *sbase, char *filter, char **attrs, int noattrs, int nobind, 75 int innerloop, int maxretries, int delay, int force, int chaserefs, 76 int idx ); 77 78 static void * 79 do_onethread( void *arg ); 80 81 static void * 82 do_onerwthread( void *arg ); 83 84 #define MAX_THREAD 1024 85 /* Use same array for readers and writers, offset writers by MAX_THREAD */ 86 int rt_pass[MAX_THREAD*2]; 87 int rt_fail[MAX_THREAD*2]; 88 int *rwt_pass = rt_pass + MAX_THREAD; 89 int *rwt_fail = rt_fail + MAX_THREAD; 90 ldap_pvt_thread_t rtid[MAX_THREAD*2], *rwtid = rtid + MAX_THREAD; 91 92 /* 93 * Shared globals (command line args) 94 */ 95 LDAP *ld = NULL; 96 char *entry = NULL; 97 char *filter = NULL; 98 int loops = LOOPS; 99 int outerloops = 1; 100 int retries = RETRIES; 101 int delay = 0; 102 int force = 0; 103 int chaserefs = 0; 104 char *srchattrs[] = { "1.1", NULL }; 105 char **attrs = srchattrs; 106 int noattrs = 0; 107 int nobind = 0; 108 int threads = 1; 109 int rwthreads = 0; 110 int verbose = 0; 111 112 int noconns = 1; 113 LDAP **lds = NULL; 114 115 static void 116 thread_error(int idx, char *string) 117 { 118 char thrstr[BUFSIZ]; 119 120 snprintf(thrstr, BUFSIZ, "error on tidx: %d: %s", idx, string); 121 tester_error( thrstr ); 122 } 123 124 static void 125 thread_output(int idx, char *string) 126 { 127 char thrstr[BUFSIZ]; 128 129 snprintf(thrstr, BUFSIZ, "tidx: %d says: %s", idx, string); 130 tester_error( thrstr ); 131 } 132 133 static void 134 thread_verbose(int idx, char *string) 135 { 136 char thrstr[BUFSIZ]; 137 138 if (!verbose) 139 return; 140 snprintf(thrstr, BUFSIZ, "tidx: %d says: %s", idx, string); 141 tester_error( thrstr ); 142 } 143 144 static void 145 usage( char *name ) 146 { 147 fprintf( stderr, 148 "usage: %s " 149 "-H <uri> | ([-h <host>] -p <port>) " 150 "-D <manager> " 151 "-w <passwd> " 152 "-e <entry> " 153 "[-A] " 154 "[-C] " 155 "[-F] " 156 "[-N] " 157 "[-v] " 158 "[-c connections] " 159 "[-f filter] " 160 "[-i <ignore>] " 161 "[-l <loops>] " 162 "[-L <outerloops>] " 163 "[-m threads] " 164 "[-M threads] " 165 "[-r <maxretries>] " 166 "[-t <delay>] " 167 "[-T <attrs>] " 168 "[<attrs>] " 169 "\n", 170 name ); 171 exit( EXIT_FAILURE ); 172 } 173 174 int 175 main( int argc, char **argv ) 176 { 177 int i; 178 char *uri = NULL; 179 char *host = "localhost"; 180 int port = -1; 181 char *manager = NULL; 182 struct berval passwd = { 0, NULL }; 183 char outstr[BUFSIZ]; 184 int ptpass; 185 int testfail = 0; 186 187 188 tester_init( "slapd-mtread", TESTER_READ ); 189 190 /* by default, tolerate referrals and no such object */ 191 tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" ); 192 193 while ( (i = getopt( argc, argv, "ACc:D:e:Ff:H:h:i:L:l:M:m:p:r:t:T:w:v" )) != EOF ) { 194 switch ( i ) { 195 case 'A': 196 noattrs++; 197 break; 198 199 case 'C': 200 chaserefs++; 201 break; 202 203 case 'H': /* the server uri */ 204 uri = strdup( optarg ); 205 break; 206 207 case 'h': /* the servers host */ 208 host = strdup( optarg ); 209 break; 210 211 case 'i': 212 tester_ignore_str2errlist( optarg ); 213 break; 214 215 case 'N': 216 nobind++; 217 break; 218 219 case 'v': 220 verbose++; 221 break; 222 223 case 'p': /* the servers port */ 224 if ( lutil_atoi( &port, optarg ) != 0 ) { 225 usage( argv[0] ); 226 } 227 break; 228 229 case 'D': /* the servers manager */ 230 manager = strdup( optarg ); 231 break; 232 233 case 'w': /* the server managers password */ 234 passwd.bv_val = strdup( optarg ); 235 passwd.bv_len = strlen( optarg ); 236 memset( optarg, '*', passwd.bv_len ); 237 break; 238 239 case 'c': /* the number of connections */ 240 if ( lutil_atoi( &noconns, optarg ) != 0 ) { 241 usage( argv[0] ); 242 } 243 break; 244 245 case 'e': /* DN to search for */ 246 entry = strdup( optarg ); 247 break; 248 249 case 'f': /* the search request */ 250 filter = strdup( optarg ); 251 break; 252 253 case 'F': 254 force++; 255 break; 256 257 case 'l': /* the number of loops */ 258 if ( lutil_atoi( &loops, optarg ) != 0 ) { 259 usage( argv[0] ); 260 } 261 break; 262 263 case 'L': /* the number of outerloops */ 264 if ( lutil_atoi( &outerloops, optarg ) != 0 ) { 265 usage( argv[0] ); 266 } 267 break; 268 269 case 'M': /* the number of R/W threads */ 270 if ( lutil_atoi( &rwthreads, optarg ) != 0 ) { 271 usage( argv[0] ); 272 } 273 if (rwthreads > MAX_THREAD) 274 rwthreads = MAX_THREAD; 275 break; 276 277 case 'm': /* the number of threads */ 278 if ( lutil_atoi( &threads, optarg ) != 0 ) { 279 usage( argv[0] ); 280 } 281 if (threads > MAX_THREAD) 282 threads = MAX_THREAD; 283 break; 284 285 case 'r': /* the number of retries */ 286 if ( lutil_atoi( &retries, optarg ) != 0 ) { 287 usage( argv[0] ); 288 } 289 break; 290 291 case 't': /* delay in seconds */ 292 if ( lutil_atoi( &delay, optarg ) != 0 ) { 293 usage( argv[0] ); 294 } 295 break; 296 297 case 'T': 298 attrs = ldap_str2charray( optarg, "," ); 299 if ( attrs == NULL ) { 300 usage( argv[0] ); 301 } 302 break; 303 304 default: 305 usage( argv[0] ); 306 break; 307 } 308 } 309 310 if (( entry == NULL ) || ( port == -1 && uri == NULL )) 311 usage( argv[0] ); 312 313 if ( *entry == '\0' ) { 314 fprintf( stderr, "%s: invalid EMPTY entry DN.\n", 315 argv[0] ); 316 exit( EXIT_FAILURE ); 317 } 318 319 if ( argv[optind] != NULL ) { 320 attrs = &argv[optind]; 321 } 322 323 if (noconns < 1) 324 noconns = 1; 325 if (noconns > MAXCONN) 326 noconns = MAXCONN; 327 lds = (LDAP **) calloc( sizeof(LDAP *), noconns); 328 if (lds == NULL) { 329 fprintf( stderr, "%s: Memory error: calloc noconns.\n", 330 argv[0] ); 331 exit( EXIT_FAILURE ); 332 } 333 334 uri = tester_uri( uri, host, port ); 335 /* One connection and one connection only */ 336 do_conn( uri, manager, &passwd, &ld, nobind, retries, 0 ); 337 lds[0] = ld; 338 for(i = 1; i < noconns; i++) { 339 do_conn( uri, manager, &passwd, &lds[i], nobind, retries, i ); 340 } 341 342 ldap_pvt_thread_initialize(); 343 344 snprintf(outstr, BUFSIZ, "MT Test Start: conns: %d (%s)", noconns, uri); 345 tester_error(outstr); 346 snprintf(outstr, BUFSIZ, "Threads: RO: %d RW: %d", threads, rwthreads); 347 tester_error(outstr); 348 349 /* Set up read only threads */ 350 for ( i = 0; i < threads; i++ ) { 351 ldap_pvt_thread_create( &rtid[i], 0, do_onethread, &rtid[i]); 352 snprintf(outstr, BUFSIZ, "Created RO thread %d", i); 353 thread_verbose(-1, outstr); 354 } 355 /* Set up read/write threads */ 356 for ( i = 0; i < rwthreads; i++ ) { 357 ldap_pvt_thread_create( &rwtid[i], 0, do_onerwthread, &rwtid[i]); 358 snprintf(outstr, BUFSIZ, "Created RW thread %d", i + MAX_THREAD); 359 thread_verbose(-1, outstr); 360 } 361 362 ptpass = outerloops * loops; 363 364 /* wait for read only threads to complete */ 365 for ( i = 0; i < threads; i++ ) 366 ldap_pvt_thread_join(rtid[i], NULL); 367 /* wait for read/write threads to complete */ 368 for ( i = 0; i < rwthreads; i++ ) 369 ldap_pvt_thread_join(rwtid[i], NULL); 370 371 for(i = 0; i < noconns; i++) { 372 if ( lds[i] != NULL ) { 373 ldap_unbind_ext( lds[i], NULL, NULL ); 374 } 375 } 376 free( lds ); 377 378 for ( i = 0; i < threads; i++ ) { 379 snprintf(outstr, BUFSIZ, "RO thread %d pass=%d fail=%d", i, 380 rt_pass[i], rt_fail[i]); 381 tester_error(outstr); 382 if (rt_fail[i] != 0 || rt_pass[i] != ptpass) { 383 snprintf(outstr, BUFSIZ, "FAIL RO thread %d", i); 384 tester_error(outstr); 385 testfail++; 386 } 387 } 388 for ( i = 0; i < rwthreads; i++ ) { 389 snprintf(outstr, BUFSIZ, "RW thread %d pass=%d fail=%d", i + MAX_THREAD, 390 rwt_pass[i], rwt_fail[i]); 391 tester_error(outstr); 392 if (rwt_fail[i] != 0 || rwt_pass[i] != ptpass) { 393 snprintf(outstr, BUFSIZ, "FAIL RW thread %d", i); 394 tester_error(outstr); 395 testfail++; 396 } 397 } 398 snprintf(outstr, BUFSIZ, "MT Test complete" ); 399 tester_error(outstr); 400 401 if (testfail) 402 exit( EXIT_FAILURE ); 403 exit( EXIT_SUCCESS ); 404 } 405 406 static void * 407 do_onethread( void *arg ) 408 { 409 int i, j, thisconn; 410 LDAP **mlds; 411 char thrstr[BUFSIZ]; 412 int rc, refcnt = 0; 413 int idx = (ldap_pvt_thread_t *)arg - rtid; 414 415 mlds = (LDAP **) calloc( sizeof(LDAP *), noconns); 416 if (mlds == NULL) { 417 thread_error( idx, "Memory error: thread calloc for noconns" ); 418 exit( EXIT_FAILURE ); 419 } 420 421 for ( j = 0; j < outerloops; j++ ) { 422 for(i = 0; i < noconns; i++) { 423 mlds[i] = ldap_dup(lds[i]); 424 if (mlds[i] == NULL) { 425 thread_error( idx, "ldap_dup error" ); 426 } 427 } 428 rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt); 429 snprintf(thrstr, BUFSIZ, 430 "RO Thread conns: %d refcnt: %d (rc = %d)", 431 noconns, refcnt, rc); 432 thread_verbose(idx, thrstr); 433 434 thisconn = (idx + j) % noconns; 435 if (thisconn < 0 || thisconn >= noconns) 436 thisconn = 0; 437 if (mlds[thisconn] == NULL) { 438 thread_error( idx, "(failed to dup)"); 439 tester_perror( "ldap_dup", "(failed to dup)" ); 440 exit( EXIT_FAILURE ); 441 } 442 snprintf(thrstr, BUFSIZ, "Using conn %d", thisconn); 443 thread_verbose(idx, thrstr); 444 if ( filter != NULL ) { 445 if (strchr(filter, '[')) 446 do_random2( mlds[thisconn], entry, filter, attrs, 447 noattrs, nobind, loops, retries, delay, force, 448 chaserefs, idx ); 449 else 450 do_random( mlds[thisconn], entry, filter, attrs, 451 noattrs, nobind, loops, retries, delay, force, 452 chaserefs, idx ); 453 454 } else { 455 do_read( mlds[thisconn], entry, attrs, 456 noattrs, nobind, loops, retries, delay, force, 457 chaserefs, idx ); 458 } 459 for(i = 0; i < noconns; i++) { 460 (void) ldap_destroy(mlds[i]); 461 mlds[i] = NULL; 462 } 463 } 464 free( mlds ); 465 return( NULL ); 466 } 467 468 static void * 469 do_onerwthread( void *arg ) 470 { 471 int i, j, thisconn; 472 LDAP **mlds, *ld; 473 char thrstr[BUFSIZ]; 474 char dn[256], uids[32], cns[32], *base; 475 LDAPMod *attrp[5], attrs[4]; 476 char *oc_vals[] = { "top", "OpenLDAPperson", NULL }; 477 char *cn_vals[] = { NULL, NULL }; 478 char *sn_vals[] = { NULL, NULL }; 479 char *uid_vals[] = { NULL, NULL }; 480 int ret; 481 int adds = 0; 482 int dels = 0; 483 int rc, refcnt = 0; 484 int idx = (ldap_pvt_thread_t *)arg - rtid; 485 486 mlds = (LDAP **) calloc( sizeof(LDAP *), noconns); 487 if (mlds == NULL) { 488 thread_error( idx, "Memory error: thread calloc for noconns" ); 489 exit( EXIT_FAILURE ); 490 } 491 492 snprintf(uids, sizeof(uids), "rwtest%04d", idx); 493 snprintf(cns, sizeof(cns), "rwtest%04d", idx); 494 /* add setup */ 495 for (i = 0; i < 4; i++) { 496 attrp[i] = &attrs[i]; 497 attrs[i].mod_op = 0; 498 } 499 attrp[4] = NULL; 500 attrs[0].mod_type = "objectClass"; 501 attrs[0].mod_values = oc_vals; 502 attrs[1].mod_type = "cn"; 503 attrs[1].mod_values = cn_vals; 504 cn_vals[0] = &cns[0]; 505 attrs[2].mod_type = "sn"; 506 attrs[2].mod_values = sn_vals; 507 sn_vals[0] = &cns[0]; 508 attrs[3].mod_type = "uid"; 509 attrs[3].mod_values = uid_vals; 510 uid_vals[0] = &uids[0]; 511 512 for ( j = 0; j < outerloops; j++ ) { 513 for(i = 0; i < noconns; i++) { 514 mlds[i] = ldap_dup(lds[i]); 515 if (mlds[i] == NULL) { 516 thread_error( idx, "ldap_dup error" ); 517 } 518 } 519 rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt); 520 snprintf(thrstr, BUFSIZ, 521 "RW Thread conns: %d refcnt: %d (rc = %d)", 522 noconns, refcnt, rc); 523 thread_verbose(idx, thrstr); 524 525 thisconn = (idx + j) % noconns; 526 if (thisconn < 0 || thisconn >= noconns) 527 thisconn = 0; 528 if (mlds[thisconn] == NULL) { 529 thread_error( idx, "(failed to dup)"); 530 tester_perror( "ldap_dup", "(failed to dup)" ); 531 exit( EXIT_FAILURE ); 532 } 533 snprintf(thrstr, BUFSIZ, "START RW Thread using conn %d", thisconn); 534 thread_verbose(idx, thrstr); 535 536 ld = mlds[thisconn]; 537 if (entry != NULL) 538 base = entry; 539 else 540 base = DEFAULT_BASE; 541 snprintf(dn, 256, "cn=%s,%s", cns, base); 542 543 adds = 0; 544 dels = 0; 545 for (i = 0; i < loops; i++) { 546 ret = ldap_add_ext_s(ld, dn, &attrp[0], NULL, NULL); 547 if (ret == LDAP_SUCCESS) { 548 adds++; 549 ret = ldap_delete_ext_s(ld, dn, NULL, NULL); 550 if (ret == LDAP_SUCCESS) { 551 dels++; 552 rt_pass[idx]++; 553 } else { 554 thread_output(idx, ldap_err2string(ret)); 555 rt_fail[idx]++; 556 } 557 } else { 558 thread_output(idx, ldap_err2string(ret)); 559 rt_fail[idx]++; 560 } 561 } 562 563 snprintf(thrstr, BUFSIZ, 564 "INNER STOP RW Thread using conn %d (%d/%d)", 565 thisconn, adds, dels); 566 thread_verbose(idx, thrstr); 567 568 for(i = 0; i < noconns; i++) { 569 (void) ldap_destroy(mlds[i]); 570 mlds[i] = NULL; 571 } 572 } 573 574 free( mlds ); 575 return( NULL ); 576 } 577 578 static void 579 do_conn( char *uri, char *manager, struct berval *passwd, 580 LDAP **ldp, int nobind, int maxretries, int conn_num ) 581 { 582 LDAP *ld = NULL; 583 int version = LDAP_VERSION3; 584 int i = 0, do_retry = maxretries; 585 int rc = LDAP_SUCCESS; 586 char thrstr[BUFSIZ]; 587 588 retry:; 589 ldap_initialize( &ld, uri ); 590 if ( ld == NULL ) { 591 snprintf( thrstr, BUFSIZ, "connection: %d", conn_num ); 592 tester_error( thrstr ); 593 tester_perror( "ldap_initialize", NULL ); 594 exit( EXIT_FAILURE ); 595 } 596 597 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 598 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 599 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); 600 601 if ( do_retry == maxretries ) { 602 snprintf( thrstr, BUFSIZ, "do_conn #%d\n", conn_num ); 603 thread_verbose( -1, thrstr ); 604 } 605 606 if ( nobind == 0 ) { 607 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); 608 if ( rc != LDAP_SUCCESS ) { 609 snprintf( thrstr, BUFSIZ, "connection: %d", conn_num ); 610 tester_error( thrstr ); 611 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 612 switch ( rc ) { 613 case LDAP_BUSY: 614 case LDAP_UNAVAILABLE: 615 if ( do_retry > 0 ) { 616 ldap_unbind_ext( ld, NULL, NULL ); 617 ld = NULL; 618 do_retry--; 619 if ( delay != 0 ) { 620 sleep( delay ); 621 } 622 goto retry; 623 } 624 /* fallthru */ 625 default: 626 break; 627 } 628 exit( EXIT_FAILURE ); 629 } 630 } 631 *ldp = ld; 632 } 633 634 static void 635 do_random( LDAP *ld, 636 char *sbase, char *filter, char **srchattrs, int noattrs, int nobind, 637 int innerloop, int maxretries, int delay, int force, int chaserefs, 638 int idx ) 639 { 640 int i = 0, do_retry = maxretries; 641 char *attrs[ 2 ]; 642 int rc = LDAP_SUCCESS; 643 int nvalues = 0; 644 char **values = NULL; 645 LDAPMessage *res = NULL, *e = NULL; 646 char thrstr[BUFSIZ]; 647 648 attrs[ 0 ] = LDAP_NO_ATTRS; 649 attrs[ 1 ] = NULL; 650 651 snprintf( thrstr, BUFSIZ, 652 "Read(%d): base=\"%s\", filter=\"%s\".\n", 653 innerloop, sbase, filter ); 654 thread_verbose( idx, thrstr ); 655 656 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE, 657 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); 658 switch ( rc ) { 659 case LDAP_SIZELIMIT_EXCEEDED: 660 case LDAP_TIMELIMIT_EXCEEDED: 661 case LDAP_SUCCESS: 662 nvalues = ldap_count_entries( ld, res ); 663 if ( nvalues == 0 ) { 664 if ( rc ) { 665 tester_ldap_error( ld, "ldap_search_ext_s", NULL ); 666 } 667 break; 668 } 669 670 values = malloc( ( nvalues + 1 ) * sizeof( char * ) ); 671 for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) ) 672 { 673 values[ i ] = ldap_get_dn( ld, e ); 674 } 675 values[ i ] = NULL; 676 677 ldap_msgfree( res ); 678 679 if ( do_retry == maxretries ) { 680 snprintf( thrstr, BUFSIZ, 681 "Read base=\"%s\" filter=\"%s\" got %d values.\n", 682 sbase, filter, nvalues ); 683 thread_verbose( idx, thrstr ); 684 } 685 686 for ( i = 0; i < innerloop; i++ ) { 687 int r = ((double)nvalues)*rand()/(RAND_MAX + 1.0); 688 689 do_read( ld, values[ r ], 690 srchattrs, noattrs, nobind, 1, maxretries, 691 delay, force, chaserefs, idx ); 692 } 693 for( i = 0; i < nvalues; i++) { 694 if (values[i] != NULL) 695 ldap_memfree( values[i] ); 696 } 697 free( values ); 698 break; 699 700 default: 701 tester_ldap_error( ld, "ldap_search_ext_s", NULL ); 702 break; 703 } 704 705 snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc ); 706 thread_verbose( idx, thrstr ); 707 } 708 709 /* substitute a generated int into the filter */ 710 static void 711 do_random2( LDAP *ld, 712 char *sbase, char *filter, char **srchattrs, int noattrs, int nobind, 713 int innerloop, int maxretries, int delay, int force, int chaserefs, 714 int idx ) 715 { 716 int i = 0, do_retry = maxretries; 717 int rc = LDAP_SUCCESS; 718 int lo, hi, range; 719 int flen; 720 LDAPMessage *res = NULL, *e = NULL; 721 char *ptr, *ftail; 722 char thrstr[BUFSIZ]; 723 char fbuf[BUFSIZ]; 724 725 snprintf( thrstr, BUFSIZ, 726 "Read(%d): base=\"%s\", filter=\"%s\".\n", 727 innerloop, sbase, filter ); 728 thread_verbose( idx, thrstr ); 729 730 ptr = strchr(filter, '['); 731 if (!ptr) 732 return; 733 ftail = strchr(filter, ']'); 734 if (!ftail || ftail < ptr) 735 return; 736 737 sscanf(ptr, "[%d-%d]", &lo, &hi); 738 range = hi - lo + 1; 739 740 flen = ptr - filter; 741 ftail++; 742 743 for ( i = 0; i < innerloop; i++ ) { 744 int r = ((double)range)*rand()/(RAND_MAX + 1.0); 745 sprintf(fbuf, "%.*s%d%s", flen, filter, r, ftail); 746 747 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE, 748 fbuf, srchattrs, noattrs, NULL, NULL, NULL, 749 LDAP_NO_LIMIT, &res ); 750 if ( res != NULL ) { 751 ldap_msgfree( res ); 752 } 753 if ( rc == 0 ) { 754 rt_pass[idx]++; 755 } else { 756 int first = tester_ignore_err( rc ); 757 char buf[ BUFSIZ ]; 758 759 rt_fail[idx]++; 760 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry ); 761 762 /* if ignore.. */ 763 if ( first ) { 764 /* only log if first occurrence */ 765 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) { 766 tester_ldap_error( ld, buf, NULL ); 767 } 768 continue; 769 } 770 771 /* busy needs special handling */ 772 tester_ldap_error( ld, buf, NULL ); 773 if ( rc == LDAP_BUSY && do_retry > 0 ) { 774 do_retry--; 775 continue; 776 } 777 break; 778 } 779 } 780 781 snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc ); 782 thread_verbose( idx, thrstr ); 783 } 784 785 static void 786 do_read( LDAP *ld, char *entry, 787 char **attrs, int noattrs, int nobind, int maxloop, 788 int maxretries, int delay, int force, int chaserefs, int idx ) 789 { 790 int i = 0, do_retry = maxretries; 791 int rc = LDAP_SUCCESS; 792 char thrstr[BUFSIZ]; 793 794 retry:; 795 if ( do_retry == maxretries ) { 796 snprintf( thrstr, BUFSIZ, "Read(%d): entry=\"%s\".\n", 797 maxloop, entry ); 798 thread_verbose( idx, thrstr ); 799 } 800 801 snprintf(thrstr, BUFSIZ, "LD %p cnt: %d (retried %d) (%s)", \ 802 (void *) ld, maxloop, (do_retry - maxretries), entry); 803 thread_verbose( idx, thrstr ); 804 805 for ( ; i < maxloop; i++ ) { 806 LDAPMessage *res = NULL; 807 808 rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE, 809 NULL, attrs, noattrs, NULL, NULL, NULL, 810 LDAP_NO_LIMIT, &res ); 811 if ( res != NULL ) { 812 ldap_msgfree( res ); 813 } 814 815 if ( rc == 0 ) { 816 rt_pass[idx]++; 817 } else { 818 int first = tester_ignore_err( rc ); 819 char buf[ BUFSIZ ]; 820 821 rt_fail[idx]++; 822 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry ); 823 824 /* if ignore.. */ 825 if ( first ) { 826 /* only log if first occurrence */ 827 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) { 828 tester_ldap_error( ld, buf, NULL ); 829 } 830 continue; 831 } 832 833 /* busy needs special handling */ 834 tester_ldap_error( ld, buf, NULL ); 835 if ( rc == LDAP_BUSY && do_retry > 0 ) { 836 do_retry--; 837 goto retry; 838 } 839 break; 840 } 841 } 842 } 843