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