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