]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-read.c
50caadeca3285a056bcbe167cb4b167adb78d9b3
[openldap] / tests / progs / slapd-read.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2018 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 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include "ac/stdlib.h"
25
26 #include "ac/ctype.h"
27 #include "ac/param.h"
28 #include "ac/socket.h"
29 #include "ac/string.h"
30 #include "ac/unistd.h"
31 #include "ac/wait.h"
32
33 #include "ldap.h"
34 #include "lutil.h"
35
36 #include "ldap_pvt.h"
37
38 #include "slapd-common.h"
39
40 #define LOOPS   100
41 #define RETRIES 0
42
43 static void
44 do_read( struct tester_conn_args *config, char *entry, LDAP **ld,
45         char **attrs, int noattrs, int nobind, int maxloop, int force );
46
47 static void
48 do_random( struct tester_conn_args *config, char *sbase,
49         char *filter, char **attrs, int noattrs, int nobind, int force );
50
51 static void
52 usage( char *name, int opt )
53 {
54         if ( opt ) {
55                 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
56                         name, opt );
57         }
58
59         fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
60                 "-e <entry> "
61                 "[-A] "
62                 "[-F] "
63                 "[-N] "
64                 "[-S[S[S]]] "
65                 "[-f filter] "
66                 "[-T <attrs>] "
67                 "[<attrs>] "
68                 "\n",
69                 name );
70         exit( EXIT_FAILURE );
71 }
72
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
76  */
77 static int swamp;
78
79 int
80 main( int argc, char **argv )
81 {
82         int             i;
83         char            *entry = NULL;
84         char            *filter  = NULL;
85         int             force = 0;
86         char            *srchattrs[] = { "1.1", NULL };
87         char            **attrs = srchattrs;
88         int             noattrs = 0;
89         int             nobind = 0;
90         struct tester_conn_args *config;
91
92         config = tester_init( "slapd-read", TESTER_READ );
93
94         /* by default, tolerate referrals and no such object */
95         tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
96
97         while ( (i = getopt( argc, argv, TESTER_COMMON_OPTS "Ae:Ff:NST:" )) != EOF ) {
98                 switch ( i ) {
99                 case 'A':
100                         noattrs++;
101                         break;
102
103                 case 'N':
104                         nobind = TESTER_INIT_ONLY;
105                         break;
106
107                 case 'e':               /* DN to search for */
108                         entry = strdup( optarg );
109                         break;
110
111                 case 'f':               /* the search request */
112                         filter = strdup( optarg );
113                         break;
114
115                 case 'F':
116                         force++;
117                         break;
118
119                 case 'S':
120                         swamp++;
121                         break;
122
123                 case 'T':
124                         attrs = ldap_str2charray( optarg, "," );
125                         if ( attrs == NULL ) {
126                                 usage( argv[0], i );
127                         }
128                         break;
129
130                 default:
131                         if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
132                                 break;
133                         }
134                         usage( argv[0], i );
135                         break;
136                 }
137         }
138
139         if ( entry == NULL )
140                 usage( argv[0], 0 );
141
142         if ( *entry == '\0' ) {
143                 fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
144                                 argv[0] );
145                 exit( EXIT_FAILURE );
146         }
147
148         if ( argv[optind] != NULL ) {
149                 attrs = &argv[optind];
150         }
151
152         tester_config_finish( config );
153
154         for ( i = 0; i < config->outerloops; i++ ) {
155                 if ( filter != NULL ) {
156                         do_random( config, entry, filter, attrs,
157                                 noattrs, nobind, force );
158
159                 } else {
160                         do_read( config, entry, NULL, attrs,
161                                 noattrs, nobind, config->loops, force );
162                 }
163         }
164
165         exit( EXIT_SUCCESS );
166 }
167
168 static void
169 do_random( struct tester_conn_args *config, char *sbase, char *filter,
170         char **srchattrs, int noattrs, int nobind, int force )
171 {
172         LDAP    *ld = NULL;
173         int     i = 0, do_retry = config->retries;
174         char    *attrs[ 2 ];
175         int     rc = LDAP_SUCCESS;
176         int     nvalues = 0;
177         char    **values = NULL;
178         LDAPMessage *res = NULL, *e = NULL;
179
180         attrs[ 0 ] = LDAP_NO_ATTRS;
181         attrs[ 1 ] = NULL;
182
183         tester_init_ld( &ld, config, nobind );
184
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 );
188         }
189
190         rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
191                 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
192         switch ( rc ) {
193         case LDAP_SIZELIMIT_EXCEEDED:
194         case LDAP_TIMELIMIT_EXCEEDED:
195         case LDAP_SUCCESS:
196                 nvalues = ldap_count_entries( ld, res );
197                 if ( nvalues == 0 ) {
198                         if ( rc ) {
199                                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
200                         }
201                         break;
202                 }
203
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 ) )
206                 {
207                         values[ i ] = ldap_get_dn( ld, e );
208                 }
209                 values[ i ] = NULL;
210
211                 ldap_msgfree( res );
212
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 );
216                 }
217
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;
221 #endif
222                         int     r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
223
224                         do_read( config, values[ r ], &ld,
225                                 srchattrs, noattrs, nobind, 1, force );
226                 }
227                 free( values );
228                 break;
229
230         default:
231                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
232                 break;
233         }
234
235         fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
236
237         if ( ld != NULL ) {
238                 ldap_unbind_ext( ld, NULL, NULL );
239         }
240 }
241
242 static void
243 do_read( struct tester_conn_args *config, char *entry, LDAP **ldp,
244         char **attrs, int noattrs, int nobind, int maxloop, int force )
245 {
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;
250
251         /* make room for msgid */
252         if ( swamp > 1 ) {
253                 msgids = (int *)calloc( sizeof(int), maxloop );
254         }
255
256 retry:;
257         if ( ld == NULL ) {
258                 tester_init_ld( &ld, config, nobind );
259         }
260
261         if ( do_retry == config->retries ) {
262                 fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
263                         (long) pid, maxloop, entry );
264         }
265
266         if ( swamp > 1 ) {
267                 do {
268                         LDAPMessage *res = NULL;
269                         int j, msgid;
270
271                         if ( i < maxloop ) {
272                                 rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
273                                                 NULL, attrs, noattrs, NULL, NULL,
274                                                 NULL, LDAP_NO_LIMIT, &msgids[i] );
275
276                                 active++;
277 #if 0
278                                 fprintf( stderr,
279                                         ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d msgid=%d: "
280                                         "entry=\"%s\"\n",
281                                         (long) pid, maxloop, i, active, msgids[i],
282                                         entry );
283 #endif
284                                 i++;
285
286                                 if ( rc ) {
287                                         char buf[BUFSIZ];
288                                         int first = tester_ignore_err( rc );
289                                         /* if ignore.. */
290                                         if ( first ) {
291                                                 /* only log if first occurrence */
292                                                 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
293                                                         tester_ldap_error( ld, "ldap_search_ext", NULL );
294                                                 }
295                                                 continue;
296                                         }
297                 
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 );
303                                                 ld = NULL;
304                                                 do_retry--;
305                                                 goto retry;
306                                         }
307                                         break;
308                                 }
309
310                                 if ( swamp > 2 ) {
311                                         continue;
312                                 }
313                         }
314
315                         rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
316                         switch ( rc ) {
317                         case -1:
318                                 /* gone really bad */
319 #if 0
320                                 fprintf( stderr,
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 );
324 #endif
325                                 goto cleanup;
326         
327                         case 0:
328                                 /* timeout (impossible) */
329                                 break;
330         
331                         case LDAP_RES_SEARCH_ENTRY:
332                         case LDAP_RES_SEARCH_REFERENCE:
333                                 /* ignore */
334                                 break;
335         
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 );
340                                 res = NULL;
341
342                                 /* linear search, bah */
343                                 for ( j = 0; j < i; j++ ) {
344                                         if ( msgids[ j ] == msgid ) {
345                                                 msgids[ j ] = -1;
346                                                 active--;
347 #if 0
348                                                 fprintf( stderr,
349                                                         "<<< PID=%ld - ReadDone maxloop=%d cnt=%d active=%d msgid=%d: "
350                                                         "entry=\"%s\"\n",
351                                                         (long) pid, maxloop, j, active, msgid, entry );
352 #endif
353                                                 break;
354                                         }
355                                 }
356                                 break;
357
358                         default:
359                                 /* other messages unexpected */
360                                 fprintf( stderr,
361                                         "### PID=%ld - Read(%d): "
362                                         "entry=\"%s\" attrs=%s%s. unexpected response tag=%d\n",
363                                         (long) pid, maxloop,
364                                         entry, attrs[0], attrs[1] ? " (more...)" : "", rc );
365                                 break;
366                         }
367
368                         if ( res != NULL ) {
369                                 ldap_msgfree( res );
370                         }
371                 } while ( i < maxloop || active > 0 );
372
373         } else {
374                 for ( ; i < maxloop; i++ ) {
375                         LDAPMessage *res = NULL;
376
377                         if (swamp) {
378                                 int msgid;
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;
383                                 else break;
384                         }
385         
386                         rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
387                                         NULL, attrs, noattrs, NULL, NULL, NULL,
388                                         LDAP_NO_LIMIT, &res );
389                         if ( res != NULL ) {
390                                 ldap_msgfree( res );
391                         }
392
393                         if ( rc ) {
394                                 int             first = tester_ignore_err( rc );
395                                 char            buf[ BUFSIZ ];
396         
397                                 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
398         
399                                 /* if ignore.. */
400                                 if ( first ) {
401                                         /* only log if first occurrence */
402                                         if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
403                                                 tester_ldap_error( ld, buf, NULL );
404                                         }
405                                         continue;
406                                 }
407         
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 );
412                                         ld = NULL;
413                                         do_retry--;
414                                         goto retry;
415                                 }
416                                 break;
417                         }
418                 }
419         }
420
421 cleanup:;
422         if ( msgids != NULL ) {
423                 free( msgids );
424         }
425
426         if ( ldp != NULL ) {
427                 *ldp = ld;
428
429         } else {
430                 fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
431
432                 if ( ld != NULL ) {
433                         ldap_unbind_ext( ld, NULL, NULL );
434                 }
435         }
436 }
437