]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
improve referral handling
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2006 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/dirent.h>
28 #include <ac/param.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/unistd.h>
32 #include <ac/wait.h>
33
34
35 #include "ldap_defaults.h"
36 #include "lutil.h"
37
38 #include "ldap.h"
39 #include "slapd-common.h"
40
41 #define SEARCHCMD               "slapd-search"
42 #define READCMD                 "slapd-read"
43 #define ADDCMD                  "slapd-addel"
44 #define MODRDNCMD               "slapd-modrdn"
45 #define MODIFYCMD               "slapd-modify"
46 #define BINDCMD                 "slapd-bind"
47 #define MAXARGS                 100
48 #define MAXREQS                 5000
49 #define LOOPS                   100
50 #define OUTERLOOPS              "1"
51 #define RETRIES                 "0"
52
53 #define TSEARCHFILE             "do_search.0"
54 #define TREADFILE               "do_read.0"
55 #define TADDFILE                "do_add."
56 #define TMODRDNFILE             "do_modrdn.0"
57 #define TMODIFYFILE             "do_modify.0"
58 #define TBINDFILE               "do_bind.0"
59
60 static char *get_file_name( char *dirname, char *filename );
61 static int  get_search_filters( char *filename, char *filters[], char *bases[] );
62 static int  get_read_entries( char *filename, char *entries[] );
63 static void fork_child( char *prog, char **args );
64 static void     wait4kids( int nkidval );
65
66 static int      maxkids = 20;
67 static int      nkids;
68
69 #ifdef HAVE_WINSOCK
70 static HANDLE   *children;
71 static char argbuf[BUFSIZ];
72 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
73 #else
74 #define ArgDup(x) strdup(x)
75 #endif
76
77 static void
78 usage( char *name )
79 {
80         fprintf( stderr,
81                 "usage: %s "
82                 "-H <uri> | ([-h <host>] -p <port>) "
83                 "-D <manager> "
84                 "-w <passwd> "
85                 "-d <datadir> "
86                 "[-j <maxchild>] "
87                 "[-l <loops>] "
88                 "[-L <outerloops>] "
89                 "-P <progdir> "
90                 "[-r <maxretries>] "
91                 "[-t <delay>] "
92                 "[-F]\n",
93                 name );
94         exit( EXIT_FAILURE );
95 }
96
97 int
98 main( int argc, char **argv )
99 {
100         int             i, j;
101         char            *uri = NULL;
102         char            *host = "localhost";
103         char            *port = NULL;
104         char            *manager = NULL;
105         char            *passwd = NULL;
106         char            *dirname = NULL;
107         char            *progdir = NULL;
108         int             loops = LOOPS;
109         char            *outerloops = OUTERLOOPS;
110         char            *retries = RETRIES;
111         char            *delay = "0";
112         DIR             *datadir;
113         struct dirent   *file;
114         int             friendly = 0;
115         /* search */
116         char            *sfile = NULL;
117         char            *sreqs[MAXREQS];
118         char            *sbase[MAXREQS];
119         int             snum = 0;
120         char            *sargs[MAXARGS];
121         int             sanum;
122         char            scmd[MAXPATHLEN];
123         char            sloops[] = "18446744073709551615UL";
124         /* read */
125         char            *rfile = NULL;
126         char            *rreqs[MAXREQS];
127         int             rnum = 0;
128         char            *rargs[MAXARGS];
129         int             ranum;
130         char            rcmd[MAXPATHLEN];
131         char            rloops[] = "18446744073709551615UL";
132         /* addel */
133         char            *afiles[MAXREQS];
134         int             anum = 0;
135         char            *aargs[MAXARGS];
136         int             aanum;
137         char            acmd[MAXPATHLEN];
138         char            aloops[] = "18446744073709551615UL";
139         /* modrdn */
140         char            *mfile = NULL;
141         char            *mreqs[MAXREQS];
142         int             mnum = 0;
143         char            *margs[MAXARGS];
144         int             manum;
145         char            mcmd[MAXPATHLEN];
146         char            mloops[] = "18446744073709551615UL";
147         /* modify */
148         char            *modfile = NULL;
149         char            *modreqs[MAXREQS];
150         char            *moddn[MAXREQS];
151         int             modnum = 0;
152         char            *modargs[MAXARGS];
153         int             modanum;
154         char            modcmd[MAXPATHLEN];
155         char            modloops[] = "18446744073709551615UL";
156         /* bind */
157         char            *bfile = NULL;
158         char            *breqs[MAXREQS];
159         char            *bcreds[MAXREQS];
160         int             bnum = 0;
161         char            *bargs[MAXARGS];
162         int             banum;
163         char            bcmd[MAXPATHLEN];
164         char            bloops[] = "18446744073709551615UL";
165
166         char            *friendlyOpt = NULL;
167
168         tester_init( "slapd-tester" );
169
170         while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
171                 switch( i ) {
172                 case 'D':               /* slapd manager */
173                         manager = ArgDup( optarg );
174                         break;
175
176                 case 'd':               /* data directory */
177                         dirname = strdup( optarg );
178                         break;
179
180                 case 'F':
181                         friendly++;
182                         break;
183
184                 case 'H':               /* slapd uri */
185                         uri = strdup( optarg );
186                         break;
187
188                 case 'h':               /* slapd host */
189                         host = strdup( optarg );
190                         break;
191
192                 case 'j':               /* the number of parallel clients */
193                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
194                                 usage( argv[0] );
195                         }
196                         break;
197
198                 case 'l':               /* the number of loops per client */
199                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
200                                 usage( argv[0] );
201                         }
202                         break;
203
204                 case 'L':               /* the number of outerloops per client */
205                         outerloops = strdup( optarg );
206                         break;
207
208                 case 'P':               /* prog directory */
209                         progdir = strdup( optarg );
210                         break;
211
212                 case 'p':               /* the servers port number */
213                         port = strdup( optarg );
214                         break;
215
216                 case 'r':               /* the number of retries in case of error */
217                         retries = strdup( optarg );
218                         break;
219
220                 case 't':               /* the delay in seconds between each retry */
221                         delay = strdup( optarg );
222                         break;
223
224                 case 'w':               /* the managers passwd */
225                         passwd = ArgDup( optarg );
226                         break;
227
228                 default:
229                         usage( argv[0] );
230                         break;
231                 }
232         }
233
234         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
235                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
236                 usage( argv[0] );
237
238 #ifdef HAVE_WINSOCK
239         children = malloc( maxkids * sizeof(HANDLE) );
240 #endif
241         /* get the file list */
242         if ( ( datadir = opendir( dirname )) == NULL ) {
243
244                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
245                                         argv[0], dirname );
246                 exit( EXIT_FAILURE );
247
248         }
249
250         /*  look for search, read, modrdn, and add/delete files */
251         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
252
253                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
254                         sfile = get_file_name( dirname, file->d_name );
255                         continue;
256                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
257                         rfile = get_file_name( dirname, file->d_name );
258                         continue;
259                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
260                         mfile = get_file_name( dirname, file->d_name );
261                         continue;
262                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
263                         modfile = get_file_name( dirname, file->d_name );
264                         continue;
265                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
266                         && ( anum < MAXREQS )) {
267                         afiles[anum++] = get_file_name( dirname, file->d_name );
268                         continue;
269                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
270                         bfile = get_file_name( dirname, file->d_name );
271                         continue;
272                 }
273         }
274
275         closedir( datadir );
276
277         /* look for search requests */
278         if ( sfile ) {
279                 snum = get_search_filters( sfile, sreqs, sbase );
280         }
281
282         /* look for read requests */
283         if ( rfile ) {
284                 rnum = get_read_entries( rfile, rreqs );
285         }
286
287         /* look for modrdn requests */
288         if ( mfile ) {
289                 mnum = get_read_entries( mfile, mreqs );
290         }
291
292         /* look for modify requests */
293         if ( modfile ) {
294                 modnum = get_search_filters( modfile, modreqs, moddn );
295         }
296
297         /* look for bind requests */
298         if ( bfile ) {
299                 bnum = get_search_filters( bfile, bcreds, breqs );
300         }
301
302         /* setup friendly option */
303
304         switch ( friendly ) {
305         case 0:
306                 break;
307
308         case 1:
309                 friendlyOpt = "-F";
310                 break;
311
312         default:
313                 /* NOTE: right now we don't need it more than twice */
314         case 2:
315                 friendlyOpt = "-FF";
316                 break;
317         }
318
319         snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
320         snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
321         snprintf( aloops, sizeof( aloops ), "%d", loops );
322         snprintf( mloops, sizeof( mloops ), "%d", loops );
323         snprintf( modloops, sizeof( modloops ), "%d", loops );
324         snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
325
326         /*
327          * generate the search clients
328          */
329
330         sanum = 0;
331         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
332                 progdir );
333         sargs[sanum++] = scmd;
334         if ( uri ) {
335                 sargs[sanum++] = "-H";
336                 sargs[sanum++] = uri;
337         } else {
338                 sargs[sanum++] = "-h";
339                 sargs[sanum++] = host;
340                 sargs[sanum++] = "-p";
341                 sargs[sanum++] = port;
342         }
343         sargs[sanum++] = "-D";
344         sargs[sanum++] = manager;
345         sargs[sanum++] = "-w";
346         sargs[sanum++] = passwd;
347         sargs[sanum++] = "-l";
348         sargs[sanum++] = sloops;
349         sargs[sanum++] = "-L";
350         sargs[sanum++] = outerloops;
351         sargs[sanum++] = "-r";
352         sargs[sanum++] = retries;
353         sargs[sanum++] = "-t";
354         sargs[sanum++] = delay;
355         if ( friendly ) {
356                 sargs[sanum++] = friendlyOpt;
357         }
358         sargs[sanum++] = "-b";
359         sargs[sanum++] = NULL;          /* will hold the search base */
360         sargs[sanum++] = "-f";
361         sargs[sanum++] = NULL;          /* will hold the search request */
362         sargs[sanum++] = NULL;
363
364         /*
365          * generate the read clients
366          */
367
368         ranum = 0;
369         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
370                 progdir );
371         rargs[ranum++] = rcmd;
372         if ( uri ) {
373                 rargs[ranum++] = "-H";
374                 rargs[ranum++] = uri;
375         } else {
376                 rargs[ranum++] = "-h";
377                 rargs[ranum++] = host;
378                 rargs[ranum++] = "-p";
379                 rargs[ranum++] = port;
380         }
381         rargs[ranum++] = "-l";
382         rargs[ranum++] = rloops;
383         rargs[ranum++] = "-L";
384         rargs[ranum++] = outerloops;
385         rargs[ranum++] = "-r";
386         rargs[ranum++] = retries;
387         rargs[ranum++] = "-t";
388         rargs[ranum++] = delay;
389         if ( friendly ) {
390                 rargs[ranum++] = friendlyOpt;
391         }
392         rargs[ranum++] = "-e";
393         rargs[ranum++] = NULL;          /* will hold the read entry */
394         rargs[ranum++] = NULL;
395
396         /*
397          * generate the modrdn clients
398          */
399
400         manum = 0;
401         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
402                 progdir );
403         margs[manum++] = mcmd;
404         if ( uri ) {
405                 margs[manum++] = "-H";
406                 margs[manum++] = uri;
407         } else {
408                 margs[manum++] = "-h";
409                 margs[manum++] = host;
410                 margs[manum++] = "-p";
411                 margs[manum++] = port;
412         }
413         margs[manum++] = "-D";
414         margs[manum++] = manager;
415         margs[manum++] = "-w";
416         margs[manum++] = passwd;
417         margs[manum++] = "-l";
418         margs[manum++] = mloops;
419         margs[manum++] = "-L";
420         margs[manum++] = outerloops;
421         margs[manum++] = "-r";
422         margs[manum++] = retries;
423         margs[manum++] = "-t";
424         margs[manum++] = delay;
425         if ( friendly ) {
426                 margs[manum++] = friendlyOpt;
427         }
428         margs[manum++] = "-e";
429         margs[manum++] = NULL;          /* will hold the modrdn entry */
430         margs[manum++] = NULL;
431         
432         /*
433          * generate the modify clients
434          */
435
436         modanum = 0;
437         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
438                 progdir );
439         modargs[modanum++] = modcmd;
440         if ( uri ) {
441                 modargs[modanum++] = "-H";
442                 modargs[modanum++] = uri;
443         } else {
444                 modargs[modanum++] = "-h";
445                 modargs[modanum++] = host;
446                 modargs[modanum++] = "-p";
447                 modargs[modanum++] = port;
448         }
449         modargs[modanum++] = "-D";
450         modargs[modanum++] = manager;
451         modargs[modanum++] = "-w";
452         modargs[modanum++] = passwd;
453         modargs[modanum++] = "-l";
454         modargs[modanum++] = modloops;
455         modargs[modanum++] = "-L";
456         modargs[modanum++] = outerloops;
457         modargs[modanum++] = "-r";
458         modargs[modanum++] = retries;
459         modargs[modanum++] = "-t";
460         modargs[modanum++] = delay;
461         if ( friendly ) {
462                 modargs[modanum++] = friendlyOpt;
463         }
464         modargs[modanum++] = "-e";
465         modargs[modanum++] = NULL;              /* will hold the modify entry */
466         modargs[modanum++] = "-a";;
467         modargs[modanum++] = NULL;              /* will hold the ava */
468         modargs[modanum++] = NULL;
469
470         /*
471          * generate the add/delete clients
472          */
473
474         aanum = 0;
475         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
476                 progdir );
477         aargs[aanum++] = acmd;
478         if ( uri ) {
479                 aargs[aanum++] = "-H";
480                 aargs[aanum++] = uri;
481         } else {
482                 aargs[aanum++] = "-h";
483                 aargs[aanum++] = host;
484                 aargs[aanum++] = "-p";
485                 aargs[aanum++] = port;
486         }
487         aargs[aanum++] = "-D";
488         aargs[aanum++] = manager;
489         aargs[aanum++] = "-w";
490         aargs[aanum++] = passwd;
491         aargs[aanum++] = "-l";
492         aargs[aanum++] = aloops;
493         aargs[aanum++] = "-L";
494         aargs[aanum++] = outerloops;
495         aargs[aanum++] = "-r";
496         aargs[aanum++] = retries;
497         aargs[aanum++] = "-t";
498         aargs[aanum++] = delay;
499         if ( friendly ) {
500                 aargs[aanum++] = friendlyOpt;
501         }
502         aargs[aanum++] = "-f";
503         aargs[aanum++] = NULL;          /* will hold the add data file */
504         aargs[aanum++] = NULL;
505
506         /*
507          * generate the bind clients
508          */
509
510         banum = 0;
511         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
512                 progdir );
513         bargs[banum++] = bcmd;
514         if ( uri ) {
515                 bargs[banum++] = "-H";
516                 bargs[banum++] = uri;
517         } else {
518                 bargs[banum++] = "-h";
519                 bargs[banum++] = host;
520                 bargs[banum++] = "-p";
521                 bargs[banum++] = port;
522         }
523         bargs[banum++] = "-l";
524         bargs[banum++] = bloops;
525         bargs[banum++] = "-L";
526         bargs[banum++] = outerloops;
527 #if 0
528         bargs[banum++] = "-r";
529         bargs[banum++] = retries;
530         bargs[banum++] = "-t";
531         bargs[banum++] = delay;
532 #endif
533         if ( friendly ) {
534                 bargs[banum++] = friendlyOpt;
535         }
536         bargs[banum++] = "-D";
537         bargs[banum++] = NULL;
538         bargs[banum++] = "-w";
539         bargs[banum++] = NULL;
540         bargs[banum++] = NULL;
541
542         for ( j = 0; j < MAXREQS; j++ ) {
543                 if ( j < snum ) {
544
545                         sargs[sanum - 2] = sreqs[j];
546                         sargs[sanum - 4] = sbase[j];
547                         fork_child( scmd, sargs );
548
549                 }
550
551                 if ( j < rnum ) {
552
553                         rargs[ranum - 2] = rreqs[j];
554                         fork_child( rcmd, rargs );
555
556                 }
557
558                 if ( j < mnum ) {
559
560                         margs[manum - 2] = mreqs[j];
561                         fork_child( mcmd, margs );
562
563                 }
564                 if ( j < modnum ) {
565
566                         modargs[modanum - 4] = moddn[j];
567                         modargs[modanum - 2] = modreqs[j];
568                         fork_child( modcmd, modargs );
569
570                 }
571
572                 if ( j < anum ) {
573
574                         aargs[aanum - 2] = afiles[j];
575                         fork_child( acmd, aargs );
576
577                 }
578
579                 if ( j < bnum ) {
580
581                         bargs[banum - 4] = breqs[j];
582                         bargs[banum - 2] = bcreds[j];
583                         fork_child( bcmd, bargs );
584
585                 }
586
587         }
588
589         wait4kids( -1 );
590
591         exit( EXIT_SUCCESS );
592 }
593
594 static char *
595 get_file_name( char *dirname, char *filename )
596 {
597         char buf[MAXPATHLEN];
598
599         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
600                 dirname, filename );
601         return( strdup( buf ));
602 }
603
604
605 static int
606 get_search_filters( char *filename, char *filters[], char *bases[] )
607 {
608         FILE    *fp;
609         int     filter = 0;
610
611         if ( (fp = fopen( filename, "r" )) != NULL ) {
612                 char  line[BUFSIZ];
613
614                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
615                         char *nl;
616
617                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
618                                 *nl = '\0';
619                         bases[filter] = ArgDup( line );
620                         fgets( line, BUFSIZ, fp );
621                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
622                                 *nl = '\0';
623
624                         filters[filter++] = ArgDup( line );
625
626                 }
627                 fclose( fp );
628         }
629
630         return( filter );
631 }
632
633
634 static int
635 get_read_entries( char *filename, char *entries[] )
636 {
637         FILE    *fp;
638         int     entry = 0;
639
640         if ( (fp = fopen( filename, "r" )) != NULL ) {
641                 char  line[BUFSIZ];
642
643                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
644                         char *nl;
645
646                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
647                                 *nl = '\0';
648                         entries[entry++] = ArgDup( line );
649
650                 }
651                 fclose( fp );
652         }
653
654         return( entry );
655 }
656
657 #ifndef HAVE_WINSOCK
658 static void
659 fork_child( char *prog, char **args )
660 {
661         pid_t   pid;
662
663         wait4kids( maxkids );
664
665         switch ( pid = fork() ) {
666         case 0:         /* child */
667 #ifdef HAVE_EBCDIC
668                 /* The __LIBASCII execvp only handles ASCII "prog",
669                  * we still need to translate the arg vec ourselves.
670                  */
671                 { char *arg2[MAXREQS];
672                 int i;
673
674                 for (i=0; args[i]; i++) {
675                         arg2[i] = ArgDup(args[i]);
676                         __atoe(arg2[i]);
677                 }
678                 arg2[i] = NULL;
679                 args = arg2; }
680 #endif
681                 execvp( prog, args );
682                 tester_perror( "execvp" );
683                 exit( EXIT_FAILURE );
684                 break;
685
686         case -1:        /* trouble */
687                 tester_perror( "fork" );
688                 break;
689
690         default:        /* parent */
691                 nkids++;
692                 break;
693         }
694 }
695
696 static void
697 wait4kids( int nkidval )
698 {
699         int             status;
700
701         while ( nkids >= nkidval ) {
702                 wait( &status );
703
704                 if ( WIFSTOPPED(status) ) {
705                         fprintf( stderr,
706                             "stopping: child stopped with signal %d\n",
707                             (int) WSTOPSIG(status) );
708
709                 } else if ( WIFSIGNALED(status) ) {
710                         fprintf( stderr, 
711                             "stopping: child terminated with signal %d%s\n",
712                             (int) WTERMSIG(status),
713 #ifdef WCOREDUMP
714                                 WCOREDUMP(status) ? ", core dumped" : ""
715 #else
716                                 ""
717 #endif
718                                 );
719                         exit( WEXITSTATUS(status)  );
720
721                 } else if ( WEXITSTATUS(status) != 0 ) {
722                         fprintf( stderr, 
723                             "stopping: child exited with status %d\n",
724                             (int) WEXITSTATUS(status) );
725                         exit( WEXITSTATUS(status) );
726
727                 } else {
728                         nkids--;
729                 }
730         }
731 }
732 #else
733
734 static void
735 wait4kids( int nkidval )
736 {
737         int rc, i;
738
739         while ( nkids >= nkidval ) {
740                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
741                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
742                         children[i] = children[i+1];
743                 nkids--;
744         }
745 }
746
747 static void
748 fork_child( char *prog, char **args )
749 {
750         int rc;
751
752         wait4kids( maxkids );
753
754         rc = _spawnvp( _P_NOWAIT, prog, args );
755
756         if ( rc == -1 ) {
757                 tester_perror( "_spawnvp" );
758         } else {
759                 children[nkids++] = (HANDLE)rc;
760         }
761 }
762 #endif