slapd-mtread.c revision 1.1.1.3.4.1 1 /* $NetBSD: slapd-mtread.c,v 1.1.1.3.4.1 2020/04/13 07:56:25 martin Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2019 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.4.1 2020/04/13 07:56:25 martin 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 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;
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