diff options
Diffstat (limited to 'ldap/c-sdk/libldap/pthreadtest.c')
-rw-r--r-- | ldap/c-sdk/libldap/pthreadtest.c | 1028 |
1 files changed, 1028 insertions, 0 deletions
diff --git a/ldap/c-sdk/libldap/pthreadtest.c b/ldap/c-sdk/libldap/pthreadtest.c new file mode 100644 index 000000000..fa913f691 --- /dev/null +++ b/ldap/c-sdk/libldap/pthreadtest.c @@ -0,0 +1,1028 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <malloc.h> +#include <values.h> +#include <errno.h> +#include <pthread.h> +#include <synch.h> + +#include <ldap.h> + +/* Authentication and search information. */ +#define NAME "cn=Directory Manager" +#define PASSWORD "rtfm11111" +#define BASE "dc=example,dc=com" +#define SCOPE LDAP_SCOPE_SUBTREE + +static void *modify_thread(); +static void *add_thread(); +static void *delete_thread(); +static void *bind_thread(); +static void *compare_thread(); +static void *search_thread(); +static void *my_mutex_alloc(); +static void my_mutex_free(); +void *my_sema_alloc( void ); +void my_sema_free( void * ); +int my_sema_wait( void * ); +int my_sema_post( void * ); +static void set_ld_error(); +static int get_ld_error(); +static void set_errno(); +static int get_errno(); +static void tsd_setup(); +static void tsd_cleanup(); +static int get_random_id( void ); +static char *get_id_str( int id ); + +/* Linked list of LDAPMessage structs for search results. */ +typedef struct ldapmsgwrapper { + LDAPMessage *lmw_messagep; + struct ldapmsgwrapper *lmw_next; +} ldapmsgwrapper; + +LDAP *ld; +pthread_key_t key; +int maxid = MAXINT; +int maxops = 0; /* zero means no limit */ +int range_filters = 0; /* if non-zero use >= and >= filters */ + +main( int argc, char **argv ) + +{ + pthread_attr_t attr; + pthread_t *threadids; + void *status; + struct ldap_thread_fns tfns; + struct ldap_extra_thread_fns extrafns; + int rc, c, errflg, i, inited_attr; + int doadd, dodelete, domodify, docompare, dosearch, dobind; + int option_extthreads, option_restart; + int each_thread_count, thread_count; + extern int optind; + extern char *optarg; + + doadd = dodelete = domodify = docompare = dobind = dosearch = 0; + option_extthreads = option_restart = 0; + inited_attr = 0; + errflg = 0; + each_thread_count = 1; /* how many of each type of thread? */ + rc = LDAP_SUCCESS; /* optimistic */ + + while (( c = getopt( argc, argv, "abcdmrsERi:n:o:S:" )) != EOF ) { + switch( c ) { + case 'a': /* perform add operations */ + ++doadd; + break; + case 'b': /* perform bind operations */ + ++dobind; + break; + case 'c': /* perform compare operations */ + ++docompare; + break; + case 'd': /* perform delete operations */ + ++dodelete; + break; + case 'm': /* perform modify operations */ + ++domodify; + break; + case 'r': /* use range filters in searches */ + ++range_filters; + break; + case 's': /* perform search operations */ + ++dosearch; + break; + case 'E': /* use extended thread functions */ + ++option_extthreads; + break; + case 'R': /* turn on LDAP_OPT_RESTART */ + ++option_restart; + break; + case 'i': /* highest # used for entry names */ + maxid = atoi( optarg ); + break; + case 'n': /* # threads for each operation */ + if (( each_thread_count = atoi( optarg )) < 1 ) { + fprintf( stderr, "thread count must be > 0\n" ); + ++errflg; + } + break; + case 'o': /* operations to perform per thread */ + if (( maxops = atoi( optarg )) < 0 ) { + fprintf( stderr, + "operation limit must be >= 0\n" ); + ++errflg; + } + break; + case 'S': /* random number seed */ + if ( *optarg == 'r' ) { + int seed = (int)time( (time_t *)0 ); + srandom( seed ); + printf( "Random seed: %d\n", seed ); + } else { + srandom( atoi( optarg )); + } + break; + default: + ++errflg; + break; + } + } + + /* Check command-line syntax. */ + thread_count = each_thread_count * ( doadd + dodelete + domodify + + dobind + docompare + dosearch ); + if ( thread_count < 1 ) { + fprintf( stderr, + "Specify at least one of -a, -b, -c, -d, -m, or -s\n" ); + ++errflg; + } + + if ( errflg || argc - optind != 2 ) { + fprintf( stderr, "usage: %s [-abcdmrsER] [-i id] [-n thr]" + " [-o oplim] [-S sd] host port\n", argv[0] ); + fputs( "\nWhere:\n" + "\t\"id\" is the highest entry id (name) to use" + " (default is MAXINT)\n" + "\t\"thr\" is the number of threads for each operation" + " (default is 1)\n" + "\t\"oplim\" is the number of ops done by each thread" + " (default is infinite)\n" + "\t\"sd\" is a random() number seed (default is 1). Use" + " the letter r for\n" + "\t\tsd to seed random() using time of day.\n" + "\t\"host\" is the hostname of an LDAP directory server\n" + "\t\"port\" is the TCP port of the LDAP directory server\n" + , stderr ); + fputs( "\nAnd the single character options are:\n" + "\t-a\tstart thread(s) to perform add operations\n" + "\t-b\tstart thread(s) to perform bind operations\n" + "\t-c\tstart thread(s) to perform compare operations\n" + "\t-d\tstart thread(s) to perform delete operations\n" + "\t-m\tstart thread(s) to perform modify operations\n" + "\t-s\tstart thread(s) to perform search operations\n" + "\t-r\tuse range filters in searches\n" + "\t-E\tinstall LDAP_OPT_EXTRA_THREAD_FN_PTRS\n" + "\t-R\tturn on LDAP_OPT_RESTART\n", stderr ); + + return( LDAP_PARAM_ERROR ); + } + + /* Create a key. */ + if ( pthread_key_create( &key, free ) != 0 ) { + perror( "pthread_key_create" ); + } + tsd_setup(); + + /* Allocate space for thread ids */ + if (( threadids = (pthread_t *)calloc( thread_count, + sizeof( pthread_t ))) == NULL ) { + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + + + /* Initialize the LDAP session. */ + if (( ld = ldap_init( argv[optind], atoi( argv[optind+1] ))) == NULL ) { + perror( "ldap_init" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + + /* Set the function pointers for dealing with mutexes + and error information. */ + memset( &tfns, '\0', sizeof(struct ldap_thread_fns) ); + tfns.ltf_mutex_alloc = (void *(*)(void)) my_mutex_alloc; + tfns.ltf_mutex_free = (void (*)(void *)) my_mutex_free; + tfns.ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock; + tfns.ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock; + tfns.ltf_get_errno = get_errno; + tfns.ltf_set_errno = set_errno; + tfns.ltf_get_lderrno = get_ld_error; + tfns.ltf_set_lderrno = set_ld_error; + tfns.ltf_lderrno_arg = NULL; + + /* Set up this session to use those function pointers. */ + + rc = ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns ); + if ( rc < 0 ) { + rc = ldap_get_lderrno( ld, NULL, NULL ); + fprintf( stderr, + "ldap_set_option (LDAP_OPT_THREAD_FN_PTRS): %s\n", + ldap_err2string( rc ) ); + goto clean_up_and_return; + } + + if ( option_extthreads ) { + /* Set the function pointers for working with semaphores. */ + + memset( &extrafns, '\0', sizeof(struct ldap_extra_thread_fns) ); + extrafns.ltf_mutex_trylock = + (int (*)(void *)) pthread_mutex_trylock; + extrafns.ltf_sema_alloc = (void *(*)(void)) my_sema_alloc; + extrafns.ltf_sema_free = (void (*)(void *)) my_sema_free; + extrafns.ltf_sema_wait = (int (*)(void *)) my_sema_wait; + extrafns.ltf_sema_post = (int (*)(void *)) my_sema_post; + + /* Set up this session to use those function pointers. */ + + if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, + (void *) &extrafns ) != 0 ) { + rc = ldap_get_lderrno( ld, NULL, NULL ); + ldap_perror( ld, "ldap_set_option" + " (LDAP_OPT_EXTRA_THREAD_FN_PTRS)" ); + goto clean_up_and_return; + } + } + + + if ( option_restart && ldap_set_option( ld, LDAP_OPT_RESTART, + LDAP_OPT_ON ) != 0 ) { + rc = ldap_get_lderrno( ld, NULL, NULL ); + ldap_perror( ld, "ldap_set_option(LDAP_OPT_RESTART)" ); + goto clean_up_and_return; + } + + /* Attempt to bind to the server. */ + rc = ldap_simple_bind_s( ld, NAME, PASSWORD ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "ldap_simple_bind_s: %s\n", + ldap_err2string( rc ) ); + goto clean_up_and_return; + } + + /* Initialize the attribute. */ + if ( pthread_attr_init( &attr ) != 0 ) { + perror( "pthread_attr_init" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++inited_attr; + + /* Specify that the threads are joinable. */ + pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); + + /* Create all the requested threads */ + thread_count = 0; + if ( domodify ) { + for ( i = 0; i < each_thread_count; ++i ) { + if ( pthread_create( &threadids[thread_count], &attr, + modify_thread, get_id_str(thread_count) ) != 0 ) { + perror( "pthread_create modify_thread" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++thread_count; + } + } + + if ( doadd ) { + for ( i = 0; i < each_thread_count; ++i ) { + if ( pthread_create( &threadids[thread_count], &attr, + add_thread, get_id_str(thread_count) ) != 0 ) { + perror( "pthread_create add_thread" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++thread_count; + } + } + + if ( dodelete ) { + for ( i = 0; i < each_thread_count; ++i ) { + if ( pthread_create( &threadids[thread_count], &attr, + delete_thread, get_id_str(thread_count) ) != 0 ) { + perror( "pthread_create delete_thread" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++thread_count; + } + } + + if ( dobind ) { + for ( i = 0; i < each_thread_count; ++i ) { + if ( pthread_create( &threadids[thread_count], &attr, + bind_thread, get_id_str(thread_count) ) != 0 ) { + perror( "pthread_create bind_thread" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++thread_count; + } + } + + if ( docompare ) { + for ( i = 0; i < each_thread_count; ++i ) { + if ( pthread_create( &threadids[thread_count], &attr, + compare_thread, get_id_str(thread_count) ) != 0 ) { + perror( "pthread_create compare_thread" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++thread_count; + } + } + + if ( dosearch ) { + for ( i = 0; i < each_thread_count; ++i ) { + if ( pthread_create( &threadids[thread_count], &attr, + search_thread, get_id_str(thread_count) ) != 0 ) { + perror( "pthread_create search_thread" ); + rc = LDAP_LOCAL_ERROR; + goto clean_up_and_return; + } + ++thread_count; + } + } + + /* Wait until these threads exit. */ + for ( i = 0; i < thread_count; ++i ) { + pthread_join( threadids[i], &status ); + } + +clean_up_and_return: + if ( ld != NULL ) { + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + ldap_unbind( ld ); + } + if ( threadids != NULL ) { + free( threadids ); + } + if ( inited_attr ) { + pthread_attr_destroy( &attr ); + } + tsd_cleanup(); + + return( rc ); +} + + +static void * +modify_thread( char *id ) +{ + LDAPMessage *res; + LDAPMessage *e; + int i, modentry, num_entries, msgid, parse_rc, finished; + int rc, opcount; + LDAPMod mod; + LDAPMod *mods[2]; + char *vals[2]; + char *dn; + ldapmsgwrapper *list, *lmwp, *lastlmwp; + struct timeval zerotime; + void *voidrc = (void *)0; + + zerotime.tv_sec = zerotime.tv_usec = 0L; + + printf( "Starting modify_thread %s.\n", id ); + opcount = 0; + tsd_setup(); + + rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)", + NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "Thread %s error: Modify thread: " + "ldap_search_ext: %s\n", id, ldap_err2string( rc ) ); + exit( 1 ); + } + list = lastlmwp = NULL; + finished = 0; + num_entries = 0; + while ( !finished ) { + rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res ); + switch ( rc ) { + case -1: + rc = ldap_get_lderrno( ld, NULL, NULL ); + fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) ); + exit( 1 ); + break; + case 0: + break; + /* Keep track of the number of entries found. */ + case LDAP_RES_SEARCH_ENTRY: + num_entries++; + if (( lmwp = (ldapmsgwrapper *) + malloc( sizeof( ldapmsgwrapper ))) == NULL ) { + fprintf( stderr, "Thread %s: Modify thread: Cannot malloc\n", id ); + exit( 1 ); + } + lmwp->lmw_messagep = res; + lmwp->lmw_next = NULL; + if ( lastlmwp == NULL ) { + list = lastlmwp = lmwp; + } else { + lastlmwp->lmw_next = lmwp; + } + lastlmwp = lmwp; + break; + case LDAP_RES_SEARCH_REFERENCE: + break; + case LDAP_RES_SEARCH_RESULT: + finished = 1; + parse_rc = ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 ); + if ( parse_rc != LDAP_SUCCESS ) { + fprintf( stderr, "Thread %s error: can't parse result code.\n", id ); + exit( 1 ); + } else { + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string( rc ) ); + } else { + printf( "Thread %s: Got %d results.\n", id, num_entries ); + } + } + break; + default: + break; + } + } + + mods[0] = &mod; + mods[1] = NULL; + vals[0] = "bar"; + vals[1] = NULL; + + for ( ;; ) { + modentry = random() % num_entries; + for ( i = 0, lmwp = list; lmwp != NULL && i < modentry; + i++, lmwp = lmwp->lmw_next ) { + /* NULL */ + } + + if ( lmwp == NULL ) { + fprintf( stderr, + "Thread %s: Modify thread could not find entry %d of %d\n", + id, modentry, num_entries ); + continue; + } + + e = lmwp->lmw_messagep; + printf( "Thread %s: Modify thread picked entry %d of %d\n", id, i, num_entries ); + dn = ldap_get_dn( ld, e ); + + mod.mod_op = LDAP_MOD_REPLACE; + mod.mod_type = "description"; + mod.mod_values = vals; + printf( "Thread %s: Modifying (%s)\n", id, dn ); + + rc = ldap_modify_ext_s( ld, dn, mods, NULL, NULL ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "ldap_modify_ext_s: %s\n", + ldap_err2string( rc ) ); + if ( rc == LDAP_SERVER_DOWN ) { + perror( "ldap_modify_ext_s" ); + voidrc = (void *)1; + goto modify_cleanup_and_return; + } + } + free( dn ); + + ++opcount; + if ( maxops != 0 && opcount >= maxops ) { + break; + } + } + +modify_cleanup_and_return: + printf( "Thread %s: attempted %d modify operations\n", id, opcount ); + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + tsd_cleanup(); + free( id ); + return voidrc; +} + + +static void * +add_thread( char *id ) +{ + LDAPMod mod[4]; + LDAPMod *mods[5]; + char dn[BUFSIZ], name[40]; + char *cnvals[2], *snvals[2], *pwdvals[2], *ocvals[3]; + int i, rc, opcount; + void *voidrc = (void *)0; + + printf( "Starting add_thread %s.\n", id ); + opcount = 0; + tsd_setup(); + + for ( i = 0; i < 4; i++ ) { + mods[i] = &mod[i]; + } + + mods[4] = NULL; + + mod[0].mod_op = 0; + mod[0].mod_type = "cn"; + mod[0].mod_values = cnvals; + cnvals[1] = NULL; + mod[1].mod_op = 0; + mod[1].mod_type = "sn"; + mod[1].mod_values = snvals; + snvals[1] = NULL; + mod[2].mod_op = 0; + mod[2].mod_type = "objectclass"; + mod[2].mod_values = ocvals; + ocvals[0] = "top"; + ocvals[1] = "person"; + ocvals[2] = NULL; + mod[3].mod_op = 0; + mod[3].mod_type = "userPassword"; + mod[3].mod_values = pwdvals; + pwdvals[1] = NULL; + mods[4] = NULL; + + for ( ;; ) { + sprintf( name, "%d", get_random_id() ); + sprintf( dn, "cn=%s, " BASE, name ); + cnvals[0] = name; + snvals[0] = name; + pwdvals[0] = name; + + printf( "Thread %s: Adding entry (%s)\n", id, dn ); + rc = ldap_add_ext_s( ld, dn, mods, NULL, NULL ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "ldap_add_ext_s: %s\n", + ldap_err2string( rc ) ); + if ( rc == LDAP_SERVER_DOWN ) { + perror( "ldap_add_ext_s" ); + voidrc = (void *)1; + goto add_cleanup_and_return; + } + } + + ++opcount; + if ( maxops != 0 && opcount >= maxops ) { + break; + } + } + +add_cleanup_and_return: + printf( "Thread %s: attempted %d add operations\n", id, opcount ); + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + tsd_cleanup(); + free( id ); + return voidrc; +} + + +static void * +delete_thread( char *id ) +{ + LDAPMessage *res; + char dn[BUFSIZ], name[40]; + int num_entries, msgid, rc, parse_rc, finished, opcount; + struct timeval zerotime; + void *voidrc = (void *)0; + + zerotime.tv_sec = zerotime.tv_usec = 0L; + + printf( "Starting delete_thread %s.\n", id ); + opcount = 0; + tsd_setup(); + + rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)", + NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "Thread %s error: Delete thread: " + "ldap_search_ext: %s\n", id, ldap_err2string( rc ) ); + exit( 1 ); + } + + finished = 0; + num_entries = 0; + while ( !finished ) { + rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res ); + switch ( rc ) { + case -1: + rc = ldap_get_lderrno( ld, NULL, NULL ); + fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) ); + exit( 1 ); + break; + case 0: + break; + /* Keep track of the number of entries found. */ + case LDAP_RES_SEARCH_ENTRY: + num_entries++; + break; + case LDAP_RES_SEARCH_REFERENCE: + break; + case LDAP_RES_SEARCH_RESULT: + finished = 1; + parse_rc = ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 ); + if ( parse_rc != LDAP_SUCCESS ) { + fprintf( stderr, "Thread %s error: can't parse result code.\n", id ); + exit( 1 ); + } else { + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string( rc ) ); + } else { + printf( "Thread %s: Got %d results.\n", id, num_entries ); + } + } + break; + default: + break; + } + } + + for ( ;; ) { + sprintf( name, "%d", get_random_id() ); + sprintf( dn, "cn=%s, " BASE, name ); + printf( "Thread %s: Deleting entry (%s)\n", id, dn ); + + if (( rc = ldap_delete_ext_s( ld, dn, NULL, NULL )) + != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_delete_ext_s" ); + if ( rc == LDAP_SERVER_DOWN ) { + perror( "ldap_delete_ext_s" ); + voidrc = (void *)1; + goto delete_cleanup_and_return; + } + } + + ++opcount; + if ( maxops != 0 && opcount >= maxops ) { + break; + } + } + +delete_cleanup_and_return: + printf( "Thread %s: attempted %d delete operations\n", id, opcount ); + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + tsd_cleanup(); + free( id ); + return voidrc; +} + + +static void * +bind_thread( char *id ) +{ + char dn[BUFSIZ], name[40]; + int rc, opcount; + void *voidrc = (void *)0; + + printf( "Starting bind_thread %s.\n", id ); + opcount = 0; + tsd_setup(); + + for ( ;; ) { + sprintf( name, "%d", get_random_id() ); + sprintf( dn, "cn=%s, " BASE, name ); + printf( "Thread %s: Binding as entry (%s)\n", id, dn ); + + if (( rc = ldap_simple_bind_s( ld, dn, name )) + != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_simple_bind_s" ); + if ( rc == LDAP_SERVER_DOWN ) { + perror( "ldap_simple_bind_s" ); + voidrc = (void *)1; + goto bind_cleanup_and_return; + } + } else { + printf( "Thread %s: bound as entry (%s)\n", id, dn ); + } + + ++opcount; + if ( maxops != 0 && opcount >= maxops ) { + break; + } + } + +bind_cleanup_and_return: + printf( "Thread %s: attempted %d bind operations\n", id, opcount ); + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + tsd_cleanup(); + free( id ); + return voidrc; +} + + +static void * +compare_thread( char *id ) +{ + char dn[BUFSIZ], name[40], cmpval[40]; + int rc, randval, opcount; + struct berval bv; + void *voidrc = (void *)0; + + printf( "Starting compare_thread %s.\n", id ); + opcount = 0; + tsd_setup(); + + for ( ;; ) { + randval = get_random_id(); + sprintf( name, "%d", randval ); + sprintf( dn, "cn=%s, " BASE, name ); + sprintf( cmpval, "%d", randval + random() % 3 ); + bv.bv_val = cmpval; + bv.bv_len = strlen( cmpval ); + + printf( "Thread %s: Comparing cn in entry (%s) with %s\n", + id, dn, cmpval ); + + rc = ldap_compare_ext_s( ld, dn, "cn", &bv, NULL, NULL ); + switch ( rc ) { + case LDAP_COMPARE_TRUE: + printf( "Thread %s: entry (%s) contains cn %s\n", + id, dn, cmpval ); + break; + case LDAP_COMPARE_FALSE: + printf( "Thread %s: entry (%s) doesn't contain cn %s\n", + id, dn, cmpval ); + break; + default: + ldap_perror( ld, "ldap_compare_ext_s" ); + if ( rc == LDAP_SERVER_DOWN ) { + perror( "ldap_compare_ext_s" ); + voidrc = (void *)1; + goto compare_cleanup_and_return; + } + } + + ++opcount; + if ( maxops != 0 && opcount >= maxops ) { + break; + } + } + +compare_cleanup_and_return: + printf( "Thread %s: attempted %d compare operations\n", id, opcount ); + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + tsd_cleanup(); + free( id ); + return voidrc; +} + + +static void * +search_thread( char *id ) +{ + LDAPMessage *res, *entry; + char *dn, filter[40]; + int rc, opcount; + void *voidrc = (void *)0; + + printf( "Starting search_thread %s.\n", id ); + opcount = 0; + tsd_setup(); + + for ( ;; ) { + if ( range_filters ) { + switch( get_random_id() % 3 ) { + case 0: + sprintf( filter, "(cn>=%d)", get_random_id()); + break; + case 1: + sprintf( filter, "(cn<=%d)", get_random_id()); + break; + case 2: + sprintf( filter, "(&(cn>=%d)(cn<=%d))", + get_random_id(), get_random_id() ); + break; + } + } else { + sprintf( filter, "cn=%d", get_random_id() ); + } + + printf( "Thread %s: Searching for entry (%s)\n", id, filter ); + + res = NULL; + if (( rc = ldap_search_ext_s( ld, BASE, SCOPE, filter, NULL, 0, + NULL, NULL, NULL, 0, &res )) != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_search_ext_s" ); + if ( rc == LDAP_SERVER_DOWN ) { + perror( "ldap_search_ext_s" ); + voidrc = (void *)1; + goto search_cleanup_and_return; + } + } + if ( res != NULL ) { + entry = ldap_first_entry( ld, res ); + if ( entry == NULL ) { + printf( "Thread %s: found no entries\n", id ); + } else { + dn = ldap_get_dn( ld, entry ); + printf( + "Thread %s: found entry (%s); %d total\n", + id, dn == NULL ? "(Null)" : dn, + ldap_count_entries( ld, res )); + ldap_memfree( dn ); + } + ldap_msgfree( res ); + } + + ++opcount; + if ( maxops != 0 && opcount >= maxops ) { + break; + } + } + +search_cleanup_and_return: + printf( "Thread %s: attempted %d search operations\n", id, opcount ); + set_ld_error( 0, NULL, NULL, NULL ); /* disposes of memory */ + tsd_cleanup(); + free( id ); + return voidrc; +} + + +static void * +my_mutex_alloc( void ) +{ + pthread_mutex_t *mutexp; + + if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) { + pthread_mutex_init( mutexp, NULL ); + } + return( mutexp ); +} + + +void * +my_sema_alloc( void ) +{ + sema_t *semptr; + + if( (semptr = malloc( sizeof(sema_t) ) ) != NULL ) { + sema_init( semptr, 0, USYNC_THREAD, NULL ); + } + return ( semptr ); +} + + +static void +my_mutex_free( void *mutexp ) +{ + pthread_mutex_destroy( (pthread_mutex_t *) mutexp ); + free( mutexp ); +} + + +void +my_sema_free( void *semptr ) +{ + sema_destroy( (sema_t *) semptr ); + free( semptr ); +} + + +int +my_sema_wait( void *semptr ) +{ + if( semptr != NULL ) + return( sema_wait( (sema_t *) semptr ) ); + else + return( -1 ); +} + + +int +my_sema_post( void *semptr ) +{ + if( semptr != NULL ) + return( sema_post( (sema_t *) semptr ) ); + else + return( -1 ); +} + + +struct ldap_error { + int le_errno; + char *le_matched; + char *le_errmsg; +}; + + +static void +tsd_setup() +{ + void *tsd; + tsd = pthread_getspecific( key ); + if ( tsd != NULL ) { + fprintf( stderr, "tsd non-null!\n" ); + pthread_exit( NULL ); + } + + tsd = (void *) calloc( 1, sizeof(struct ldap_error) ); + pthread_setspecific( key, tsd ); +} + + +static void +tsd_cleanup() +{ + void *tsd; + + if (( tsd = pthread_getspecific( key )) != NULL ) { + pthread_setspecific( key, NULL ); + free( tsd ); + } +} + + +static void +set_ld_error( int err, char *matched, char *errmsg, void *dummy ) +{ + struct ldap_error *le; + + le = pthread_getspecific( key ); + + le->le_errno = err; + + if ( le->le_matched != NULL ) { + ldap_memfree( le->le_matched ); + } + le->le_matched = matched; + + if ( le->le_errmsg != NULL ) { + ldap_memfree( le->le_errmsg ); + } + le->le_errmsg = errmsg; +} + + +static int +get_ld_error( char **matchedp, char **errmsgp, void *dummy ) +{ + struct ldap_error *le; + + le = pthread_getspecific( key ); + if ( matchedp != NULL ) { + *matchedp = le->le_matched; + } + if ( errmsgp != NULL ) { + *errmsgp = le->le_errmsg; + } + return( le->le_errno ); +} + + +static void +set_errno( int err ) +{ + errno = err; +} + + +static int +get_errno( void ) +{ + return( errno ); +} + + +static int +get_random_id() +{ + return( random() % maxid ); +} + + +static char * +get_id_str( int id ) +{ + char idstr[ 10 ]; + + sprintf( idstr, "%d", id ); + return( strdup( idstr )); +} |