RetroZilla/directory/c-sdk/ldap/libraries/libldap/nsprthreadtest.c
2015-10-20 23:03:22 -04:00

622 lines
16 KiB
C

/* ***** 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 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 <nspr.h>
#include <stdio.h>
#include <ldap.h>
#define NAME "cn=Directory Manager"
#define PASSWORD "secret99"
#define BASE "dc=example,dc=com"
static int simplebind( LDAP *ld, char *msg, int tries );
static void search_thread( void * );
static void modify_thread( void * );
static void add_thread( void * );
static void delete_thread( 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 *my_mutex_alloc( void );
static void my_mutex_free( void * );
static int my_mutex_lock( void * );
static int my_mutex_unlock( void * );
static LDAPHostEnt *my_gethostbyname( const char *name, LDAPHostEnt *result,
char *buffer, int buflen, int *statusp, void *extradata );
static LDAPHostEnt *my_gethostbyaddr( const char *addr, int length,
int type, LDAPHostEnt *result, char *buffer, int buflen,
int *statusp, void *extradata );
static LDAPHostEnt *copyPRHostEnt2LDAPHostEnt( LDAPHostEnt *ldhp,
PRHostEnt *prhp );
typedef struct ldapmsgwrapper {
LDAPMessage *lmw_messagep;
struct ldapmsgwrapper *lmw_next;
} ldapmsgwrapper;
#define CONNECTION_ERROR( lderr ) ( (lderr) == LDAP_SERVER_DOWN || \
(lderr) == LDAP_CONNECT_ERROR )
LDAP *ld;
PRUintn tsdindex;
#ifdef LDAP_MEMCACHE
LDAPMemCache *memcache = NULL;
#define MEMCACHE_SIZE (256*1024) /* 256K bytes */
#define MEMCACHE_TTL (15*60) /* 15 minutes */
#endif
main( int argc, char **argv )
{
PRThread *search_tid, *search_tid2, *search_tid3;
PRThread *search_tid4, *modify_tid, *add_tid;
PRThread *delete_tid;
struct ldap_thread_fns tfns;
struct ldap_dns_fns dnsfns;
int rc;
if ( argc != 3 ) {
fprintf( stderr, "usage: %s host port\n", argv[0] );
exit( 1 );
}
PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
if ( PR_NewThreadPrivateIndex( &tsdindex, NULL ) != PR_SUCCESS ) {
perror( "PR_NewThreadPrivateIndex" );
exit( 1 );
}
tsd_setup(); /* for main thread */
if ( (ld = ldap_init( argv[1], atoi( argv[2] ) )) == NULL ) {
perror( "ldap_open" );
exit( 1 );
}
/* set thread function pointers */
memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
tfns.ltf_mutex_alloc = my_mutex_alloc;
tfns.ltf_mutex_free = my_mutex_free;
tfns.ltf_mutex_lock = my_mutex_lock;
tfns.ltf_mutex_unlock = my_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;
if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns )
!= 0 ) {
ldap_perror( ld, "ldap_set_option: thread functions" );
exit( 1 );
}
/* set DNS function pointers */
memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) );
dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
dnsfns.lddnsfn_gethostbyname = my_gethostbyname;
dnsfns.lddnsfn_gethostbyaddr = my_gethostbyaddr;
if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns )
!= 0 ) {
ldap_perror( ld, "ldap_set_option: DNS functions" );
exit( 1 );
}
#ifdef LDAP_MEMCACHE
/* create the in-memory cache */
if (( rc = ldap_memcache_init( MEMCACHE_TTL, MEMCACHE_SIZE, NULL,
&tfns, &memcache )) != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_memcache_init failed - %s\n",
ldap_err2string( rc ));
exit( 1 );
}
if (( rc = ldap_memcache_set( ld, memcache )) != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_memcache_set failed - %s\n",
ldap_err2string( rc ));
exit( 1 );
}
#endif
/*
* set option so that the next call to ldap_simple_bind_s() after
* the server connection is lost will attempt to reconnect.
*/
if ( ldap_set_option( ld, LDAP_OPT_RECONNECT, LDAP_OPT_ON ) != 0 ) {
ldap_perror( ld, "ldap_set_option: reconnect" );
exit( 1 );
}
/* initial bind */
if ( simplebind( ld, "ldap_simple_bind_s/main", 1 ) != LDAP_SUCCESS ) {
exit( 1 );
}
/* create the operation threads */
if ( (search_tid = PR_CreateThread( PR_USER_THREAD, search_thread,
"1", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread search_thread" );
exit( 1 );
}
if ( (modify_tid = PR_CreateThread( PR_USER_THREAD, modify_thread,
"2", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread modify_thread" );
exit( 1 );
}
if ( (search_tid2 = PR_CreateThread( PR_USER_THREAD, search_thread,
"3", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread search_thread 2" );
exit( 1 );
}
if ( (add_tid = PR_CreateThread( PR_USER_THREAD, add_thread,
"4", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread add_thread" );
exit( 1 );
}
if ( (search_tid3 = PR_CreateThread( PR_USER_THREAD, search_thread,
"5", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread search_thread 3" );
exit( 1 );
}
if ( (delete_tid = PR_CreateThread( PR_USER_THREAD, delete_thread,
"6", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread delete_thread" );
exit( 1 );
}
if ( (search_tid4 = PR_CreateThread( PR_USER_THREAD, search_thread,
"7", PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
0 )) == NULL ) {
perror( "PR_CreateThread search_thread 4" );
exit( 1 );
}
PR_Cleanup();
return( 0 );
}
static int
simplebind( LDAP *ld, char *msg, int tries )
{
int rc;
while ( tries-- > 0 ) {
rc = ldap_simple_bind_s( ld, NAME, PASSWORD );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, msg );
}
if ( tries == 0 || !CONNECTION_ERROR( rc )) {
return( rc );
}
fprintf( stderr,
"%s: sleeping for 5 secs - will try %d more time(s)...\n",
msg, tries );
sleep( 5 );
}
return( rc );
}
static void
search_thread( void *arg1 )
{
LDAPMessage *res;
LDAPMessage *e;
char *a;
char **v;
char *dn;
BerElement *ber;
int i, rc, msgid;
void *tsd;
char *id = arg1;
printf( "search_thread\n" );
tsd_setup();
for ( ;; ) {
printf( "%sSearching...\n", id );
if ( (msgid = ldap_search( ld, BASE, LDAP_SCOPE_SUBTREE,
"(objectclass=*)", NULL, 0 )) == -1 ) {
ldap_perror( ld, "ldap_search_s" );
rc = ldap_get_lderrno( ld, NULL, NULL );
if ( CONNECTION_ERROR( rc ) && simplebind( ld,
"bind-search_thread", 5 ) != LDAP_SUCCESS ) {
return;
}
continue;
}
while ( (rc = ldap_result( ld, msgid, 0, NULL, &res ))
== LDAP_RES_SEARCH_ENTRY ) {
for ( e = ldap_first_entry( ld, res ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
dn = ldap_get_dn( ld, e );
/* printf( "%sdn: %s\n", id, dn ); */
free( dn );
for ( a = ldap_first_attribute( ld, e, &ber );
a != NULL; a = ldap_next_attribute( ld, e,
ber ) ) {
v = ldap_get_values( ld, e, a );
for ( i = 0; v && v[i] != 0; i++ ) {
/*
printf( "%s%s: %s\n", id, a,
v[i] );
*/
}
ldap_value_free( v );
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
ldap_msgfree( res );
/* printf( "%s\n", id ); */
}
if ( rc == -1 || ldap_result2error( ld, res, 0 ) !=
LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search" );
} else {
printf( "%sDone with one round\n", id );
}
if ( rc == -1 ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
if ( CONNECTION_ERROR( rc ) && simplebind( ld,
"bind-search_thread", 5 ) != LDAP_SUCCESS ) {
return;
}
}
}
}
static void
modify_thread( void *arg1 )
{
LDAPMessage *res;
LDAPMessage *e;
int i, modentry, entries, msgid, rc;
LDAPMod mod;
LDAPMod *mods[2];
char *vals[2];
char *dn;
char *id = arg1;
ldapmsgwrapper *list, *lmwp, *lastlmwp;
printf( "modify_thread\n" );
tsd_setup();
if ( (msgid = ldap_search( ld, BASE, LDAP_SCOPE_SUBTREE,
"(objectclass=*)", NULL, 0 )) == -1 ) {
ldap_perror( ld, "ldap_search_s" );
exit( 1 );
}
entries = 0;
list = lastlmwp = NULL;
while ( (rc = ldap_result( ld, msgid, 0, NULL, &res ))
== LDAP_RES_SEARCH_ENTRY ) {
entries++;
if (( lmwp = (ldapmsgwrapper *)
malloc( sizeof( ldapmsgwrapper ))) == NULL ) {
perror( "modify_thread: malloc" );
exit( 1 );
}
lmwp->lmw_messagep = res;
lmwp->lmw_next = NULL;
if ( lastlmwp == NULL ) {
list = lastlmwp = lmwp;
} else {
lastlmwp->lmw_next = lmwp;
}
lastlmwp = lmwp;
}
if ( rc == -1 || ldap_result2error( ld, res, 0 ) != LDAP_SUCCESS ) {
ldap_perror( ld, "modify_thread: ldap_search" );
exit( 1 );
} else {
entries++;
printf( "%sModify got %d entries\n", id, entries );
}
mods[0] = &mod;
mods[1] = NULL;
vals[0] = "bar";
vals[1] = NULL;
for ( ;; ) {
modentry = rand() % entries;
for ( i = 0, lmwp = list; lmwp != NULL && i < modentry;
i++, lmwp = lmwp->lmw_next ) {
/* NULL */
}
if ( lmwp == NULL ) {
fprintf( stderr,
"%sModify could not find entry %d of %d\n",
id, modentry, entries );
continue;
}
e = lmwp->lmw_messagep;
printf( "%sPicked entry %d of %d\n", id, i, entries );
dn = ldap_get_dn( ld, e );
mod.mod_op = LDAP_MOD_REPLACE;
mod.mod_type = "description";
mod.mod_values = vals;
printf( "%sModifying (%s)\n", id, dn );
if (( rc = ldap_modify_s( ld, dn, mods )) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_modify_s" );
if ( CONNECTION_ERROR( rc ) && simplebind( ld,
"bind-modify_thread", 5 ) != LDAP_SUCCESS ) {
return;
}
}
free( dn );
}
}
static void
add_thread( void *arg1 )
{
LDAPMod mod[5];
LDAPMod *mods[6];
char dn[BUFSIZ], name[40];
char *cnvals[2], *snvals[2], *ocvals[2];
int i, rc;
char *id = arg1;
printf( "add_thread\n" );
tsd_setup();
for ( i = 0; i < 5; i++ ) {
mods[i] = &mod[i];
}
mods[5] = 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] = "person";
ocvals[1] = NULL;
mods[3] = NULL;
for ( ;; ) {
sprintf( name, "%d", rand() );
sprintf( dn, "cn=%s, " BASE, name );
cnvals[0] = name;
snvals[0] = name;
printf( "%sAdding entry (%s)\n", id, dn );
if (( rc = ldap_add_s( ld, dn, mods )) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_add_s" );
if ( CONNECTION_ERROR( rc ) && simplebind( ld,
"bind-add_thread", 5 ) != LDAP_SUCCESS ) {
return;
}
}
}
}
static void
delete_thread( void *arg1 )
{
LDAPMessage *res;
char dn[BUFSIZ], name[40];
int entries, msgid, rc;
char *id = arg1;
printf( "delete_thread\n" );
tsd_setup();
if ( (msgid = ldap_search( ld, BASE, LDAP_SCOPE_SUBTREE,
"(objectclass=*)", NULL, 0 )) == -1 ) {
ldap_perror( ld, "delete_thread: ldap_search_s" );
exit( 1 );
}
entries = 0;
while ( (rc = ldap_result( ld, msgid, 0, NULL, &res ))
== LDAP_RES_SEARCH_ENTRY ) {
entries++;
ldap_msgfree( res );
}
entries++;
if ( rc == -1 || ldap_result2error( ld, res, 1 ) != LDAP_SUCCESS ) {
ldap_perror( ld, "delete_thread: ldap_search" );
} else {
printf( "%sDelete got %d entries\n", id, entries );
}
for ( ;; ) {
sprintf( name, "%d", rand() );
sprintf( dn, "cn=%s, " BASE, name );
printf( "%sDeleting entry (%s)\n", id, dn );
if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_delete_s" );
if ( CONNECTION_ERROR( rc ) && simplebind( ld,
"bind-delete_thread", 5 ) != LDAP_SUCCESS ) {
return;
}
}
}
}
struct ldap_error {
int le_errno;
char *le_matched;
char *le_errmsg;
};
static void
tsd_setup()
{
void *tsd;
tsd = (void *) PR_GetThreadPrivate( tsdindex );
if ( tsd != NULL ) {
fprintf( stderr, "tsd non-null!\n" );
exit( 1 );
}
tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
if ( PR_SetThreadPrivate( tsdindex, tsd ) != 0 ) {
perror( "PR_SetThreadPrivate" );
exit( 1 );
}
}
static void
set_ld_error( int err, char *matched, char *errmsg, void *dummy )
{
struct ldap_error *le;
le = (void *) PR_GetThreadPrivate( tsdindex );
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 = PR_GetThreadPrivate( tsdindex );
if ( matchedp != NULL ) {
*matchedp = le->le_matched;
}
if ( errmsgp != NULL ) {
*errmsgp = le->le_errmsg;
}
return( le->le_errno );
}
static void
set_errno( int oserrno )
{
/* XXXmcs: should this be PR_SetError( oserrno, 0 )? */
PR_SetError( PR_UNKNOWN_ERROR, oserrno );
}
static int
get_errno( void )
{
/* XXXmcs: should this be PR_GetError()? */
return( PR_GetOSError());
}
static void *
my_mutex_alloc( void )
{
return( (void *)PR_NewLock());
}
static void
my_mutex_free( void *mutex )
{
PR_DestroyLock( (PRLock *)mutex );
}
static int
my_mutex_lock( void *mutex )
{
PR_Lock( (PRLock *)mutex );
return( 0 );
}
static int
my_mutex_unlock( void *mutex )
{
if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
return( -1 );
}
return( 0 );
}
static LDAPHostEnt *
my_gethostbyname( const char *name, LDAPHostEnt *result,
char *buffer, int buflen, int *statusp, void *extradata )
{
PRHostEnt prhent;
if ( PR_GetHostByName( name, buffer, buflen,
&prhent ) != PR_SUCCESS ) {
return( NULL );
}
return( copyPRHostEnt2LDAPHostEnt( result, &prhent ));
}
static LDAPHostEnt *
my_gethostbyaddr( const char *addr, int length, int type, LDAPHostEnt *result,
char *buffer, int buflen, int *statusp, void *extradata )
{
PRHostEnt prhent;
if ( PR_GetHostByAddr( (PRNetAddr *)addr, buffer, buflen,
&prhent ) != PR_SUCCESS ) {
return( NULL );
}
return( copyPRHostEnt2LDAPHostEnt( result, &prhent ));
}
static LDAPHostEnt *
copyPRHostEnt2LDAPHostEnt( LDAPHostEnt *ldhp, PRHostEnt *prhp )
{
ldhp->ldaphe_name = prhp->h_name;
ldhp->ldaphe_aliases = prhp->h_aliases;
ldhp->ldaphe_addrtype = prhp->h_addrtype;
ldhp->ldaphe_length = prhp->h_length;
ldhp->ldaphe_addr_list = prhp->h_addr_list;
return( ldhp );
}