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