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