]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-read.c
Happy new year (belated)
[openldap] / tests / progs / slapd-read.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2014 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( char *uri, char *manager, struct berval *passwd,
45         char *entry, LDAP **ld,
46         char **attrs, int noattrs, int nobind, int maxloop,
47         int maxretries, int delay, int force, int chaserefs );
48
49 static void
50 do_random( char *uri, char *manager, struct berval *passwd,
51         char *sbase, char *filter, char **attrs, int noattrs, int nobind,
52         int innerloop, int maxretries, int delay, int force, int chaserefs );
53
54 static void
55 usage( char *name )
56 {
57         fprintf( stderr,
58                 "usage: %s "
59                 "-H <uri> | ([-h <host>] -p <port>) "
60                 "-D <manager> "
61                 "-w <passwd> "
62                 "-e <entry> "
63                 "[-A] "
64                 "[-C] "
65                 "[-F] "
66                 "[-N] "
67                 "[-f filter] "
68                 "[-i <ignore>] "
69                 "[-l <loops>] "
70                 "[-L <outerloops>] "
71                 "[-r <maxretries>] "
72                 "[-t <delay>] "
73                 "[-T <attrs>] "
74                 "[<attrs>] "
75                 "\n",
76                 name );
77         exit( EXIT_FAILURE );
78 }
79
80 /* -S: just send requests without reading responses
81  * -SS: send all requests asynchronous and immediately start reading responses
82  * -SSS: send all requests asynchronous; then read responses
83  */
84 static int swamp;
85
86 int
87 main( int argc, char **argv )
88 {
89         int             i;
90         char            *uri = NULL;
91         char            *host = "localhost";
92         int             port = -1;
93         char            *manager = NULL;
94         struct berval   passwd = { 0, NULL };
95         char            *entry = NULL;
96         char            *filter  = NULL;
97         int             loops = LOOPS;
98         int             outerloops = 1;
99         int             retries = RETRIES;
100         int             delay = 0;
101         int             force = 0;
102         int             chaserefs = 0;
103         char            *srchattrs[] = { "1.1", NULL };
104         char            **attrs = srchattrs;
105         int             noattrs = 0;
106         int             nobind = 0;
107
108         tester_init( "slapd-read", TESTER_READ );
109
110         /* by default, tolerate referrals and no such object */
111         tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
112
113         while ( (i = getopt( argc, argv, "ACD:e:Ff:H:h:i:L:l:p:r:St:T:w:" )) != EOF ) {
114                 switch ( i ) {
115                 case 'A':
116                         noattrs++;
117                         break;
118
119                 case 'C':
120                         chaserefs++;
121                         break;
122
123                 case 'H':               /* the server uri */
124                         uri = strdup( optarg );
125                         break;
126
127                 case 'h':               /* the servers host */
128                         host = strdup( optarg );
129                         break;
130
131                 case 'i':
132                         tester_ignore_str2errlist( optarg );
133                         break;
134
135                 case 'N':
136                         nobind++;
137                         break;
138
139                 case 'p':               /* the servers port */
140                         if ( lutil_atoi( &port, optarg ) != 0 ) {
141                                 usage( argv[0] );
142                         }
143                         break;
144
145                 case 'D':               /* the servers manager */
146                         manager = strdup( optarg );
147                         break;
148
149                 case 'w':               /* the server managers password */
150                         passwd.bv_val = strdup( optarg );
151                         passwd.bv_len = strlen( optarg );
152                         memset( optarg, '*', passwd.bv_len );
153                         break;
154
155                 case 'e':               /* DN to search for */
156                         entry = strdup( optarg );
157                         break;
158
159                 case 'f':               /* the search request */
160                         filter = strdup( optarg );
161                         break;
162
163                 case 'F':
164                         force++;
165                         break;
166
167                 case 'l':               /* the number of loops */
168                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
169                                 usage( argv[0] );
170                         }
171                         break;
172
173                 case 'L':               /* the number of outerloops */
174                         if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
175                                 usage( argv[0] );
176                         }
177                         break;
178
179                 case 'r':               /* the number of retries */
180                         if ( lutil_atoi( &retries, optarg ) != 0 ) {
181                                 usage( argv[0] );
182                         }
183                         break;
184
185                 case 'S':
186                         swamp++;
187                         break;
188
189                 case 't':               /* delay in seconds */
190                         if ( lutil_atoi( &delay, optarg ) != 0 ) {
191                                 usage( argv[0] );
192                         }
193                         break;
194
195                 case 'T':
196                         attrs = ldap_str2charray( optarg, "," );
197                         if ( attrs == NULL ) {
198                                 usage( argv[0] );
199                         }
200                         break;
201
202                 default:
203                         usage( argv[0] );
204                         break;
205                 }
206         }
207
208         if (( entry == NULL ) || ( port == -1 && uri == NULL ))
209                 usage( argv[0] );
210
211         if ( *entry == '\0' ) {
212                 fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
213                                 argv[0] );
214                 exit( EXIT_FAILURE );
215         }
216
217         if ( argv[optind] != NULL ) {
218                 attrs = &argv[optind];
219         }
220
221         uri = tester_uri( uri, host, port );
222
223         for ( i = 0; i < outerloops; i++ ) {
224                 if ( filter != NULL ) {
225                         do_random( uri, manager, &passwd, entry, filter, attrs,
226                                 noattrs, nobind, loops, retries, delay, force,
227                                 chaserefs );
228
229                 } else {
230                         do_read( uri, manager, &passwd, entry, NULL, attrs,
231                                 noattrs, nobind, loops, retries, delay, force,
232                                 chaserefs );
233                 }
234         }
235
236         exit( EXIT_SUCCESS );
237 }
238
239 static void
240 do_random( char *uri, char *manager, struct berval *passwd,
241         char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
242         int innerloop, int maxretries, int delay, int force, int chaserefs )
243 {
244         LDAP    *ld = NULL;
245         int     i = 0, do_retry = maxretries;
246         char    *attrs[ 2 ];
247         int     rc = LDAP_SUCCESS;
248         int     version = LDAP_VERSION3;
249         int     nvalues = 0;
250         char    **values = NULL;
251         LDAPMessage *res = NULL, *e = NULL;
252
253         attrs[ 0 ] = LDAP_NO_ATTRS;
254         attrs[ 1 ] = NULL;
255
256         ldap_initialize( &ld, uri );
257         if ( ld == NULL ) {
258                 tester_perror( "ldap_initialize", NULL );
259                 exit( EXIT_FAILURE );
260         }
261
262         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
263         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
264                 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
265
266         if ( do_retry == maxretries ) {
267                 fprintf( stderr, "PID=%ld - Read(%d): base=\"%s\", filter=\"%s\".\n",
268                                 (long) pid, innerloop, sbase, filter );
269         }
270
271         if ( nobind == 0 ) {
272                 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
273                 if ( rc != LDAP_SUCCESS ) {
274                         tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
275                         switch ( rc ) {
276                         case LDAP_BUSY:
277                         case LDAP_UNAVAILABLE:
278                         /* fallthru */
279                         default:
280                                 break;
281                         }
282                         exit( EXIT_FAILURE );
283                 }
284         }
285
286         rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
287                 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
288         switch ( rc ) {
289         case LDAP_SIZELIMIT_EXCEEDED:
290         case LDAP_TIMELIMIT_EXCEEDED:
291         case LDAP_SUCCESS:
292                 nvalues = ldap_count_entries( ld, res );
293                 if ( nvalues == 0 ) {
294                         if ( rc ) {
295                                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
296                         }
297                         break;
298                 }
299
300                 values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
301                 for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
302                 {
303                         values[ i ] = ldap_get_dn( ld, e );
304                 }
305                 values[ i ] = NULL;
306
307                 ldap_msgfree( res );
308
309                 if ( do_retry == maxretries ) {
310                         fprintf( stderr, "  PID=%ld - Read base=\"%s\" filter=\"%s\" got %d values.\n",
311                                 (long) pid, sbase, filter, nvalues );
312                 }
313
314                 for ( i = 0; i < innerloop; i++ ) {
315 #if 0   /* use high-order bits for better randomness (Numerical Recipes in "C") */
316                         int     r = rand() % nvalues;
317 #endif
318                         int     r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
319
320                         do_read( uri, manager, passwd, values[ r ], &ld,
321                                 srchattrs, noattrs, nobind, 1, maxretries,
322                                 delay, force, chaserefs );
323                 }
324                 free( values );
325                 break;
326
327         default:
328                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
329                 break;
330         }
331
332         fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
333
334         if ( ld != NULL ) {
335                 ldap_unbind_ext( ld, NULL, NULL );
336         }
337 }
338
339 static void
340 do_read( char *uri, char *manager, struct berval *passwd, char *entry,
341         LDAP **ldp, char **attrs, int noattrs, int nobind, int maxloop,
342         int maxretries, int delay, int force, int chaserefs )
343 {
344         LDAP    *ld = ldp ? *ldp : NULL;
345         int     i = 0, do_retry = maxretries;
346         int     rc = LDAP_SUCCESS;
347         int             version = LDAP_VERSION3;
348         int             *msgids = NULL, active = 0;
349
350         /* make room for msgid */
351         if ( swamp > 1 ) {
352                 msgids = (int *)calloc( sizeof(int), maxloop );
353         }
354
355 retry:;
356         if ( ld == NULL ) {
357                 ldap_initialize( &ld, uri );
358                 if ( ld == NULL ) {
359                         tester_perror( "ldap_initialize", NULL );
360                         exit( EXIT_FAILURE );
361                 }
362
363                 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
364                 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
365                         chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
366
367                 if ( do_retry == maxretries ) {
368                         fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
369                                 (long) pid, maxloop, entry );
370                 }
371
372                 if ( nobind == 0 ) {
373                         rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
374                         if ( rc != LDAP_SUCCESS ) {
375                                 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
376                                 switch ( rc ) {
377                                 case LDAP_BUSY:
378                                 case LDAP_UNAVAILABLE:
379                                         if ( do_retry > 0 ) {
380                                                 ldap_unbind_ext( ld, NULL, NULL );
381                                                 ld = NULL;
382                                                 do_retry--;
383                                                 if ( delay != 0 ) {
384                                                     sleep( delay );
385                                                 }
386                                                 goto retry;
387                                         }
388                                 /* fallthru */
389                                 default:
390                                         break;
391                                 }
392                                 exit( EXIT_FAILURE );
393                         }
394                 }
395         }
396
397         if ( swamp > 1 ) {
398                 do {
399                         LDAPMessage *res = NULL;
400                         int j, msgid;
401
402                         if ( i < maxloop ) {
403                                 rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
404                                                 NULL, attrs, noattrs, NULL, NULL,
405                                                 NULL, LDAP_NO_LIMIT, &msgids[i] );
406
407                                 active++;
408 #if 0
409                                 fprintf( stderr,
410                                         ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d msgid=%d: "
411                                         "entry=\"%s\"\n",
412                                         (long) pid, maxloop, i, active, msgids[i],
413                                         entry );
414 #endif
415                                 i++;
416
417                                 if ( rc ) {
418                                         char buf[BUFSIZ];
419                                         int first = tester_ignore_err( rc );
420                                         /* if ignore.. */
421                                         if ( first ) {
422                                                 /* only log if first occurrence */
423                                                 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
424                                                         tester_ldap_error( ld, "ldap_search_ext", NULL );
425                                                 }
426                                                 continue;
427                                         }
428                 
429                                         /* busy needs special handling */
430                                         snprintf( buf, sizeof( buf ), "entry=\"%s\"\n", entry );
431                                         tester_ldap_error( ld, "ldap_search_ext", buf );
432                                         if ( rc == LDAP_BUSY && do_retry > 0 ) {
433                                                 ldap_unbind_ext( ld, NULL, NULL );
434                                                 ld = NULL;
435                                                 do_retry--;
436                                                 goto retry;
437                                         }
438                                         break;
439                                 }
440
441                                 if ( swamp > 2 ) {
442                                         continue;
443                                 }
444                         }
445
446                         rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
447                         switch ( rc ) {
448                         case -1:
449                                 /* gone really bad */
450 #if 0
451                                 fprintf( stderr,
452                                         ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d: "
453                                         "entry=\"%s\" ldap_result()=%d\n",
454                                         (long) pid, maxloop, i, active, entry, rc );
455 #endif
456                                 goto cleanup;
457         
458                         case 0:
459                                 /* timeout (impossible) */
460                                 break;
461         
462                         case LDAP_RES_SEARCH_ENTRY:
463                         case LDAP_RES_SEARCH_REFERENCE:
464                                 /* ignore */
465                                 break;
466         
467                         case LDAP_RES_SEARCH_RESULT:
468                                 /* just remove, no error checking (TODO?) */
469                                 msgid = ldap_msgid( res );
470                                 ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
471                                 res = NULL;
472
473                                 /* linear search, bah */
474                                 for ( j = 0; j < i; j++ ) {
475                                         if ( msgids[ j ] == msgid ) {
476                                                 msgids[ j ] = -1;
477                                                 active--;
478 #if 0
479                                                 fprintf( stderr,
480                                                         "<<< PID=%ld - ReadDone maxloop=%d cnt=%d active=%d msgid=%d: "
481                                                         "entry=\"%s\"\n",
482                                                         (long) pid, maxloop, j, active, msgid, entry );
483 #endif
484                                                 break;
485                                         }
486                                 }
487                                 break;
488
489                         default:
490                                 /* other messages unexpected */
491                                 fprintf( stderr,
492                                         "### PID=%ld - Read(%d): "
493                                         "entry=\"%s\" attrs=%s%s. unexpected response tag=%d\n",
494                                         (long) pid, maxloop,
495                                         entry, attrs[0], attrs[1] ? " (more...)" : "", rc );
496                                 break;
497                         }
498
499                         if ( res != NULL ) {
500                                 ldap_msgfree( res );
501                         }
502                 } while ( i < maxloop || active > 0 );
503
504         } else {
505                 for ( ; i < maxloop; i++ ) {
506                         LDAPMessage *res = NULL;
507
508                         if (swamp) {
509                                 int msgid;
510                                 rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
511                                                 NULL, attrs, noattrs, NULL, NULL,
512                                                 NULL, LDAP_NO_LIMIT, &msgid );
513                                 if ( rc == LDAP_SUCCESS ) continue;
514                                 else break;
515                         }
516         
517                         rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
518                                         NULL, attrs, noattrs, NULL, NULL, NULL,
519                                         LDAP_NO_LIMIT, &res );
520                         if ( res != NULL ) {
521                                 ldap_msgfree( res );
522                         }
523
524                         if ( rc ) {
525                                 int             first = tester_ignore_err( rc );
526                                 char            buf[ BUFSIZ ];
527         
528                                 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
529         
530                                 /* if ignore.. */
531                                 if ( first ) {
532                                         /* only log if first occurrence */
533                                         if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
534                                                 tester_ldap_error( ld, buf, NULL );
535                                         }
536                                         continue;
537                                 }
538         
539                                 /* busy needs special handling */
540                                 tester_ldap_error( ld, buf, NULL );
541                                 if ( rc == LDAP_BUSY && do_retry > 0 ) {
542                                         ldap_unbind_ext( ld, NULL, NULL );
543                                         ld = NULL;
544                                         do_retry--;
545                                         goto retry;
546                                 }
547                                 break;
548                         }
549                 }
550         }
551
552 cleanup:;
553         if ( msgids != NULL ) {
554                 free( msgids );
555         }
556
557         if ( ldp != NULL ) {
558                 *ldp = ld;
559
560         } else {
561                 fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
562
563                 if ( ld != NULL ) {
564                         ldap_unbind_ext( ld, NULL, NULL );
565                 }
566         }
567 }
568