Back to index

lightning-sunbird  0.9+nobinonly
pthreadtest.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <malloc.h>
00042 #include <values.h>
00043 #include <errno.h>
00044 #include <pthread.h>
00045 #include <synch.h>
00046 
00047 #include <ldap.h>
00048 
00049 /* Authentication and search information. */
00050 #define NAME         "cn=Directory Manager"
00051 #define PASSWORD     "rtfm11111"
00052 #define BASE         "dc=example,dc=com"
00053 #define SCOPE        LDAP_SCOPE_SUBTREE
00054 
00055 static void *modify_thread();
00056 static void *add_thread();
00057 static void *delete_thread();
00058 static void *bind_thread();
00059 static void *compare_thread();
00060 static void *search_thread();
00061 static void *my_mutex_alloc();
00062 static void my_mutex_free();
00063 void *my_sema_alloc( void );
00064 void my_sema_free( void * );
00065 int my_sema_wait( void * );
00066 int my_sema_post( void * );
00067 static void set_ld_error();
00068 static int  get_ld_error();
00069 static void set_errno();
00070 static int  get_errno();
00071 static void tsd_setup();
00072 static void tsd_cleanup();
00073 static int get_random_id( void );
00074 static char *get_id_str( int id );
00075 
00076 /* Linked list of LDAPMessage structs for search results. */
00077 typedef struct ldapmsgwrapper {
00078     LDAPMessage                    *lmw_messagep;
00079     struct ldapmsgwrapper   *lmw_next;
00080 } ldapmsgwrapper;
00081 
00082 LDAP          *ld;
00083 pthread_key_t key;
00084 int           maxid = MAXINT;
00085 int           maxops = 0;          /* zero means no limit */
00086 int           range_filters = 0;   /* if non-zero use >= and >= filters */
00087 
00088 main( int argc, char **argv )
00089 
00090 {
00091        pthread_attr_t                     attr;
00092        pthread_t                   *threadids;
00093        void                        *status;
00094        struct ldap_thread_fns             tfns;
00095        struct ldap_extra_thread_fns       extrafns;
00096        int           rc, c, errflg, i, inited_attr;
00097        int           doadd, dodelete, domodify, docompare, dosearch, dobind;
00098        int           option_extthreads, option_restart;
00099        int           each_thread_count, thread_count;
00100        extern int    optind;
00101        extern char   *optarg;
00102 
00103        doadd = dodelete = domodify = docompare = dobind = dosearch = 0;
00104        option_extthreads = option_restart = 0;
00105        inited_attr = 0;
00106        errflg = 0;
00107        each_thread_count = 1;      /* how many of each type of thread? */
00108        rc = LDAP_SUCCESS;   /* optimistic */
00109 
00110        while (( c = getopt( argc, argv, "abcdmrsERi:n:o:S:" )) != EOF ) {
00111               switch( c ) {
00112               case 'a':            /* perform add operations */
00113                      ++doadd;
00114                      break;
00115               case 'b':            /* perform bind operations */
00116                      ++dobind;
00117                      break;
00118               case 'c':            /* perform compare operations */
00119                      ++docompare;
00120                      break;
00121               case 'd':            /* perform delete operations */
00122                      ++dodelete;
00123                      break;
00124               case 'm':            /* perform modify operations */
00125                      ++domodify;
00126                      break;
00127               case 'r':            /* use range filters in searches */
00128                      ++range_filters;
00129                      break;
00130               case 's':            /* perform search operations */
00131                      ++dosearch;
00132                      break;
00133               case 'E':            /* use extended thread functions */
00134                      ++option_extthreads;
00135                      break;
00136               case 'R':            /* turn on LDAP_OPT_RESTART */
00137                      ++option_restart;
00138                      break;
00139               case 'i':            /* highest # used for entry names */
00140                      maxid = atoi( optarg );
00141                      break;
00142               case 'n':            /* # threads for each operation */
00143                      if (( each_thread_count = atoi( optarg )) < 1 ) {
00144                             fprintf( stderr, "thread count must be > 0\n" );
00145                             ++errflg;
00146                      }
00147                      break;
00148               case 'o':            /* operations to perform per thread */
00149                      if (( maxops = atoi( optarg )) < 0 ) {
00150                             fprintf( stderr,
00151                                 "operation limit must be >= 0\n" );
00152                             ++errflg;
00153                      }
00154                      break;
00155               case 'S':            /* random number seed */
00156                      if ( *optarg == 'r' ) {
00157                             int    seed = (int)time( (time_t *)0 );
00158                             srandom( seed );
00159                             printf( "Random seed: %d\n", seed );
00160                      } else {
00161                             srandom( atoi( optarg ));
00162                      }
00163                      break;
00164               default:
00165                      ++errflg;
00166                      break;
00167               }
00168        }
00169        
00170        /* Check command-line syntax. */
00171        thread_count = each_thread_count * ( doadd + dodelete + domodify
00172            + dobind + docompare + dosearch );
00173        if ( thread_count < 1 ) {
00174               fprintf( stderr,
00175                   "Specify at least one of -a, -b, -c, -d, -m, or -s\n" );
00176               ++errflg;
00177        }
00178 
00179        if ( errflg || argc - optind != 2 ) {
00180               fprintf( stderr, "usage: %s [-abcdmrsER] [-i id] [-n thr]"
00181                   " [-o oplim] [-S sd] host port\n", argv[0] );
00182               fputs( "\nWhere:\n"
00183                   "\t\"id\" is the highest entry id (name) to use"
00184                      " (default is MAXINT)\n"
00185                   "\t\"thr\" is the number of threads for each operation"
00186                      " (default is 1)\n"
00187                   "\t\"oplim\" is the number of ops done by each thread"
00188                      " (default is infinite)\n"
00189                   "\t\"sd\" is a random() number seed (default is 1).  Use"
00190                      " the letter r for\n"
00191                      "\t\tsd to seed random() using time of day.\n"
00192                   "\t\"host\" is the hostname of an LDAP directory server\n"
00193                   "\t\"port\" is the TCP port of the LDAP directory server\n"
00194                   , stderr );
00195               fputs( "\nAnd the single character options are:\n"
00196                   "\t-a\tstart thread(s) to perform add operations\n"
00197                   "\t-b\tstart thread(s) to perform bind operations\n"
00198                   "\t-c\tstart thread(s) to perform compare operations\n"
00199                   "\t-d\tstart thread(s) to perform delete operations\n"
00200                   "\t-m\tstart thread(s) to perform modify operations\n"
00201                   "\t-s\tstart thread(s) to perform search operations\n"
00202                   "\t-r\tuse range filters in searches\n"
00203                   "\t-E\tinstall LDAP_OPT_EXTRA_THREAD_FN_PTRS\n"
00204                   "\t-R\tturn on LDAP_OPT_RESTART\n", stderr );
00205 
00206               return( LDAP_PARAM_ERROR );
00207        }
00208 
00209        /* Create a key. */
00210        if ( pthread_key_create( &key, free ) != 0 ) {
00211               perror( "pthread_key_create" );
00212        }
00213        tsd_setup();
00214 
00215        /* Allocate space for thread ids */
00216        if (( threadids = (pthread_t *)calloc( thread_count,
00217            sizeof( pthread_t ))) == NULL ) {
00218               rc = LDAP_LOCAL_ERROR;
00219               goto clean_up_and_return;
00220        }
00221 
00222 
00223        /* Initialize the LDAP session. */
00224        if (( ld = ldap_init( argv[optind], atoi( argv[optind+1] ))) == NULL ) {
00225               perror( "ldap_init" );
00226               rc = LDAP_LOCAL_ERROR;
00227               goto clean_up_and_return;
00228        }
00229 
00230        /* Set the function pointers for dealing with mutexes
00231           and error information. */
00232        memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
00233        tfns.ltf_mutex_alloc = (void *(*)(void)) my_mutex_alloc;
00234        tfns.ltf_mutex_free = (void (*)(void *)) my_mutex_free;
00235        tfns.ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock;
00236        tfns.ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock;
00237        tfns.ltf_get_errno = get_errno;
00238        tfns.ltf_set_errno = set_errno;
00239        tfns.ltf_get_lderrno = get_ld_error;
00240        tfns.ltf_set_lderrno = set_ld_error;
00241        tfns.ltf_lderrno_arg = NULL;
00242 
00243        /* Set up this session to use those function pointers. */
00244 
00245        rc = ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns );
00246        if ( rc < 0 ) {
00247               rc = ldap_get_lderrno( ld, NULL, NULL );
00248               fprintf( stderr,
00249                   "ldap_set_option (LDAP_OPT_THREAD_FN_PTRS): %s\n",
00250                   ldap_err2string( rc ) );
00251               goto clean_up_and_return;
00252        }
00253 
00254        if ( option_extthreads ) {
00255               /* Set the function pointers for working with semaphores. */
00256 
00257               memset( &extrafns, '\0', sizeof(struct ldap_extra_thread_fns) );
00258               extrafns.ltf_mutex_trylock =
00259                   (int (*)(void *)) pthread_mutex_trylock;
00260               extrafns.ltf_sema_alloc = (void *(*)(void)) my_sema_alloc;
00261               extrafns.ltf_sema_free = (void (*)(void *)) my_sema_free;
00262               extrafns.ltf_sema_wait = (int (*)(void *)) my_sema_wait;
00263               extrafns.ltf_sema_post = (int (*)(void *)) my_sema_post;
00264 
00265               /* Set up this session to use those function pointers. */
00266 
00267               if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
00268                   (void *) &extrafns ) != 0 ) {
00269                      rc = ldap_get_lderrno( ld, NULL, NULL );
00270                      ldap_perror( ld, "ldap_set_option"
00271                          " (LDAP_OPT_EXTRA_THREAD_FN_PTRS)" );
00272                      goto clean_up_and_return;
00273               }
00274        }
00275 
00276 
00277        if ( option_restart && ldap_set_option( ld, LDAP_OPT_RESTART,
00278            LDAP_OPT_ON ) != 0 ) {
00279               rc = ldap_get_lderrno( ld, NULL, NULL );
00280               ldap_perror( ld, "ldap_set_option(LDAP_OPT_RESTART)" );
00281               goto clean_up_and_return;
00282        }
00283 
00284        /* Attempt to bind to the server. */
00285        rc = ldap_simple_bind_s( ld, NAME, PASSWORD );
00286        if ( rc != LDAP_SUCCESS ) {
00287               fprintf( stderr, "ldap_simple_bind_s: %s\n",
00288                   ldap_err2string( rc ) );
00289               goto clean_up_and_return;
00290        }
00291 
00292        /* Initialize the attribute. */
00293        if ( pthread_attr_init( &attr ) != 0 ) {
00294               perror( "pthread_attr_init" );
00295               rc = LDAP_LOCAL_ERROR;
00296               goto clean_up_and_return;
00297        }
00298        ++inited_attr;
00299 
00300        /* Specify that the threads are joinable. */
00301        pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
00302 
00303        /* Create all the requested threads */
00304        thread_count = 0;
00305        if ( domodify ) {
00306               for ( i = 0; i < each_thread_count; ++i ) {
00307                      if ( pthread_create( &threadids[thread_count], &attr,
00308                          modify_thread, get_id_str(thread_count) ) != 0 ) {
00309                             perror( "pthread_create modify_thread" );
00310                          rc = LDAP_LOCAL_ERROR;
00311                          goto clean_up_and_return;
00312                      }
00313                      ++thread_count;
00314               }
00315        }
00316 
00317        if ( doadd ) {
00318               for ( i = 0; i < each_thread_count; ++i ) {
00319                      if ( pthread_create( &threadids[thread_count], &attr,
00320                          add_thread, get_id_str(thread_count) ) != 0 ) {
00321                             perror( "pthread_create add_thread" );
00322                          rc = LDAP_LOCAL_ERROR;
00323                          goto clean_up_and_return;
00324                      }
00325                      ++thread_count;
00326               }
00327        }
00328 
00329        if ( dodelete ) {
00330               for ( i = 0; i < each_thread_count; ++i ) {
00331                      if ( pthread_create( &threadids[thread_count], &attr,
00332                          delete_thread, get_id_str(thread_count) ) != 0 ) {
00333                             perror( "pthread_create delete_thread" );
00334                          rc = LDAP_LOCAL_ERROR;
00335                          goto clean_up_and_return;
00336                      }
00337                      ++thread_count;
00338               }
00339        }
00340 
00341        if ( dobind ) {
00342               for ( i = 0; i < each_thread_count; ++i ) {
00343                      if ( pthread_create( &threadids[thread_count], &attr,
00344                          bind_thread, get_id_str(thread_count) ) != 0 ) {
00345                             perror( "pthread_create bind_thread" );
00346                          rc = LDAP_LOCAL_ERROR;
00347                          goto clean_up_and_return;
00348                      }
00349                      ++thread_count;
00350               }
00351        }
00352 
00353        if ( docompare ) {
00354               for ( i = 0; i < each_thread_count; ++i ) {
00355                      if ( pthread_create( &threadids[thread_count], &attr,
00356                          compare_thread, get_id_str(thread_count) ) != 0 ) {
00357                             perror( "pthread_create compare_thread" );
00358                          rc = LDAP_LOCAL_ERROR;
00359                          goto clean_up_and_return;
00360                      }
00361                      ++thread_count;
00362               }
00363        }
00364 
00365        if ( dosearch ) {
00366               for ( i = 0; i < each_thread_count; ++i ) {
00367                      if ( pthread_create( &threadids[thread_count], &attr,
00368                          search_thread, get_id_str(thread_count) ) != 0 ) {
00369                             perror( "pthread_create search_thread" );
00370                          rc = LDAP_LOCAL_ERROR;
00371                          goto clean_up_and_return;
00372                      }
00373                      ++thread_count;
00374               }
00375        }
00376 
00377        /* Wait until these threads exit. */
00378        for ( i = 0; i < thread_count; ++i ) {
00379               pthread_join( threadids[i], &status );
00380        }
00381 
00382 clean_up_and_return:
00383        if ( ld != NULL ) {
00384               set_ld_error( 0, NULL, NULL, NULL );  /* disposes of memory */
00385               ldap_unbind( ld );
00386        }
00387        if ( threadids != NULL ) {
00388               free( threadids );
00389        }
00390        if ( inited_attr ) {
00391               pthread_attr_destroy( &attr );
00392        }
00393        tsd_cleanup();
00394 
00395        return( rc );
00396 }
00397 
00398 
00399 static void *
00400 modify_thread( char *id )
00401 {
00402        LDAPMessage   *res;
00403        LDAPMessage   *e;
00404        int           i, modentry, num_entries, msgid, parse_rc, finished;
00405        int           rc, opcount;
00406        LDAPMod              mod;
00407        LDAPMod              *mods[2];
00408        char          *vals[2];
00409        char          *dn;
00410        ldapmsgwrapper       *list, *lmwp, *lastlmwp;
00411        struct timeval       zerotime;
00412        void          *voidrc = (void *)0;
00413 
00414        zerotime.tv_sec = zerotime.tv_usec = 0L;
00415 
00416        printf( "Starting modify_thread %s.\n", id );
00417        opcount = 0;
00418        tsd_setup();
00419 
00420        rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)",
00421               NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid );
00422        if ( rc != LDAP_SUCCESS ) {
00423               fprintf( stderr, "Thread %s error: Modify thread: "
00424               "ldap_search_ext: %s\n", id, ldap_err2string( rc ) );
00425               exit( 1 );
00426        }
00427        list = lastlmwp = NULL;
00428        finished = 0;
00429        num_entries = 0;
00430        while ( !finished ) {
00431               rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res );
00432               switch ( rc ) {
00433               case -1:
00434                      rc = ldap_get_lderrno( ld, NULL, NULL );
00435                      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
00436                      exit( 1 );
00437                      break;
00438               case 0:
00439                      break;
00440               /* Keep track of the number of entries found. */
00441               case LDAP_RES_SEARCH_ENTRY:
00442                      num_entries++;
00443                      if (( lmwp = (ldapmsgwrapper *)
00444                             malloc( sizeof( ldapmsgwrapper ))) == NULL ) {
00445                             fprintf( stderr, "Thread %s: Modify thread: Cannot malloc\n", id );
00446                             exit( 1 );
00447                      }
00448                      lmwp->lmw_messagep = res;
00449                      lmwp->lmw_next = NULL;
00450                      if ( lastlmwp == NULL ) {
00451                             list = lastlmwp = lmwp;
00452                      } else {
00453                             lastlmwp->lmw_next = lmwp;
00454                      }
00455                      lastlmwp = lmwp;
00456                      break;
00457               case LDAP_RES_SEARCH_REFERENCE:
00458                      break;
00459               case LDAP_RES_SEARCH_RESULT:
00460                      finished = 1;
00461                      parse_rc = ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
00462                      if ( parse_rc != LDAP_SUCCESS ) {
00463                             fprintf( stderr, "Thread %s error: can't parse result code.\n", id );
00464                             exit( 1 );
00465                      } else {
00466                             if ( rc != LDAP_SUCCESS ) {
00467                                    fprintf( stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string( rc ) );
00468                             } else {
00469                                    printf( "Thread %s: Got %d results.\n", id, num_entries );
00470                             }
00471                      }
00472                      break;
00473               default:
00474                      break;
00475               }
00476        }
00477 
00478        mods[0] = &mod;
00479        mods[1] = NULL;
00480        vals[0] = "bar";
00481        vals[1] = NULL;
00482 
00483        for ( ;; ) {
00484               modentry = random() % num_entries;
00485               for ( i = 0, lmwp = list; lmwp != NULL && i < modentry;
00486                   i++, lmwp = lmwp->lmw_next ) {
00487                      /* NULL */
00488               }
00489 
00490               if ( lmwp == NULL ) {
00491                      fprintf( stderr,
00492                          "Thread %s: Modify thread could not find entry %d of %d\n",
00493                          id, modentry, num_entries );
00494                      continue;
00495               }
00496 
00497               e = lmwp->lmw_messagep;
00498               printf( "Thread %s: Modify thread picked entry %d of %d\n", id, i, num_entries );
00499               dn = ldap_get_dn( ld, e );
00500 
00501               mod.mod_op = LDAP_MOD_REPLACE;
00502               mod.mod_type = "description";
00503               mod.mod_values = vals;
00504               printf( "Thread %s: Modifying (%s)\n", id, dn );
00505 
00506               rc = ldap_modify_ext_s( ld, dn, mods, NULL, NULL );
00507               if ( rc != LDAP_SUCCESS ) {
00508                      fprintf( stderr, "ldap_modify_ext_s: %s\n",
00509                          ldap_err2string( rc ) );
00510                      if ( rc == LDAP_SERVER_DOWN ) {
00511                             perror( "ldap_modify_ext_s" );
00512                             voidrc = (void *)1;
00513                             goto modify_cleanup_and_return;
00514                      }
00515               }
00516               free( dn );
00517 
00518               ++opcount;
00519               if ( maxops != 0 && opcount >= maxops ) {
00520                      break;
00521               }
00522        }
00523 
00524 modify_cleanup_and_return:
00525        printf( "Thread %s: attempted %d modify operations\n", id, opcount );
00526        set_ld_error( 0, NULL, NULL, NULL );      /* disposes of memory */
00527        tsd_cleanup();
00528        free( id );
00529        return voidrc;
00530 }
00531 
00532 
00533 static void *
00534 add_thread( char *id )
00535 {
00536        LDAPMod       mod[4];
00537        LDAPMod       *mods[5];
00538        char   dn[BUFSIZ], name[40];
00539        char   *cnvals[2], *snvals[2], *pwdvals[2], *ocvals[3];
00540        int    i, rc, opcount;
00541        void   *voidrc = (void *)0;
00542 
00543        printf( "Starting add_thread %s.\n", id );
00544        opcount = 0;
00545        tsd_setup();
00546 
00547        for ( i = 0; i < 4; i++ ) {
00548               mods[i] = &mod[i];
00549        }
00550 
00551        mods[4] = NULL;
00552 
00553        mod[0].mod_op = 0;
00554        mod[0].mod_type = "cn";
00555        mod[0].mod_values = cnvals;
00556        cnvals[1] = NULL;
00557        mod[1].mod_op = 0;
00558        mod[1].mod_type = "sn";
00559        mod[1].mod_values = snvals;
00560        snvals[1] = NULL;
00561        mod[2].mod_op = 0;
00562        mod[2].mod_type = "objectclass";
00563        mod[2].mod_values = ocvals;
00564        ocvals[0] = "top";
00565        ocvals[1] = "person";
00566        ocvals[2] = NULL;
00567        mod[3].mod_op = 0;
00568        mod[3].mod_type = "userPassword";
00569        mod[3].mod_values = pwdvals;
00570        pwdvals[1] = NULL;
00571        mods[4] = NULL;
00572 
00573        for ( ;; ) {
00574               sprintf( name, "%d", get_random_id() );
00575               sprintf( dn, "cn=%s, " BASE, name );
00576               cnvals[0] = name;
00577               snvals[0] = name;
00578               pwdvals[0] = name;
00579 
00580               printf( "Thread %s: Adding entry (%s)\n", id, dn );
00581               rc = ldap_add_ext_s( ld, dn, mods, NULL, NULL ); 
00582               if ( rc != LDAP_SUCCESS ) {
00583                      fprintf( stderr, "ldap_add_ext_s: %s\n",
00584                          ldap_err2string( rc ) );
00585                      if ( rc == LDAP_SERVER_DOWN ) {
00586                             perror( "ldap_add_ext_s" );
00587                             voidrc = (void *)1;
00588                             goto add_cleanup_and_return;
00589                      }
00590               }
00591 
00592               ++opcount;
00593               if ( maxops != 0 && opcount >= maxops ) {
00594                      break;
00595               }
00596        }
00597 
00598 add_cleanup_and_return:
00599        printf( "Thread %s: attempted %d add operations\n", id, opcount );
00600        set_ld_error( 0, NULL, NULL, NULL );      /* disposes of memory */
00601        tsd_cleanup();
00602        free( id );
00603        return voidrc;
00604 }
00605 
00606 
00607 static void *
00608 delete_thread( char *id )
00609 {
00610        LDAPMessage   *res;
00611        char          dn[BUFSIZ], name[40];
00612        int           num_entries, msgid, rc, parse_rc, finished, opcount;
00613        struct timeval       zerotime;
00614        void          *voidrc = (void *)0;
00615 
00616        zerotime.tv_sec = zerotime.tv_usec = 0L;
00617 
00618        printf( "Starting delete_thread %s.\n", id );
00619        opcount = 0;
00620        tsd_setup();
00621 
00622        rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)",
00623               NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid );
00624        if ( rc != LDAP_SUCCESS ) {
00625               fprintf( stderr, "Thread %s error: Delete thread: "
00626               "ldap_search_ext: %s\n", id, ldap_err2string( rc ) );
00627               exit( 1 );
00628        }
00629 
00630        finished = 0;
00631        num_entries = 0;
00632        while ( !finished ) {
00633               rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res );
00634               switch ( rc ) {
00635               case -1:
00636                      rc = ldap_get_lderrno( ld, NULL, NULL );
00637                      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
00638                      exit( 1 );
00639                      break;
00640               case 0:
00641                      break;
00642               /* Keep track of the number of entries found. */
00643               case LDAP_RES_SEARCH_ENTRY:
00644                      num_entries++;
00645                      break;
00646               case LDAP_RES_SEARCH_REFERENCE:
00647                      break;
00648               case LDAP_RES_SEARCH_RESULT:
00649                      finished = 1;
00650                      parse_rc = ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
00651                      if ( parse_rc != LDAP_SUCCESS ) {
00652                             fprintf( stderr, "Thread %s error: can't parse result code.\n", id );
00653                             exit( 1 );
00654                      } else {
00655                             if ( rc != LDAP_SUCCESS ) {
00656                                    fprintf( stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string( rc ) );
00657                             } else {
00658                                    printf( "Thread %s: Got %d results.\n", id, num_entries );
00659                             }
00660                      }
00661                      break;
00662               default:
00663                      break;
00664               }
00665        }
00666 
00667        for ( ;; ) {
00668               sprintf( name, "%d", get_random_id() );
00669               sprintf( dn, "cn=%s, " BASE, name );
00670               printf( "Thread %s: Deleting entry (%s)\n", id, dn );
00671 
00672               if (( rc = ldap_delete_ext_s( ld, dn, NULL, NULL ))
00673                   != LDAP_SUCCESS ) {
00674                      ldap_perror( ld, "ldap_delete_ext_s" );
00675                      if ( rc == LDAP_SERVER_DOWN ) {
00676                             perror( "ldap_delete_ext_s" );
00677                             voidrc = (void *)1;
00678                             goto delete_cleanup_and_return;
00679                      }
00680               }
00681 
00682               ++opcount;
00683               if ( maxops != 0 && opcount >= maxops ) {
00684                      break;
00685               }
00686        }
00687 
00688 delete_cleanup_and_return:
00689        printf( "Thread %s: attempted %d delete operations\n", id, opcount );
00690        set_ld_error( 0, NULL, NULL, NULL );      /* disposes of memory */
00691        tsd_cleanup();
00692        free( id );
00693        return voidrc;
00694 }
00695 
00696 
00697 static void *
00698 bind_thread( char *id )
00699 {
00700        char          dn[BUFSIZ], name[40];
00701        int           rc, opcount;
00702        void          *voidrc = (void *)0;
00703 
00704        printf( "Starting bind_thread %s.\n", id );
00705        opcount = 0;
00706        tsd_setup();
00707 
00708        for ( ;; ) {
00709               sprintf( name, "%d", get_random_id() );
00710               sprintf( dn, "cn=%s, " BASE, name );
00711               printf( "Thread %s: Binding as entry (%s)\n", id, dn );
00712 
00713               if (( rc = ldap_simple_bind_s( ld, dn, name ))
00714                   != LDAP_SUCCESS ) {
00715                      ldap_perror( ld, "ldap_simple_bind_s" );
00716                      if ( rc == LDAP_SERVER_DOWN ) {
00717                             perror( "ldap_simple_bind_s" );
00718                             voidrc = (void *)1;
00719                             goto bind_cleanup_and_return;
00720                      }
00721               } else {
00722                      printf( "Thread %s: bound as entry (%s)\n", id, dn );
00723               }
00724 
00725               ++opcount;
00726               if ( maxops != 0 && opcount >= maxops ) {
00727                      break;
00728               }
00729        }
00730 
00731 bind_cleanup_and_return:
00732        printf( "Thread %s: attempted %d bind operations\n", id, opcount );
00733        set_ld_error( 0, NULL, NULL, NULL );      /* disposes of memory */
00734        tsd_cleanup();
00735        free( id );
00736        return voidrc;
00737 }
00738 
00739 
00740 static void *
00741 compare_thread( char *id )
00742 {
00743        char          dn[BUFSIZ], name[40], cmpval[40];
00744        int           rc, randval, opcount;
00745        struct berval bv;
00746        void          *voidrc = (void *)0;
00747 
00748        printf( "Starting compare_thread %s.\n", id );
00749        opcount = 0;
00750        tsd_setup();
00751 
00752        for ( ;; ) {
00753               randval = get_random_id();
00754               sprintf( name, "%d", randval );
00755               sprintf( dn, "cn=%s, " BASE, name );
00756               sprintf( cmpval, "%d", randval + random() % 3 );
00757               bv.bv_val = cmpval;
00758               bv.bv_len = strlen( cmpval );
00759 
00760               printf( "Thread %s: Comparing cn in entry (%s) with %s\n",
00761                   id, dn, cmpval );
00762 
00763               rc = ldap_compare_ext_s( ld, dn, "cn", &bv, NULL, NULL );
00764               switch ( rc ) {
00765               case LDAP_COMPARE_TRUE:
00766                      printf( "Thread %s: entry (%s) contains cn %s\n",
00767                          id, dn, cmpval );
00768                      break;
00769               case LDAP_COMPARE_FALSE:
00770                      printf( "Thread %s: entry (%s) doesn't contain cn %s\n",
00771                          id, dn, cmpval );
00772                      break;
00773               default:
00774                      ldap_perror( ld, "ldap_compare_ext_s" );
00775                      if ( rc == LDAP_SERVER_DOWN ) {
00776                             perror( "ldap_compare_ext_s" );
00777                             voidrc = (void *)1;
00778                             goto compare_cleanup_and_return;
00779                      }
00780               }
00781 
00782               ++opcount;
00783               if ( maxops != 0 && opcount >= maxops ) {
00784                      break;
00785               }
00786        }
00787 
00788 compare_cleanup_and_return:
00789        printf( "Thread %s: attempted %d compare operations\n", id, opcount );
00790        set_ld_error( 0, NULL, NULL, NULL );      /* disposes of memory */
00791        tsd_cleanup();
00792        free( id );
00793        return voidrc;
00794 }
00795 
00796 
00797 static void *
00798 search_thread( char *id )
00799 {
00800        LDAPMessage   *res, *entry;
00801        char          *dn, filter[40];
00802        int           rc, opcount;
00803        void          *voidrc = (void *)0;
00804 
00805        printf( "Starting search_thread %s.\n", id );
00806        opcount = 0;
00807        tsd_setup();
00808 
00809        for ( ;; ) {
00810               if ( range_filters ) {
00811                      switch( get_random_id() % 3 ) {
00812                      case 0:
00813                             sprintf( filter, "(cn>=%d)", get_random_id());
00814                             break;
00815                      case 1:
00816                             sprintf( filter, "(cn<=%d)", get_random_id());
00817                             break;
00818                      case 2:
00819                             sprintf( filter, "(&(cn>=%d)(cn<=%d))",
00820                                 get_random_id(), get_random_id() );
00821                             break;
00822                      }
00823               } else {
00824                      sprintf( filter, "cn=%d", get_random_id() );
00825               }
00826 
00827               printf( "Thread %s: Searching for entry (%s)\n", id, filter );
00828 
00829               res = NULL;
00830               if (( rc = ldap_search_ext_s( ld, BASE, SCOPE, filter, NULL, 0,
00831                   NULL, NULL, NULL, 0, &res )) != LDAP_SUCCESS ) {
00832                      ldap_perror( ld, "ldap_search_ext_s" );
00833                      if ( rc == LDAP_SERVER_DOWN ) {
00834                             perror( "ldap_search_ext_s" );
00835                             voidrc = (void *)1;
00836                             goto search_cleanup_and_return;
00837                      }
00838               }
00839               if ( res != NULL ) {
00840                      entry = ldap_first_entry( ld, res );
00841                      if ( entry == NULL ) {
00842                             printf( "Thread %s: found no entries\n", id );
00843                      } else {
00844                             dn = ldap_get_dn( ld, entry );
00845                             printf(
00846                                 "Thread %s: found entry (%s); %d total\n",
00847                                 id, dn == NULL ? "(Null)" : dn,
00848                                 ldap_count_entries( ld, res ));
00849                             ldap_memfree( dn );
00850                      }
00851                      ldap_msgfree( res );
00852               }
00853 
00854               ++opcount;
00855               if ( maxops != 0 && opcount >= maxops ) {
00856                      break;
00857               }
00858        }
00859 
00860 search_cleanup_and_return:
00861        printf( "Thread %s: attempted %d search operations\n", id, opcount );
00862        set_ld_error( 0, NULL, NULL, NULL );      /* disposes of memory */
00863        tsd_cleanup();
00864        free( id );
00865        return voidrc;
00866 }
00867 
00868 
00869 static void *
00870 my_mutex_alloc( void )
00871 {
00872        pthread_mutex_t      *mutexp;
00873 
00874        if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) {
00875               pthread_mutex_init( mutexp, NULL );
00876        }
00877        return( mutexp );
00878 }
00879 
00880 
00881 void *
00882 my_sema_alloc( void )
00883 {
00884        sema_t *semptr;
00885 
00886        if( (semptr = malloc( sizeof(sema_t) ) ) != NULL ) {
00887               sema_init( semptr, 0, USYNC_THREAD, NULL );
00888        }
00889        return ( semptr );
00890 }
00891 
00892 
00893 static void
00894 my_mutex_free( void *mutexp )
00895 {
00896        pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
00897        free( mutexp );
00898 }
00899 
00900 
00901 void
00902 my_sema_free( void *semptr )
00903 {
00904        sema_destroy( (sema_t *) semptr );
00905        free( semptr );
00906 }
00907 
00908 
00909 int
00910 my_sema_wait( void *semptr )
00911 {
00912        if( semptr != NULL )
00913               return( sema_wait( (sema_t *) semptr ) );
00914        else
00915               return( -1 );
00916 }
00917 
00918 
00919 int
00920 my_sema_post( void *semptr )
00921 {
00922        if( semptr != NULL )
00923               return( sema_post( (sema_t *) semptr ) );
00924        else
00925               return( -1 );
00926 }
00927 
00928 
00929 struct ldap_error {
00930        int    le_errno;
00931        char   *le_matched;
00932        char   *le_errmsg;
00933 };
00934 
00935 
00936 static void
00937 tsd_setup()
00938 {
00939        void   *tsd;
00940        tsd = pthread_getspecific( key );
00941        if ( tsd != NULL ) {
00942               fprintf( stderr, "tsd non-null!\n" );
00943               pthread_exit( NULL );
00944        }
00945 
00946        tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
00947        pthread_setspecific( key, tsd );
00948 }
00949 
00950 
00951 static void
00952 tsd_cleanup()
00953 {
00954        void   *tsd;
00955 
00956        if (( tsd = pthread_getspecific( key )) != NULL ) {
00957               pthread_setspecific( key, NULL );
00958               free( tsd );
00959        }
00960 }
00961 
00962 
00963 static void
00964 set_ld_error( int err, char *matched, char *errmsg, void *dummy )
00965 {
00966        struct ldap_error *le;
00967 
00968        le = pthread_getspecific( key );
00969 
00970        le->le_errno = err;
00971 
00972        if ( le->le_matched != NULL ) {
00973               ldap_memfree( le->le_matched );
00974        }
00975        le->le_matched = matched;
00976 
00977        if ( le->le_errmsg != NULL ) {
00978               ldap_memfree( le->le_errmsg );
00979        }
00980        le->le_errmsg = errmsg;
00981 }
00982 
00983 
00984 static int
00985 get_ld_error( char **matchedp, char **errmsgp, void *dummy )
00986 {
00987        struct ldap_error *le;
00988 
00989        le = pthread_getspecific( key );
00990        if ( matchedp != NULL ) {
00991               *matchedp = le->le_matched;
00992        }
00993        if ( errmsgp != NULL ) {
00994               *errmsgp = le->le_errmsg;
00995        }
00996        return( le->le_errno );
00997 }
00998 
00999 
01000 static void
01001 set_errno( int err )
01002 {
01003        errno = err;
01004 }
01005 
01006 
01007 static int
01008 get_errno( void )
01009 {
01010        return( errno );
01011 }
01012 
01013 
01014 static int
01015 get_random_id()
01016 {
01017        return( random() % maxid );
01018 }
01019 
01020 
01021 static char *
01022 get_id_str( int id )
01023 {
01024        char   idstr[ 10 ];
01025 
01026        sprintf( idstr, "%d", id );
01027        return( strdup( idstr ));
01028 }