Author: nhosoi
Update of /cvs/dirsec/ldapserver/ldap/servers/slapd/tools/rsearch In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv12072/rsearch
Added Files: Makefile addthread.c addthread.h infadd.c infadd.h main.c nametable.c nametable.h rsearch.c rsearch.h sdattable.c sdattable.h searchthread.c searchthread.h Log Message: [170348] RSEARCH needs to be updated Integrating rsearch and infadd source codes from DSRK into the Directory Server build tree.
--- NEW FILE Makefile --- # # BEGIN COPYRIGHT BLOCK # This Program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; version 2 of the License. # # This Program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this Program; if not, write to the Free Software Foundation, Inc., 59 Temple # Place, Suite 330, Boston, MA 02111-1307 USA. # # In addition, as a special exception, Red Hat, Inc. gives You the additional # right to link the code of this Program with code not covered under the GNU # General Public License ("Non-GPL Code") and to distribute linked combinations # including the two, subject to the limitations in this paragraph. Non-GPL Code # permitted under this exception must only link to the code of this Program # through those well defined interfaces identified in the file named EXCEPTION # found in the source code files (the "Approved Interfaces"). The files of # Non-GPL Code may instantiate templates or use macros or inline functions from # the Approved Interfaces without causing the resulting work to be covered by # the GNU General Public License. Only Red Hat, Inc. may make changes or # additions to the list of Approved Interfaces. You must obey the GNU General # Public License in all respects for all of the Program code and other code used # in conjunction with the Program except the Non-GPL Code covered by this # exception. If you modify this file, you may extend this exception to your # version of the file, but you are not obligated to do so. If you do not wish to # provide this exception without modification, you must delete this exception # statement from your version and license this file solely under the GPL without # exception. # # # Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. # Copyright (C) 2005 Red Hat, Inc. # All rights reserved. # END COPYRIGHT BLOCK # # # gnu makefile for LDAP Server tools. #
LDAP_SRC = ../../../.. BUILD_ROOT = ../../../../..
NOSTDCLEAN=true # don't let nsconfig.mk define target clean NOSTDSTRIP=true # don't let nsconfig.mk define target strip NSPR20=true # probably should be defined somewhere else (not sure where)
OBJDEST = $(OBJDIR)/servers/tools/obj BINDIR = $(RELDIR)/shared/bin DATDIR = $(RELDIR)/shared/data
SLAPD_OBJDIR = $(LDAP_OBJDIR)
include $(BUILD_ROOT)/nsdefs.mk include $(BUILD_ROOT)/nsconfig.mk include $(LDAP_SRC)/nsldap.mk INCLUDES+=-I$(DB_INCLUDE)
SLAPDHDIR = ../
ifeq ($(ARCH), OSF1) PLATFORM_SPECIFIC_EXTRA_LIBRARY = -lcxx else # OSF1 # oems might need to edit this for their platform PLATFORM_SPECIFIC_EXTRA_LIBRARY = endif # OSF1
INCLUDES += $(SSLINCLUDE) DEFS += $(SSL)
CFLAGS += $(ARCH_CFLAGS)
INCLUDES += -I$(SLAPDHDIR) -I$(LDAP_ADMINCDIR) INCLUDES += -I$(ACLINC) INCLUDES += -I ../../plugins/rever LDFLAGS += $(EXLDFLAGS) $(SSLLIBFLAG)
DEPLIBS=
EXTRA_LIBS_DEP = $(LDAPSDK_DEP) $(DB_LIB_DEP) $(LDAP_COMMON_LIBS_DEP)
EXTRA_LIBS += $(LDAPLINK) $(DB_LIB) \ $(PLATFORM_SPECIFIC_EXTRA_LIBRARY) \ $(ALIBS) $(NSPRLINK) $(SECURITYLINK) \ $(THREADSLIB) $(LDAP_COMMON_LIBS)
ifeq ($(ARCH), Linux) EXTRA_LIBS += -lcrypt endif
KEYUPG_LIBS_DEP= KEYUPG_LIBS=$(LDAP_LIBLITEKEY)
# It looks like all of the latest versions of Unix that we ship on # have a good enough heap implementations that they don't need # SmartHeap. We still need it on NT. ifneq ($(ARCH), WINNT) LDAP_DONT_USE_SMARTHEAP=1 endif
# Don't use smartheap for debug builds on NT ifeq ($(ARCH), WINNT) ifeq ($(DEBUG), full) LDAP_DONT_USE_SMARTHEAP=1 endif endif
ifndef LDAP_DONT_USE_SMARTHEAP include $(BUILD_ROOT)/ns_usesh.mk _smartheap_depend = $(SH_LIB_DEP) else CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP endif
RSEARCHSRC := nametable.c sdattable.c searchthread.c rsearch.c INFADDSRC := nametable.c addthread.c infadd.c
DATAFILES := scripts/dbgen-GivenNames scripts/dbgen-FamilyNames scripts/dbgen-OrgUnits
DBGEN := scripts/dbgen.pl
ifeq ($(OS_ARCH), WINNT) OBJEXT :=.obj else OBJEXT :=.o endif
RSEARCHOBJS = $(addprefix $(OBJDEST)/, $(RSEARCHSRC:.c=$(OBJEXT))) INFADDOBJS = $(addprefix $(OBJDEST)/, $(INFADDSRC:.c=$(OBJEXT))) HDIR = $(LDAP_SRC)/include
ALL_OBJS = $(RSEARCHOBJS) $(INFADDOBJS)
RSEARCH = $(addsuffix $(EXE_SUFFIX), $(addprefix $(BINDIR)/, rsearch)) INFADD = $(addsuffix $(EXE_SUFFIX), $(addprefix $(BINDIR)/, infadd)) DBGEN = $(addsuffix $(EXE_SUFFIX), $(addprefix $(BINDIR)/, dbgen.pl))
BINS= $(RSEARCH) $(INFADD) $(DBGEN)
all: $(OBJDEST) $(BINDIR) $(BINS) $(DATDIR)
$(RSEARCH): $(RSEARCHOBJS) $(BINDIR) $(LINK_EXE) $(RSEARCHOBJS) $(LDAP_LIBLDIF) -chmod 755 $(RSEARCH)
$(INFADD): $(INFADDOBJS) $(BINDIR) $(LINK_EXE) $(INFADDOBJS) $(LDAP_LIBLDIF) -chmod 755 $(INFADD)
$(DBGEN): scripts/dbgen.pl $(BINDIR) cp scripts/dbgen.pl $(BINDIR) -chmod 755 $(DBGEN)
$(OBJDEST): if [ ! -d $(OBJDEST) ]; then \ $(MKDIR) $(OBJDEST); \ fi
$(BINDIR): if [ ! -d $(BINDIR) ]; then \ $(MKDIR) $(BINDIR); \ fi
$(DATDIR): -$(RM) -r $(DATDIR) -$(MKDIR) $(DATDIR) cp scripts/dbgen-* $(DATDIR)
clean: -$(RM) $(ALL_OBJS) -$(RM) -r $(BINS) $(DATDIR)
--- NEW FILE addthread.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef XP_UNIX #include <unistd.h> #endif #include "nspr.h" #include <netinet/tcp.h> /* for TCP_NODELAY */ #include "ldap.h" #include "addthread.h" #include "infadd.h"
/* local data for a search thread */ struct _addthread { PRUint32 addCount; PRUint32 addTotal; PRUint32 failCount; double mintime; double maxtime; LDAP *ld; PRThread *tid; PRLock *lock; int id; int alive; char *blob; int retry; };
/*** unique id generator ***/ static unsigned long uniqueid = 0; void at_initID(unsigned long i) { uniqueid = i; /* before threading */ }
unsigned long getID(void) { static PRLock *lock = NULL; unsigned long ret;
if (!lock) { /* initialize */ lock = PR_NewLock(); } PR_Lock(lock); ret = uniqueid++; PR_Unlock(lock); return ret; }
/* new addthread */ AddThread *at_new(void) { AddThread *at = (AddThread *)malloc(sizeof(AddThread));
if (!at) return NULL; at->addCount = at->failCount = at->addTotal = 0; at->mintime = 10000; at->maxtime = 0; at->ld = NULL; at->tid = NULL; at->id = 0; at->alive = 1; at->retry = 0; at->lock = PR_NewLock(); at->blob = NULL; /* make sure the id generator has initialized */ getID(); return at; }
static void at_bail(AddThread *at) { PR_Lock(at->lock); at->alive = -10; PR_Unlock(at->lock); }
void at_setThread(AddThread *at, PRThread *tid, int id) { at->tid = tid; at->id = id; }
int at_getThread(AddThread *at, PRThread **tid) { if (tid) *tid = at->tid; return at->id; }
static void at_enableTCPnodelay(AddThread *at) { LBER_SOCKET s = 0; int val = 1;
if (ldap_get_option(at->ld, LDAP_OPT_DESC, (void *)&s) != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed on ldap_get_option\n", at->id); return; } if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val))) fprintf(stderr, "T%d: failed in setsockopt\n", at->id); }
/* NOTE: currently these are unused */ #if 0 /* abruptly disconnect an LDAP connection without unbinding */ static void at_disconnect(AddThread *at) { LBER_SOCKET s = 0;
if (ldap_get_option(at->ld, LDAP_OPT_DESC, (void *)&s) != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed on ldap_get_option\n", at->id); return; } #ifdef XP_WIN if (closesocket(s)) fprintf(stderr, "T%d: failed to disconnect\n", at->id); #else if (close(s)) fprintf(stderr, "T%d: failed to disconnect\n", at->id); #endif } #endif
static void at_bind(AddThread *at) { int ret; int retry = 0;
at->ld = ldap_init(hostname, port); if (! at->ld) { fprintf(stderr, "T%d: failed to init: %s port %d\n", at->id, hostname, port); return; } while (retry < 10) { ret = ldap_simple_bind_s(at->ld, strlen(username) ? username : NULL, strlen(password) ? password : NULL); if (LDAP_SUCCESS == ret) { return; /* ok */ } else if (LDAP_CONNECT_ERROR == ret) { retry++; } else { break; } } fprintf(stderr, "T%d: failed to bind, ldap_simple_bind_s returned %d\n", at->id, ret); }
#if 0 static void at_unbind(AddThread *at) { if (ldap_unbind(at->ld) != LDAP_SUCCESS) fprintf(stderr, "T%d: failed to unbind\n", at->id); } #endif /* 0 */
static void at_random_tel_number(char *s) { static char *areaCode[] = { "303", "408", "415", "423", "510", "650", "714", "803", "864", "901" }; int index = rand() % 10;
sprintf(s, "+1 %s %03d %04d", areaCode[index], rand()%1000, rand()%10000); }
static int at_add(AddThread *at) { LDAPMod *attrs[10]; LDAPMod attr_cn, attr_sn, attr_givenname, attr_objectclass, attr_uid, attr_mail, attr_telephonenumber, attr_audio, attr_password; struct berval audio_berval; struct berval *audio_values[2]; char dn[100], uid[10], telno[20], *sn, *givenname, cn[50], mail[50]; char *cn_values[2], *sn_values[2], *givenname_values[2]; char *uid_values[2], *mail_values[2], *telno_values[2]; #if 1 char *objectclass_values[] = { "top", "person", "organizationalPerson", "inetOrgPerson", NULL }; #else char *objectclass_values[] = { "inetOrgPerson", NULL }; #endif int ret;
/* make up the strings */ sprintf(uid, "%lu", getID()); at_random_tel_number(telno); sn = nt_getrand(family_names); givenname = nt_getrand(given_names); sprintf(cn, "%s %s %s", givenname, sn, uid); sprintf(mail, "%s%s@example.com", givenname, uid); sprintf(dn, "cn=%s,%s", cn, suffix);
cn_values[0] = cn; cn_values[1] = NULL; sn_values[0] = sn; sn_values[1] = NULL; givenname_values[0] = givenname; givenname_values[1] = NULL; uid_values[0] = uid; uid_values[1] = NULL; mail_values[0] = mail; mail_values[1] = NULL; telno_values[0] = telno; telno_values[1] = NULL;
attrs[0] = &attr_objectclass; attrs[1] = &attr_cn; attrs[2] = &attr_sn; attrs[3] = &attr_givenname; attrs[4] = &attr_uid; attrs[5] = &attr_password; attrs[6] = &attr_mail; attrs[7] = &attr_telephonenumber; if (blobsize > 0) { audio_values[0] = &audio_berval; audio_values[1] = 0; audio_berval.bv_len = (blobsize > 32000) ? ((long)rand() * 1039) % blobsize : (rand() % blobsize); audio_berval.bv_val = at->blob; attr_audio.mod_op = LDAP_MOD_BVALUES; attr_audio.mod_type = "audio"; attr_audio.mod_values = (char **)&audio_values; attrs[8] = &attr_audio; attrs[9] = 0; } else attrs[8] = 0;
attr_cn.mod_op = LDAP_MOD_ADD; attr_cn.mod_type = "cn"; attr_cn.mod_values = cn_values; attr_sn.mod_op = LDAP_MOD_ADD; attr_sn.mod_type = "sn"; attr_sn.mod_values = sn_values; attr_givenname.mod_op = LDAP_MOD_ADD; attr_givenname.mod_type = "givenname"; attr_givenname.mod_values = givenname_values; attr_objectclass.mod_op = LDAP_MOD_ADD; attr_objectclass.mod_type = "objectClass"; attr_objectclass.mod_values = objectclass_values; attr_uid.mod_op = LDAP_MOD_ADD; attr_uid.mod_type = "uid"; attr_uid.mod_values = uid_values; attr_password.mod_op = LDAP_MOD_ADD; attr_password.mod_type = "userpassword"; attr_password.mod_values = uid_values; attr_mail.mod_op = LDAP_MOD_ADD; attr_mail.mod_type = "mail"; attr_mail.mod_values = mail_values; attr_telephonenumber.mod_op = LDAP_MOD_ADD; attr_telephonenumber.mod_type = "telephonenumber"; attr_telephonenumber.mod_values = telno_values;
#if 0 for (i = 0; attrs[i]; i++) { fprintf(stderr, "attr '%s': ", attrs[i]->mod_type); if (strcasecmp(attrs[i]->mod_type, "audio") == 0) fprintf(stderr, "binary data len=%lu\n", ((struct berval **)(attrs[i]->mod_values))[0]->bv_len); else fprintf(stderr, "'%s'\n", attrs[i]->mod_values[0]); } #endif ret = ldap_add_s(at->ld, dn, attrs); if (ret != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed to add, error = %d\n", at->id, ret); } return ret; }
/* the main thread */ void infadd_start(void *v) { AddThread *at = (AddThread *)v; PRIntervalTime timer; PRUint32 span, i; int notBound = 1; int ret;
/* make the blob if necessary */ if (blobsize > 0) { at->blob = (char *)malloc(blobsize); if (! at->blob) { fprintf(stderr, "T%d: can't allocate blob!\n", at->id); return; } for (i = 0; i < blobsize; i++) at->blob[i] = (char)(rand() & 0xff); }
at->alive = 1; while (1) { timer = PR_IntervalNow();
/* bind if we need to */ if (notBound) { at_bind(at); if (noDelay) at_enableTCPnodelay(at); notBound = 0; }
ret = at_add(at); if (LDAP_SUCCESS == ret) { span = PR_IntervalToMilliseconds(PR_IntervalNow()-timer); /* update data */ PR_Lock(at->lock); at->addCount++; at->addTotal++; if (at->mintime > span) at->mintime = span; if (at->maxtime < span) at->maxtime = span; at->alive = 1; at->retry = 0; PR_Unlock(at->lock); } else if (LDAP_CONNECT_ERROR == ret && at->retry < 10) { PR_Lock(at->lock); at->retry++; PR_Unlock(at->lock); } else { at_bail(at); return; }
} }
/* fetches the current min/max times and the search count, and clears them */ void at_getCountMinMax(AddThread *at, PRUint32 *count, PRUint32 *min, PRUint32 *max, PRUint32 *total) { PR_Lock(at->lock); if (count) { *count = at->addCount; at->addCount = 0; } if (min) { *min = at->mintime; at->mintime = 10000; } if (max) { *max = at->maxtime; at->maxtime = 0; } if (total) *total = at->addTotal; at->alive--; PR_Unlock(at->lock); }
int at_alive(AddThread *at) { int alive;
PR_Lock(at->lock); alive = at->alive; PR_Unlock(at->lock); return alive; }
--- NEW FILE addthread.h --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#ifndef _ADDTHREAD_H #define _ADDTHREAD_H
typedef struct _addthread AddThread;
AddThread *at_new(void); void at_setThread(AddThread *at, PRThread *tid, int id); int at_getThread(AddThread *at, PRThread **tid); void infadd_start(void *v); void at_getCountMinMax(AddThread *at, PRUint32 *count, PRUint32 *min, PRUint32 *max, PRUint32 *total); int at_alive(AddThread *at); void at_initID(unsigned long i);
#endif
--- NEW FILE infadd.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
/* * XP port of dboreham's NT tool "infinite_add" * robey, june 1998 * * note: i didn't really port this one, i just wrote a quick version * from scratch. */
#ifdef LINUX #include <sys/param.h> #include <sys/sysinfo.h> #include <getopt.h> #endif
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <time.h> #include "nspr.h" #include "nametable.h" #include "addthread.h"
#define DEFAULT_HOSTNAME "localhost" #define DEFAULT_PORT 389 #define DEFAULT_THREADS 1 #define DEFAULT_INTERVAL 10000
/* global data for the threads to share */ char *hostname = DEFAULT_HOSTNAME; PRUint16 port = DEFAULT_PORT; int thread_count = DEFAULT_THREADS; char *suffix = NULL; char *username = NULL; char *password = NULL; PRUint32 blobsize = 0; PRUint32 sampleInterval = DEFAULT_INTERVAL; int noDelay = 0; int quiet = 0; int verbose = 0; int saveQuit = 0; int lmtCount = 0; unsigned long firstUID = 0; NameTable *given_names = NULL, *family_names = NULL;
void usage() { fprintf(stdout, "Usage: infadd -s suffix -u bindDN -w password [options]\n" "\nOptions:\n" "-h hostname (default: %s)\n" "-p port (default: %d)\n" "-t threads -- number of threads to spin (default: %d)\n" "-d -- use TCP no-delay\n" "-q -- quiet mode (no status updates)\n" "-v -- verbose mode (give per-thread statistics)\n" "-I num -- first uid (default: 0)\n" "-l count -- limit count; stops when the total count exceeds <count>\n" "-i msec -- sample interval in milliseconds (default: %u)\n" "-R size -- generate <size> random names instead of using\n" " data files\n" "-z size -- add binary blob of average size of <size> bytes\n" "\n", DEFAULT_HOSTNAME, DEFAULT_PORT, DEFAULT_THREADS, DEFAULT_INTERVAL); }
/* generate a random name * this generates 'names' like "Gxuvbnrc" but hey, there are Bosnian towns * with less pronouncable names... */ char *randName(void) { char *x; int i, len = (rand() % 7) + 5;
x = (char *)malloc(len+1); if (!x) return NULL; x[0] = (rand() % 26)+'A'; for (i = 1; i < len; i++) x[i] = (rand() % 26)+'a'; x[len] = 0; return x; }
int fill_table(NameTable *nt, PRUint32 size) { PRUint32 i; char *x; int ret;
fprintf(stdout, "Generating random names: 0 "); for (i = 0; i < size; i++) { x = randName(); /* check for duplicates */ while (nt_cis_check(nt, x)) { free(x); x = randName(); } ret = nt_push(nt, x); if ((i % 100) == 0) { fprintf(stdout, "\b\b\b\b\b\b\b%-7d", i); } } fprintf(stdout, "\b\b\b\b\b\b\b%d. Done.\n", size); return ret; }
int main(int argc, char **argv) { int ch, index, numThreads, numDead; PRUint32 use_random = 0; AddThread **threads; PRUint32 total = 0, ntotal = 0; int counter; char familynames[35], givennames[35];
srand(time(NULL)); if (argc < 2) { usage(); exit(1); }
while ((ch = getopt(argc, argv, "h:p:s:u:w:z:dR:t:i:I:l:qvS")) != EOF) switch (ch) { case 'h': hostname = optarg; break; case 'p': port = (PRUint16)atoi(optarg); break; case 's': suffix = optarg; break; case 'u': username = optarg; break; case 'w': password = optarg; break; case 'z': blobsize = atoi(optarg); break; case 'R': use_random = (PRUint32)atol(optarg); break; case 't': thread_count = atoi(optarg); break; case 'i': sampleInterval = (PRUint32)atol(optarg); break; case 'd': noDelay = 1; break; case 'q': quiet = 1; break; case 'v': verbose = 1; break; case 'S': saveQuit = 1; break; case 'l': lmtCount = atoi(optarg); break; case 'I': firstUID = atoi(optarg); break; default: usage(); exit(1); }
if (!suffix || !username || !password) { printf("infadd: missing option\n"); usage(); exit(1); }
if (use_random < 0 || sampleInterval <= 0 || thread_count <= 0 || lmtCount < 0 || blobsize < 0 || firstUID < 0) { printf("infadd: invalid option value\n"); usage(); exit(-1); }
argc -= optind; argv += optind;
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 0);
given_names = nt_new(0); family_names = nt_new(0); if (use_random) { fill_table(given_names, use_random); fill_table(family_names, use_random); } else { if (!access("../data/dbgen-FamilyNames", R_OK)) { strcpy(familynames, "../data/dbgen-FamilyNames"); strcpy(givennames, "../data/dbgen-GivenNames"); } else { strcpy(familynames, "../../data/dbgen-FamilyNames"); strcpy(givennames, "../../data/dbgen-GivenNames"); } fprintf(stdout, "Loading Given-Names ...\n"); if (!nt_load(given_names, givennames)) { fprintf(stdout, "*** Failed to read name table\n"); exit(1); }
fprintf(stdout, "Loading Family-Names ...\n"); if (!nt_load(family_names, familynames)) { fprintf(stdout, "*** Failed to read name table\n"); exit(1); } }
if (saveQuit) { fprintf(stdout, "Saving Given-Names ...\n"); nt_save(given_names, givennames); fprintf(stdout, "Saving Family-Names ...\n"); nt_save(family_names, familynames); exit(0); }
if (firstUID) { at_initID(firstUID); }
/* start up threads */ threads = (AddThread **)malloc(thread_count * sizeof(AddThread *));
index = 0; while (thread_count--) { AddThread *at; PRThread *thr;
at = at_new(); thr = PR_CreateThread(PR_SYSTEM_THREAD, infadd_start, (void *)at, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); at_setThread(at, thr, index+1); threads[index++] = at; } numThreads = index;
fprintf(stdout, "infadd: %d thread%s launched.\n\n", numThreads, numThreads == 1 ? "" : "s");
numDead = 0; counter = 0; while (numThreads) { int x, alive; double tmpv;
PR_Sleep(PR_MillisecondsToInterval(sampleInterval));
counter++;
/* now check for deadies */ for (x = 0; x < numThreads; x++) { alive = at_alive(threads[x]); if (alive < 1) { int y; PRThread *tid;
fprintf(stdout, "T%d DEAD", at_getThread(threads[x], &tid)); if (alive <= -4) { fprintf(stdout, " -- Dead thread being reaped.\n"); PR_JoinThread(tid); for (y = x+1; y < numThreads; y++) threads[y-1] = threads[y]; numThreads--; numDead++; x--; } else fprintf(stdout, " (waiting)\n"); } }
/* check the total count */ ntotal = 0; total = 0; for (x = 0; x < numThreads; x++) { PRUint32 count, min, max, ntot;
at_getCountMinMax(threads[x], &count, &min, &max, &ntot); total += count; ntotal += ntot; if (!quiet && verbose) fprintf(stdout, "T%d min:%5ums, max:%5ums, count: %3u, total: %u\n", at_getThread(threads[x], NULL), min, max, count, ntot); } if (!quiet && (numThreads > 1 || !verbose)) { fprintf(stdout, "Average rate:%7.2f, total: %u\n", (double)total/(double)numThreads, ntotal); } if (lmtCount && ntotal >= lmtCount) { if (!quiet) { fprintf(stdout, "Total added records: %d, Average rate: %7.2f/thrd, " "%6.2f/sec = %6.4fmsec/op\n", ntotal, (double)ntotal/(double)numThreads, (tmpv = (double)ntotal*1000.0/(counter*sampleInterval)), (double)1000.0/tmpv); } exit(1); } /* watchdogs were reset when we fetched the min/max counters */ }
fprintf(stdout, "All threads died. :(\n"); exit(1); }
--- NEW FILE infadd.h --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#ifndef _INFADD_H #define _INFADD_H
#include "nametable.h"
/* global data for the threads to share */ extern char *hostname; extern PRUint16 port; extern char *suffix; extern char *username; extern char *password; extern PRUint32 blobsize; extern NameTable *given_names; extern NameTable *family_names; extern int noDelay;
#endif
--- NEW FILE main.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
/* * this was just easier to start from scratch. windows is too different * from nspr. */
#include <stdio.h> #include <stdlib.h> #ifdef XP_UNIX #include <unistd.h>
#endif #include "nspr.h" #include "rsearch.h" #include "nametable.h" #include "searchthread.h"
void usage() { printf("\nUsage: rsearch -h host -p port -s suffix -D bindDN -w password\n" "-b -- bind before every operation\n" "-u -- don't unbind---just close the connection\n" "-f filter -- Filter\n" "-v -- verbose\n" "-y -- nodelay\n" "-q -- quiet\n" "-l -- logging\n" "-m -- Operaton: Modify. -i required\n" "-d -- Operaton: Delete. -i required\n" "-c -- Operaton: Compare. -i required\n" "-i file -- name file\n" "-A attrs -- Attribute List\n" "-n number -- Reserved for future use\n" "-j number -- Sample interval, in seconds\n" "-t number -- Threads\n\n"); }
/* * Convert a string of the form "foo bar baz" * into an array of strings. Returns a pointer * to allocated memory. Array contains pointers * to the string passed in. So the array needs freed, * but the pointers don't. */ char **string_to_list(char* s) { int string_count = 0; int in_space = 1; char *p;
for (p = s; *p != '\0'; p++) { if (in_space) { if (' ' != *p) { /* We just found the beginning of a string */ string_count++; in_space = 0; } } else if (' ' == *p) { /* Back in space again */ in_space = 1; } }
/* Now we have the suckers counted */ if (string_count > 0) { char **return_array = (char **)malloc((string_count+1)*sizeof(char *)); int index = 0;
in_space = 1; for (p = s; *p != '\0'; p++) { if (in_space) { if (' ' != *p) { /* We just found the beginning of a string */ return_array[index++] = p; in_space = 0; } } else if (' ' == *p) { /* Back in space again */ in_space = 1; *p = '\0'; } } return_array[index] = 0; return return_array; } else return 0; }
/* global data for the threads to share */ char *hostname = "localhost"; int port = 389; int numeric = 0; int threadCount = 1; int verbose = 0; int logging = 0; int doBind = 0; int cool = 0; int quiet = 0; int noDelay = 0; int noUnBind = 0; char *suffix = "o=Ace Industry,c=us"; char *filter = "cn=*jones*"; char *nameFile = 0; char *bindDN = "cn=Directory Manager"; char *bindPW = "unrestricted"; char **attrToReturn = 0; char *attrList = 0; Operation opType = op_search; NameTable *ntable = NULL; int sampleInterval = 10000;
void main(int argc, char** argv) { int index = 0, numThreads, numDead = 0; int ch; SearchThread **threads;
while ((ch = getopt(argc, argv, "j:i:h:s:f:p:t:D:w:n:A:bvlyqmcdu")) != EOF) switch (ch) { case 'h': hostname = optarg; break; case 's': suffix = optarg; break; case 'f': filter = optarg; break; case 'i': nameFile = optarg; break; case 'D': bindDN = optarg; break; case 'w': bindPW = optarg; break; case 'A': attrList = optarg; break; case 'p': port = atoi(optarg); break; case 'b': doBind = 1; break; case 'u': noUnBind = 1; break; case 'n': numeric = atoi(optarg); break; case 't': threadCount = atoi(optarg); break; case 'j': sampleInterval = atoi(optarg) * 1000; break; case 'v': verbose = 1; break; case 'q': quiet = 1; break; case 'l': logging = 1; break; case 'y': noDelay = 1; break; case 'm': opType = op_modify; break; case 'd': opType = op_delete; break; case 'c': opType = op_compare; break; case '?': usage(); exit(1); break; default: break; } argc -= optind; argv += optind;
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 0);
ntable = nt_new(0); if (nameFile) { if (!nt_load(ntable, nameFile)) { printf("Failed to read name table\n"); exit(1); } }
if (attrList) attrToReturn = string_to_list(attrList);
/* a "vector" */ threads = (SearchThread **)malloc(threadCount * sizeof(SearchThread *));
while (threadCount--) { SearchThread *st; PRThread *thr;
st = st_new(); thr = PR_CreateThread(PR_SYSTEM_THREAD, search_start, (void *)st, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); st_setThread(st, thr, index+1); threads[index++] = st; } numThreads = index;
printf("rsearch: %d threads launched.\n\n", numThreads);
while (numThreads != numDead) { int x;
PR_Sleep(PR_MillisecondsToInterval(sampleInterval));
/* now check for deadies */ for (x = 0; x < numThreads; x++) { if (!st_alive(threads[x])) { int y; PRThread *tid;
printf("T%d DEAD.\n", st_getThread(threads[x], &tid)); PR_JoinThread(tid); for (y = x+1; y < numThreads; y++) threads[y-1] = threads[y]; numThreads--; numDead++; x--; } }
/* print out stats */ if (!quiet) { PRUint32 total = 0;
for (x = 0; x < numThreads; x++) { PRUint32 count, min, max;
st_getCountMinMax(threads[x], &count, &min, &max); total += count; printf("T%d min=%4ums, max=%4ums, count = %u\n", st_getThread(threads[x], NULL), min, max, count); } if (numThreads > 1) printf("Average rate = %.2f\n", (double)total/(double)numThreads); } /* watchdogs were reset when we fetched the min/max counters */ }
printf("All threads died. (?)\n"); exit(1); }
--- NEW FILE nametable.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "nspr.h" #include "nametable.h"
struct _nametable { char **data; PRUint32 capacity; PRUint32 size; };
int get_large_random_number() { #ifdef _WIN32 return rand(); #else return random(); #endif }
/* * replacement for fgets * This isn't like the real fgets. It fills in 's' but strips off any * trailing linefeed character(s). The return value is 0 if it went * okay. */ int PR_GetLine(PRFileDesc *fd, char *s, unsigned int n) { PRInt32 start, newstart; int x; char *p;
/* grab current location in file */ start = PR_Seek(fd, 0, PR_SEEK_CUR); x = PR_Read(fd, s, n-1); if (x <= 0) return 1; /* EOF or other error */ s[x] = 0; p = strchr(s, '\n'); if (p == NULL) p = strchr(s, '\r'); if (p == NULL) { /* assume there was one anyway */ return 0; } *p = 0; newstart = start+strlen(s)+1; if ((p != s) && (*(p-1) == '\r')) *(p-1) = 0; PR_Seek(fd, newstart, PR_SEEK_SET); return 0; }
/* new nametable */ NameTable *nt_new(int capacity) { NameTable *nt = (NameTable *)malloc(sizeof(NameTable));
if (!nt) return NULL; if (capacity > 0) { nt->data = (char **)malloc(sizeof(char *) * capacity); if (! nt->data) { free(nt); return NULL; } } else { nt->data = NULL; } nt->capacity = capacity; nt->size = 0; return nt; }
/* destroy nametable */ void nt_destroy(NameTable *nt) { int i;
if (nt->size) { for (i = 0; i < nt->size; i++) free(nt->data[i]); } free(nt->data); free(nt); }
/* push a string into the nametable */ int nt_push(NameTable *nt, char *s) { char **ndata;
if (nt->size >= nt->capacity) { /* expando! */ nt->capacity += NT_STEP; ndata = (char **)realloc(nt->data, sizeof(char *) * nt->capacity); if (!ndata) return 0; nt->data = ndata; } nt->data[nt->size++] = s; return nt->size; }
/* push the contents of a file into the nt, one line per entry */ int nt_load(NameTable *nt, const char *filename) { PRFileDesc *fd;
fd = PR_Open(filename, PR_RDONLY, 0); if (!fd) return 0;
while (PR_Available(fd) > 0) { char temp[256], *s; if (PR_GetLine(fd, temp, 256)) break; s = strdup(temp); if (!s) break; if (!nt_push(nt, s)) break; } PR_Close(fd); return nt->size; }
/* write a nametable out into a file */ int nt_save(NameTable *nt, const char *filename) { PRFileDesc *fd; int i;
fd = PR_Open(filename, PR_WRONLY|PR_CREATE_FILE, 0644); if (!fd) return 0;
for (i = 0; i < nt->size; i++) { PR_Write(fd, nt->data[i], strlen(nt->data[i])); PR_Write(fd, "\n", 1); } PR_Close(fd); return 1; }
/* painstakingly determine if a given entry is already in the list */ int nt_cis_check(NameTable *nt, const char *name) { int i;
for (i = 0; i < nt->size; i++) if (strcasecmp(nt->data[i], name) == 0) return 1; return 0; }
/* select a specific entry */ char *nt_get(NameTable *nt, int entry) { return nt->data[entry]; }
char *nt_getrand(NameTable *nt) { if (! nt->size) return NULL; /* FIXME: rand() on NT will never return a number >32k */ return nt->data[get_large_random_number() % nt->size]; }
/* get all entries */ char **nt_get_all(NameTable *nt ) { return nt->data ; }
--- NEW FILE nametable.h --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#ifndef _NAMETABLE_H #define _NAMETABLE_H
/* * a NameTable is a block that just holds an array of (dynamically allocated) * strings. you can read them all in from a file, and then fetch a specific * entry, or just a random one. */ typedef struct _nametable NameTable;
/* size that the array should grow by when it fills up */ #define NT_STEP 32
NameTable *nt_new(int capacity); void nt_destroy(NameTable *nt); int nt_push(NameTable *nt, char *s); int nt_load(NameTable *nt, const char *filename); int nt_save(NameTable *nt, const char *filename); int nt_cis_check(NameTable *nt, const char *name); char *nt_get(NameTable *nt, int entry); char **nt_get_all(NameTable *nt ); char *nt_getrand(NameTable *nt); int PR_GetLine(PRFileDesc *fd, char *s, unsigned int n); int get_large_random_number();
#endif
--- NEW FILE rsearch.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
/* * XP port of dboreham's NT tool "repeated_search" * robey, march 1998 */
#ifdef LINUX #include <sys/param.h> #include <sys/sysinfo.h> #include <getopt.h> #endif
#include <stdio.h> #include <stdlib.h> #ifdef XP_UNIX #include <unistd.h> #endif #include "nspr.h" #include "rsearch.h" #include "nametable.h" #include "searchthread.h" #include "ldap.h"
#define DEFAULT_HOSTNAME "localhost" #define DEFAULT_PORT 389 #define DEFAULT_THREADS 1 #define DEFAULT_INTERVAL 10000
void usage() { printf("\nUsage: rsearch -D binddn -w bindpw -s suffix -f filter [options]\n" "-\? -- print Usage (this message)\n" "-H -- print Usage (this message)\n" "-h host -- ldap server host (default: %s)\n" "-p port -- ldap server port (default: %d)\n" "-S scope -- search SCOPE [%d,%d,or %d] (default: %d)\n" "-b -- bind before every operation\n" "-u -- don't unbind -- just close the connection\n" "-L -- set linger -- connection discarded when closed\n" "-N -- No operation -- just bind (ignore mdc)\n" "-v -- verbose\n" "-y -- nodelay\n" "-q -- quiet\n" #ifndef NDSRK "-l -- logging\n" #endif /* NDSRK */ "-m -- operaton: modify non-indexed attr (description). -B required\n" "-M -- operaton: modify indexed attr (telephonenumber). -B required\n" "-d -- operaton: delete. -B required\n" "-c -- operaton: compare. -B required\n" "-i file -- name file; used for the search filter\n" "-B file -- [DN and] UID file (use '-B \?' to see the format)\n" "-A attrs -- list of attributes for search request\n" "-a file -- list of attributes for search request in a file\n" " -- (use '-a \?' to see the format ; -a & -A are mutually exclusive)\n" "-n number -- (reserved for future use)\n" "-j number -- sample interval, in seconds (default: %u)\n" "-t number -- threads (default: %d)\n" "-T number -- Time limit, in seconds; cmd stops when exceeds <number>\n" "-V -- show running average\n" "-C num -- take num samples, then stop\n" "-R num -- drop connection & reconnect every num searches\n" "-x -- Use -B file for binding; ignored if -B is not given\n" "\n", DEFAULT_HOSTNAME, DEFAULT_PORT, LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE, LDAP_SCOPE_SUBTREE, (DEFAULT_INTERVAL/1000), DEFAULT_THREADS); exit(1); }
void usage_B() { printf("\nFormat of the file for the '-B <file>' option:\n" "(Assuming each passwd is identical to its corresponding UID.)\n" "\n" "Format 1.\n" "=========\n" "UID: <uid>\n" "...\n" "\n" "Format 2.\n" "=========\n" "DN: <dn>\n" "UID: <uid>\n" "...\n" "\n"); }
void usage_A() { printf("\nNote: -A and -a are mutually exclusive options\n"); printf("\nFormat of the file for the '-a <file>' option:\n" "\n" "Format :\n" "=========\n" "<attr>\n" "<attr>\n" "...\n" "\n");
}
/* * Convert a string of the form "foo bar baz" * into an array of strings. Returns a pointer * to allocated memory. Array contains pointers * to the string passed in. So the array needs freed, * but the pointers don't. */ char **string_to_list(char* s) { int string_count = 0; int in_space = 1; char *p;
for (p = s; *p != '\0'; p++) { if (in_space) { if (' ' != *p) { /* We just found the beginning of a string */ string_count++; in_space = 0; } } else if (' ' == *p) { /* Back in space again */ in_space = 1; } }
/* Now we have the suckers counted */ if (string_count > 0) { char **return_array = (char **)malloc((string_count+1)*sizeof(char *)); int index = 0;
in_space = 1; for (p = s; *p != '\0'; p++) { if (in_space) { if (' ' != *p) { /* We just found the beginning of a string */ return_array[index++] = p; in_space = 0; } } else if (' ' == *p) { /* Back in space again */ in_space = 1; *p = '\0'; } } return_array[index] = 0; return return_array; } else return 0; }
/* global data for the threads to share */ char *hostname = DEFAULT_HOSTNAME; int port = DEFAULT_PORT; int numeric = 0; int threadCount = DEFAULT_THREADS; int verbose = 0; int logging = 0; int doBind = 0; int cool = 0; int quiet = 0; int noDelay = 0; int noUnBind = 0; int noOp = 0; int showRunningAvg = 0; int countLimit = 0; int reconnect = 0; char *suffix = NULL; char *filter = NULL; char *nameFile = 0; char *searchDatFile = 0; char *attrFile = 0; char *bindDN = NULL; char *bindPW = NULL; char **attrToReturn = 0; char *attrList = 0; Operation opType = op_search; NameTable *ntable = NULL; NameTable *attrTable = NULL; SDatTable *sdattable = NULL; int sampleInterval = DEFAULT_INTERVAL; int timeLimit = 0; int setLinger = 0; int useBFile = 0; int myScope = LDAP_SCOPE_SUBTREE;
int main(int argc, char** argv) { int index = 0, numThreads, numDead = 0; int ch; int lifeTime; SearchThread **threads; PRUint32 total; double rate, val, cumrate; double sumVal; int counter;
if (argc == 1) { usage(); exit(1); }
while ((ch = getopt(argc, argv, "B:a:j:i:h:s:f:p:t:T:D:w:n:A:S:C:R:bvlyqmMcduNLHx?V")) != EOF) switch (ch) { case 'h': hostname = optarg; break; case 's': suffix = optarg; break; case 'f': filter = optarg; break; case 'i': nameFile = optarg; break; case 'B': if (optarg[0] == '?') { usage_B(); exit(1); } searchDatFile = optarg; break; case 'D': bindDN = optarg; break; case 'w': bindPW = optarg; break; case 'A': if (!attrFile) attrList = optarg; else usage(); break; case 'p': port = atoi(optarg); break; case 'S': myScope = atoi(optarg); if (myScope < LDAP_SCOPE_BASE || myScope > LDAP_SCOPE_SUBTREE) myScope = LDAP_SCOPE_SUBTREE; break; case 'C': countLimit = atoi(optarg); break; case 'b': doBind = 1; break; case 'u': noUnBind = 1; break; case 'L': setLinger = 1; break; case 'n': numeric = atoi(optarg); break; case 't': threadCount = atoi(optarg); break; case 'j': sampleInterval = atoi(optarg) * 1000; break; case 'v': verbose = 1; break; case 'q': quiet = 1; break; case 'l': logging = 1; break; case 'y': noDelay = 1; break; case 'm': opType = op_modify; break; case 'M': opType = op_idxmodify; break; case 'd': opType = op_delete; break; case 'c': opType = op_compare; break; case 'N': noOp = 1; doBind = 1; /* no use w/o this */ break; case 'T': timeLimit = atoi(optarg); break; case 'V': showRunningAvg = 1; break; case 'R': reconnect = atoi(optarg); break; case 'x': useBFile = 1; break; case 'a': if (optarg[0] == '?') { usage_A(); exit(1); } if (!attrList) attrFile = optarg; else usage(); break; case '?': case 'H': default : usage(); }
if ( !suffix || !filter || !bindDN || !bindPW ) { printf("rsearch: missing option\n"); usage(); }
if ( timeLimit < 0 || threadCount <= 0 || sampleInterval <= 0 ) { printf("rsearch: invalid option value\n"); usage(); } argc -= optind; argv += optind;
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 0);
ntable = nt_new(0); if (nameFile) { if (!nt_load(ntable, nameFile)) { printf("Failed to read name table\n"); exit(1); } }
attrTable = nt_new(0); if (attrFile) { if (!nt_load(attrTable , attrFile)) { printf ("Failed to read attr name table\n"); exit(1); } }
sdattable = sdt_new(0); if (searchDatFile) { if (!sdt_load(sdattable, searchDatFile)) { printf("Failed to read search data table: %s\n", searchDatFile); exit(1); } }
if (attrList) attrToReturn = string_to_list(attrList);
/* a "vector" */ threads = (SearchThread **)malloc(threadCount * sizeof(SearchThread *));
while (threadCount--) { SearchThread *st; PRThread *thr;
st = st_new(); thr = PR_CreateThread(PR_SYSTEM_THREAD, search_start, (void *)st, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); st_setThread(st, thr, index+1); threads[index++] = st; } numThreads = index;
printf("rsearch: %d threads launched.\n\n", numThreads);
lifeTime = 0; counter = 0; sumVal = 0; cumrate = 0.0; while (numThreads) { int x, alive;
PR_Sleep(PR_MillisecondsToInterval(sampleInterval));
counter++; lifeTime += sampleInterval/1000; /* now check for deadies */ for (x = 0; x < numThreads; x++) { alive = st_alive(threads[x]); if (alive < 1) { int y; PRThread *tid;
printf("T%d no heartbeat", st_getThread(threads[x], &tid)); if (alive <= -4) { printf(" -- Dead thread being reaped.\n"); PR_JoinThread(tid); for (y = x+1; y < numThreads; y++) threads[y-1] = threads[y]; numThreads--; numDead++; x--; } else printf(" (waiting)\n"); } }
/* print out stats */ total = 0; for (x = 0; x < numThreads; x++) { PRUint32 count, min, max;
st_getCountMinMax(threads[x], &count, &min, &max); total += count; if (!quiet && verbose) printf("T%d min=%4ums, max=%4ums, count = %u\n", st_getThread(threads[x], NULL), min, max, count); } rate = (double)total / (double)numThreads; val = 1000.0 * (double)total / (double)sampleInterval; cumrate += rate; if ((numThreads > 1) || (!verbose)) { if (!quiet) { if (showRunningAvg) printf("Rate: %7.2f/thr (cumul rate: %7.2f/thr)\n", rate, cumrate/(double)counter); else printf("Rate: %7.2f/thr (%6.2f/sec =%7.4fms/op), " "total:%6u (%d thr)\n", rate, val, (double)1000.0/val, total, numThreads); } } if (countLimit && (counter >= countLimit)) { printf("Thank you, and good night.\n"); exit(0); } if (timeLimit && (lifeTime >= timeLimit)) { double tmpv; if (verbose) printf("%d sec >= %d\n", lifeTime, timeLimit); printf("Final Average rate: " "%6.2f/sec = %6.4fmsec/op, total:%6u\n", (tmpv = (val + sumVal)/counter), (double)1000.0/tmpv, total); exit(0); } sumVal += val; /* watchdogs were reset when we fetched the min/max counters */ }
printf("All threads died. (?)\n"); exit(1); }
--- NEW FILE rsearch.h --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#ifndef _RSEARCH_H #define _RSEARCH_H
typedef enum { op_search, op_modify, op_idxmodify, op_add, op_delete, op_compare } Operation; #include "nametable.h" #include "sdattable.h"
/* global data for the threads to share */ extern char *hostname; extern int port; extern int numeric; /**/ extern int threadCount; /**/ extern int verbose; /**/ extern int logging; extern int doBind; extern int setLinger; /**/ extern int cool; /**/ extern int quiet; extern int noDelay; extern int noUnBind; extern int noOp; extern int myScope; extern char *suffix; extern char *filter; /**/ extern char *nameFile; extern char *bindDN; extern char *bindPW; extern char **attrToReturn; /**/ extern char *attrList; extern Operation opType; extern NameTable *ntable; extern NameTable *attrTable; extern SDatTable *sdattable; /**/ extern int sampleInterval; extern int reconnect; extern int useBFile;
#endif
--- NEW FILE sdattable.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "nspr.h" #include "nametable.h" #include "sdattable.h"
struct _sdattable { char **dns; char **uids; PRUint32 capacity; PRUint32 size; };
/* new searchdata table */ SDatTable *sdt_new(int capacity) { SDatTable *sdt = (SDatTable *)malloc(sizeof(SDatTable));
if (!sdt) return NULL; if (capacity > 0) { sdt->dns = (char **)malloc(sizeof(char *) * capacity); if (! sdt->dns) { free(sdt); return NULL; } sdt->uids = (char **)malloc(sizeof(char *) * capacity); if (! sdt->uids) { free(sdt->dns); free(sdt); return NULL; } } else { sdt->dns = NULL; sdt->uids = NULL; } sdt->capacity = capacity; sdt->size = 0; return sdt; }
/* destroy searchdata table */ void sdt_destroy(SDatTable *sdt) { int i;
if (sdt->size) { for (i = 0; i < sdt->size; i++) { if (sdt->dns[i]) free(sdt->dns[i]); if (sdt->uids[i]) free(sdt->uids[i]); } } if (sdt->dns); free(sdt->dns); if (sdt->uids); free(sdt->uids); free(sdt); }
/* push a string into the searchdata table */ int sdt_push(SDatTable *sdt, char *dn, char *uid) { char **sddns, **sddns0; char **sduids;
if (!dn && !uid) return sdt->size;
if (sdt->size >= sdt->capacity) { /* expando! */ sdt->capacity += SDT_STEP; sddns = (char **)realloc(sdt->dns, sizeof(char *) * sdt->capacity); if (!sddns) return 0; sddns0 = sdt->dns; sdt->dns = sddns; sduids = (char **)realloc(sdt->uids, sizeof(char *) * sdt->capacity); if (!sduids) { sdt->dns = sddns0; /* restore */ return 0; } sdt->uids = sduids; }
sdt->dns[sdt->size] = dn; /* might be null */ sdt->uids[sdt->size] = uid; /* never be null */ return ++sdt->size; }
/* push the contents of a file into the sdt, one line per entry */ int sdt_load(SDatTable *sdt, const char *filename) { PRFileDesc *fd;
fd = PR_Open(filename, PR_RDONLY, 0); if (!fd) return 0;
while (PR_Available(fd) > 0) { int rval; char temp[256]; char *dn = NULL; char *uid = NULL; while (!(rval = PR_GetLine(fd, temp, 256))) { char *p; if (!strncasecmp(temp, "dn:", 3)) { for (p = temp + 4; *p == ' ' || *p == '\t'; p++) ; dn = strdup(p); if (!dn) break; } else if (!strncasecmp(temp, "uid:", 4)) { for (p = temp + 5; *p == ' ' || *p == '\t'; p++) ; uid = strdup(p); if (!uid) break; } if (uid) { /* dn should come earlier than uid */ if (!sdt_push(sdt, dn, uid)) goto out; break; } } if (rval) break; /* PR_GetLine failed */ } out: PR_Close(fd); return sdt->size; }
/* write a searchdata table out into a file */ int sdt_save(SDatTable *sdt, const char *filename) { PRFileDesc *fd; int i;
fd = PR_Open(filename, PR_WRONLY|PR_CREATE_FILE, 0644); if (!fd) return 0;
for (i = 0; i < sdt->size; i++) { if (sdt->dns[i]) { PR_Write(fd, "dn: ", 4); PR_Write(fd, sdt->dns[i], strlen(sdt->dns[i])); PR_Write(fd, "\n", 1); } if (sdt->dns[i]) { PR_Write(fd, "uid: ", 5); PR_Write(fd, sdt->uids[i], strlen(sdt->uids[i])); PR_Write(fd, "\n", 1); } } PR_Close(fd); return 1; }
/* painstakingly determine if a given entry is already in the list */ int sdt_cis_check(SDatTable *sdt, const char *name) { int i;
for (i = 0; i < sdt->size; i++) { if (strcasecmp(sdt->dns[i], name) == 0) return 1; if (strcasecmp(sdt->uids[i], name) == 0) return 1; } return 0; }
/* select a specific entry */ char *sdt_dn_get(SDatTable *sdt, int entry) { return sdt->dns[entry]; }
void sdt_dn_set(SDatTable *sdt, int entry, char *dn) { sdt->dns[entry] = strdup(dn); }
char *sdt_uid_get(SDatTable *sdt, int entry) { return sdt->uids[entry]; }
int sdt_getrand(SDatTable *sdt) { if (! sdt->size) return -1; /* FIXME: rand() on NT will never return a number >32k */ return get_large_random_number() % sdt->size; }
int sdt_getlen(SDatTable *sdt) { return sdt->size; }
--- NEW FILE sdattable.h --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#ifndef _SDATTABLE_H #define _SDATTABLE_H
/* * a SDatTable is a block that just holds an array of (dynamically allocated) * dn & uid pair (dn might be empty). you can read them all in from a file, * and then fetch a specific entry, or just a random one. */ typedef struct _sdattable SDatTable;
/* size that the array should grow by when it fills up */ #define SDT_STEP 32
SDatTable *sdt_new(int capacity); void sdt_destroy(SDatTable *sdt); int sdt_push(SDatTable *sdt, char *dn, char *uid); int sdt_load(SDatTable *sdt, const char *filename); int sdt_save(SDatTable *sdt, const char *filename); int sdt_cis_check(SDatTable *sdt, const char *name); char *sdt_dn_get(SDatTable *sdt, int entry); void sdt_dn_set(SDatTable *sdt, int entry, char *dn); char *sdt_uid_get(SDatTable *sdt, int entry); int sdt_getrand(SDatTable *sdt); int sdt_getlen(SDatTable *sdt);
#endif
--- NEW FILE searchthread.c --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef XP_UNIX #include <unistd.h> #endif #include <time.h> #include <errno.h> #include "nspr.h" #include <sys/types.h> #include <sys/socket.h> #include <netinet/tcp.h> /* for TCP_NODELAY */ #include "ldap.h" #include "rsearch.h" #include "searchthread.h"
/* local data for a search thread */ struct _searchthread { PRUint32 searchCount; PRUint32 failCount; double mintime; double maxtime; LDAP *ld; LDAP *ld2; /* aux LDAP handle */ LBER_SOCKET soc; PRThread *tid; PRLock *lock; int id; int alive; int retry; };
/* new searchthread */ SearchThread *st_new(void) { SearchThread *st = (SearchThread *)malloc(sizeof(SearchThread));
if (!st) return NULL; st->searchCount = st->failCount = 0; st->mintime = 10000; st->maxtime = 0; st->ld = NULL; st->ld2 = NULL; st->soc = -1; st->tid = NULL; st->id = 0; st->alive = 1; st->lock = PR_NewLock(); st->retry = 0; srand(time(0)); return st; }
void st_setThread(SearchThread *st, PRThread *tid, int id) { st->tid = tid; st->id = id; }
int st_getThread(SearchThread *st, PRThread **tid) { if (tid) *tid = st->tid; return st->id; }
static void st_enableTCPnodelay(SearchThread *st) { int val = 1;
if (st->soc < 0) { if (ldap_get_option(st->ld, LDAP_OPT_DESC, (void *)&st->soc) != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed on ldap_get_option\n", st->id); return; } } if (setsockopt(st->soc, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val))) fprintf(stderr, "T%d: failed in setsockopt 1\n", st->id); }
/* abruptly disconnect an LDAP connection without unbinding */ static void st_disconnect(SearchThread *st) { if (st->soc < 0) { if (ldap_get_option(st->ld, LDAP_OPT_DESC, (void *)&st->soc) != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed on ldap_get_option\n", st->id); return; } } #ifdef XP_WIN if (closesocket(st->soc)) fprintf(stderr, "T%d: failed to disconnect\n", st->id); #else if (close(st->soc)) fprintf(stderr, "T%d: failed to disconnect\n", st->id); #endif st->soc = -1; }
static int st_bind_core(SearchThread *st, LDAP **ld, char *dn, char *uid) { int ret = 0; int retry = 0; while (1) { ret = ldap_simple_bind_s(*ld, dn, uid); if (LDAP_SUCCESS == ret) { break; } else if (LDAP_CONNECT_ERROR == ret && retry < 10) { retry++; } else { fprintf(stderr, "T%d: failed to bind, ldap_simple_bind_s" "(%s, %s) returned 0x%x (errno %d)\n", st->id, dn, uid, ret, errno); *ld = NULL; return 0; } } return 1; }
static int st_bind(SearchThread *st) { if (!st->ld) { st->ld = ldap_init(hostname, port); if (!st->ld) { fprintf(stderr, "T%d: failed to init\n", st->id); return 0; } } if (!st->ld2) { /* aux LDAP handle */ st->ld2 = ldap_init(hostname, port); if (!st->ld2) { fprintf(stderr, "T%d: failed to init 2\n", st->id); return 0; } if (0 == st_bind_core(st, &(st->ld2), strlen(bindDN) ? bindDN : NULL, strlen(bindPW) ? bindPW : NULL)) { return 0; } }
if (opType != op_delete && opType != op_modify && opType != op_idxmodify && sdattable && sdt_getlen(sdattable) > 0) { int e; char *dn, *uid;
do { e = sdt_getrand(sdattable); } while (e < 0); dn = sdt_dn_get(sdattable, e); uid = sdt_uid_get(sdattable, e);
if (useBFile) { /* in this test, assuming uid == password */ if (dn) { if (0 == st_bind_core(st, &(st->ld), dn, uid)) { return 0; } } else if (uid) { char filterBuffer[100]; char *pFilter; struct timeval timeout; int scope = LDAP_SCOPE_SUBTREE, attrsOnly = 0; LDAPMessage *result; int retry = 0;
pFilter = filterBuffer; sprintf(filterBuffer, "(uid=%s)", uid); timeout.tv_sec = 3600; timeout.tv_usec = 0; while (1) { int ret = ldap_search_st(st->ld2, suffix, scope, pFilter, NULL, attrsOnly, &timeout, &result); if (LDAP_SUCCESS == ret) { break; } else if ((LDAP_CONNECT_ERROR == ret || (LDAP_TIMEOUT == ret)) && retry < 10) { retry++; } else { fprintf(stderr, "T%d: failed to search 1, error=0x%x\n", st->id, ret); return 0; } } dn = ldap_get_dn(st->ld2, result);
if (0 == st_bind_core(st, &(st->ld), dn, uid)) { return 0; } } else { fprintf(stderr, "T%d: no data found, dn: %p, uid: %p\n", st->id, dn, uid); return 0; } } else { if (0 == st_bind_core(st, &(st->ld), dn, uid)) { return 0; } } } else { if (0 == st_bind_core(st, &(st->ld), strlen(bindDN) ? bindDN : NULL, strlen(bindPW) ? bindPW : NULL)) { return 0; } } if (st->soc < 0) { if (ldap_get_option(st->ld, LDAP_OPT_DESC, (void *)&st->soc) != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed on ldap_get_option\n", st->id); return 0; } } if (setLinger) { int val; struct linger l; val = sizeof(struct linger); l.l_onoff = 1; l.l_linger = 0; if (setsockopt(st->soc, SOL_SOCKET, SO_LINGER, (char *)&l, val) < 0) { fprintf(stderr, "T%d: failed in setsockopt 2, errno %d (%d)\n", st->id, errno, st->soc); st->soc = -1; return 0; } } return 1; }
static void st_unbind(SearchThread *st) { if (ldap_unbind(st->ld) != LDAP_SUCCESS) fprintf(stderr, "T%d: failed to unbind\n", st->id); st->ld = NULL; st->soc = -1; }
static int st_search(SearchThread *st) { char filterBuffer[100]; char *pFilter; struct timeval timeout; int scope, attrsOnly = 0; LDAPMessage *result; int ret;
scope = myScope; if (ntable || numeric) { char *s = NULL; char num[8];
if (! numeric) { do { s = nt_getrand(ntable); } while ((s) && (strlen(s) < 1)); } else { sprintf(num, "%d", get_large_random_number() % numeric); s = num; } sprintf(filterBuffer, filter, s); pFilter = filterBuffer; } else { pFilter = filter; }
/* Try to get attributes from the attrNameTable */ if (!attrToReturn) attrToReturn = nt_get_all(attrTable);
timeout.tv_sec = 30; timeout.tv_usec = 0; ret = ldap_search_st(st->ld, suffix, scope, pFilter, attrToReturn, attrsOnly, &timeout, &result); if (ret != LDAP_SUCCESS) { fprintf(stderr, "T%d: failed to search 2, error=0x%02X\n", st->id, ret); } ldap_msgfree(result); return ret; }
static void st_make_random_tel_number(char *pstr) { static char *area_codes[] = {"303", "415", "408", "650", "216", "580", 0};
int idx = rand() % 6;
sprintf(pstr, "+1 %s %03d %04d", area_codes[idx], rand() % 1000, rand() % 10000); }
static int st_modify_nonidx(SearchThread *st) { LDAPMod *attrs[2]; LDAPMod attr_description; int e; int rval; char *dn = NULL; char description[256]; char *description_values[2];
/* Decide what entry to modify, for this we need a table */ if (NULL == sdattable || sdt_getlen(sdattable) == 0) { fprintf(stderr, "-m option requires a DN file. Use -B file.\n"); return 0; }
/* Get the target dn */ do { e = sdt_getrand(sdattable); } while (e < 0); dn = sdt_dn_get(sdattable, e);
sprintf(description, "%s modified at %lu", dn, time(NULL)); description_values[0] = description; description_values[1] = NULL;
attrs[0] = &attr_description; attrs[1] = NULL;
attr_description.mod_op = LDAP_MOD_REPLACE; attr_description.mod_type = "description"; attr_description.mod_values = description_values;
rval = ldap_modify_s(st->ld, dn, attrs); if (rval != LDAP_SUCCESS) { fprintf(stderr, "T%d: Failed to modify error=0x%x\n", st->id, rval); fprintf(stderr, "dn: %s\n", dn); } return rval; }
static int st_modify_idx(SearchThread *st) { LDAPMod *attrs[2]; LDAPMod attr_telephonenumber; int e; int rval; char *dn = NULL; char telno[32]; char *telephonenumber_values[2];
/* Decide what entry to modify, for this we need a table */ if (NULL == sdattable || sdt_getlen(sdattable) == 0) { fprintf(stderr, "-m option requires a DN file. Use -B file.\n"); return 0; }
/* Get the target dn */ do { e = sdt_getrand(sdattable); } while (e < 0); dn = sdt_dn_get(sdattable, e);
/* Make new mod values */ st_make_random_tel_number(telno);
telephonenumber_values[0] = telno; telephonenumber_values[1] = NULL;
attrs[0] = &attr_telephonenumber; attrs[1] = NULL;
attr_telephonenumber.mod_op = LDAP_MOD_REPLACE; attr_telephonenumber.mod_type = "telephonenumber"; attr_telephonenumber.mod_values = telephonenumber_values;
rval = ldap_modify_s(st->ld, dn, attrs); if (rval != LDAP_SUCCESS) { fprintf(stderr, "T%d: Failed to modify error=0x%x\n", st->id, rval); fprintf(stderr, "dn: %s\n", dn); } return rval; }
static int st_compare(SearchThread *st) { int rval; int compare_true; int correct_answer; int e; char *dn = NULL; char *uid = NULL; char uid0[100];
/* Decide what entry to modify, for this we need a table */ if (NULL == sdattable || sdt_getlen(sdattable) == 0) { fprintf(stderr, "-c option requires a DN file. Use -B file.\n"); return 0; }
/* Get the target dn */ do { e = sdt_getrand(sdattable); } while (e < 0); dn = sdt_dn_get(sdattable, e); uid = sdt_uid_get(sdattable, e);
compare_true = ( (rand() % 5) < 2 );
if (!compare_true) { strcpy(uid0, uid); uid0[0] = '@'; /* make it not matched */ uid = uid0; } rval = ldap_compare_s(st->ld, dn, "uid", uid); correct_answer = compare_true ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; if (rval == correct_answer) { rval = LDAP_SUCCESS; } else { fprintf(stderr, "T%d: Failed to compare error=0x%x (%d)\n", st->id, rval, correct_answer); fprintf(stderr, "dn: %s, uid: %s\n", dn, uid); } return rval; }
static int st_delete(SearchThread *st) { char *dn = NULL; int rval; int e;
/* Decide what entry to modify, for this we need a table */ if (NULL == sdattable || sdt_getlen(sdattable) == 0) { fprintf(stderr, "-d option requires a DN file. Use -B file.\n"); return 0; }
/* Get the target dn */ do { e = sdt_getrand(sdattable); } while (e < 0); dn = sdt_dn_get(sdattable, e);
rval = ldap_delete_s(st->ld, dn); if (rval != LDAP_SUCCESS) { if (rval == LDAP_NO_SUCH_OBJECT) { rval = LDAP_SUCCESS; } else { fprintf(stderr, "T%d: Failed to delete error=0x%x\n", st->id, rval); fprintf(stderr, "dn: %s\n", dn); } } return rval; }
/* the main thread */ void search_start(void *v) { SearchThread *st = (SearchThread *)v; PRIntervalTime timer; int notBound = 1, res, searches = 0; PRUint32 span;
st->alive = 1; st->ld = 0; while (1) { timer = PR_IntervalNow();
/* bind if we need to */ if (doBind || notBound) { res = st_bind(st); if (noDelay) st_enableTCPnodelay(st); if (!res) { st_unbind(st); continue; /* error */ } notBound = 0; }
/* do the operation */ if (!noOp) { switch(opType) { case op_modify: res = st_modify_nonidx(st); break; case op_idxmodify: res = st_modify_idx(st); break; case op_search: res = st_search(st); break; case op_compare: res = st_compare(st); break; case op_delete: res = st_delete(st); break; default: fprintf(stderr, "Illegal operation type specified.\n"); return; } } if (LDAP_SUCCESS == res) { st->retry = 0; } else if (LDAP_CONNECT_ERROR == res && st->retry < 10) { st->retry++; } else { break; /* error */ } if (doBind) { if (noUnBind) st_disconnect(st); st_unbind(st); } else if (reconnect) { searches++; if (searches >= reconnect) { /* unceremoniously disconnect, reconnect next cycle */ st_disconnect(st); st_unbind(st); notBound = 1; searches = 0; } }
span = PR_IntervalToMilliseconds(PR_IntervalNow()-timer); /* update data */ PR_Lock(st->lock); if (0 == st->retry) { /* only when succeeded */ st->searchCount++; if (st->mintime > span) st->mintime = span; if (st->maxtime < span) st->maxtime = span; } st->alive = 1; PR_Unlock(st->lock); } }
/* fetches the current min/max times and the search count, and clears them */ void st_getCountMinMax(SearchThread *st, PRUint32 *count, PRUint32 *min, PRUint32 *max) { PR_Lock(st->lock); if (count) { *count = st->searchCount; st->searchCount = 0; } if (min) { *min = st->mintime; st->mintime = 10000; } if (max) { *max = st->maxtime; st->maxtime = 0; } st->alive--; PR_Unlock(st->lock); }
int st_alive(SearchThread *st) { int alive;
PR_Lock(st->lock); alive = st->alive; PR_Unlock(st->lock); return alive; }
--- NEW FILE searchthread.h --- /** BEGIN COPYRIGHT BLOCK * Copyright 2001 Sun Microsystems, Inc. * Portions copyright 1999, 2001 Netscape Communications Corporation. * All rights reserved. * END COPYRIGHT BLOCK **/
#ifndef _SEARCHTHREAD_H #define _SEARCHTHREAD_H
typedef struct _searchthread SearchThread;
SearchThread *st_new(void); void st_setThread(SearchThread *st, PRThread *tid, int id); int st_getThread(SearchThread *st, PRThread **tid); void search_start(void *v); void st_getCountMinMax(SearchThread *st, PRUint32 *count, PRUint32 *min, PRUint32 *max); int st_alive(SearchThread *st);
#endif
389-commits@lists.fedoraproject.org