2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2017 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 * This work was initially developed by Kurt Spanier for inclusion
17 * in OpenLDAP Software.
24 #include "ac/stdlib.h"
28 #include "ac/socket.h"
29 #include "ac/string.h"
30 #include "ac/unistd.h"
38 #include "slapd-common.h"
44 do_read( struct tester_conn_args *config, char *entry, LDAP **ld,
45 char **attrs, int noattrs, int nobind, int maxloop, int force );
48 do_random( struct tester_conn_args *config, char *sbase,
49 char *filter, char **attrs, int noattrs, int nobind, int force );
52 usage( char *name, int opt )
55 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
59 fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
73 /* -S: just send requests without reading responses
74 * -SS: send all requests asynchronous and immediately start reading responses
75 * -SSS: send all requests asynchronous; then read responses
80 main( int argc, char **argv )
86 char *srchattrs[] = { "1.1", NULL };
87 char **attrs = srchattrs;
90 struct tester_conn_args *config;
92 config = tester_init( "slapd-read", TESTER_READ );
94 /* by default, tolerate referrals and no such object */
95 tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
97 while ( (i = getopt( argc, argv, TESTER_COMMON_OPTS "Ae:Ff:NST:" )) != EOF ) {
104 nobind = TESTER_INIT_ONLY;
107 case 'e': /* DN to search for */
108 entry = strdup( optarg );
111 case 'f': /* the search request */
112 filter = strdup( optarg );
124 attrs = ldap_str2charray( optarg, "," );
125 if ( attrs == NULL ) {
131 if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
142 if ( *entry == '\0' ) {
143 fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
145 exit( EXIT_FAILURE );
148 if ( argv[optind] != NULL ) {
149 attrs = &argv[optind];
152 tester_config_finish( config );
154 for ( i = 0; i < config->outerloops; i++ ) {
155 if ( filter != NULL ) {
156 do_random( config, entry, filter, attrs,
157 noattrs, nobind, force );
160 do_read( config, entry, NULL, attrs,
161 noattrs, nobind, config->loops, force );
165 exit( EXIT_SUCCESS );
169 do_random( struct tester_conn_args *config, char *sbase, char *filter,
170 char **srchattrs, int noattrs, int nobind, int force )
173 int i = 0, do_retry = config->retries;
175 int rc = LDAP_SUCCESS;
177 char **values = NULL;
178 LDAPMessage *res = NULL, *e = NULL;
180 attrs[ 0 ] = LDAP_NO_ATTRS;
183 tester_init_ld( &ld, config, nobind );
185 if ( do_retry == config->retries ) {
186 fprintf( stderr, "PID=%ld - Read(%d): base=\"%s\", filter=\"%s\".\n",
187 (long) pid, config->loops, sbase, filter );
190 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
191 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
193 case LDAP_SIZELIMIT_EXCEEDED:
194 case LDAP_TIMELIMIT_EXCEEDED:
196 nvalues = ldap_count_entries( ld, res );
197 if ( nvalues == 0 ) {
199 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
204 values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
205 for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
207 values[ i ] = ldap_get_dn( ld, e );
213 if ( do_retry == config->retries ) {
214 fprintf( stderr, " PID=%ld - Read base=\"%s\" filter=\"%s\" got %d values.\n",
215 (long) pid, sbase, filter, nvalues );
218 for ( i = 0; i < config->loops; i++ ) {
219 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
220 int r = rand() % nvalues;
222 int r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
224 do_read( config, values[ r ], &ld,
225 srchattrs, noattrs, nobind, 1, force );
231 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
235 fprintf( stderr, " PID=%ld - Read done (%d).\n", (long) pid, rc );
238 ldap_unbind_ext( ld, NULL, NULL );
243 do_read( struct tester_conn_args *config, char *entry, LDAP **ldp,
244 char **attrs, int noattrs, int nobind, int maxloop, int force )
246 LDAP *ld = ldp ? *ldp : NULL;
247 int i = 0, do_retry = config->retries;
248 int rc = LDAP_SUCCESS;
249 int *msgids = NULL, active = 0;
251 /* make room for msgid */
253 msgids = (int *)calloc( sizeof(int), maxloop );
258 tester_init_ld( &ld, config, nobind );
261 if ( do_retry == config->retries ) {
262 fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
263 (long) pid, maxloop, entry );
268 LDAPMessage *res = NULL;
272 rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
273 NULL, attrs, noattrs, NULL, NULL,
274 NULL, LDAP_NO_LIMIT, &msgids[i] );
279 ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d msgid=%d: "
281 (long) pid, maxloop, i, active, msgids[i],
288 int first = tester_ignore_err( rc );
291 /* only log if first occurrence */
292 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
293 tester_ldap_error( ld, "ldap_search_ext", NULL );
298 /* busy needs special handling */
299 snprintf( buf, sizeof( buf ), "entry=\"%s\"\n", entry );
300 tester_ldap_error( ld, "ldap_search_ext", buf );
301 if ( rc == LDAP_BUSY && do_retry > 0 ) {
302 ldap_unbind_ext( ld, NULL, NULL );
315 rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
318 /* gone really bad */
321 ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d: "
322 "entry=\"%s\" ldap_result()=%d\n",
323 (long) pid, maxloop, i, active, entry, rc );
328 /* timeout (impossible) */
331 case LDAP_RES_SEARCH_ENTRY:
332 case LDAP_RES_SEARCH_REFERENCE:
336 case LDAP_RES_SEARCH_RESULT:
337 /* just remove, no error checking (TODO?) */
338 msgid = ldap_msgid( res );
339 ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
342 /* linear search, bah */
343 for ( j = 0; j < i; j++ ) {
344 if ( msgids[ j ] == msgid ) {
349 "<<< PID=%ld - ReadDone maxloop=%d cnt=%d active=%d msgid=%d: "
351 (long) pid, maxloop, j, active, msgid, entry );
359 /* other messages unexpected */
361 "### PID=%ld - Read(%d): "
362 "entry=\"%s\" attrs=%s%s. unexpected response tag=%d\n",
364 entry, attrs[0], attrs[1] ? " (more...)" : "", rc );
371 } while ( i < maxloop || active > 0 );
374 for ( ; i < maxloop; i++ ) {
375 LDAPMessage *res = NULL;
379 rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
380 NULL, attrs, noattrs, NULL, NULL,
381 NULL, LDAP_NO_LIMIT, &msgid );
382 if ( rc == LDAP_SUCCESS ) continue;
386 rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
387 NULL, attrs, noattrs, NULL, NULL, NULL,
388 LDAP_NO_LIMIT, &res );
394 int first = tester_ignore_err( rc );
397 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
401 /* only log if first occurrence */
402 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
403 tester_ldap_error( ld, buf, NULL );
408 /* busy needs special handling */
409 tester_ldap_error( ld, buf, NULL );
410 if ( rc == LDAP_BUSY && do_retry > 0 ) {
411 ldap_unbind_ext( ld, NULL, NULL );
422 if ( msgids != NULL ) {
430 fprintf( stderr, " PID=%ld - Read done (%d).\n", (long) pid, rc );
433 ldap_unbind_ext( ld, NULL, NULL );