[Fedora-directory-commits] ldapserver/ldap/servers/slapd/tools/ldclt Makefile, NONE, 1.1 README, NONE, 1.1 data.c, NONE, 1.1 ldap-private.h, NONE, 1.1 ldapfct.c, NONE, 1.1 ldclt.c, NONE, 1.1 ldclt.h, NONE, 1.1 ldclt.man, NONE, 1.1 ldclt.use, NONE, 1.1 ldcltU.c, NONE, 1.1 opCheck.c, NONE, 1.1 parser.c, NONE, 1.1 port.c, NONE, 1.1 port.h, NONE, 1.1 remote.h, NONE, 1.1 repcheck.c, NONE, 1.1 repslave.c, NONE, 1.1 scalab01.c, NONE, 1.1 scalab01.h, NONE, 1.1 srv.c, NONE, 1.1 threadMain.c, NONE, 1.1 utils.c, NONE, 1.1 utils.h, NONE, 1.1 version.c, NONE, 1.1 workarounds.c, NONE, 1.1

Noriko Hosoi (nhosoi) fedora-directory-commits at redhat.com
Wed Jan 11 01:54:38 UTC 2006


Author: nhosoi

Update of /cvs/dirsec/ldapserver/ldap/servers/slapd/tools/ldclt
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv8602/ldclt

Added Files:
	Makefile README data.c ldap-private.h ldapfct.c ldclt.c 
	ldclt.h ldclt.man ldclt.use ldcltU.c opCheck.c parser.c port.c 
	port.h remote.h repcheck.c repslave.c scalab01.c scalab01.h 
	srv.c threadMain.c utils.c utils.h version.c workarounds.c 
Log Message:
[164596] LDCLT distributed with Directory Server
integrated ldclt from DSRK into the DS source 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) 2006 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#
#
#	This Makefile is targetted to build the ldclt tool. This tool is a 
#	multithreaded ldap client, specially targetted to ensure good 
#	reliability of the product under test.
#
# -----------------------------------------------------------------------------

LDAP_SRC = ../../../..
BUILD_ROOT = ../../../../..

OBJDEST         = $(OBJDIR)/servers/tools/obj
BINDIR = $(RELDIR)/shared/bin
DATDIR = $(RELDIR)/shared/data

include $(BUILD_ROOT)/nsdefs.mk
include $(BUILD_ROOT)/nsconfig.mk
include $(LDAP_SRC)/nsldap.mk

ifeq ($(OS_ARCH), WINNT)
OBJEXT          =.obj
else
OBJEXT          =.o
endif

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)

LDCLTSRC	= \
		data.c \
		ldapfct.c \
		ldclt.c \
		ldcltU.c \
		parser.c \
		port.c \
		scalab01.c \
		threadMain.c \
		utils.c \
		version.c \
		workarounds.c

#ifdef SUN_DS_3_X_SUPPORT
LDCLTSRC	+= opCheck.c
#endif

LDCLTOBJS	= $(addprefix $(OBJDEST)/, $(LDCLTSRC:.c=$(OBJEXT)))

HDIR            = $(LDAP_SRC)/include

LDCLTBIN	= $(addsuffix $(EXE_SUFFIX), $(addprefix $(BINDIR)/, ldclt))

INC_FILES	= \
		ldclt.h \
		port.h \
		utils.h \
		remote.h

INC_PLUGINS	= \
		scalab01.h 

ADDLIBS		= $(LDAPLIBS) $(SPEC_LIBS) $(SYSTEM_LIBS) $(END)

CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP 

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)

##########################################################################

all: $(OBJDEST) $(BINDIR) $(LDCLTBIN)

clean:
	-$(RM) $(LDCLTOBJS) $(LDCLTBIN)

$(OBJDEST): 
	if [ ! -d $(OBJDEST) ]; then \
		$(MKDIR) $(OBJDEST); \
	fi

$(BINDIR):
	if [ ! -d $(BINDIR) ]; then \
		$(MKDIR) $(BINDIR); \
	fi

$(LDCLTBIN): $(LDCLTOBJS)
	$(LINK_EXE) $(LDCLTOBJS) $(EXTRA_LIBS)
	-chmod 755 $(LDCLTBIN)



--- NEW FILE README ---
CVS snapshot in sync with ldclt 4.23


--- NEW FILE data.c ---
#ident "ldclt @(#)data.c	1.8 01/03/23"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		data.c
	AUTHOR :	Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		11 January 1999
	DESCRIPTION :	
			This file implements the management of the data that 
			are manipulated by ldclt.
			It is targetted to contain all the functions needed for 
			the images, etc...
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
11/01/99 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
06/03/00 | JL Schwing	| 1.2 : Test malloc() return value.
---------+--------------+------------------------------------------------------
28/11/00 | JL Schwing	| 1.3 : Port on NT 4.
---------+--------------+------------------------------------------------------
30/11/00 | JL Schwing	| 1.4 : Implement loadImages for NT.
---------+--------------+------------------------------------------------------
30/11/00 | JL Schwing	| 1.5 : Port on OSF1.
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.6 : Port on Linux.
---------+--------------+------------------------------------------------------
06/03/01 | JL Schwing	| 1.7 : Better error messages if images not found.
---------+--------------+------------------------------------------------------
23/03/01 | JL Schwing	| 1.8 : Implements data file list support in variants.
---------+--------------+------------------------------------------------------
*/

#include <stdio.h>	/* printf(), etc... */
#include <stdlib.h>	/* realloc(), etc... */
#include <string.h>	/* strlen(), etc... */
#include <errno.h>	/* errno, etc... */			/*JLS 06-03-00*/
#include <sys/types.h>	/* Misc types... */
#include <sys/stat.h>	/* stat(), etc... */
#include <fcntl.h>	/* open(), etc... */
#include <lber.h>	/* ldap C-API BER declarations */
#include <ldap.h>	/* ldap C-API declarations */
#ifndef _WIN32							/*JLS 28-11-00*/
#include <unistd.h>	/* close(), etc... */
#include <dirent.h>	/* opendir(), etc... */
#include <pthread.h>	/* pthreads(), etc... */
#include <sys/mman.h>	/* mmap(), etc... */
#endif								/*JLS 28-11-00*/

#include "port.h"	/* Portability definitions */		/*JLS 28-11-00*/
#include "ldclt.h"	/* This tool's include file */






/* ****************************************************************************
	FUNCTION :	getExtend
	PURPOSE :	Get the extension of the given string, i.e. the part
			that is after the last '.'
	INPUT :		str	= string to process
	OUTPUT :	None.
	RETURN :	The extension.
	DESCRIPTION :
 *****************************************************************************/
char *getExtend (
	char	*str)
{
  int	 i;
  for (i=strlen(str)-1; (i>=0) && (str[i]!='.') ; i--);
  return (&(str[i+1]));
}




/* ****************************************************************************
	FUNCTION :	loadImages
	PURPOSE :	Load the images from the given directory.
	INPUT :		dirpath	= directory where the images are located.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int loadImages (
	char	*dirpath)
{
#ifdef _WIN32
  WIN32_FIND_DATA	 fileData;	/* Current file */
  HANDLE		 dirContext;	/* Directory context */
  char			*findPath;	/* To build the find path */
  char			*pt;		/* To read the images */
#else /* _WIN32 */
  DIR		*dirp;		/* Directory data */
  struct dirent	*direntp;	/* Directory entry */
#endif /* _WIN32 */
  char		*fileName;	/* As read from the system */
  char		 name [1024];	/* To build the full path */
  struct stat	 stat_buf;	/* To read the image size */
  int		 fd;		/* To open the image */
  int		 ret;		/* Return value */

  /*
   * Initialization
   */
  mctx.images     = NULL;
  mctx.imagesNb   = 0;
  mctx.imagesLast = -1;

  if ((ret = ldclt_mutex_init(&(mctx.imagesLast_mutex))) != 0)
  {
    fprintf (stderr, "ldclt: %s\n", strerror (ret));
    fprintf (stderr, "Error: cannot initiate imagesLast_mutex\n");
    fflush (stderr);
    return (-1);
  }

  /*
   * Open the directory
   */
#ifdef _WIN32
  findPath = (char *) malloc (strlen (dirpath) + 5);
  strcpy (findPath, dirpath);
  strcat (findPath, "/*.*");
  dirContext = FindFirstFile (findPath, &fileData);
  if (dirContext == INVALID_HANDLE_VALUE)
  {
    fprintf (stderr, "ldlct: cannot load images from %s\n", dirpath);
    fprintf (stderr, "ldclt: try using -e imagesdir=path\n");	/*JLS 06-03-01*/
    fflush (stderr);
    free (findPath);
    return (-1);
  }
#else /* _WIN32 */
  dirp = opendir (dirpath);
  if (dirp == NULL)
  {
    perror (dirpath);
    fprintf (stderr, "ldlct: cannot load images from %s\n", dirpath);
    fprintf (stderr, "ldclt: try using -e imagesdir=path\n");	/*JLS 06-03-01*/
    fflush (stderr);
    return (-1);
  }
#endif /* _WIN32 */

  /*
   * Process the directory.
   * We will only accept the .jpg files, as stated by the RFC.
   */
#ifdef _WIN32
  fileName = fileData.cFileName;
  do
  {
#else
  while ((direntp = readdir (dirp)) != NULL)
  {
    fileName = direntp->d_name;
#endif
    if (!strcmp (getExtend (fileName), "jpg"))
    {
      /*
       * Allocate a new image, and initiates with its name.
       */
      mctx.imagesNb++;
      mctx.images = 
		(image *) realloc (mctx.images, mctx.imagesNb * sizeof (image));
      if (mctx.images == NULL)					/*JLS 06-03-00*/
      {								/*JLS 06-03-00*/
	printf ("Error: cannot realloc(mctx.images), error=%d (%s)\n",
		errno, strerror (errno));			/*JLS 06-03-00*/
	return (-1);						/*JLS 06-03-00*/
      }								/*JLS 06-03-00*/
      mctx.images[mctx.imagesNb-1].name = 
		(char *) malloc (strlen(fileName) + 1);
      if (mctx.images[mctx.imagesNb-1].name == NULL)		/*JLS 06-03-00*/
      {								/*JLS 06-03-00*/
	printf ("Error: cannot malloc(mctx.images[%d]).name, error=%d (%s)\n",
		mctx.imagesNb-1, errno, strerror (errno));	/*JLS 06-03-00*/
	return (-1);						/*JLS 06-03-00*/
      }								/*JLS 06-03-00*/
      strcpy (mctx.images[mctx.imagesNb-1].name, fileName);

      /*
       * Read the image size
       */
      strcpy (name, dirpath);
      strcat (name, "/");
      strcat (name, fileName);
      if (stat (name, &stat_buf) < 0)
      {
	perror (name);
	fprintf (stderr, "Cannot stat(%s)\n", name);
	fflush (stderr);
	return (-1);
      }
      mctx.images[mctx.imagesNb-1].length = stat_buf.st_size;

      /*
       * Open the image
       */
      fd = open (name, O_RDONLY);
      if (fd < 0)
      {
	perror (name);
	fprintf (stderr, "Cannot open(%s)\n", name);
	fflush (stderr);
	return (-1);
      }

#ifdef _WIN32
      /*
       * Allocate buffer and read the data :-(
       */
      mctx.images[mctx.imagesNb-1].data = (char *) malloc (stat_buf.st_size);
      if (mctx.images[mctx.imagesNb-1].data == NULL)
      {
	fprintf (stderr, "Cannot malloc(%d) to load %s\n",
				stat_buf.st_size, name);
	fflush (stderr);
	return (-1);
      }
      if (read (fd, mctx.images[mctx.imagesNb-1].data, stat_buf.st_size) < 0)
      {
	perror (name);
	fprintf (stderr, "Cannot read(%s)\n", name);
	fflush (stderr);
	return (-1);
      }
#else /* _WIN32 */
      /*
       * mmap() the image
       */
      mctx.images[mctx.imagesNb-1].data = mmap (0, stat_buf.st_size,
			PROT_READ, MAP_SHARED, fd, 0);
      if (mctx.images[mctx.imagesNb-1].data == (char *)MAP_FAILED)
      {
	perror (name);
	fprintf (stderr, "Cannot mmap(%s)\n", name);
	fflush (stderr);
	return (-1);
      }
#endif /* _WIN32 */

      /*
       * Close the image. The mmap() will remain available, and this
       * close() will save file descriptors.
       */
      if (close (fd) < 0)
      {
	perror (name);
	fprintf (stderr, "Cannot close(%s)\n", name);
	fflush (stderr);
	return (-1);
      }
    }
#ifdef _WIN32
  } while (FindNextFile(dirContext, &fileData) == TRUE);
#else
  } /* while ((direntp = readdir (dirp)) != NULL) */
#endif

  /*
   * Close the directory
   */
#ifndef _WIN32
  if (closedir (dirp) < 0)
  {
    perror (dirpath);
    fprintf (stderr, "Cannot closedir(%s)\n", dirpath);
    fflush (stderr);
    return (-1);
  }
#endif

  /*
   * Normal end
   */
#ifdef _WIN32
  free (findPath);
#endif
  return (0);
}






/* ****************************************************************************
	FUNCTION :	getImage
	PURPOSE :	Add a random image to the given attribute.
	INPUT :		None.
	OUTPUT :	attribute	= the attribute where the image should 
					  be added.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int getImage (
	LDAPMod		*attribute)
{
  int	 imageNumber;	/* The image we will select */
  int	 ret;		/* Return value */

  /*
   * Select the next image
   */
  if ((ret = ldclt_mutex_lock (&(mctx.imagesLast_mutex))) != 0)	/*JLS 29-11-00*/
  {
    fprintf (stderr, 
	"Cannot mutex_lock(imagesLast_mutex), error=%d (%s)\n", 
	ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }
  mctx.imagesLast++;
  if (mctx.imagesLast == mctx.imagesNb)
    mctx.imagesLast = 0;
  imageNumber = mctx.imagesLast;
  if ((ret = ldclt_mutex_unlock (&(mctx.imagesLast_mutex))) != 0)
  {
    fprintf (stderr,
	"Cannot mutex_unlock(imagesLast_mutex), error=%d (%s)\n",
	ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Create the data structure required
   */
  attribute->mod_bvalues = (struct berval **) 
		malloc (2 * sizeof (struct berval *));
  if (attribute->mod_bvalues == NULL)				/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf ("Error: cannot malloc(attribute->mod_bvalues), error=%d (%s)\n",
		errno, strerror (errno));			/*JLS 06-03-00*/
    return (-1);						/*JLS 06-03-00*/
  }								/*JLS 06-03-00*/
  attribute->mod_bvalues[0] = (struct berval *) malloc (sizeof (struct berval));
  if (attribute->mod_bvalues[0] == NULL)			/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf ("Error: cannot malloc(attribute->mod_bvalues[0]), error=%d (%s)\n",
		errno, strerror (errno));			/*JLS 06-03-00*/
    return (-1);						/*JLS 06-03-00*/
  }								/*JLS 06-03-00*/
  attribute->mod_bvalues[1] = NULL;

  /*
   * Fill the bvalue with the image data
   */
  attribute->mod_bvalues[0]->bv_len = mctx.images[imageNumber].length;
  attribute->mod_bvalues[0]->bv_val = mctx.images[imageNumber].data;

  /*
   * Normal end
   */
  return (0);
}







						/* New */	/*JLS 23-03-01*/
/* ****************************************************************************
	FUNCTION :	loadDataListFile
	PURPOSE :	Load the data list file given in argument.
	INPUT :		dlf->fname	= file to process
	OUTPUT :	dlf		= file read
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
loadDataListFile (
	data_list_file	*dlf)
{
  FILE	*ifile;			/* Input file */
  char	 line[MAX_FILTER];	/* To read ifile */

  /*
   * Open the file
   */
  ifile = fopen (dlf->fname, "r");
  if (ifile == NULL)
  {
    perror (dlf->fname);
    fprintf (stderr, "Error: cannot open file \"%s\"\n", dlf->fname);
    return (-1);
  }

  /*
   * Count the entries.
   * Allocate the array.
   * Rewind the file.
   */
  for (dlf->strNb=0 ; fgets(line, MAX_FILTER, ifile) != NULL ; dlf->strNb++);
  dlf->str = (char **) malloc (dlf->strNb * sizeof (char *));
  if (fseek (ifile, 0, SEEK_SET) != 0)
  {
    perror (dlf->fname);
    fprintf (stderr, "Error: cannot rewind file \"%s\"\n", dlf->fname);
    return (-1);
  }

  /*
   * Read all the entries from this file
   */
  dlf->strNb=0;
  while (fgets(line, MAX_FILTER, ifile) != NULL)
  {
    if ((strlen (line) > 0) && (line[strlen(line)-1]=='\n'))
      line[strlen(line)-1] = '\0';
    dlf->str[dlf->strNb] = strdup (line);
    dlf->strNb++;
  }

  /*
   * Close the file
   */
  if (fclose (ifile) != 0)
  {
    perror (dlf->fname);
    fprintf (stderr, "Error: cannot fclose file \"%s\"\n", dlf->fname);
    return (-1);
  }
  return (0);
}







						/* New */	/*JLS 23-03-01*/
/* ****************************************************************************
	FUNCTION :	dataListFile
	PURPOSE :	Find the given data_list_file either in the list of
			files already loaded, either load it.
	INPUT :		fname	= file name.
	OUTPUT :	None.
	RETURN :	NULL if error, else the requested file.
	DESCRIPTION :
 *****************************************************************************/
data_list_file *
dataListFile (
	char	*fname)
{
  data_list_file	*dlf;	/* To process the request */

  /*
   * Maybe we already have loaded this file ?
   */
  for (dlf=mctx.dlf ; dlf != NULL ; dlf=dlf->next)
    if (!strcmp (fname, dlf->fname))
      return (dlf);

  /*
   * Well, it looks like we should load a new file ;-)
   * Allocate a new data structure, chain it in mctx and load the file.
   */
  dlf = (data_list_file *) malloc (sizeof (data_list_file));
  dlf->next  = mctx.dlf;
  mctx.dlf   = dlf;
  dlf->fname = strdup (fname);
  if (loadDataListFile (dlf) < 0)
    return (NULL);

  /*
   * Loaded...
   */
  return (dlf);
}








/* End of file */


--- NEW FILE ldap-private.h ---
#ident "@(#)ldap-private.h	1.6 06/10/98 SMI"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

#ifndef _LDAP_PRIVATE_H
#define _LDAP_PRIVATE_H

#ifdef _REENTRANT
#ifndef MAX_THREAD_ID
#define MAX_THREAD_ID 500
#endif /* MAX_THREAD_ID */
#else /* _REENTRANT */
#ifndef MAX_THREAD_ID
#define MAX_THREAD_ID 1
#endif /* MAX_THREAD_ID */
#endif /* _REENTRANT */

#define COMPAT20
#define COMPAT30
#if defined(COMPAT20) || defined(COMPAT30)
#define COMPAT
#endif

#ifdef LDAP_DNS
#define LDAP_OPT_DNS		0x00000001	/* use DN & DNS */
#endif /* LDAP_DNS */

/*
#define DBG_LOCK1(st) printf("%d> %s %d:%s\n", _thr_self(), st, __LINE__, __FILE__);
#define DBG_LOCK2(ld,st) printf("%d> %s ld_lockcount=%d %d:%s\n",  _thr_self(), st, (ld)->ld_lockcount, __LINE__, __FILE__);
*/
#define DBG_LOCK1(st)
#define DBG_LOCK2(ld,st)

#define LOCK_RESPONSE(ld) \
	if ((ld)->ld_response_lockthread != _thr_self()) { \
		DBG_LOCK1("waiting for response lock") \
		pthread_mutex_lock( &((ld)->ld_response_mutex) ); \
		DBG_LOCK1("got response lock") \
		(ld)->ld_response_lockthread = _thr_self(); \
	} else  { \
	        (ld)->ld_response_lockcount++; \
		DBG_LOCK2(ld, "fake ldap lock") \
	}

#define UNLOCK_RESPONSE(ld) \
	if ((ld)->ld_response_lockcount==0) { \
		(ld)->ld_response_lockthread = 0; \
		pthread_mutex_unlock( &((ld)->ld_response_mutex) ); \
		DBG_LOCK1("freed response lock") \
	} else  { \
	        (ld)->ld_response_lockcount--; \
	        DBG_LOCK2(ld, "fake ldap unlock") \
	}

#define LOCK_LDAP(ld) \
	if ((ld)->ld_lockthread != _thr_self()) { \
	        DBG_LOCK1("waiting for ldap lock") \
                pthread_mutex_lock( &((ld)->ld_ldap_mutex) ); \
		DBG_LOCK1("got ldap lock") \
		(ld)->ld_lockthread = _thr_self(); \
	} else  { \
	        (ld)->ld_lockcount++; \
		DBG_LOCK2(ld, "fake ldap lock") \
	}

#define UNLOCK_LDAP(ld) \
	if ((ld)->ld_lockcount==0) { \
                (ld)->ld_lockthread = 0; \
		pthread_mutex_unlock( &((ld)->ld_ldap_mutex) ); \
		DBG_LOCK1("freed ldap lock") \
	} else  { \
	        (ld)->ld_lockcount--; \
	        DBG_LOCK2(ld, "fake ldap unlock") \
	}

#define LOCK_POLL(ld) 	pthread_mutex_lock( &ld->ld_poll_mutex )
#define UNLOCK_POLL(ld) pthread_mutex_unlock( &ld->ld_poll_mutex )

/*
 * This structure represents both ldap messages and ldap responses.
 * These are really the same, except in the case of search responses,
 * where a response has multiple messages.
 */
typedef struct ldapmsg {
	int		lm_msgid;	/* the message id */
	int		lm_msgtype;	/* the message type */
	BerElement	*lm_ber;	/* the ber encoded message contents */
	struct ldapmsg	*lm_chain;	/* for search - next msg in the resp */
	struct ldapmsg	*lm_next;	/* next response */
	unsigned long	lm_time;	/* used to maintain cache */
} _struct_LDAPMessage;

typedef struct ldap_filt_list {
    char			*lfl_tag;
    char			*lfl_pattern;
    char			*lfl_delims;
    LDAPFiltInfo		*lfl_ilist;
    struct ldap_filt_list	*lfl_next;
} _struct_FiltList;

typedef struct ldap_filt_desc {
	LDAPFiltList		*lfd_filtlist;
	LDAPFiltInfo		*lfd_curfip;
	LDAPFiltInfo		lfd_retfi;
	char			lfd_filter[ LDAP_FILT_MAXSIZ ];
	char			*lfd_curval;
	char			*lfd_curvalcopy;
	char			**lfd_curvalwords;
	char			*lfd_filtprefix;
	char			*lfd_filtsuffix;
} _struct_FiltDesc;

/*
 * structure for tracking LDAP server host, ports, DNs, etc.
 */
typedef struct ldap_server {
	char			*lsrv_host;
	char			*lsrv_dn;	/* if NULL, use default */
	int			lsrv_port;
	struct ldap_server	*lsrv_next;
} LDAPServer;


/*
 * structure for representing an LDAP server connection
 */
typedef struct ldap_conn {
	Sockbuf			*lconn_sb;
	int			lconn_refcnt;
	unsigned long		lconn_lastused;	/* time */
	int			lconn_status;
#define LDAP_CONNST_NEEDSOCKET		1
#define LDAP_CONNST_CONNECTING		2
#define LDAP_CONNST_CONNECTED		3
	LDAPServer		*lconn_server;
	char			*lconn_krbinstance;
	struct ldap_conn	*lconn_next;
} LDAPConn;

/*
 * Structure used to keep track of search references
 */
typedef struct ldap_reference {
	char ** lref_refs;
	struct ldap_reference *lref_next;
} LDAPRef;

/*
 * structure used to track outstanding requests
 */
typedef struct ldapreq {
	int		lr_msgid;	/* the message id */
	int		lr_status;	/* status of request */
#define LDAP_REQST_INPROGRESS	1
#define LDAP_REQST_CHASINGREFS	2
#define LDAP_REQST_NOTCONNECTED	3
#define LDAP_REQST_WRITING	4
	int		lr_outrefcnt;	/* count of outstanding referrals */
	int		lr_origid;	/* original request's message id */
	int		lr_parentcnt;	/* count of parent requests */
	int		lr_res_msgtype;	/* result message type */
	int		lr_res_errno;	/* result LDAP errno */
	char		*lr_res_error;	/* result error string */
	char		*lr_res_matched;/* result matched DN string */
	BerElement	*lr_ber;	/* ber encoded request contents */
	LDAPConn	*lr_conn;	/* connection used to send request */
	LDAPRef		*lr_references;
	char	 **lr_ref_followed; /* referral being followed */
	char	 **lr_ref_unfollowed; /* Not being followed */
	char	 **lr_ref_tofollow; /* referral to follow if the one being
								   followed fails. */
	struct ldapreq	*lr_parent;	/* request that spawned this referral */
	struct ldapreq	*lr_refnext;	/* next referral spawned */
	struct ldapreq	*lr_prev;	/* previous request */
	struct ldapreq	*lr_next;	/* next request */
} LDAPRequest;

/*
 * structure for client cache
 */
#define LDAP_CACHE_BUCKETS	31	/* cache hash table size */
typedef struct ldapcache {
	LDAPMessage	*lc_buckets[LDAP_CACHE_BUCKETS];/* hash table */
	LDAPMessage	*lc_requests;			/* unfulfilled reqs */
	long		lc_timeout;			/* request timeout */
	long		lc_maxmem;			/* memory to use */
	long		lc_memused;			/* memory in use */
	int		lc_enabled;			/* enabled? */
	unsigned long	lc_options;			/* options */
#define LDAP_CACHE_OPT_CACHENOERRS	0x00000001
#define LDAP_CACHE_OPT_CACHEALLERRS	0x00000002
}  LDAPCache;
#define NULLLDCACHE ((LDAPCache *)NULL)

/*
 * structure representing an ldap connection
 */
typedef struct ldap {
	Sockbuf		ld_sb;		/* socket descriptor & buffer */
	char		*ld_host;
	int		ld_version;
	char		ld_lberoptions;
	int		ld_deref;

	int		ld_timelimit;
	int		ld_sizelimit;

	LDAPFiltDesc	*ld_filtd;	/* from getfilter for ufn searches */
	char		*ld_ufnprefix;	/* for incomplete ufn's */

	int		ld_errno[MAX_THREAD_ID];	/* thread-specific */
#define ld_errno ld_errno[ldap_thr_index()]
	char		*ld_error[MAX_THREAD_ID];	/* thread-specific */
#define ld_error ld_error[ldap_thr_index()]
	char		*ld_matched[MAX_THREAD_ID];	/* thread-specific */
#define ld_matched ld_matched[ldap_thr_index()]
	char		**ld_referrals[MAX_THREAD_ID];	/* thread-specific */
#define ld_referrals ld_referrals[ldap_thr_index()]
	LDAPControl	**ld_ret_ctrls[MAX_THREAD_ID];	/* thread-specific */
#define ld_ret_ctrls ld_ret_ctrls[ldap_thr_index()]
	int		ld_msgid;

	int ld_follow_referral; /* flag set to true if lib follow referrals */
	LDAPRequest	*ld_requests;	/* list of outstanding requests -- referrals*/

	LDAPMessage	*ld_responses;	/* list of outstanding responses */
	int		*ld_abandoned;	/* array of abandoned requests */

	pthread_mutex_t	ld_response_mutex; /* mutex for responses part of structure */
	pthread_t	ld_response_lockthread; /* thread which currently holds the response lock */
	int		ld_response_lockcount;  /* response lock depth */
	
	char		*ld_attrbuffer[MAX_THREAD_ID];
#define ld_attrbuffer ld_attrbuffer[ldap_thr_index()]
	LDAPCache	*ld_cache;	/* non-null if cache is initialized */
	char		*ld_cldapdn;	/* DN used in connectionless search */

	/* it is OK to change these next four values directly */
	int		ld_cldaptries;	/* connectionless search retry count */
	int		ld_cldaptimeout;/* time between retries */
	int		ld_refhoplimit;	/* limit on referral nesting */
	int ld_restart; /* Decide if continue after interruption */
#ifdef LDAP_SSL
	int ld_use_ssl;
	char *ld_ssl_key;
#endif 
	unsigned long	ld_options;	/* boolean options */

	/* do not mess with the rest though */
	char		*ld_defhost;	/* full name of default server */
	int		ld_defport;	/* port of default server */
	BERTranslateProc ld_lber_encode_translate_proc;
	BERTranslateProc ld_lber_decode_translate_proc;

	LDAPConn	*ld_defconn;	/* default connection */
	LDAPConn	*ld_conns;	/* list of server connections */
	void		*ld_selectinfo;	/* platform specifics for select */

	LDAP_REBIND_FUNCTION *ld_rebindproc;
	void *ld_rebind_extra_arg;
/* 	int		(*ld_rebindproc)( struct ldap *ld, char **dnp, */
/* 				char **passwdp, int *authmethodp, int freeit ); */
				/* routine to get info needed for re-bind */

	pthread_mutex_t	ld_ldap_mutex; /* mutex for thread dependent part of struct */
	pthread_t	ld_lockthread; /* thread which currently holds the lock */
	int		ld_lockcount;  /* lock depth */
	pthread_mutex_t	ld_poll_mutex; /* a seperate lock for polling */

	LDAPControl **ld_srvctrls; /* Controls used by ldap and server */
	LDAPControl **ld_cltctrls; /* Client side controls */

/* KE: Lists of unsolicited notifications */
	LDAPMessage *ld_notifs[MAX_THREAD_ID];
#define ld_notifs ld_notifs[ldap_thr_index()]
} _struct_LDAP;

/*
 * handy macro to check whether LDAP struct is set up for CLDAP or not
 */
#define LDAP_IS_CLDAP( ld )	( ld->ld_sb.sb_naddr > 0 )


#endif /* _LDAP_PRIVATE_H */


--- NEW FILE ldapfct.c ---
#ident "ldclt @(#)ldapfct.c	1.68 01/05/04"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		ldapfct.c
	AUTHOR :	Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		04 December 1998
	DESCRIPTION :
			This file contains the ldap part of this tool.
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
04/12/98 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
09/12/98 | JL Schwing	| 1.2 : Forget to free ldap returned data.
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.3 : Add nb of errors statistics.
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.4 : Implement asynchronous mode.
---------+--------------+------------------------------------------------------
11/12/98 | JL Schwing	| 1.5 : fflush(stdout) after each printf.
---------+--------------+------------------------------------------------------
14/12/98 | JL Schwing	| 1.6 : Implement "-e close".
			| New function my_ldap_err2string() to prevent crashes.
---------+--------------+------------------------------------------------------
16/12/98 | JL Schwing	| 1.7 : Implement "-e add" and "-e delete".
			| Create separate functions for connection operations.
---------+--------------+------------------------------------------------------
23/12/98 | JL Schwing	| 1.8 : Factorise the doXxxx() functions.
			| Fix SIGSEGV in ldap_parse_result().
			| Implement result decoding in doAddEntry().
---------+--------------+------------------------------------------------------
24/12/98 | JL Schwing	| 1.9 : Bug fix - should support no message in async.
			| Bug fix - forget to check mctx.asyncMax !!!
			| Modify the getPending() algorythm to empty the queue
			|   (if possible).
---------+--------------+------------------------------------------------------
29/12/98 | JL Schwing	| 1.10: Implement -Q.
			| Bug fix mode -q when asynchronous.
---------+--------------+------------------------------------------------------
11/01/99 | JL Schwing	| 1.11: Implement "-e emailPerson".
			| Bug fix - bad building of rdn in buildNewEntry().
---------+--------------+------------------------------------------------------
13/01/99 | JL Schwing	| 1.12: Implement "-e string".
---------+--------------+------------------------------------------------------
14/01/99 | JL Schwing	| 1.13: Implement "-s <scope>".
---------+--------------+------------------------------------------------------
15/01/99 | JL Schwing	| 1.14: Create automatically the missing nodes.
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.15: Implements "-e randombase".
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.16: Implements "-e v2".
---------+--------------+------------------------------------------------------
20/01/99 | JL Schwing	| 1.17: Bug fix - should'nt fail in createMissingNodes()
			|   if error 68 (Already exists).
			| Increment counter for intermediate node(s) too.
---------+--------------+------------------------------------------------------
23/01/99 | JL Schwing	| 1.18: Improve traces.
			| Bug fix - remove leading spaces from rdn.
---------+--------------+------------------------------------------------------
26/01/99 | JL Schwing	| 1.19: Implement "-e noloop".
---------+--------------+------------------------------------------------------
01/02/99 | JL Schwing	| 1.20: Create *all* the nodes in createMissingNodes()
---------+--------------+------------------------------------------------------
03/02/99 | JL Schwing	| 1.21: Create the leaf entry after createMissingNodes()
---------+--------------+------------------------------------------------------
26/02/99 | JL Schwing	| 1.22: Detect "\," in createMissingNodes().
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| 1.23: Add call to opAdd().
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| 1.24: Forget some calls to opAdd().
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| 1.25: Too many calls to opAdd() !!!
---------+--------------+------------------------------------------------------
19/05/99 | JL Schwing	| 1.27: Implements doRename().
			| Do not print messages about intermediate nodes created
			|   in quiet mode.
			| MOdify getPending()to support rename operations.
---------+--------------+------------------------------------------------------
06/03/00 | JL Schwing	| 1.28: Test malloc() return value.
---------+--------------+------------------------------------------------------
06/03/00 | A. Hornik	| 1.29: Bug fix - SEGV if no passwd provided.
---------+--------------+------------------------------------------------------
03/08/00 | JL Schwing	| 1.30: Improve errors decoding. This improvement
			|   is to retrieve the additional error string that
			|   is returned by the server.  This is implemented for
			|   the asynchronous operations and for the synchronous
			|   search only, because for the other synchronous ops
			|   we should use ldap_get_lderrno() that is not
			|   implement in Solaris's libldap.
			| Add new function printErrorFromLdap().
---------+--------------+------------------------------------------------------
03/08/00 | JL Schwing	| 1.31: Fix SIGSEGV in printErrorFromLdap().
---------+--------------+------------------------------------------------------
11/08/00 | JL Schwing	| 1.32: Improve error decoding.
---------+--------------+------------------------------------------------------
18/08/00 | JL Schwing	| 1.33: Print begin and end dates.
---------+--------------+------------------------------------------------------
25/08/00 | JL Schwing	| 1.34: Implement consistent exit status...
---------+--------------+------------------------------------------------------
11/10/00 | B Kolics     | 1.35: Added SSL connection initialization to
	 |              |       connectToServer, createMissingNodes
---------+--------------+------------------------------------------------------
26/10/00 | B Kolics     | 1.36: Moved SSL client initialization to basicInit
-------------------------------------------------------------------------------
07/11/00 | JL Schwing	| 1.37: Implements dynamic load of ssl-related
			|   functions.
---------+--------------+------------------------------------------------------
07/11/00 | JL Schwing	| 1.38: Implement "-e inetOrgPerson".
			| Add new error message in createMissingNodes().
---------+--------------+------------------------------------------------------
13/11/00 | JL Schwing	| 1.39: Add new options "-e randombaselow and ...high"
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| 1.40: Will now use utils.c functions.
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| 1.41 : Port on AIX.
---------+--------------+------------------------------------------------------
21/11/00 | JL Schwing	| 1.42: Implement "-e attreplace=name:mask"
			| Add new function buildNewModAttrib().
---------+--------------+------------------------------------------------------
24/11/00 | B Kolics	| 1.43: Added SSL client authentication
---------+--------------+------------------------------------------------------
29/11/00 | JL Schwing	| 1.44: Port on NT 4.
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.45: Port on Linux.
---------+--------------+------------------------------------------------------
14/12/00 | JL Schwing	| 1.46: Add more trace in VERY_VERBOSE mode.
			| Fix some trace messages.
			| Add new function dnFromMessage().
---------+--------------+------------------------------------------------------
15/12/00 | JL Schwing	| 1.47: Implement "-e counteach".
			| Implement "-e withnewparent" - cf bug Scopus 526148
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.48: Add new exit status EXIT_RESSOURCE.
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.49: Bug fix when -e rename,counteach
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.50: Bug fix - support errors the user wants to 
			|   ignore in connectToServer().
			| Also a bug fix in tttctx->exitStatus management.
---------+--------------+------------------------------------------------------
03/01/01 | JL Schwing	| 1.51: Implement "-e attrsonly=value".
---------+--------------+------------------------------------------------------
05/01/01 | JL Schwing	| 1.52: Implement "-e randombinddn" and associated
			|   "-e randombinddnlow/high"
			| Add new function buildNewBindDN().
---------+--------------+------------------------------------------------------
05/03/01 | JL Schwing	| 1.53: Fix the "anonymous" mode.
---------+--------------+------------------------------------------------------
08/03/01 | JL Schwing	| 1.54: Change referrals handling.
			| Add new functions refRebindProc() and referralSetup().
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.55: Implement "-e commoncounter"
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.56: Lint cleanup.
			| Port on _WIN32.
---------+--------------+------------------------------------------------------
15/03/01 | JL Schwing	| 1.57: Implement "-e attrlist=name:name:name"
			| Implement "-e randomattrlist=name:name:name"
[...3107 lines suppressed...]
   * disconnection, bind/unbind/close etc... requested by the user.
   * The cost is one more function call in this application, but the
   * resulting source code will be much more easiest to maintain.
   */
  if (connectToServer (tttctx) < 0)				/*JLS 18-12-00*/
    return (-1);						/*JLS 18-12-00*/
  if (!(tttctx->binded))					/*JLS 18-12-00*/
    return (0);							/*JLS 18-12-00*/

  /*
   * Build the filter
   */
  if (buildRandomRdnOrFilter (tttctx) < 0)
    return (-1);

  /*
   * Prepear the attribute list
   */
  if (mctx.attrlistNb == 0)					/*JLS 15-03-01*/
    attrlist = NULL;						/*JLS 15-03-01*/
  else								/*JLS 15-03-01*/
    if (mctx.mode & RANDOM_ATTRLIST)				/*JLS 15-03-01*/
      attrlist = selectRandomAttrList (tttctx);			/*JLS 15-03-01*/
    else							/*JLS 15-03-01*/
      attrlist = mctx.attrlist;					/*JLS 15-03-01*/

  /*
   * Do the search
   * Maybe we are in synchronous mode ? I hope so, it is really
   * much simple ;-)
   */
  if (!(mctx.mode & ASYNC))
  {
    ret = ldap_search_s (tttctx->ldapCtx, tttctx->bufBaseDN, mctx.scope,
		tttctx->bufFilter, attrlist, 			/*JLS 15-03-01*/
		mctx.attrsonly, &res);				/*JLS 03-01-01*/
    if (ret != LDAP_SUCCESS)
    {
      if (!((mctx.mode & QUIET) && ignoreError (ret)))
	(void) printErrorFromLdap (tttctx, res, ret,		/*JLS 03-08-00*/
		"Cannot ldap_search()");			/*JLS 03-08-00*/
      if (addErrorStat (ret) < 0)
	return (-1);
      if ((ret == LDAP_NO_SUCH_OBJECT) && 			/*JLS 15-12-00*/
	  (mctx.mode & COUNT_EACH))				/*JLS 15-12-00*/
      {								/*JLS 15-12-00*/
	if (incrementNbOpers (tttctx) < 0)			/*JLS 15-12-00*/
	  return (-1);						/*JLS 15-12-00*/
      }								/*JLS 15-12-00*/
    }
    else
    {
      if (incrementNbOpers (tttctx) < 0)/* Memorize operation */
	return (-1);

      /*
       * Don't forget to free the returned message !
       */
      if ((ret = ldap_msgfree (res)) < 0)
      {
	if (!((mctx.mode & QUIET) && ignoreError (ret)))
	{
	  printf ("ldclt[%d]: T%03d: Cannot ldap_msgfree(), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
	  fflush (stdout);
	}
	if (addErrorStat (ret) < 0)
	  return (-1);
      }
    }

    /*
     * End of synchronous operation
     */
    return (0);
  }

  /*
   * Here, we are in asynchronous mode...
   * Too bad, lot of things to do here.
   * First, let's see if we are above the reading threshold.
   */
  if (tttctx->pendingNb >= mctx.asyncMin)
  {
    /*
     * Retrieve the next pending request
     */
    ret = ldap_result (tttctx->ldapCtx, LDAP_RES_ANY, 1, &(mctx.timeval), &res);
    if (ret < 0)
    {
      if (!((mctx.mode & QUIET) && ignoreError (ret)))
	(void) printErrorFromLdap (tttctx, res, ret,		/*JLS 03-08-00*/
		"Cannot ldap_result()");			/*JLS 03-08-00*/
      if (addErrorStat (ret) < 0)
	return (-1);
    }
    else
    {
      tttctx->pendingNb--;

      /*
       * Don't forget to free the returned message !
       */
      if ((ret = ldap_msgfree (res)) < 0)
      {
	if (!((mctx.mode & QUIET) && ignoreError (ret)))
	{
	  printf ("ldclt[%d]: T%03d: Cannot ldap_msgfree(), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
	  fflush (stdout);
	}
	if (addErrorStat (ret) < 0)
	  return (-1);
      }
    }
  }

  /*
   * Maybe we may send another request ?
   * Well... there is no proper way to retrieve the error number for
   * this, so I guess I may use direct access to the ldap context
   * to read the field ld_errno.
   */
  if (tttctx->pendingNb > mctx.asyncMax)
  {
    if ((mctx.mode & VERBOSE)   &&
	(tttctx->asyncHit == 1) &&
	(!(mctx.mode & SUPER_QUIET)))
    {
      tttctx->asyncHit = 1;
      printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
               mctx.pid, tttctx->thrdNum);
      fflush (stdout);
    }
  }
  else
  {
    if ((mctx.mode & VERBOSE)   &&
	(tttctx->asyncHit == 1) &&
	(!(mctx.mode & SUPER_QUIET)))
    {
      tttctx->asyncHit = 0;
      printf ("ldclt[%d]: T%03d: Restart sending.\n",
               mctx.pid, tttctx->thrdNum);
      fflush (stdout);
    }

    ret = ldap_search (tttctx->ldapCtx, tttctx->bufBaseDN, mctx.scope,
		tttctx->bufFilter, attrlist, 			/*JLS 15-03-01*/
		mctx.attrsonly);				/*JLS 03-01-01*/
    if (ret < 0)
    {
      if (ldap_get_option (tttctx->ldapCtx, LDAP_OPT_ERROR_NUMBER, &ret) < 0)
      {
	printf ("ldclt[%d]: T%03d: Cannot ldap_get_option(LDAP_OPT_ERROR_NUMBER)\n",
		mctx.pid, tttctx->thrdNum);
	fflush (stdout);
	return (-1);
      }
      else
      {
	if (!((mctx.mode & QUIET) && ignoreError (ret)))
	{
	  printf ("ldclt[%d]: T%03d: Cannot ldap_search(), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
	  fflush (stdout);
	}
	if (addErrorStat (ret) < 0)
	  return (-1);
	if ((ret == LDAP_NO_SUCH_OBJECT) && 			/*JLS 15-12-00*/
	    (mctx.mode & COUNT_EACH))				/*JLS 15-12-00*/
	{							/*JLS 15-12-00*/
	  if (incrementNbOpers (tttctx) < 0)			/*JLS 15-12-00*/
	    return (-1);					/*JLS 15-12-00*/
	}							/*JLS 15-12-00*/
      }
    }
    else
    {
      /*
       * Memorize the operation
       */
      if (incrementNbOpers (tttctx) < 0)
	return (-1);
      tttctx->pendingNb++;
    }
  }

  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
             mctx.pid, tttctx->thrdNum, tttctx->pendingNb);

  /*
   * End of asynchronous operation... and also end of function.
   */
  return (0);
}


/* End of file */


--- NEW FILE ldclt.c ---
#ident "ldclt @(#)ldclt.c	1.89 01/06/19"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		ldclt.c
	AUTHOR :	Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		03 December 1998
	DESCRIPTION :	
			This file is the main file of the ldclt tool. This tool 
			is targetted to be a multi-threaded ldap client, 
			specially designed to ensure good reliability of both 
			the basic ldap server purpose, and the replication 
			processes. It is *not* targetted against the 
			functionnality aspect of the product, but rather on the 
			stress and long-term operation.
 	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
03/12/98 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.2 : Add statistics report when exiting.
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.3 : Trap SIGQUIL to issue statistics without exit.
			| Bug fix - call ldap_err2string() to decode ldap errs.
---------+--------------+------------------------------------------------------
11/12/98 | JL Schwing	| 1.4 : Implement max errors threshold.
			| fflush(stdout) after each printf.
			| Will exit(0) on SIGINT
---------+--------------+------------------------------------------------------
14/12/98 | JL Schwing	| 1.5 : Implement "-e close".
			| Ensure thread not dead prior to issue "no activity" 
			| Add statts for the number of dead threads.
---------+--------------+------------------------------------------------------
16/12/98 | JL Schwing	| 1.6 : Implement "-e add" and "-e delete".
			| Improve printout of options.
---------+--------------+------------------------------------------------------
24/12/98 | JL Schwing	| 1.7 : Fix memory problem.
---------+--------------+------------------------------------------------------
28/12/98 | JL Schwing	| 1.8 : Add more statistics.
---------+--------------+------------------------------------------------------
29/12/98 | JL Schwing	| 1.9 : Implement -Q.
---------+--------------+------------------------------------------------------
29/12/98 | JL Schwing	| 1.10: Don't print pending stats if not asynchronous.
---------+--------------+------------------------------------------------------
29/12/98 | JL Schwing	| 1.11: Fix typo.
---------+--------------+------------------------------------------------------
30/12/98 | JL Schwing	| 1.12: Protect messages "no activity for %d seconds"
			|   by SUPER_QUIET mode.
---------+--------------+------------------------------------------------------
11/01/99 | JL Schwing	| 1.13: Implement "-e emailPerson".
---------+--------------+------------------------------------------------------
13/01/99 | JL Schwing	| 1.14: Implement "-e string".
---------+--------------+------------------------------------------------------
14/01/99 | JL Schwing	| 1.15: Implement "-s <scope>".
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.16: Implement "-e randombase".
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.17: Implement "-e v2".
---------+--------------+------------------------------------------------------
21/01/99 | JL Schwing	| 1.18: Implement "-e ascii".
---------+--------------+------------------------------------------------------
26/01/99 | JL Schwing	| 1.19: Implement "-e noloop".
---------+--------------+------------------------------------------------------
28/01/99 | JL Schwing	| 1.20: Implement "-T <total>".
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| 1.21: Implement operations list.
---------+--------------+------------------------------------------------------
06/05/99 | JL Schwing	| 1.25: Add proper shutdwon (wait for check threads).
			| Implement "-P <master port>".
---------+--------------+------------------------------------------------------
06/05/99 | JL Schwing	| 1.26: Implement "-e modrdn".
---------+--------------+------------------------------------------------------
06/05/99 | F. Pistolesi	| 1.27: Some fixes.
---------+--------------+------------------------------------------------------
07/05/99 | JL Schwing	| 1.28: Some fixes.
---------+--------------+------------------------------------------------------
19/05/99 | JL Schwing	| 1.30: Implement "-e rename".
			| Set the threads status to DEAD when nb of opers done.
			| Lint-cleanup.
---------+--------------+------------------------------------------------------
21/05/99 | JL Schwing	| 1.31: Fix Unitialized Memory Read for head's mutex.
---------+--------------+------------------------------------------------------
27/05/99 | JL Schwing	| 1.32 : Add statistics to check threads.
---------+--------------+------------------------------------------------------
28/05/99 | JL Schwing	| 1.33 : Add new option -W (wait).
---------+--------------+------------------------------------------------------
02/06/99 | JL Schwing	| 1.34 : Add flag in main ctx to know if slave was 
			|   connected or not.
			| Add counter of operations received in check threads.
---------+--------------+------------------------------------------------------
06/03/00 | JL Schwing	| 1.35: Test malloc() and strdup() return value.
---------+--------------+------------------------------------------------------
04/08/00 | JL Schwing	| 1.36: Add stats on nb inactivity per thread.
---------+--------------+------------------------------------------------------
08/08/00 | JL Schwing	| 1.37: Print global statistics every 1000 loops.
---------+--------------+------------------------------------------------------
18/08/00 | JL Schwing	| 1.38: Print global statistics every 90 loops.
			| Bug fix in this new feature.
			| Print ldclt version.
			| Print date of begin and of end.
			| Add new function ldcltExit().
---------+--------------+------------------------------------------------------
25/08/00 | JL Schwing	| 1.39: Implement consistent exit status...
---------+--------------+------------------------------------------------------
25/08/00 | JL Schwing	| 1.40: Will only load images if -e emailPerson
---------+--------------+------------------------------------------------------
11/10/00 | B Kolics     | 1.41: Implement "-Z certfile".
---------+--------------+------------------------------------------------------
26/10/00 | B Kolics     | 1.42: Move SSL client initialization to basicInit()
-------------------------------------------------------------------------------
07/11/00 | JL Schwing	| 1.43: Add handlers for dynamic load of ssl-related
			|   functions.
			| Add new function sslDynLoadInit().
-----------------------------------------------------------------------------
07/11/00 | JL Schwing	| 1.44: Implement "-e inetOrgPerson".
---------+--------------+------------------------------------------------------
08/11/00 | JL Schwing	| 1.45: Improve error message when initiating ssl.
---------+--------------+------------------------------------------------------
13/11/00 | JL Schwing	| 1.46: Add new options "-e randombaselow and ...high"
			| Made use of exit (EXIT_PARAMS) in main().
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| 1.47: Port on AIX.
---------+--------------+------------------------------------------------------
16/11/00 | JL Schwing	| 1.48: Implement "-e imagesdir=path".
---------+--------------+------------------------------------------------------
17/11/00 | JL Schwing	| 1.49: Implement "-e smoothshutdown".
			| Forget to add mode decoding.
			| Add new function shutdownThreads().
---------+--------------+------------------------------------------------------
21/11/00 | JL Schwing	| 1.50: Implement "-e attreplace=name:mask"
			| Add new function parseFilter().
---------+--------------+------------------------------------------------------
22/11/00 | JL Schwing	| 1.51: Will now use LD_LIBRARY_PATH to load libssl.
---------+--------------+------------------------------------------------------
24/11/00 | B Kolics     | 1.52: Added SSL client authentication
---------+--------------+------------------------------------------------------
29/11/00 | JL Schwing	| 1.53: Port on NT 4.
---------+--------------+------------------------------------------------------
30/11/00 | JL Schwing	| 1.54: Bug fix - bad error message if -eimagesdir=path
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.55: Port on Linux.
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.56: Port on HP-UX.
---------+--------------+------------------------------------------------------
07/12/00 | JL Schwing	| 1.57: Bug fix - crash SIGBUS in main:1840 if no
			|   filter is provided to the tool.
			| Build the argv list before parsing.
---------+--------------+------------------------------------------------------
15/12/00 | JL Schwing	| 1.58: Implement "-e counteach".
			| Implement "-e withnewparent".
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.59: Fix an exit status problem.
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.60: Minor fix/improvement in -I management.
---------+--------------+------------------------------------------------------
19/12/00 | JL Schwing	| 1.61: Implement "-e noglobalstats".
---------+--------------+------------------------------------------------------
19/12/00 | JL Schwing	| 1.62: Add comments.
---------+--------------+------------------------------------------------------
[...2667 lines suppressed...]
			s1ctx.cnxduration);			/*JLS 12-01-01*/
      ldcltExit (EXIT_PARAMS);					/*JLS 12-01-01*/
    }								/*JLS 12-01-01*/
    if (s1ctx.maxcnxnb <= 0)					/*JLS 12-01-01*/
    {								/*JLS 12-01-01*/
      fprintf (stderr, "Error : -e scalab01_maxcnxnb=%d <= 0\n",/*JLS 12-01-01*/
			s1ctx.maxcnxnb);			/*JLS 12-01-01*/
      ldcltExit (EXIT_PARAMS);					/*JLS 12-01-01*/
    }								/*JLS 12-01-01*/
    if (s1ctx.wait <= 0)					/*JLS 12-01-01*/
    {								/*JLS 12-01-01*/
      fprintf (stderr, "Error : -e scalab01_wait=%d <= 0\n",	/*JLS 12-01-01*/
			s1ctx.wait);				/*JLS 12-01-01*/
      ldcltExit (EXIT_PARAMS);					/*JLS 12-01-01*/
    }								/*JLS 12-01-01*/
  }								/*JLS 12-01-01*/
  if ((mctx.referral == REFERRAL_REBIND) &&			/*JLS 14-03-01*/
      ((mctx.bindDN == NULL) || (mctx.passwd == NULL)))		/*JLS 14-03-01*/
  {								/*JLS 14-03-01*/
    fprintf (stderr, "Error: -e referral=rebind needs -D and -w\n");/*14-03-01*/
    ldcltExit (EXIT_PARAMS);					/*JLS 14-03-01*/
  }								/*JLS 14-03-01*/
  if ((mctx.mode & COMMON_COUNTER) &&				/*JLS 14-03-01*/
      (!((mctx.mode & INCREMENTAL) || (mctx.mod2 & M2_OBJECT))))/*JLS 28-03-01*/
  {								/*JLS 14-03-01*/
    fprintf (stderr, "Error: -e commoncounter needs -e incr or -e object\n");
    ldcltExit (EXIT_PARAMS);					/*JLS 14-03-01*/
  }								/*JLS 14-03-01*/
  if ((mctx.attrlistNb != 0) && (!(mctx.mode & EXACT_SEARCH)))	/*JLS 15-03-01*/
  {								/*JLS 15-03-01*/
    fprintf(stderr,"Error : -e attrlist requires -e esearch\n");/*JLS 15-03-01*/
    ldcltExit (EXIT_PARAMS);					/*JLS 15-03-01*/
  }								/*JLS 15-03-01*/
  if ((mctx.mod2 & M2_GENLDIF) && (mctx.mode & VALID_OPERS))	/*JLS 19-03-01*/
  {								/*JLS 19-03-01*/
    fprintf(stderr,"Error : -e genldif is exclusive.\n"); 	/*JLS 19-03-01*/
    ldcltExit (EXIT_PARAMS);					/*JLS 19-03-01*/
  }								/*JLS 19-03-01*/
  if ((mctx.mod2 & M2_RDN_VALUE) && (!(mctx.mod2 & M2_OBJECT)))	/*JLS 23-03-01*/
  {								/*JLS 23-03-01*/
    fprintf(stderr,"Error : -e rdn needs -e object.\n"); 	/*JLS 23-03-01*/
    ldcltExit (EXIT_PARAMS);					/*JLS 23-03-01*/
  }								/*JLS 23-03-01*/

  /*
   * Maybe we should load ssl library ?
   */
  if (mctx.mode & SSL)						/*JLS 07-11-00*/
    if (sslDynLoadInit() < 0)					/*JLS 07-11-00*/
      ldcltExit (EXIT_LOADSSL);					/*JLS 07-11-00*/

  /*
   * Basic initialization from the user's parameters/options
   */
  if (basicInit() < 0)
    ldcltExit (EXIT_INIT);					/*JLS 18-12-00*/

  /*
   * What are we doing now...
   */
  if (mctx.mode & VERBOSE)
  {
    printf ("%s\n", argvList);					/*JLS 07-12-00*/
    printf ("Process ID         = %d\n", mctx.pid);
    printf ("Host to connect    = %s\n", mctx.hostname);
    printf ("Port number        = %d\n", mctx.port);
    if (mctx.bindDN == NULL)
      printf ("Bind DN            = NULL\n");
    else
      printf ("Bind DN            = %s\n", mctx.bindDN);
    if (mctx.passwd == NULL)
      printf ("Passwd             = NULL\n");
    else
      printf ("Passwd             = %s\n", mctx.passwd);
    switch (mctx.referral)					/*JLS 08-03-01*/
    {								/*JLS 08-03-01*/
      case REFERRAL_OFF:					/*JLS 08-03-01*/
	printf ("Referral           = off\n");			/*JLS 08-03-01*/
	break;							/*JLS 08-03-01*/
      case REFERRAL_ON:						/*JLS 08-03-01*/
	printf ("Referral           = on\n");			/*JLS 08-03-01*/
	break;							/*JLS 08-03-01*/
      case REFERRAL_REBIND:					/*JLS 08-03-01*/
	printf ("Referral           = rebind\n");		/*JLS 08-03-01*/
	break;							/*JLS 08-03-01*/
    }								/*JLS 08-03-01*/
    printf ("Base DN            = %s\n", mctx.baseDN);
    if (mctx.filter == NULL)
      printf ("Filter             = NULL\n");
    else
      printf ("Filter             = \"%s\"\n", mctx.filter);
    if (mctx.attrlistNb > 0)					/*JLS 15-03-01*/
    {								/*JLS 15-03-01*/
      printf ("Attributes list    =");				/*JLS 15-03-01*/
      for (i=0 ; i<mctx.attrlistNb ; i++)			/*JLS 15-03-01*/
	printf (" %s", mctx.attrlist[i]);			/*JLS 15-03-01*/
      printf ("\n");						/*JLS 15-03-01*/
    }								/*JLS 15-03-01*/
    printf ("Max times inactive = %d\n", mctx.inactivMax);
    printf ("Max allowed errors = %d\n", mctx.maxErrors);
    printf ("Number of samples  = %d\n", mctx.nbSamples);
    printf ("Number of threads  = %d\n", mctx.nbThreads);
    printf ("Total op. req.     = %d\n", mctx.totalReq);
    printf ("Running mode       = 0x%08x\n", mctx.mode);
    printf ("Running mode       =");
    dumpModeValues ();						/*JLS 19-03-01*/
    printf ("\n");
    if (mctx.mode & SCALAB01)					/*JLS 12-01-01*/
    {								/*JLS 12-01-01*/
      printf("Scalab01 cnx dur.  = %d sec\n",s1ctx.cnxduration);/*JLS 12-01-01*/
      printf ("Scalab01 max nb cnx= %d\n", s1ctx.maxcnxnb);	/*JLS 12-01-01*/
      printf ("Scalab01 wait time = %d sec\n", s1ctx.wait);	/*JLS 12-01-01*/
    }								/*JLS 12-01-01*/
    printf ("LDAP oper. timeout = %d sec\n", mctx.timeout);
    printf ("Sampling interval  = %d sec\n", mctx.sampling);
    if (mctx.mode & EXACT_SEARCH)
    {								/*JLS 03-01-01*/
      switch (mctx.scope)
      {
	case LDAP_SCOPE_BASE:
		printf ("Scope              = base\n");
		break;
	case LDAP_SCOPE_ONELEVEL:
		printf ("Scope              = one level\n");
		break;
	case LDAP_SCOPE_SUBTREE:
		printf ("Scope              = subtree\n");
		break;
      }
      printf ("Attrsonly          = %d\n", mctx.attrsonly);	/*JLS 03-01-01*/
    }								/*JLS 03-01-01*/
    if (mctx.images != NULL)					/*JLS 17-11-00*/
      printf ("Images directory   = %s\n", mctx.imagesDir);	/*JLS 17-11-00*/
    if ((mctx.mode & NEED_RANGE) && (mctx.randomLow >= 0))	/*JLS 28-03-01*/
      printf ("Values range       = [%d , %d]\n", 
				mctx.randomLow, mctx.randomHigh);
    if ((mctx.mode & (RANDOM | INCREMENTAL)) &&
	(!(mctx.mod2 & M2_RDN_VALUE)))				/*JLS 23-03-01*/
    {
      printf ("Filter's head      = \"%s\"\n", mctx.randomHead);
      printf ("Filter's tail      = \"%s\"\n", mctx.randomTail);
    }
    if (mctx.mode & RANDOM_BASE)
    {
      printf ("Base DN's head     = \"%s\"\n", mctx.baseDNHead);
      printf ("Base DN's tail     = \"%s\"\n", mctx.baseDNTail);
      printf ("Base DN's range    = [%d , %d]\n", 		/*JLS 13-11-00*/
			mctx.baseDNLow, mctx.baseDNHigh);	/*JLS 13-11-00*/
    }
    if (mctx.mode & RANDOM_BINDDN)				/*JLS 05-01-01*/
    {								/*JLS 05-01-01*/
      printf ("Bind DN's head     = \"%s\"\n", mctx.bindDNHead);/*JLS 05-01-01*/
      printf ("Bind DN's tail     = \"%s\"\n", mctx.bindDNTail);/*JLS 05-01-01*/
      printf ("Bind DN's range    = [%d , %d]\n", 		/*JLS 05-01-01*/
			mctx.bindDNLow, mctx.bindDNHigh);	/*JLS 05-01-01*/
      printf ("Bind passwd's head = \"%s\"\n", mctx.passwdHead);/*JLS 05-01-01*/
      printf ("Bind passwd's tail = \"%s\"\n", mctx.passwdTail);/*JLS 05-01-01*/
    }								/*JLS 05-01-01*/
    if (mctx.mode & ATTR_REPLACE)				/*JLS 21-11-00*/
    {								/*JLS 21-11-00*/
      printf ("Attribute's head   = \"%s\"\n", mctx.attrplHead);/*JLS 21-11-00*/
      printf ("Attribute's tail   = \"%s\"\n", mctx.attrplTail);/*JLS 21-11-00*/
    }								/*JLS 21-11-00*/
    if (mctx.mode & ASYNC)
    {
      printf ("Async max pending  = %d\n", mctx.asyncMax);
      printf ("Async min pending  = %d\n", mctx.asyncMin);
    }
    for (i=0 ; i<mctx.ignErrNb ; i++)
      printf ("Ignore error       = %d (%s)\n", 
		mctx.ignErr[i], my_ldap_err2string (mctx.ignErr[i]));
    fflush (stdout);
    if (mctx.slavesNb > 0)
    {
      printf ("Slave(s) to check  =");
      for (i=0 ; i<mctx.slavesNb ; i++)
	printf (" %s", mctx.slaves[i]);
      printf ("\n");
    }
  }

  /*
   * Let's go!
   */
  tim = time(NULL);
  printf ("ldclt[%d]: Starting at %s\n", mctx.pid, ctime (&tim));			/*JLS 18-08-00*/
  if (runThem() < 0)
    ldcltExit (EXIT_OTHER);					/*JLS 25-08-00*/
  if (initMainThread() < 0)
    ldcltExit (EXIT_OTHER);					/*JLS 25-08-00*/
  if (monitorThem() < 0)
    ldcltExit (EXIT_OTHER);					/*JLS 25-08-00*/
  if (printGlobalStatistics() < 0)
    ldcltExit (EXIT_OTHER);					/*JLS 25-08-00*/

  ldcltExit (mctx.exitStatus);					/*JLS 25-08-00*/
}


/* End of file */


--- NEW FILE ldclt.h ---
#ident "ldclt @(#)ldclt.h	1.66 01/05/04"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		ldclt.h
	AUTHOR :	Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		03 December 1998
	DESCRIPTION :
			This file is the main include file of the tool named
			"ldclt"
 	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
03/12/98 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.2 : Add stats numbers in main_context.
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.3 : Implement asynchronous mode.
---------+--------------+------------------------------------------------------
11/12/98 | JL Schwing	| 1.4 : Implement max errors threshold.
---------+--------------+------------------------------------------------------
14/12/98 | JL Schwing	| 1.5 : Implement "-e close".
---------+--------------+------------------------------------------------------
16/12/98 | JL Schwing	| 1.6 : Implement "-e add" and "-e delete".
			| Add counter nb timeouts (no activity).
---------+--------------+------------------------------------------------------
28/12/98 | JL Schwing	| 1.7 : Add tag asyncHit.
---------+--------------+------------------------------------------------------
29/12/98 | JL Schwing	| 1.8 : Implement -Q.
---------+--------------+------------------------------------------------------
11/01/99 | JL Schwing	| 1.9 : Implement "-e emailPerson".
---------+--------------+------------------------------------------------------
13/01/99 | JL Schwing	| 1.10: Implement "-e string".
---------+--------------+------------------------------------------------------
14/01/99 | JL Schwing	| 1.11: Implement "-s <scope>".
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.12: Implement "-e randombase".
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.13: Implement "-e v2".
---------+--------------+------------------------------------------------------
21/01/99 | JL Schwing	| 1.14: Implement "-e ascii".
---------+--------------+------------------------------------------------------
26/01/99 | JL Schwing	| 1.15: Implement "-e noloop".
---------+--------------+------------------------------------------------------
28/01/99 | JL Schwing	| 1.16: Implement "-T <total>".
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| 1.17: Implement operations list.
---------+--------------+------------------------------------------------------
06/05/99 | JL Schwing	| 1.22: Implement "-e modrdn".
---------+--------------+------------------------------------------------------
19/05/99 | JL Schwing	| 1.25: Implement "-e rename".
---------+--------------+------------------------------------------------------
27/05/99 | JL Schwing	| 1.26 : Add statistics to check threads.
---------+--------------+------------------------------------------------------
28/05/99 | JL Schwing	| 1.27 : Add new option -W (wait).
---------+--------------+------------------------------------------------------
02/06/99 | JL Schwing	| 1.28 : Add flag in main ctx to know if slave was
			|   connected or not.
			| Add counter of operations received in check threads.
---------+--------------+------------------------------------------------------
04/08/00 | JL Schwing	| 1.29: Add stats on nb inactivity per thread.
---------+--------------+------------------------------------------------------
08/08/00 | JL Schwing	| 1.30: Print global statistics every 1000 loops.
---------+--------------+------------------------------------------------------
18/08/00 | JL Schwing	| 1.31: Print global statistics every 15'
			| Print begin and end dates.
---------+--------------+------------------------------------------------------
25/08/00 | JL Schwing	| 1.32: Implement consistent exit status...
---------+--------------+------------------------------------------------------
19/09/00 | JL Schwing	| 1.33: Port on Netscape's libldap. This is realized in
			|   such a way that this library become the default
			|   way so a ifdef for Solaris will be used...
---------+--------------+----------------------------------------------------
11/10/00 | B Kolics     | 1.34: Added 'SSL' to the list of running modes and
         |              |       certfile to main_context structure
---------+--------------+------------------------------------------------------
07/11/00 | JL Schwing	| 1.35: Add handlers for dynamic load of ssl-related
			|   functions.
-----------------------------------------------------------------------------
07/11/00 | JL Schwing	| 1.36: Implement "-e inetOrgPerson".
---------+--------------+------------------------------------------------------
13/11/00 | JL Schwing	| 1.37: Add new options "-e randombaselow and ...high"
---------+--------------+------------------------------------------------------
16/11/00 | JL Schwing	| 1.38: Implement "-e imagesdir=path".
			| lint-cleanup.
---------+--------------+------------------------------------------------------
17/11/00 | JL Schwing	| 1.39: Implement "-e smoothshutdown".
---------+--------------+------------------------------------------------------
21/11/00 | JL Schwing	| 1.40: Implement "-e attreplace=name:mask"
			| Increase max number of threads from 512 to 1000.
---------+--------------+------------------------------------------------------
22/11/00 | JL Schwing	| 1.41: Will now use LD_LIBRARY_PATH to load libssl.
---------+--------------+------------------------------------------------------
24/11/00 | JL Schwing	| 1.41: Added SSL client authentication
---------+--------------+------------------------------------------------------
28/11/00 | JL Schwing	| 1.43: Port on NT 4.
---------+--------------+------------------------------------------------------
15/12/00 | JL Schwing	| 1.44: Add more trace in VERY_VERBOSE mode.
---------+--------------+------------------------------------------------------
15/12/00 | JL Schwing	| 1.45: Implement "-e counteach".
			| Implement "-e withnewparent".
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.46: Add exit status EXIT_INIT and EXIT_RESSOURCE.
---------+--------------+------------------------------------------------------
03/01/01 | JL Schwing	| 1.47: Implement "-e attrsonly=value".
---------+--------------+------------------------------------------------------
05/01/01 | JL Schwing	| 1.48: Implement "-e randombinddn" and associated
			|   "-e randombinddnlow/high"
---------+--------------+------------------------------------------------------
08/01/01 | JL Schwing	| 1.49: Implement "-e scalab01".
---------+--------------+------------------------------------------------------
12/01/01 | JL Schwing	| 1.50: Second set of options for -e scalab01
---------+--------------+------------------------------------------------------
06/03/01 | JL Schwing	| 1.51: Change DEF_ATTRSONLY from 1 to 0
---------+--------------+------------------------------------------------------
08/03/01 | JL Schwing	| 1.52: Change referrals handling.
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.53: Implement "-e commoncounter"
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.54: Implement "-e dontsleeponserverdown".
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.55: Lint cleanup.
---------+--------------+------------------------------------------------------
15/03/01 | JL Schwing	| 1.56: Implement "-e attrlist=name:name:name"
			| Implement "-e randomattrlist=name:name:name"
---------+--------------+------------------------------------------------------
19/03/01 | JL Schwing	| 1.57: Implement "-e object=filename"
			| Implement "-e genldif=filename"
---------+--------------+------------------------------------------------------
21/03/01 | JL Schwing	| 1.58: Implements variables in "-e object=filename"
---------+--------------+------------------------------------------------------
23/03/01 | JL Schwing	| 1.59: Implements data file list support in variants.
			| Implements "-e rdn=value".
---------+--------------+------------------------------------------------------
28/03/01 | JL Schwing	| 1.60: Update options checking for "-e rdn=value".
---------+--------------+------------------------------------------------------
28/03/01 | JL Schwing	| 1.61: Support -e commoncounter with -e rdn/object
			| Increase MAX_ATTRIBS from 20 to 40
			| Remove MAX_ATTRLIST - use MAX_ATTRIBS.
---------+--------------+------------------------------------------------------
02/04/01 | JL Schwing	| 1.62: Bug fix : large files support for -e genldif.
---------+--------------+------------------------------------------------------
05/04/01 | JL Schwing	| 1.63: Implement -e append.
---------+--------------+------------------------------------------------------
11/04/01 | JL Schwing	| 1.64: Implement [INCRFROMFILE<NOLOOP>(myfile)]
---------+--------------+------------------------------------------------------
03/05/01 | JL Schwing	| 1.64: Implement -e randombinddnfromfile=filename.
---------+--------------+------------------------------------------------------
04/05/01 | JL Schwing	| 1.65: Implement -e bindonly.
---------+--------------+------------------------------------------------------
*/

#ifndef LDCLT_H
#define LDCLT_H

/*
 * Misc constant definitions
 */
#define DEF_ATTRSONLY	      0	/* ldap_search() default */	/*JLS 06-03-01*/
#define DEF_GLOBAL_NB	     90 /* Prt glob stats every 15' */	/*JLS 18-08-00*/
#define DEF_INACTIV_MAX	      3 /* Inactivity max nb times */
#define DEF_MAX_ERRORS	   1000 /* Max errors before exit */
#define	DEF_NB_THREADS	     10 /* Nb client threads */
#define DEF_PORT	    389 /* Ldap server port */
#define DEF_SAMPLING	     10 /* Default sampling rate */
#define DEF_TIMEOUT	     30 /* Ldap operations timeout */
#define DEF_PORT_CHECK	  16000 /* Port used for check processing */
#define MAX_ATTRIBS	     40 /* Max number of attributes */	/*JLS 28-03-01*/
#define MAX_DN_LENGTH	   1024 /* Max length for a DN */
#define MAX_ERROR_NB	   0x62 /* Max ldap err number + 1 */
#define MAX_IGN_ERRORS	     20 /* Max errors ignored */
#define MAX_FILTER	    512 /* Max filters length */
#define MAX_THREADS	   1000 /* Max number of threads */	/*JLS 21-11-00*/
#define MAX_SLAVES	     20 /* Max number of slaves */

#define DEF_IMAGES_PATH	"../../data/ldclt/images"
#define DEF_REFERRAL	REFERRAL_ON				/*JLS 08-03-01*/
#define DEF_SCOPE	LDAP_SCOPE_SUBTREE	/* Default for -s */

#ifndef SSL_LIB
#define SSL_LIB "libldapssl41.so"
#endif
#ifndef SSL_LIB_PATH
#define SSL_LIB_PATH "/qa/ldap/tools/ldclt/src/lib-sparc/ldapcsdk"
#endif

/*
 * Referral choices...
 */
#define	REFERRAL_OFF		0				/*JLS 08-03-01*/
#define	REFERRAL_ON		1				/*JLS 08-03-01*/
#define	REFERRAL_REBIND		2				/*JLS 08-03-01*/

/*
 * Running modes
 * Will be used as well for main_context and for thread_context
 * Don't forget to update dumpModeValues().
 */
#define	NOTHING		0x00000000 /* Nothing special */
#define VERBOSE		0x00000001 /* -v : verbose */
#define VERY_VERBOSE	0x00000002 /* -V : very verbose */
#define ASYNC		0x00000004 /* -a : asynchonous mode */
#define QUIET		0x00000008 /* -q : quiet */
#define SUPER_QUIET	0x00000010 /* -Q : super quiet */
#define SSL             0x00000020 /* -Z certfile :SSL enabled *//*BK 11-10-00*/
#define CLTAUTH         0x00000040 /* .... */			/* BK 23-11-00*/
/**/
#define RANDOM_ATTRLIST	0x00000080 /* -e randomattrlist*/	/*JLS 15-03-01*/
#define DONT_SLEEP_DOWN	0x00000100 /* -e dontsleeponserverdown*//*JLS 14-03-01*/
#define COMMON_COUNTER	0x00000200 /* -e commoncounter */	/*JLS 14-03-01*/
#define SCALAB01	0x00000400 /* -e scalab01 */		/*JLS 08-01-01*/
#define RANDOM_BINDDN	0x00000800 /* -e randombinddn */	/*JLS 05-01-01*/
#define WITH_NEWPARENT	0x00001000 /* -e withnewparent */	/*JLS 15-12-00*/
#define COUNT_EACH	0x00002000 /* -e counteach */		/*JLS 15-12-00*/
#define ATTR_REPLACE	0x00004000 /* -e attreplace */		/*JLS 21-11-00*/
#define SMOOTHSHUTDOWN	0x00008000 /* -e smoothshutdown */	/*JLS 17-11-00*/
#define	OC_INETORGPRSON	0x00010000 /* -e inetOrgPerson : oc= */	/*JLS 07-11-00*/
#define RENAME_ENTRIES	0x00020000 /* -e rename   : rename entries */
#define NOLOOP		0x00040000 /* -e noloop   : don't loop nb */
#define ASCII_7BITS	0x00080000 /* -e ascii    : ascii 7bits */
#define LDAP_V2		0x00100000 /* -e v2       : ldap v2 */
#define RANDOM_BASE	0x00200000 /* -e randombase : string mode */
#define STRING		0x00400000 /* -e string   : string mode */
#define OC_EMAILPERSON	0x00800000 /* -e emailPerson : oc = person */
#define DELETE_ENTRIES	0x01000000 /* -e delete   : delete */
#define OC_PERSON	0x02000000 /* -e person   : oc = person */
#define ADD_ENTRIES	0x04000000 /* -e add      : add entries */
#define INCREMENTAL	0x08000000 /* -e incr     : incremental */
#define CLOSE_FD	0x10000000 /* -e close    : close fd */
#define RANDOM		0x20000000 /* -e random   : rnd values */
#define BIND_EACH_OPER	0x40000000 /* -e bindeach : bnd each op */
#define EXACT_SEARCH	0x80000000 /* -e esearch  : exact srch */

#define M2_OBJECT	0x00000001 /* -e object */		/*JLS 19-03-01*/
#define M2_GENLDIF	0x00000002 /* -e genldif */		/*JLS 19-03-01*/
#define M2_RDN_VALUE	0x00000004 /* -e rdn */			/*JLS 23-03-01*/
#define M2_APPEND	0x00000008 /* -e append */		/*JLS 05-04-01*/
#define M2_RNDBINDFILE	0x00000010 /* -e randombinddnfromfile *//*JLS 03-05-01*/
#define M2_BINDONLY	0x00000020 /* -e bindonly */		/*JLS 04-05-01*/

/*
 * Combinatory defines
 *  - NEED_FILTER	: filter required
 *  - NEED_RANGE	: -r and -R required
 *  - NEED_RND_INCR	: need entry generator
 *  - VALID_OPERS	: valid operations
 */
#define NEED_FILTER	(ADD_ENTRIES|DELETE_ENTRIES|EXACT_SEARCH|RENAME_ENTRIES|ATTR_REPLACE|SCALAB01)
#define NEED_RANGE	(INCREMENTAL|RANDOM)
#define NEED_RND_INCR	(ADD_ENTRIES|DELETE_ENTRIES|RENAME_ENTRIES)
#define VALID_OPERS	(ADD_ENTRIES|DELETE_ENTRIES|EXACT_SEARCH|RENAME_ENTRIES|ATTR_REPLACE|SCALAB01)
#define M2_VALID_OPERS	(M2_GENLDIF|M2_BINDONLY)
#define NEED_CLASSES	(ADD_ENTRIES)
#define THE_CLASSES	(OC_PERSON|OC_EMAILPERSON|OC_INETORGPRSON)

/*
 * The threads status - check thread_context.status
 */
#define FREE		-1 /* Slot is free */
#define CREATED		 0 /* Just created */
#define INITIATED	 1 /* Initiated */
#define RUNNING		 2 /* Doing it's job */
#define DEAD		 9 /* Thread is dead */
#define MUST_SHUTDOWN	10 /* Monitor command this */		/*JLS 17-11-00*/

/*
 * Exit status
 * The biggest is the number, the higher priority is.
 * Cf the end of monitorThem().
 */
#define EXIT_OK		 0 /* No problem during execution */	/*JLS 25-08-00*/
#define EXIT_PARAMS	 2 /* Error in parameters */		/*JLS 25-08-00*/
#define EXIT_MAX_ERRORS	 3 /* Max errors reached */		/*JLS 25-08-00*/
#define EXIT_NOBIND	 4 /* Cannot bind */			/*JLS 25-08-00*/
#define EXIT_LOADSSL	 5 /* Cannot load libssl */		/*JLS 07-11-00*/
#define EXIT_MUTEX	 6 /* Mutex error */			/*JLS 17-11-00*/
#define EXIT_INIT	 7 /* Initialization error */		/*JLS 18-12-00*/
#define EXIT_RESSOURCE	 8 /* Ressource limitation */		/*JLS 18-12-00*/
#define EXIT_OTHER	99 /* Other kind of error */		/*JLS 25-08-00*/

/*
 * Some constants from Sun's ldap.h are not provided by
 * Netscape implementation...
 */
#ifdef SOLARIS_LIBLDAP						/*JLS 19-09-00*/
#define WORKAROUND_4197228	1				/*JLS 19-09-00*/
#else								/*JLS 19-09-00*/
#define	LDAP_REQ_BIND			0x60			/*JLS 19-09-00*/
#define	LDAP_REQ_UNBIND			0x42			/*JLS 19-09-00*/
#define	LDAP_REQ_SEARCH			0x63			/*JLS 19-09-00*/
#define	LDAP_REQ_MODIFY			0x66			/*JLS 19-09-00*/
#define	LDAP_REQ_ADD			0x68			/*JLS 19-09-00*/
#define	LDAP_REQ_DELETE			0x4a			/*JLS 19-09-00*/
#define	LDAP_REQ_MODRDN			0x6c			/*JLS 19-09-00*/
#define	LDAP_REQ_COMPARE		0x6e			/*JLS 19-09-00*/
#define	LDAP_REQ_ABANDON		0x50			/*JLS 19-09-00*/
#define	LDAP_REQ_EXTENDED		0x77			/*JLS 19-09-00*/
#define	LDAP_REQ_UNBIND_30		0x62			/*JLS 19-09-00*/
#define	LDAP_REQ_DELETE_30		0x6a			/*JLS 19-09-00*/
#define	LDAP_REQ_ABANDON_30		0x70			/*JLS 19-09-00*/
#endif								/*JLS 19-09-00*/

/*
 * This structure is the internal representation of an image
 */
typedef struct image {
	char	*name;
	int	 length;
	char	*data;
} image;

/*
 * Internal representation of a data list file
 */
typedef struct data_list_file {					/*JLS 23-03-01*/
	char		 *fname;	/* File name */
	char		**str;		/* Strings array */
	int		  strNb;	/* Nb of strings */
	struct data_list_file	 *next;	/* Next file */
} data_list_file;

/*
 * This structure is the internal representation of an LDAP attribute
 */
typedef struct {
	char	*type;		/* e.g. "objectclass" or "cn" */
	int	 length;	/* Length of the value */
	char	*value;		/* The attribute value */
	int	 dontFree;	/* Don't free the value */
} attribute;

/*
 * This structure is used to memorize an operation successfully
 * performed by the tool in order to be checked later on.
 * The operation type is a LDAP constant LDAP_REQ_ADD, etc...
 * ATTENTION: don't forget to maintain in sync with the struct thoper below.
 */
typedef struct oper {
	int		 type;		/* Operation type */
	char		*dn;		/* Target's DN */
	attribute	 attribs[MAX_ATTRIBS];	/* Attributes to check */
					/* attribs[i].type == NULL marks the */
					/* end of the attributes */
	char		*newRdn;	/* For rename operation */
	char		*newParent;	/* For rename operation */
	int		 skipped;	/* Thread that skipped it */
	ldclt_mutex_t	 skipped_mutex;	/* Protect skipped */	/*JLS 28-11-00*/
	struct oper	*next;		/* Next operation */
} oper;

/*
 * Same as before, but this is a per thread "lost" operation list
 */
typedef struct _simpl_op {
	int		  type;
	int		  first;  	/* Keeps in order replies */
	char		 *dn;
	attribute	  attribs[MAX_ATTRIBS];
	char		 *newRdn;
	char		 *newParent;
	struct _simpl_op *next;
} thoper;

/*
 * This structure will allow to manage the handlers for ssl-related
 * dynamic loaded functions.
 */
typedef struct ssl_context {					/*JLS 07-11-00*/
#ifndef _WIN32
	void	*libssl;	/* lib ssl handler */		/*JLS 07-11-00*/
	LDAP	*(*ldapssl_init)(const char *, int, int);	/*JLS 07-11-00*/
	int	 (*ldapssl_client_init)(const char*, void*);	/*JLS 07-11-00*/
	int	 (*ldapssl_clientauth_init)(char *, void *, int, char *, void*);
								/* BK 23-11-00*/
        int      (*ldapssl_enable_clientauth)(LDAP *, char *, char *, char *);
                                                                /* BK 22-11-00*/
#else /* _WIN32 */
	LDAP	* (LDAP_CALL *ldapssl_init)(const char *, int, int);
	int	  (LDAP_CALL *ldapssl_client_init)(const char*, void*);
	int	  (LDAP_CALL *ldapssl_clientauth_init)(char *, void *, int, char *, void*);
        int       (LDAP_CALL *ldapssl_enable_clientauth)(LDAP *, char *, char *, char *);
#endif /* _WIN32 */
} ssl_context;							/*JLS 07-11-00*/

/*
 * Versatile object attribute's field
 * - If ldclt should use a common counter, then this counter will
 *   be in the mctx structure and will be found by the commonField
 *   pointer.
 */
#define HOW_CONSTANT	      0	/* Constant value */
#define HOW_INCR_FROM_FILE    1 /* Increment string from file *//*JLS 11-04-01*/
#define HOW_INCR_FROM_FILE_NL 2 /* Incr string file noloop*/	/*JLS 11-04-01*/
#define HOW_INCR_NB	      3 /* Increment number */		/*JLS 23-03-01*/
#define HOW_INCR_NB_NOLOOP    4 /* Increment number no loop */	/*JLS 23-03-01*/
#define HOW_RND_FROM_FILE     5 /* Random string from file */	/*JLS 23-03-01*/
#define HOW_RND_NUMBER	      6	/* Random number */
#define HOW_RND_STRING	      7	/* Random string */
#define HOW_VARIABLE	      8	/* Retrieve variable value */	/*JLS 21-03-01*/
typedef struct vers_field {					/*JLS 21-03-01*/
	int		 how;		/* How to build this field */
	int		 cnt;		/* Counter */		/*JLS 23-03-01*/
	ldclt_mutex_t	 cnt_mutex;	/* Protect cnt */	/*JLS 28-03-01*/
	struct vers_field *commonField;	/* Common field */	/*JLS 28-03-01*/
	char		*cst;		/* Constant field */
	data_list_file	*dlf;		/* Data list file */	/*JLS 23-03-01*/
	int		 high;		/* High value */
	int		 low;		/* Low value */
	int		 nb;		/* Number of items */
	int		 var;		/* Variable number */
	struct vers_field *next;	/* Next field */
} vers_field;

/*
 * Versatile object's attribute
 */
typedef struct vers_attribute {					/*JLS 19-03-01*/
	char		*buf;	/* Store the generated value */	/*JLS 21-03-01*/
	char		*name;	/* Attribute name */
	char		*src;	/* Source line */
	vers_field	*field;	/* First field */		/*JLS 21-03-01*/
} vers_attribute;

/*
 * This structure contains the definitions related to the versatile
 * object classes managed by ldclt.
 * The field 'rdn' of vers_object is a trick we will use to be
 * able to support the same random mechanism for the entry's rdn
 * generation than for the attributes themselves.
 */
#define VAR_MIN		'A'					/*JLS 21-03-01*/
#define VAR_MAX		'H'					/*JLS 21-03-01*/
typedef struct vers_object {					/*JLS 19-03-01*/
	vers_attribute	 attribs[MAX_ATTRIBS];
	int		 attribsNb;
	vers_attribute	*rdn;		/* Object's rdn */	/*JLS 23-03-01*/
	char		*rdnName;	/* Attrib. name */	/*JLS 23-03-01*/
	char		*var[VAR_MAX-VAR_MIN];			/*JLS 21-03-01*/
	char		*fname;		/* Object definition */
} vers_object;

/*
 * This structure contain the *process* context, used only by the
 * main thread(s).
 * Another dedicated structure is used by each test thread.
 */
typedef struct main_context {
	int		 asyncMin;	/* Min pend for read */
	int		 asyncMax;	/* Max async pending */
	char		*attrlist[MAX_ATTRIBS];			/*JLS 15-03-01*/
	int		 attrlistNb;	/* Nb attrib in list */	/*JLS 15-03-01*/
	char		*attrpl;	/* Attrib argument */	/*JLS 21-11-00*/
	char		*attrplHead;	/* Attrib value head */	/*JLS 21-11-00*/
	char		*attrplName;	/* Attrib name */	/*JLS 21-11-00*/
	int		 attrplNbDigit;	/* Attrib nb digits */	/*JLS 21-11-00*/
	char		*attrplTail;	/* Attrib value tail */	/*JLS 21-11-00*/
	int		 attrsonly;	/* search() param. */	/*JLS 03-01-01*/
	char		*baseDN;	/* Base DN to use */
	int		 baseDNLow;	/* Base DN's low val */	/*JLS 13-11-00*/
	int		 baseDNHigh;	/* Base DN's high val *//*JLS 13-11-00*/
	int		 baseDNNbDigit;	/* Base DN's nb of digits */
	char		*baseDNHead;	/* Base DN's head string */
	char		*baseDNTail;	/* Base DN's tail string */
	char		*bindDN;	/* Bind DN */
	int		 bindDNLow;	/* Bind DN's low val */	/*JLS 05-01-01*/
	int		 bindDNHigh;	/* Bind DN's high val *//*JLS 05-01-01*/
	int		 bindDNNbDigit;	/* Bind DN's ndigits */	/*JLS 05-01-01*/
	char		*bindDNHead;	/* Bind DN's head */	/*JLS 05-01-01*/
	char		*bindDNTail;	/* Bind DN's tail */	/*JLS 05-01-01*/
        char            *certfile;      /* certificate file */ /* BK 11-10-00 */
        char            *cltcertname;   /* client cert name */ /* BK 23 11-00 */
	data_list_file	*dlf;		/* Data list files */	/*JLS 23-03-01*/
	int		 errors[MAX_ERROR_NB]; /* Err stats */
	int		 errorsBad;	/* Bad errors */
	ldclt_mutex_t	 errors_mutex;	/* Protect errors */	/*JLS 28-11-00*/
	int		 exitStatus;	/* Exit status */	/*JLS 25-08-00*/
	char		*filter;	/* Filter for req. */
	char		*genldifName;	/* Where to put ldif */	/*JLS 19-03-01*/
	int		 genldifFile;	/* Where to put ldif */	/*JLS 19-03-01*/
	char		*hostname;	/* Host to connect */
	int		 globStatsCnt;	/* Global stats loop */ /*JLS 08-08-00*/
	int		 ignErr[MAX_IGN_ERRORS]; /* Err ignor */
	int		 ignErrNb;	/* Nb err ignored */
	image		*images;	/* The images */
	char		*imagesDir;	/* Where are images */	/*JLS 16-11-00*/
	int		 imagesNb;	/* Nb of images */
	int		 imagesLast;	/* Last selected image */
	ldclt_mutex_t	 imagesLast_mutex; /* Protect imagesLast */
	int		 inactivMax;	/* Allowed inactivity */
        char            *keydbfile;     /* key DB file */       /* BK 23-11-00*/
        char            *keydbpin;      /* key DB password */   /* BK 23-11-00*/
	int		 lastVal;	/* To build filters */	/*JLS 14-03-01*/
	ldclt_mutex_t	 lastVal_mutex;	/* Protect lastVal */	/*JLS 14-03-01*/
	int		 maxErrors;	/* Max allowed errors */
	unsigned int	 mode;		/* Running mode */
	unsigned int	 mod2;		/* Running mode - 2 */	/*JLS 19-03-01*/
	int		 nbNoActivity;	/* Nb times no activ. */
	int		 nbSamples;	/* Samples to get */
	int		 nbThreads;	/* Nb of client */
	vers_object	 object;	/* Object to generate *//*JLS 19-03-01*/
	oper		*opListTail;	/* Tail of operation list */
	ldclt_mutex_t	 opListTail_mutex; /* Protect opListTail */
	char		*passwd;	/* Bind passwd */
	int		 passwdNbDigit;	/* Passwd's ndigits */	/*JLS 05-01-01*/
	char		*passwdHead;	/* Passwd's head */	/*JLS 05-01-01*/
	char		*passwdTail;	/* Passwd's tail */	/*JLS 05-01-01*/
	int		 pid;		/* Process ID */
	int		 port;		/* Port to use */
	int		 randomLow;	/* Rnd's low value */
	int		 randomHigh;	/* Rnd's high val */
	int		 randomNbDigit;	/* Rnd's nb of digits */
	char		*randomHead;	/* Rnd's head string */
	char		*randomTail;	/* Rnd's tail string */
	data_list_file	*rndBindDlf;	/* Rnd bind file data *//*JLS 03-05-01*/
	char		*rndBindFname;	/* Rnd bind file name *//*JLS 03-05-01*/
	int		 referral;	/* Referral followed */	/*JLS 08-03-01*/
	int		 sampling;	/* Sampling frequency */
	int		 scope;		/* Searches scope */
	int		 slaveConn;	/* Slave has connected */
	char		*slaves[MAX_SLAVES]; /* Slaves list */
	int		 slavesNb;	/* Number of slaves */
	ssl_context	 sslctx;	/* SSL dyn. load ctx */	/*JSL 07-11-00*/
	int		 timeout;	/* LDAP op. t.o. */
	struct timeval	 timeval;	/* Timeval structure */
	struct timeval	 timevalZero;	/* Timeout of zero */
	int		 totalReq;	/* Total requested */
	int		 totNbOpers;	/* Total opers number */
	int		 totNbSamples;	/* Total samples nb */
	int		 waitSec;	/* Wait between two operations */
} main_context;


/*
 * This structure is aimed to ease the managing of asynchronous
 * operations, keeping in memory the msgid returned by the library and
 * a free string meaning something for the user.
 * It is targetted that this string is something like a DN, and is
 * locally managed by the list functions.
 */
typedef struct msgid_cell {
	LDAPMod			**attribs;		/* Attributes */
	char			  dn[MAX_DN_LENGTH];	/* entry's dn */
	int			  msgid;		/* msg id */
	char			  str[MAX_DN_LENGTH];	/* free str */
	struct msgid_cell	 *next;			/* next cell */
} msgid_cell;

/*
 * This structure contain the context associated with each thread.
 * It is targetted to be initiated by the main thread, and maintained
 * by each thread.
 */
typedef struct thread_context {
	int		 active;	/* thread is active */
	int		 asyncHit;	/* async max hit */
	char		*attrlist[MAX_ATTRIBS];			/*JLS 15-03-01*/
	int		 binded;	/* thread is binded */
	int		 exitStatus;	/* Exit status */	/*JLS 25-08-00*/
	int		 fd;		/* fd to the server */
	int		 lastVal;	/* To build filters */
	LDAP		*ldapCtx;	/* LDAP context */
	unsigned int	 mode;		/* Running mode */
	int		 nbInactRow;	/* Nb inactive in row *//*JLS 04-08-00*/
	int		 nbInactTot;	/* Nb inactive total */	/*JLS 04-08-00*/
	int		 nbOpers;	/* Nb of operations */
	ldclt_mutex_t	 nbOpers_mutex;	/* Protect nbOpers */	/*JLS 28-11-00*/
	vers_object	*object;	/* Template */		/*JLS 21-03-01*/
	int		 pendingNb;	/* Pending opers */
	int		 status;	/* Status */
	ldclt_mutex_t	 status_mutex;	/* Protect status */	/*JLS 28-11-00*/
	ldclt_tid	 tid;		/* Thread's id */	/*JLS 28-11-00*/
	char		 thrdId[8];	/* This thread ident */	/*JLS 08-01-01*/
	int		 thrdNum;	/* This thread number */
	int		 totOpers;	/* Total nb operations */
	int		 totalReq;	/* Total nb operations requested */
	/*
	 * Now some convenient buffers ;-)
	 */
	char		 buf2 [MAX_FILTER];
	char		*bufObject1;				/*JLS 19-03-01*/
	char		*bufAttrpl;	/* Attribute replace */	/*JLS 21-11-00*/
	char		*bufBaseDN;	/* Base DN to use */
	char		*bufBindDN;	/* Bind DN to use */	/*JLS 05-01-01*/
	char		*bufFilter;	/* Filter to use */
	char		*bufPasswd;	/* Bind passwd to use *//*JLS 05-01-01*/
	/*
 	 * Note about matcheddnp management. This pointer is managed by the 
	 * function dnFromMessage() that need it to free or remember the string
	 * returned by the library. DO NOT manage this field another way.
	 */
	char		*matcheddnp;	/* See above */		/*JLS 15-12-00*/
	int		 startAttrpl;	/* Insert random here *//*JLS 21-11-00*/
	int		 startBaseDN;	/* Insert random here */
	int		 startBindDN;	/* Insert random here *//*JLS 05-01-01*/
	int		 startPasswd;	/* Insert random here *//*JLS 05-01-01*/
	int		 startRandom;	/* Insert random here */
	msgid_cell	*firstMsgId;	/* pending messages */
	msgid_cell	*lastMsgId;	/* last one */
} thread_context;

/*
 * This structure gather the information used by a check thread
 */
typedef struct check_context {
	oper		*headListOp;	/* Head list of operation */
	thoper		*dcOper;	/* Double check operation list */
	char		*slaveName;	/* Name of the slave */
	int		 sockfd;	/* Socket fd after accept() */
	int		 status;	/* Status */
	int		 thrdNum;	/* Thread number */
	int		 calls;		/* Number of timeouts */
	ldclt_tid	 tid;		/* Thread's id */	/*JLS 28-11-00*/
	int		 nbEarly;	/* err = Early */
	int		 nbLate;	/* err = Late replica */
	int		 nbLostOp;	/* err = Lost op */
	int		 nbNotOnList;	/* err = Not on list */
	int		 nbOpRecv;	/* Nb operations received */
	int		 nbRepFail32;	/* err = Replica failed err=32 */
	int		 nbRepFail68;	/* err = Replica failed err=68 */
	int		 nbRepFailX;	/* err = Replica failed err=X */
	int		 nbStillOnQ;	/* err = still on Queue */
} check_context;



/*
 * Extern declarations of global variables.
 */
extern main_context	 mctx;		/* Main context */
extern thread_context	 tctx[];	/* Thread contextes */
extern check_context	 cctx[];	/* Check thread contextes */


/*
 * Extern functions prototypes (for exported functions)
 */
	/* From ldclt.c */
extern void	 ldcltExit (int status);			/*JLS 18-08-00*/
extern int	 printGlobalStatistics (void);			/*JLS 16-11-00*/
	/* From ldcltU.c */
extern void	 usage (void);
	/* From threadMain.c */
extern int	 addErrorStat (int err);
extern int	 getThreadStatus (thread_context *tttctx,	/*JLS 17-11-00*/
				int *status);			/*JLS 17-11-00*/
extern int	 ignoreError  (int err);
extern int	 incrementCommonCounter (thread_context *tttctx);   /*14-03-01*/
extern int	 incrementCommonCounterObject (			/*JLS 28-03-01*/
				thread_context *tttctx, 	/*JLS 28-03-01*/
				vers_field *field);		/*JLS 28-03-01*/
extern int	 incrementNbOpers (thread_context *tttctx);
extern int	 msgIdAdd     (thread_context *tttctx, int msgid, char *str,
				char *dn, LDAPMod **attribs);
extern LDAPMod **msgIdAttribs (thread_context *tttctx, int msgid);
extern int	 msgIdDel     (thread_context *tttctx, int msgid, int freeAttr);
extern char	*msgIdDN      (thread_context *tttctx, int msgid);
extern char	*msgIdStr     (thread_context *tttctx, int msgid);
extern int	 randomString (thread_context *tttctx, int nbDigits);
extern char    **selectRandomAttrList (thread_context *tttctx);	/*JLS 15-03-01*/
extern int	 setThreadStatus (thread_context *tttctx,	/*JLS 17-11-00*/
				int status);			/*JLS 17-11-00*/
extern void	*threadMain   (void *);
	/* From ldapfct.c */
extern int	 connectToServer (thread_context *tttctx);	/*JLS 14-03-01*/
extern char	*dnFromMessage (thread_context *tttctx, LDAPMessage *res);
extern int	 doAddEntry    (thread_context *tttctx);
extern int	 doAttrReplace (thread_context *tttctx);	/*JLS 21-11-00*/
extern int	 doBindOnly    (thread_context *tttctx);	/*JLS 04-05-01*/
extern int	 doDeleteEntry (thread_context *tttctx);
extern int	 doExactSearch (thread_context *tttctx);
extern int	 doGenldif     (thread_context *tttctx);	/*JLS 19-03-01*/
extern int	 doRename      (thread_context *tttctx);
extern int	 freeAttrib (LDAPMod **attrs);
extern void	 ldclt_flush_genldif (void);			/*JLS 02-04-01*/
extern char	*my_ldap_err2string (int err);
extern char    **strList1 (char *str1);				/*JLS 08-01-01*/
	/* From data.c */
extern data_list_file	*dataListFile (char *fname);		/*JLS 23-03-01*/
extern int	 getImage   (LDAPMod *attribute);
extern int	 loadImages (char *dirpath);
	/* From workarounds.c */
extern int	 getFdFromLdapSession (LDAP *ld, int *fd);
	/* From opCheck.c */
extern int	 opAdd (thread_context *tttctx, int type, char *dn,
			LDAPMod **attribs, char *newRdn, char *newParent);
extern void	*opCheckMain (void *);
extern void	*opCheckLoop (void *);
extern int	 opNext (check_context *ctctx, oper **op);
extern int	 opRead (check_context *ctctx, int num, oper **op);
	/* From parser.c */
extern int	 parseAttribValue (char *fname, 		/*JLS 23-03-01*/
			vers_object *obj, char *line, 		/*JLS 23-03-01*/
			vers_attribute *attrib);		/*JLS 23-03-01*/
extern int	 readObject (vers_object *obj);			/*JLS 19-03-01*/


#endif /* LDCLT_H */

/* End of file */


--- NEW FILE ldclt.man ---
#ident "ldclt @(#)ldclt.man	1.56 01/05/04"

ldclt(1)                        SUNQAldap                ldclt(1)

NAME
        ldclt - ldap client for stress and reliability testing.

SYNOPSIS
        ldclt [-qQvV] [-e <execParams>] [-t <timeout>]
              [-b <base DN>] [-h <host>] [-p <port>]
              [-D <bind DN>] [-w <passwd>]
              [-n <nb threads>] [-i <nb times>] [-N <nb samples>]
              [-r <low> -R <high>]
              [-a <max pending>] [-E <max errors>]
              [-I <ignored error>] [-T <total>]
              [-f <filter>] [-s <scope>]
	      [-S <slave>] [-P<master port>]
	      [-W <waitsec>] [-Z <certfile>]

AVAILABILITY
        SUNQAldap

DESCRIPTION
        ldclt is a multi-threaded test tool targetted to stress a
        ldap server with multiple simultaneous requests.

        The  tool  automatically set its ulimit parameters to fit
        with the options.

        The tool uses a minimum of 16Mo of memory, and maybe more
        depending on the operations requested.

        A  summary  of global statistics regarding the operations
        performed,  and the errors that occurs, is printed at the
        exit of the tool, as well as every 90 loops (15 minutes).

	http://www-icnc.france/~jls/icnc_qa_lab_faq_05.html#ldclt

	Mailing list : ldclt at france.sun.com

    Referrals
	By default, ldclt will let the ldap library try to follow
	referrals as anonymous.  The  option  "-e referral=value"
	allows to change this behaviour :
	  on     : (default) follow as anonymous.
	  off    : do not follow.
	  rebind : try to rebind with the same binDN and passwd.

    Search operation
	The option  -e attrsonly=value  is used to request or not
	the  attributes  values.  It  is recommanded to use ldclt
	with the the default value (== 0) of this option.
	Extract from the C-SDK documentation :
	  0 : both  attribute  types  and  attribute  values  are
	      returned.
	  1 : only attribute types are returned.

	The options -e attrlist=name:name:name and similar option
	-e randomattrlist=name:name:name  allows to specify which
	attributes are retrieved from the server.

    Error decoding
	The tool try to decode the error as much as possible, but
	sometimes  not  enough  information  is  send back to the
	client.  This  happen  if chaining the backend feature of
	DS 5.0  or more is used,  when one of the farm servers is
	stopped. The error returned is "Operations error" without
	any more information in synchronous mode  (except for the
	search).

	This  is  a problem resides in the libldap implementation
	of Solaris.

	Implementation note : This improvement is to retrieve the
	additional  error  string that is returned by the server.
	This  is implemented for the  asynchronous operations and
	for  the  synchronous search only,  because for the other
	synchronous ops we should use ldap_get_lderrno()  that is
	not implement in Solaris's libldap.

    Missing nodes
	The  tool  automatically create the missing nodes.  These
	nodes are created using the DN and passwd given in  argu-
	ments to ldclt, and thus it may be possible that the tool
	cannot  initiate an empty database if it is not cn=admin,
	because only cn=admin may create the root entry.

	Note  that  when  it  occurs,  the  tool doesn't retry to
	create the original entry IF running *asynchronously*.

	Special  consideration  about rename entries  :  from the
	c-sdk function description, if the parent node of the new
	dn doesn't exist,  the error returned LDAP_PROTOCOL_ERROR
	may report as well three other problems :
	 - BER problem, unlike to happen
	 - newrdn is invalid, also unlike to happen
	 - ldclt is not running ldap v3 - ok, we could leave with
	   this issue.
	 - the newparent is invalid.  I thing  that we could take
	   this for "doesn't exist"...

	The  current version of this tool recognize the following
	naming attributes:
		cn	organizationalRole
		o	organization
		ou	organizationalUnit

    Close(fd) vs ldap_unbind(ld)
        The  option  "-e bindeach"  made  the tool to release the
        connection  to  the  server  after  each  operation being
        processed.  This  is  intended  to  simulate many clients
        doing quick operations.

        Without  any  other  option,  the  connection is properly
        released  with  a ldap_unbind(ld),  but if the additional
        option "-e close" is used,  the socket with the server is
        close() simulating a suddent exit of the client process.

    Random
        This feature is activated by the option "-e random". When
        used with filters,  the  tool will seek the given filters
        for  the  first sequence of 'X' and will take this as the
        place where the random numbers should be put. The span of
        the  random numbers  generated is given by the options -r
        and -R.

        For example, if the tool is called with the options:

                -f mail=a0000XXXXXX at sympatico.ca -e random -r0 \
                -R 9000000

        the following filters will be generated:

                mail=a0000492027 at sympatico.ca
                mail=a0000001941 at sympatico.ca
                mail=a0000075117 at sympatico.ca
                mail=a0000589623 at sympatico.ca
                mail=a0000283543 at sympatico.ca
                mail=a0000051688 at sympatico.ca
                etc...

	The  same  feature may be applied to the base DN,  and is
	activated     by     the    options    "-e   randombase",
	"-e randombaselow=value" and "-e randombasehigh=value".

	The  same  feature may be applied to the bind DN,  and is
	activated    by    the    options    "-e   randombinddn",
	"-e randombinddnlow=value", "-e randombinddnhigh=value".

    Incremental
        This feature is activated by the option "-e incr", and is
        similar to the "Random" feature described above.  It will
        replace  the 'X'  partern by incremental numbers starting
        by  the value of "-r" and ending with "-R".  When the top
        value is reached, return back to the lower value.

	The  option  "-e noloop"  will prevent ldclt from looping
	the numbers:  when  the  -R  value is reached, the thread
	dies.

	The  option  "-e commoncounter" will made all the threads
	use  the  same counter rather than each thread having its
	own private counter. This may be used for example to have
	many threads adding entries without "collisions".

    String
	This feature is activated by the option "-e string",  and
	will  make this tool generates random strings for the 'X'
	partern rather than random numbers.

	This option is only valid with the mode "-e random",  and
	will be applied as well to the base DN if "-e randombase"
	is  set,  and  to  the  bind  DN and bind password if the
	option "-e randombinddn" is set.

	The option  "-e ascii"  will produce characters less than
	0x7f, otherwise UTF-8 will be produced.

    Signals
        The signal SIGINT (^C or kill -2) is trapped to perform a
        smooth exit of the tool, with statistics report.

        The signal SIGQUIT (^\ or kill -3) is  trapped  to  issue
        the  current  statistics numbers, but without exiting the
        tool.

    Entry generator
	If  you  do not want to use the hard-coded object classes
	person/emailPerson/inetOrgPerson (see below), you may use
	the option  "-e object=filename" to give ldclt a template
	to build the entries.

	The same syntax may be used for the option "-e rdn=value"
	including variables.  The  RDN is build first and you may
	retrieve the variables you defined in it for the object.

	You could use the option  -e commoncounter with the entry
	generator.  When  used,  all  the variants INCRNNOLOOP or
	INCRN will share the same counter (if you are using three
	times  one  of  these variants,  three different counters
	will be used).

	The option  -e commoncounter  is also compatible with the
	variants INCRFROMFILE and INCRFROMFILENOLOOP.

	File grammar :

	    # Comment start with a '#'
	    #
	    LINE           = ATTRIBUTE_NAME: FIELD+
	    ATTRIBUTE_NAME = constant_string
	    FIELD          = constant_string | VARIANT
	    VARIANT        = [VAR=VDEF] | [VAR] | [VDEF]
	    VAR            = letter A to H
	    VDEF           = see below

	The keywords and associated args are listed below.  Note
	that the separator is ';' and not ','.

	    INCRFROMFILE(file_name)
		Will select each entry of file_name in sequence.
		After the last entry,  will  reset the index for
		to process again the first entry.
	    INCRFROMFILENOLOOP(file_name)
		Will select each entry of file_name in sequence.
		After the last entry, the thread will exit.
	    INCRN(low;hign;nb)
		Increment  a  counter  that  will go from low to
		high,  and  will loop to restart with low.  This
		counter is VARIANT-specific.
		Similar to "-e incr".
	    INCRNNOLOOP(low;high;nb)
		Same as INCRN,  except that the thread will exit
		when  reaching  the value high (after processing
		of this value).
		Similar to "-e incr,noloop".
	    RNDFROMFILE(file_name)
		Select a random string from the file.  One entry
		per line is expected.
	    RNDN(low;high;length)
		Build  a  random number of length digits,  value
		selected from low to high.
	    RNDS(lenght)
		Build a random string.

	Here is an example of template file :

	    # Example.
	    #
	    objectclass: person
	    sn: mr [RNDS(12)] final
	    description: blob [RNDN(1,5,6)] blib

	Resulting entries :

	    dn: cn=mr00000,ou=object,o=test.com
	    cn: mr00000
	    objectclass: person
	    sn: mr 2[kK-:9)_(qv final
	    description: blob 000005 blib

	    dn: cn=mr00001,ou=object,o=test.com
	    cn: mr00001
	    objectclass: person
	    sn: mr Jwf01XrZs.mt final
	    description: blob 000002 blib

    Person
        Activated  by "-e person" and valid only for the "-e add"
        feature,  the new  entries are of the  objectclass=person
        as described here:

    EmailPerson
        Activated by "-e emailPerson" and valid only for the "-e
	add" feature,  the  new  entries are of the objectclass=
	emailPerson  as described here.  These entries contain a
	jpegPhoto attribute, and thus are very big entries.  The
	jpeg  image  itself  is randomly (in fact: sequencially)
	selected from /opt/SUNQA/ldap/lib/images/*.jpg or in the
	directory specified by -e imagesdir=path.

    InetOrgPerson
	Activated  by  "-e inetOrgPerson",  it  is  the Netscape 
	version of emailPerson.

    Scalab01 scenario
	This scenario is activated by the  "-e scalab01"  and is
	a  special  evolution  of  ldclt  for the purpose of the
	system tests "scalab01". This scenario simulates a modem
	pool that uses LDAP to store information about users, as
	well as to autheticate them by binding.

	The associated options are :
	  -e scalab01
		Activate this scenario.

	  -e scalab01_cnxduration
		Specifies  the  maximum cnx duration in seconds.
		Default value is 3600 seconds.

	  -e scalab01_maxcnxnb
		Modem pool size. Default size if 5000.

	  -e scalab01_wait
		Sleep() in seconds while to attempts to connect.
		Default value is 10 seconds.

OPTIONS
        The valid options are:

        -a <number>
                Asynchronous mode. When used, the tool will issue
                asynchronous  requests,  with a maximum number of
                pending requests (aka results non-read). There is
                a  threshold   at  "max pending / 2"  giving  the
                minimum  number  of  pending operations needed to
                read the answers from the server.

                Each thread will process with the same algorythm,
                each having the same thresholds.

        -b <DN> Specify the base DN to use. Default "o=sun,c=us".

        -D <DN> Bind DN.  See -w for the password. You could use
		the  option  "-e randombinddn"  to randomize the
		bind  DN.   Read  below  in  -e  options for the
		details.

        -e <parm1,parm2,etc...>
                Execution  parameters.   This  option is used to
                select the kind of tests that should be run.  It
                is possible to specify more than one value  (see
                example below). The valid values are:

                  add
			Add entries.

		  append
			Append new entries to genldif file.
			See also -e genldif.

		  ascii
			Ascii 7-bits strings.

		  attreplace=name:mask
			Will replace the attribute "name" with a
			random string value build using the mask
			i.e. :
			  attreplace=sn:"mr XXXX Jr"
			Note :  You DO NOT need to use -e random
			nor -e string with this option.

		  attrlist=name:name:name
			Specify   the   list  of  attributes  to
			retrieve.
			See also -e randomattrlist.

		  attrsonly=0|1
			This ldap_search() parameter means  :  0
			specifies  that both attribute types and
			attribute  values  are  returned  and  1
			specifies that  only attribute types are
			returned.
			Default value : 0

                  bindeach
			Bind for each operation.

		  bindonly
			ldclt  will only perform ldap_bind() and
			ldap_unbind()  or  close()  depending on
			the options.
			See also -e close.

                  close
			Will  disconnect  from  the  server by a
			close()  on  the  fd,  rather  than by a
			ldap_unbind().

		  cltcertname=certificate_name
			Use  certificate_name   for  SSL  client
			authentication. The certificate database
			is specified with the -Z option.
			SSL client  authentication  requires the
			option -Z  and  cltcertname,  keydbfile,
			keydbpin  execution   parameters  to  be
			specified.

		  commoncounter
			Valid  only  with  -e incr or -e object.
			All   the  threads  will  use  the  same
			counter, i.e. T000 will process entry n,
			T001 entry n+1, etc...
			When  used with an object (-e object) or
			within a rdn (-e rdn),  a common counter
			will  be  used  for  each  variant field
			INCRN  or  INCRNNOLOOP.  Each field will
			have its own common counter.

		  counteach
			To  count  each operation,  and not only
			the  ones  that  succeed.  Without  this
			option,   an  add  request  with  result
			68==LDAP_ALREADY_EXISTS  is not counted,
			that  may  mislead  the statistics about
			the thread's activity.
			The  changes are that we will count as a
			valid request :
			 - add    ==> LDAP_ALREADY_EXISTS
			 - delete ==> LDAP_NO_SUCH_OBJECT
			 - rename ==> LDAP_ALREADY_EXISTS
			              LDAP_NO_SUCH_OBJECT
			              LDAP_PROTOCOL_ERROR
			 - search ==> LDAP_NO_SUCH_OBJECT

                  delete
			ldap_delete() entries.

		  dontsleeponserverdown
			By  default,  ldclt  sleep  1 second when
			occurs  an  error  like  81 or  91  (i.e.
			server  down).  This  should  avoid ldclt
			looping when server is down, otherwise it
			may  take 100% of all 10 CPUs of a E6000.
			Basically,  the client machine is down if
			this happen.

		  emailPerson
			The    new    entries   objectclass   is
			emailPerson.    See   details  above  in
			DESCRIPTION.

                  esearch
			Exact  search.  No wildcards expected in
			the filter.

		  genldif=filename
			Create  a  ldif  file  using ldclt entry
			generator.
			See also -e append.

		  imagesdir=<path>
			The images are taken from the given path
			rather than from the default directory :
				/opt/SUNQA/ldap/lib/images

                  incr
			Incremental values, from -r to -R values
			When -R is reached, go back to -r.
			See also -e commoncounter.

		  inetOrgPerson
			The    new    entries    objectclass  is
			inetOrgPerson.   See  details  above  in
			DESCRIPTION.

		  keydbfile=key_DB_filename
			The file name of the key database.
			SSL client  authentication  requires the
			option -Z  and  cltcertname,  keydbfile,
			keydbpin  execution   parameters  to  be
			specified.

		  keydbpin=key_DB_password
			Password required  for accessing the key
			database    specified    in    keydbfile
			execution parameter.
			SSL client  authentication  requires the
			option -Z  and  cltcertname,  keydbfile,
			keydbpin  execution   parameters  to  be
			specified.

		  noglobalstats
			Don't  print the periodical global stats
			(by default : every 90 loops).

		  noloop
			Does not loop the numbers. Cf the option
			"-e incr".

		  object=filename
			Entries  will  be created using template
			from the given file.  See  details above
			in DESCRIPTION.
			See "-e rdn=attrname:value".

                  person
			The  new  entries objectclass is person.
			See details in DESCRIPTION.

                  random
			Random filters, etc...  generation.  See
			details above in this tool description.

		  randomattrlist=name:name:name
			Specify  the  list  of  attributes  from
			which  ldclt will randomly select one to
			be retrieved.
			See also -e attrlist.

		  randombase
			Random base DN generation.

		  randombaselow=<number>
			Low value range for random base DN.

		  randombasehigh=<number>
			High value range for random base DN.

		  randombinddn
			Random   bind   DN   and  bind  password
			generation.  When used, this option will
			produce a random value that will be used
			to  randomize  the  bind DN and password
			with the same random value. e.g. cn=m123
			and passwd123 will be generated.
			If  you  want to have fix password  (the
			same password) for each bind DN, just no
			'X' in the password.

		  randombinddnfromfile=filename
			A bind DN and its corresponding password
			will be randomly selected from the given
			file. Each line must contain the bind DN
			and  password,  separated by one or more
			tabs.  Leading & trailing spaces are not
			ignored.
			Exclusive with -e randombinddn and with
			-D / -w.

		  randombinddnlow=<number>
			Low value range for random bind DN.

		  randombinddnhigh=<number>
			High value range for random bind DN.

		  rdn=attrname:value
			Similar  to the option  "-f filterspec",
			this feature allow to use the full power
			of the entry generator (see DESCRIPTION)
			to  build the rdn of the entry that will
			be processed.
			Requires "-e object=".
			Exclusive with -f.

		  referral=value
			Change referral  behaviour.  See details
			above in the DESCRIPTION section.

		  rename
			Rename  entries  (aka modrdn).  See also
			-e withnewparent.

		  scalab01
			Activates the scalab01 scenario.  Please
			read the corresponding section above for
			the   other   associated   options   and
			behaviour.

		  string
			Will generate random strings rather than
			numbers. See details above in the string
			sub-section.

		  v2
			Ldap v2 mode.

		  withnewparent
			The ldap_rename()  will be called with a
			newparent argument. By default, only the
			new  rdn  is  specified.  This option is
			valid only with -e rename.

        -E <number>
                Specify  the  maximum  number of times one error
                may occur. It is usefull to detect a big problem
                on  the server side,  and to exit the tool.  The
                default value is 1000.

        -f <filter>
                Filter  for searches.  The syntax is the same as
                specified in ldap's RFCs.
		See option "-e rdn=attrname:value".

        -h <hostname>
                Host to connect. Default "localhost".

        -i <number of 10 seconds>
                Number  of  times  inactivity allowed.  The tool
                ensure that no thread is starving,  i.e.  expect
                that all the threads should perform at least one
                operation every 10 seconds. This parameter gives
                the  number  of  times  a thread may be starving
                before  releasing an alert message.  The default
                value is 3 (30 seconds).

        -I <error number>
                The tool will ignore the errors the same  number
                as the ones specified with -I.  These errors may
                be for example:
                   32 : No such object  - when -e random,delete
                   68 : Already exists  - when -e random,add

		When  used,  this option will configure ldclt to
		ignore/support these errors during the ldap_bind
		to the server.  Otherwise, any error that happen
		during  the  connection is a fatal error for the
		thread where it occurs.

		Note that although ldclt support a certain level
		of  errors  during  connection,  any  error that
		happen  while  creating missing nodes is a fatal
		error.

        -n <number>
                Number  of threads. Each thread is a ldap client
                for  the  ldap  server  under test.  The maximum
                number of threads is system-dependand, and is of
                1000 threads. The default number is 10 threads.

        -N <number>
                Number  of samples (10 seconds each).  It is the
                time  the tool should run.  A value of 360 means
                360 samples of 10 seconds,  i.e. 3600 seconds of
                testing (one hour). Default infinite.

        -p <port number>
                Server port. Default port 389.

	-P <master port number>
		This  is  the  port used to communicate with the
		slaves in order to check the replication.

        -q      Quiet mode. When used, the errors of the option
                -I are not printed.  The messages "Intermediate
		nodes created for xxx" are not printed either.

        -Q      Super  quiet  mode.  In  addition  to  -q,  the
                following messages are not printed:
                   Max pending request hit.
                   No activity for %d seconds.
                   Restart sending.

        -r <number>
                Range's low value.

        -R <number>
                Range's high value.

	-s <scope>
		Valid only for searches.  May be base,  subtree
		or one. The default value is subtree.

	-S <slave>
		The  slave host given in argument will be under
		monitoring   to   ensure  that  the  operations
		performed  on  the  server are well realized on
		the given  slave.  This option may be used more
		than one time to indicate more than one slave.

        -t <seconds>
                LDAP operations timeout. Default 30 seconds.

	-T <total>
		Total number of operations requested per thread
		before exit.  When used,  this  parameter  will
		cause each thread to exit when this  number  of
		operations is reached.

        -v      Verbose.

        -V      Very verbose.

        -w <password>
                Bind passwd. See option -D.

	-W <wait seconds>
		Wait between two operations. Default=0 seconds.

	-Z <certfile>
		Establish secure  communication with the server
		over  SSL  using  certfile  as the  certificate
		database.

EXIT STATUS

	ldclt exit status may be :

	   0 : no problem during execution.
	   1 : please report this to me - shouldn't happen !!
	   2 : error in parameters.
	   3 : max errors reached.
	   4 : cannot bind.
	   5 : cannot load libssl.
	   6 : mutex error.
	   7 : initialization problem.
	   8 : ressource limitation (malloc, etc...).
	  99 : other kind of error - please report to me.

EXAMPLES
        jls at chronos$ ldclt -v \
                -h aegir -e esearch,random \
                -r0 -R900000 \
                -bo=Sympatico,c=CA \
                -fmail=a0000XXXXXX at sympatico.ca \
                -ebindeach -n230 -i6
        Host to connect    = aegir
        Port number        = 389
        Bind DN            = NULL
        Passwd             = NULL
        Base DN            = o=Sympatico,c=CA
        Filter             = mail=a0000XXXXXX at sympatico.ca
        Max times inactive = 6
        Number of samples  = 20
        Number of threads  = 5
        Running mode       = 0x0000001d
        Sampling interval  = 10 sec
        Random range       = [0 , 900000]
        Filter's head      = mail=a0000
        Filter's tail      = @sympatico.ca
        Average rate:    9.98/thr  (229.50/sec), total:   2295
        Average rate:   10.13/thr  (233.00/sec), total:   2330
        Average rate:   10.05/thr  (231.10/sec), total:   2311
        Average rate:   10.17/thr  (233.80/sec), total:   2338
        Average rate:    9.99/thr  (229.80/sec), total:   2298
        ^CCatch SIGINT - exit...
        jls at chronos$

NOTES
	This tool doesn't retry to create the original entry when
	the creation of the missing nodes is activated. This is a
	known missing feature of the asynchronous mode.

	Please  read  the file "History" delivered with this tool
	for more information about new features, todo list, etc.

	IMPORTANT NOTE : you may specify a filter that return lot
	of  entries  (e.g. : -f "cn=*")  but you should then know
	that  such  filters  leads to retrieve a lot of data from
	the server.  These data  are malloc() and free() by ldclt
	and the ldap C library,  but as you may have many threads
	running  at  the  same time in ldclt,  you will have many
	times these data allocated, leading to a *very) big ldclt
	process, even more than 1Gb.  It is not a memory leak but
	rather allocation of lot of data.  If you want the server
	to  retrieve  a lot of data from its database and however
	limit  the  ressources required by ldclt,  use the option
	"-e attrsonly=1".

AUTHORS
        Jean-Luc Schwing
	Fabio Pistolesi : replication check.
	Bertold Kolics  : SSL.



--- NEW FILE ldclt.use ---
usage: ldclt [-qQvV] [-E <max errors>]
             [-b <base DN>] [-h <host>] [-p <port>] [-t <timeout>]
             [-D <bind DN>] [-w <passwd>]
             [-e <execParams>] [-a <max pending>]
	     [-n <nb threads>] [-i <nb times>] [-N <nb samples>]
	     [-I <err number>] [-T <total>]
	     [-r <low> -R <high>]
	     [-f <filter>] [-s <scope>]
	     [-S <slave>] [-P<master port>]
	     [-W <waitsec>] [-Z <certfile>]

	This tool is a ldap client targetted to validate the reliability of
	the product under test under hard use.

	The valid options are:
	 -a  Asynchronous mode, with max pending operations.
	 -b  Give the base DN to use. Default "o=sun,c=us".
	 -D  Bind DN. See -w
	 -E  Max errors allowed.                   Default 1000.
	 -e  Execution parameters:
		add	    : ldap_add() entries.
		append      : append entries to the genldif file.
		ascii	    : ascii 7-bits strings.
		attreplace=name:mask    : replace attribute of existing entry.
		attrlist=name:name:name : specify list of attribs to retrieve
		attrsonly=0|1  : ldap_search() parameter. Set 0 to read values.
		bindeach    : ldap_bind() for each operation.
		bindonly    : only bind/unbind, no other operation is performed.
		close       : will close() the fd, rather than ldap_unbind().
		cltcertname=name : name of the SSL client certificate
		commoncounter    : all threads share the same counter.
		counteach   : count each operation not only successful ones.
		delete                : ldap_delete() entries.
		dontsleeponserverdown : will loop very fast if server down.
		emailPerson           : objectclass=emailPerson (-e add only).
		esearch	              : exact search.
		genldif=filename      : generates a ldif file
		imagesdir=path        : specify where are the images.
		incr	              : incremental values.
		inetOrgPerson         : objectclass=inetOrgPerson (-e add only).
		keydbfile=file        : filename of the key database
		keydbpin=password     : password for accessing the key database
		noglobalstats         : don't print periodical global statistics
		noloop	              : does not loop the incremental numbers.
		object=filename       : build object from input file
		person	              : objectclass=person (-e add only).
		random	              : random filters, etc...
		randomattrlist=name:name:name : random select attrib in the list
		randombase             : random base DN.
		randombaselow=value    : low value for random generator.
		randombasehigh=value   : high value for random generator.
		randombinddn           : random bind DN.
		randombinddnfromfile=fine : retrieve bind DN & passwd from file
		randombinddnlow=value  : low value for random generator.
		randombinddnhigh=value : high value for random generator.
		rdn=attrname:value     : alternate for -f.
		referral=on|off|rebind : change referral behaviour.
		scalab01               : activates scalab01 scenario.
		scalab01_cnxduration   : maximum connection duration.
		scalab01_maxcnxnb      : modem pool size.
		scalab01_wait          : sleep() between 2 attempts to connect.
		string	    : create random strings rather than random numbers.
		v2	    : ldap v2.
		withnewparent : rename with newparent specified as argument.
	 -f  Filter for searches.
	 -h  Host to connect.                      Default "localhost".
	 -i  Number of times inactivity allowed.   Default 3 (30 seconds)
	 -I  Ignore errors (cf. -E).               Default none.
	 -n  Number of threads.                    Default 10.
	 -N  Number of samples (10 seconds each).  Default infinite.
	 -p  Server port.                          Default 389.
	 -P  Master port (to check replication).   Default 16000.
	 -q  Quiet mode. See option -I.
	 -Q  Super quiet mode.
	 -r  Range's low value.
	 -R  Range's high value.
	 -s  Scope. May be base, subtree or one.   Default subtree.
	 -S  Slave to check.
	 -t  LDAP operations timeout. Default 30 seconds.
	 -T  Total number of operations per thread.	   Default infinite.
	 -v  Verbose.
	 -V  Very verbose.
	 -w  Bind passwd. See -D.
	 -W  Wait between two operations.          Default 0 seconds.
	 -Z  certfile. Turn on SSL and use certfile as the certificate DB



--- NEW FILE ldcltU.c ---
/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

#include <stdio.h>


/*
 * usage: ldclt [-qQvV] [-E <max errors>]
 *              [-b <base DN>] [-h <host>] [-p <port>] [-t <timeout>]
 *              [-D <bind DN>] [-w <passwd>]
 *              [-e <execParams>] [-a <max pending>]
 * 	     [-n <nb threads>] [-i <nb times>] [-N <nb samples>]
 * 	     [-I <err number>] [-T <total>]
 * 	     [-r <low> -R <high>]
 * 	     [-f <filter>] [-s <scope>]
 * 	     [-S <slave>] [-P<master port>]
 * 	     [-W <waitsec>] [-Z <certfile>]
 * 
 * 	This tool is a ldap client targetted to validate the reliability of
 * 	the product under test under hard use.
 * 
 * 	The valid options are:
 * 	 -a  Asynchronous mode, with max pending operations.
 * 	 -b  Give the base DN to use. Default "o=sun,c=us".
 * 	 -D  Bind DN. See -w
 * 	 -E  Max errors allowed.                   Default 1000.
 * 	 -e  Execution parameters:
 * 		add	    : ldap_add() entries.
 * 		append      : append entries to the genldif file.
 * 		ascii	    : ascii 7-bits strings.
 * 		attreplace=name:mask    : replace attribute of existing entry.
 * 		attrlist=name:name:name : specify list of attribs to retrieve
 * 		attrsonly=0|1  : ldap_search() parameter. Set 0 to read values.
 * 		bindeach    : ldap_bind() for each operation.
 * 		bindonly    : only bind/unbind, no other operation is performed.
 * 		close       : will close() the fd, rather than ldap_unbind().
 * 		cltcertname=name : name of the SSL client certificate
 * 		commoncounter    : all threads share the same counter.
 * 		counteach   : count each operation not only successful ones.
 * 		delete                : ldap_delete() entries.
 * 		dontsleeponserverdown : will loop very fast if server down.
 * 		emailPerson           : objectclass=emailPerson (-e add only).
 * 		esearch	              : exact search.
 * 		genldif=filename      : generates a ldif file
 * 		imagesdir=path        : specify where are the images.
 * 		incr	              : incremental values.
 * 		inetOrgPerson         : objectclass=inetOrgPerson (-e add only).
 * 		keydbfile=file        : filename of the key database
 * 		keydbpin=password     : password for accessing the key database
 * 		noglobalstats         : don't print periodical global statistics
 * 		noloop	              : does not loop the incremental numbers.
 * 		object=filename       : build object from input file
 * 		person	              : objectclass=person (-e add only).
 * 		random	              : random filters, etc...
 * 		randomattrlist=name:name:name : random select attrib in the list
 * 		randombase             : random base DN.
 * 		randombaselow=value    : low value for random generator.
 * 		randombasehigh=value   : high value for random generator.
 * 		randombinddn           : random bind DN.
 * 		randombinddnfromfile=fine : retrieve bind DN & passwd from file
 * 		randombinddnlow=value  : low value for random generator.
 * 		randombinddnhigh=value : high value for random generator.
 * 		rdn=attrname:value     : alternate for -f.
 * 		referral=on|off|rebind : change referral behaviour.
 * 		scalab01               : activates scalab01 scenario.
 * 		scalab01_cnxduration   : maximum connection duration.
 * 		scalab01_maxcnxnb      : modem pool size.
 * 		scalab01_wait          : sleep() between 2 attempts to connect.
 * 		smoothshutdown         : main thread waits till the worker threads exit.
 * 		string	    : create random strings rather than random numbers.
 * 		v2	    : ldap v2.
 * 		withnewparent : rename with newparent specified as argument.
 * 	 -f  Filter for searches.
 * 	 -h  Host to connect.                      Default "localhost".
 * 	 -i  Number of times inactivity allowed.   Default 3 (30 seconds)
 * 	 -I  Ignore errors (cf. -E).               Default none.
 * 	 -n  Number of threads.                    Default 10.
 * 	 -N  Number of samples (10 seconds each).  Default infinite.
 * 	 -p  Server port.                          Default 389.
 * 	 -P  Master port (to check replication).   Default 16000.
 * 	 -q  Quiet mode. See option -I.
 * 	 -Q  Super quiet mode.
 * 	 -r  Range's low value.
 * 	 -R  Range's high value.
 * 	 -s  Scope. May be base, subtree or one.   Default subtree.
 * 	 -S  Slave to check.
 * 	 -t  LDAP operations timeout. Default 30 seconds.
 * 	 -T  Total number of operations per thread.	   Default infinite.
 * 	 -v  Verbose.
 * 	 -V  Very verbose.
 * 	 -w  Bind passwd. See -D.
 * 	 -W  Wait between two operations.          Default 0 seconds.
 * 	 -Z  certfile. Turn on SSL and use certfile as the certificate DB
 */
void usage ()
{
  (void) printf ("\n");
  (void) printf ("usage: ldclt [-qQvV] [-E <max errors>]\n");
  (void) printf ("             [-b <base DN>] [-h <host>] [-p <port>] [-t <timeout>]\n");
  (void) printf ("             [-D <bind DN>] [-w <passwd>]\n");
  (void) printf ("             [-e <execParams>] [-a <max pending>]\n");
  (void) printf ("	     [-n <nb threads>] [-i <nb times>] [-N <nb samples>]\n");
  (void) printf ("	     [-I <err number>] [-T <total>]\n");
  (void) printf ("	     [-r <low> -R <high>]\n");
  (void) printf ("	     [-f <filter>] [-s <scope>]\n");
  (void) printf ("	     [-S <slave>] [-P<master port>]\n");
  (void) printf ("	     [-W <waitsec>] [-Z <certfile>]\n");
  (void) printf ("\n");
  (void) printf ("	This tool is a ldap client targetted to validate the reliability of\n");
  (void) printf ("	the product under test under hard use.\n");
  (void) printf ("\n");
  (void) printf ("	The valid options are:\n");
  (void) printf ("	 -a  Asynchronous mode, with max pending operations.\n");
  (void) printf ("	 -b  Give the base DN to use. Default \"o=sun,c=us\".\n");
  (void) printf ("	 -D  Bind DN. See -w\n");
  (void) printf ("	 -E  Max errors allowed.                   Default 1000.\n");
  (void) printf ("	 -e  Execution parameters:\n");
  (void) printf ("		add	    : ldap_add() entries.\n");
  (void) printf ("		append      : append entries to the genldif file.\n");
  (void) printf ("		ascii	    : ascii 7-bits strings.\n");
  (void) printf ("		attreplace=name:mask    : replace attribute of existing entry.\n");
  (void) printf ("		attrlist=name:name:name : specify list of attribs to retrieve\n");
  (void) printf ("		attrsonly=0|1  : ldap_search() parameter. Set 0 to read values.\n");
  (void) printf ("		bindeach    : ldap_bind() for each operation.\n");
  (void) printf ("		bindonly    : only bind/unbind, no other operation is performed.\n");
  (void) printf ("		close       : will close() the fd, rather than ldap_unbind().\n");
  (void) printf ("		cltcertname=name : name of the SSL client certificate\n");
  (void) printf ("		commoncounter    : all threads share the same counter.\n");
  (void) printf ("		counteach   : count each operation not only successful ones.\n");
  (void) printf ("		delete                : ldap_delete() entries.\n");
  (void) printf ("		dontsleeponserverdown : will loop very fast if server down.\n");
  (void) printf ("		emailPerson           : objectclass=emailPerson (-e add only).\n");
  (void) printf ("		esearch	              : exact search.\n");
  (void) printf ("		genldif=filename      : generates a ldif file\n");
  (void) printf ("		imagesdir=path        : specify where are the images.\n");
  (void) printf ("		incr	              : incremental values.\n");
  (void) printf ("		inetOrgPerson         : objectclass=inetOrgPerson (-e add only).\n");
  (void) printf ("		keydbfile=file        : filename of the key database\n");
  (void) printf ("		keydbpin=password     : password for accessing the key database\n");
  (void) printf ("		noglobalstats         : don't print periodical global statistics\n");
  (void) printf ("		noloop	              : does not loop the incremental numbers.\n");
  (void) printf ("		object=filename       : build object from input file\n");
  (void) printf ("		person	              : objectclass=person (-e add only).\n");
  (void) printf ("		random	              : random filters, etc...\n");
  (void) printf ("		randomattrlist=name:name:name : random select attrib in the list\n");
  (void) printf ("		randombase             : random base DN.\n");
  (void) printf ("		randombaselow=value    : low value for random generator.\n");
  (void) printf ("		randombasehigh=value   : high value for random generator.\n");
  (void) printf ("		randombinddn           : random bind DN.\n");
  (void) printf ("		randombinddnfromfile=fine : retrieve bind DN & passwd from file\n");
  (void) printf ("		randombinddnlow=value  : low value for random generator.\n");
  (void) printf ("		randombinddnhigh=value : high value for random generator.\n");
  (void) printf ("		rdn=attrname:value     : alternate for -f.\n");
  (void) printf ("		referral=on|off|rebind : change referral behaviour.\n");
  (void) printf ("		scalab01               : activates scalab01 scenario.\n");
  (void) printf ("		scalab01_cnxduration   : maximum connection duration.\n");
  (void) printf ("		scalab01_maxcnxnb      : modem pool size.\n");
  (void) printf ("		scalab01_wait          : sleep() between 2 attempts to connect.\n");
  (void) printf ("		smoothshutdown         : main thread waits till the worker threads exit.\n");
  (void) printf ("		string	    : create random strings rather than random numbers.\n");
  (void) printf ("		v2	    : ldap v2.\n");
  (void) printf ("		withnewparent : rename with newparent specified as argument.\n");
  (void) printf ("	 -f  Filter for searches.\n");
  (void) printf ("	 -h  Host to connect.                      Default \"localhost\".\n");
  (void) printf ("	 -i  Number of times inactivity allowed.   Default 3 (30 seconds)\n");
  (void) printf ("	 -I  Ignore errors (cf. -E).               Default none.\n");
  (void) printf ("	 -n  Number of threads.                    Default 10.\n");
  (void) printf ("	 -N  Number of samples (10 seconds each).  Default infinite.\n");
  (void) printf ("	 -p  Server port.                          Default 389.\n");
  (void) printf ("	 -P  Master port (to check replication).   Default 16000.\n");
  (void) printf ("	 -q  Quiet mode. See option -I.\n");
  (void) printf ("	 -Q  Super quiet mode.\n");
  (void) printf ("	 -r  Range's low value.\n");
  (void) printf ("	 -R  Range's high value.\n");
  (void) printf ("	 -s  Scope. May be base, subtree or one.   Default subtree.\n");
  (void) printf ("	 -S  Slave to check.\n");
  (void) printf ("	 -t  LDAP operations timeout. Default 30 seconds.\n");
  (void) printf ("	 -T  Total number of operations per thread.	   Default infinite.\n");
  (void) printf ("	 -v  Verbose.\n");
  (void) printf ("	 -V  Very verbose.\n");
  (void) printf ("	 -w  Bind passwd. See -D.\n");
  (void) printf ("	 -W  Wait between two operations.          Default 0 seconds.\n");
  (void) printf ("	 -Z  certfile. Turn on SSL and use certfile as the certificate DB\n");
  (void) printf ("\n");
} /* usage() */



/* End of file */


--- NEW FILE opCheck.c ---
/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		opCheck.c
	AUTHOR :        Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		04 May 1999
	DESCRIPTION :
			This file contains the functions used to manage and
			check the operations performed by the tool.
			These functions manages the operation list
			"mctx.opListTail", match an entry retrieved from the
			server to the attributes memorized for one operation,
			etc...
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
05/05/99 | F. Pistolesi	| 1.8 : Add communication with remote host.
			| Implement operations check.
---------+--------------+------------------------------------------------------
06/05/99 | JL Schwing	| 1.10: Implements opDecOper().
			| Add more traces in VERY_VERBOSE
---------+--------------+------------------------------------------------------
20/05/99 | JL Schwing	| 1.18: Add params (newRdn and newParent) to opAdd()
			| Decode operations in Cnnn messages.
			| No more exit on EINTR in accept()
			| Fix memory leak in thOperFree()
---------+--------------+------------------------------------------------------
21/05/99 | JL Schwing	| 1.19: Minor fixes in messages.
			| Purify cleanup - Free memory read in opCheckLoop()
			| Fix thOperFree() - pb when head of list to delete
			| Fix memory leak in opNext().
---------+--------------+------------------------------------------------------
26/05/99 | JL Schwing	| 1.21: Bug fix - return(-1) bad place in opNext().
			| Minor fixes in messages.
---------+--------------+------------------------------------------------------
27/05/99 | JL Schwing	| 1.22 : Add statistics to check threads.
---------+--------------+------------------------------------------------------
27/05/99 | F. Pistolesi	| 1.23 : Fix statistics and other algorythms.
---------+--------------+------------------------------------------------------
31/05/99 | JL Schwing	| 1.25 : Bug fix - should test opRead() returned pointer
---------+--------------+------------------------------------------------------
02/06/99 | JL Schwing	| 1.26 : Add flag in main ctx to know if slave was 
			|   connected or not.
			| Add counter of operations received in check threads.
---------+--------------+------------------------------------------------------
06/03/00 | JL Schwing	| 1.27: Test malloc() return value.
---------+--------------+------------------------------------------------------
18/08/00 | JL Schwing	| 1.28: Print begin and end dates.
---------+--------------+------------------------------------------------------
17/11/00 | JL Schwing	| 1.29: Implement "-e smoothshutdown".
---------+--------------+------------------------------------------------------
29/11/00 | JL Schwing	| 1.30: Port on NT 4.
---------+--------------+------------------------------------------------------
*/

#include <pthread.h>		/* Posix threads */
#include <errno.h>		/* errno, etc... */
#include <stdlib.h>		/* exit(), etc... */
#include <unistd.h> 		/* sleep(), etc... */
#include <stdio.h>		/* printf(), etc... */
#include <signal.h>		/* sigset(), etc... */
#include <string.h>		/* strerror(), etc... */
#include <sys/resource.h>	/* setrlimit(), etc... */
#include <lber.h>		/* ldap C-API BER decl. */
#include <ldap.h>		/* ldap C-API decl. */
#include <sys/poll.h>		/* djani : while porting */
#include <sys/socket.h>		/* djani : while porting */
#include <sys/types.h> 		/* djani : while porting */
#include <netdb.h>		/* djani : while porting */
#include <netinet/in.h> 	/* djani : while porting */
#ifdef LDAP_H_FROM_QA_WKA
#include <proto-ldap.h>		/* ldap C-API prototypes */
#endif
#include "port.h"		/* Portability definitions */	/*JLS 29-11-00*/
#include "ldclt.h"		/* This tool's include file */
#include "remote.h"		/* Definitions common with the slave */

enum {SINGLE=0,FIRST,MIDDLE,LAST};






/* ****************************************************************************
	FUNCTION :	opDecOper
	PURPOSE :	This function decodes an LDAP operation and return a
			printable string.
	INPUT :		op	= operation to decode
	OUTPUT :	None.
	RETURN :	The decoded string.
	DESCRIPTION :
 *****************************************************************************/
char *
opDecOper (
	int	 op)
{
  switch (op)
  {
    case LDAP_REQ_MODIFY:	return ("modify");	break;
    case LDAP_REQ_ADD:		return ("add");		break;
    case LDAP_REQ_DELETE:	return ("delete");	break;
    case LDAP_REQ_MODRDN:	return ("modrdn");	break;
    default:			return ("??unknown??");	break;
  }
}







/* ****************************************************************************
	FUNCTION :	LDAPMod2attributes
	PURPOSE :	Convert a LDAPMod-like array of attributes to the
			internal attributes array.
	INPUT :		mods	= LDAPMod array. If NULL, attribs[] is
				  initiated as an empty array.
	OUTPUT :	attribs	= struct attribute array. This array is of
				  MAX_ATTRIBS length.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
LDAPMod2attributes (
	LDAPMod		**mods,
	attribute	 *attribs)
{
  int	 i;	/* For the loop */

  /*
   * Maybe there is no mods ?? This occurs for rename operation, for example.
   */
  if (mods == NULL)
  {
    attribs[0].type = NULL;
    return (0);
  }

  /*
   * Process each entry
   */
  for (i=0 ; i< MAX_ATTRIBS && mods[i] != NULL ; i++)
  {
    attribs[i].type = strdup (mods[i]->mod_type);
    if (attribs[i].type == NULL)				/*JLS 06-03-00*/
    {								/*JLS 06-03-00*/
      printf ("Error: cannot strdup(attribs[%d].type), error=%d (%s)\n",
		i, errno, strerror (errno));			/*JLS 06-03-00*/
      return (-1);						/*JLS 06-03-00*/
    }								/*JLS 06-03-00*/

    /*
     * Well, if it is a binary value, it is most likely an image
     * that is read by mmap and always available. Thus there is no reason
     * to copy it, just modify the pointers.
     */
    if (mods[i]->mod_op & LDAP_MOD_BVALUES)
    {
      attribs[i].dontFree = 1;
      attribs[i].length   = mods[i]->mod_bvalues[0]->bv_len;
      attribs[i].value    = mods[i]->mod_bvalues[0]->bv_val;
    }
    else
    {
      attribs[i].dontFree = 0;
      attribs[i].length   = strlen (mods[i]->mod_values[0]);
      attribs[i].value    = strdup (mods[i]->mod_values[0]);
      if (attribs[i].value == NULL)				/*JLS 06-03-00*/
      {								/*JLS 06-03-00*/
        printf ("Error: cannot strdup(attribs[%d].value), error=%d (%s)\n",
		i, errno, strerror (errno));			/*JLS 06-03-00*/
        return (-1);						/*JLS 06-03-00*/
      }								/*JLS 06-03-00*/
    }
  }

  /*
   * Don't forget to mark the end !
   */
  if (i<MAX_ATTRIBS)
    attribs[i].type = NULL;
  return (0);
}









/* ****************************************************************************
	FUNCTION :	freeAttributesArray
	PURPOSE :	This function is targetted to free an array of
			struct attribute. It does not free the array itself,
			but only the types and values memorized in it.
	INPUT :		attribs	= array to free.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
freeAttributesArray (
	attribute	*attribs)
{
  int	 i;	/* For the loop */

  for (i=0;i<MAX_ATTRIBS&&attribs[i].type != NULL;i++)
  {
    free (attribs[i].type);
    if (!(attribs[i].dontFree))
      free (attribs[i].value);
  }
  return (0);
}









/* ****************************************************************************
	FUNCTION :	opAdd
	PURPOSE :	Add a new operation to the list.
	INPUT :		tttctx	  = thread context
			type	  = operation type
			dn	  = target's DN
			attribs	  = operation attributes
			newRdn	  = new rdn    (valid for rename only)
			newParent = new parent (valid for rename only)
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :	Note that the attributes given in argument are
			directly memorized (i.e. no copy), hence they should
			*not* be freed by the calling function.
 *****************************************************************************/
int
opAdd (
	thread_context	 *tttctx,
	int		  type,
	char		 *dn,
	LDAPMod		**attribs,
	char		 *newRdn,
	char		 *newParent)
{
  int	 ret;		/* Return value */
  oper	*newOper;	/* New operation to memorize */

  if (mctx.mode & VERY_VERBOSE)
    printf ("T%03d: opAdd (%s, %s)\n", tttctx->thrdNum, opDecOper(type), dn);


  /*
   * Go to protected section. This will enforce the correct sequencing
   * of the operations performed because the whole function is lock
   * for the threads.
   * Note: Maybe reduce the size of this section ? To be checked.
   */
  if ((ret = pthread_mutex_lock (&(mctx.opListTail_mutex))) != 0)
  {
    fprintf (stderr,
	"T%03d: cannot pthread_mutex_lock(opListTail), error=%d (%s)\n",
	tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Create the new cell
   */
  newOper            = (oper *) malloc (sizeof (oper));
  if (newOper == NULL)						/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf ("T%03d: cannot malloc(newOper), error=%d (%s)\n",	/*JLS 06-03-00*/
		tttctx->thrdNum, errno, strerror (errno));	/*JLS 06-03-00*/
    return (-1);						/*JLS 06-03-00*/
  }								/*JLS 06-03-00*/
  newOper->next      = NULL;
  newOper->type      = type;
  newOper->skipped   = mctx.slavesNb;
  newOper->dn        = strdup (dn);
  if (newOper->dn == NULL)					/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf("T%03d: cannot strdup(newOper->dn), error=%d (%s)\n",/*JLS 06-03-00*/
		tttctx->thrdNum, errno, strerror (errno));	/*JLS 06-03-00*/
    return (-1);						/*JLS 06-03-00*/
  }								/*JLS 06-03-00*/
  newOper->newRdn    = (newRdn    == NULL ? NULL : strdup (newRdn));
  if (newOper->newRdn == NULL)					/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf ("T%03d: cannot strdup(newOper->newRdn), error=%d (%s)\n",
		tttctx->thrdNum, errno, strerror (errno));	/*JLS 06-03-00*/
    return (-1);						/*JLS 06-03-00*/
  }								/*JLS 06-03-00*/
  newOper->newParent = (newParent == NULL ? NULL : strdup (newParent));
  if (newOper->newParent == NULL)				/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf ("T%03d: cannot strdup(newOper->newParent), error=%d (%s)\n",
		tttctx->thrdNum, errno, strerror (errno));	/*JLS 06-03-00*/
    return (-1);						/*JLS 06-03-00*/
  }								/*JLS 06-03-00*/
  if (LDAPMod2attributes (attribs, newOper->attribs) < 0)
    return (-1);

  /*
   * Don't forget to initiate this cell's mutex !
   */
  if ((ret = pthread_mutex_init(&(newOper->skipped_mutex), NULL)) != 0)
  {
    fprintf (stderr,
	"T%03d: cannot initiate skipped_mutex error=%d (%s)\n",
	tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Link the cell
   */
  mctx.opListTail->next = newOper;
  mctx.opListTail       = newOper;

  /*
   * Release the mutex
   */
  if ((ret = pthread_mutex_unlock (&(mctx.opListTail_mutex))) != 0)
  {
    fprintf (stderr,
	"T%03d: cannot pthread_mutex_unlock(opListTail), error=%d (%s)\n",
	tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  return (0);
}







/* ****************************************************************************
	FUNCTION :	opNext
	PURPOSE :	Return the next available operation. May return NULL
			if no operation available.
	INPUT :		ctctx	= thread context
	OUTPUT :	op	= next operation. May be NULL.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
opNext (
	check_context	 *ctctx,
	oper		**op)
{
  int	 ret;		/* Return value */
  oper	*newHead;	/* The new head operation */

  /*
   * Maybe there is no new operation ?
   */
  if (ctctx->headListOp->next == NULL)
  {
    *op = NULL;
    if (mctx.mode & VERY_VERBOSE)
      printf ("C%03d: opNext --> NULL\n", ctctx->thrdNum);
    return (0);
  }

  /*
   * Ok, there is one new operation. Let's skip the head and
   * go to the new operation...
   */
  if ((ret = pthread_mutex_lock (&(ctctx->headListOp->skipped_mutex))) != 0)
  {
    fprintf (stderr,
	"C%03d: cannot pthread_mutex_lock(skipped_mutex), error=%d (%s)\n",
	ctctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }
  newHead = ctctx->headListOp->next;
  ctctx->headListOp->skipped--;

  /*
   * If there is another thread that has not skipped, let's move to the
   * next operation and unlock the counter.
   */
  if (ctctx->headListOp->skipped != 0)
  {
    if ((ret = pthread_mutex_unlock (&(ctctx->headListOp->skipped_mutex))) != 0)
    {
      fprintf (stderr,
	"C%03d: cannot pthread_mutex_unlock(skipped_mutex), error=%d (%s)\n",
	ctctx->thrdNum, ret, strerror (ret));
      fflush (stderr);
      return (-1);
    }
  }
  else
  {
    /*
     * Well, looks like we are the last thread to skip.... Let's free this
     * operation. BTW, there is no reason to unlock/release the mutex because
     * it will be destroyed !
     * Note: may be NULL when LDAP_REQ_DELETE for example.
     */
    if (ctctx->headListOp->attribs != NULL)
      if (freeAttributesArray (ctctx->headListOp->attribs) < 0)
	return (-1);
    if (ctctx->headListOp->dn != NULL)
      free (ctctx->headListOp->dn);
    if (ctctx->headListOp->newRdn != NULL)
      free (ctctx->headListOp->newRdn);
    if (ctctx->headListOp->newParent != NULL)
      free (ctctx->headListOp->newParent);
    free (ctctx->headListOp);
  }

  /*
   * End of function
   */
  *op = ctctx->headListOp = newHead;
  if (mctx.mode & VERY_VERBOSE)
    printf ("C%03d: opNext --> (%s, %s)\n",
		ctctx->thrdNum, opDecOper ((*op)->type), (*op)->dn);
  return (0);
}









/* ****************************************************************************
	FUNCTION :	opRead
	PURPOSE :	Read the n'th operation from the head.
	INPUT :		ctctx	= thread context
			num	= number of the operation to retrieve
	OUTPUT :	op	= returned operation. May be NULL.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
opRead (
	check_context	 *ctctx,
	int		  num,
	oper		**op)
{
  *op = ctctx->headListOp;
  while (num != 0)
  {
    /*
     * Maybe not enough entries in the list ?
     */
    if (*op == NULL)
      return (0);
    *op = (*op)->next;
    num--;
  }

  /*
   * If there, we got it :-)
   */
  return (0);
}






/* ****************************************************************************
	FUNCTION :	thOperAdd
	PURPOSE :	This function copies an operation to the late
			operation list
	INPUT :		head list and operation to copy
	OUTPUT :	None.
	RETURN :	New head
	DESCRIPTION :
 *****************************************************************************/
thoper *
thOperAdd ( thoper *head, oper *elem, int f)
{
  thoper *new,*t=head;
  int i;

  new=malloc(sizeof(thoper));
  if (new == NULL)						/*JLS 06-03-00*/
  {								/*JLS 06-03-00*/
    printf ("Txxx: cannot malloc(new), error=%d (%s)\n",	/*JLS 06-03-00*/
		errno, strerror (errno));			/*JLS 06-03-00*/
    ldcltExit (1);						/*JLS 18-08-00*/
  }								/*JLS 06-03-00*/
  new->next=NULL;
  new->first=f;
  new->type=elem->type;
  new->dn=strdup(elem->dn);
  if (elem->newRdn != NULL)
    new->newRdn=strdup(elem->newRdn);
  if (elem->newParent != NULL)
    new->newParent=strdup(elem->newParent);
  for(i=0;i<MAX_ATTRIBS&&elem->attribs[i].type;i++)
  {
    new->attribs[i].type=strdup(elem->attribs[i].type);
    if (new->attribs[i].type == NULL)				/*JLS 06-03-00*/
    {								/*JLS 06-03-00*/
      printf ("Txxx: cannot strdup(new->attribs[%d].type), error=%d (%s)\n",
		errno, i, strerror (errno));			/*JLS 06-03-00*/
      ldcltExit (1);						/*JLS 18-08-00*/
    }								/*JLS 06-03-00*/
    new->attribs[i].length   = elem->attribs[i].length;
    if((new->attribs[i].dontFree=elem->attribs[i].dontFree))
      new->attribs[i].value = elem->attribs[i].value;
    else
    {
      new->attribs[i].value = strdup(elem->attribs[i].value);
      if (new->attribs[i].value == NULL)			/*JLS 06-03-00*/
      {								/*JLS 06-03-00*/
        printf ("Txxx: cannot strdup(new->attribs[%d].value), error=%d (%s)\n",
		errno, i, strerror (errno));			/*JLS 06-03-00*/
        ldcltExit (1);						/*JLS 18-08-00*/
      }								/*JLS 06-03-00*/
    }
  }
  if(i<MAX_ATTRIBS)
    new->attribs[i].type=NULL;
  if(head==NULL)
    return new;
  for(t=head;t->next;)
    t=t->next;
  t->next=new;
  return head;
}






/* ****************************************************************************
	FUNCTION :	thOperFree
	PURPOSE :	This function frees memory for a late operation
	INPUT :		Head of list and operation to delete
	OUTPUT :	None.
	RETURN :	new head
	DESCRIPTION :
 *****************************************************************************/
thoper *
thOperFree (thoper *head, thoper *elem)
{
  thoper *t;

  freeAttributesArray(elem->attribs);
  free (elem->dn);
  if (elem->newRdn != NULL)
    free (elem->newRdn);
  if (elem->newParent != NULL)
    free (elem->newParent);
  if(head!=elem)
  {
	for(t=head;t->next!=elem;)
		t=t->next;
	t->next=t->next->next;
  }
  else
    head = head->next;
  free(elem);
  return head;
}






/* ****************************************************************************
	FUNCTION :	opCheckLoop
	PURPOSE :	This function is the per slave check function
	INPUT :		arg	= this check thread's check_context
	OUTPUT :	None.
	RETURN :	None.
	DESCRIPTION :
 *****************************************************************************/
void *
opCheckLoop ( void* arg)
{
  struct check_context *cctx=(struct check_context *)arg;
  struct pollfd pfd;
  repconfirm *recOper;
  oper *myop;
  thoper *t;
  unsigned char recbuf[1500];
  int ret,i,timeout;
  int		 cnt;		/* To count loops for timeout purpose */
  int		 fndlt;		/* Found late operation */
  int		 nbRead;	/* Nb char read() */
  int		 status;	/* Thread status */		/*JLS 17-11-00*/

  recOper=(repconfirm*)recbuf;
  pfd.fd=cctx->sockfd;
  pfd.events=(POLLIN|POLLPRI);
  pfd.revents=0;
  cctx->status=INITIATED;
  if((timeout=mctx.timeout)<30)
	timeout=30;
  /*
   * First time in here?
   */
  if(cctx->calls==1)
	cctx->dcOper=NULL;

  while((ret=poll(&pfd,1,500))>=0)
  {
	if(ret)
	{
		/*
		 * Exit if read error on the net
		 */
		if ((nbRead = read (pfd.fd,recOper,sizeof(repconfirm)))<0)
			break;
		if (nbRead != sizeof(repconfirm))
			printf ("C%03d(%s): Partial header read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, sizeof(repconfirm));
		recOper->type=ntohl(recOper->type);
		recOper->res=ntohl(recOper->res);
		recOper->dnSize=ntohl(recOper->dnSize);
		/*
		 * Beware of structure alignment
		 */
		if((nbRead=read(pfd.fd,recOper->dn+sizeof(recOper->dn),recOper->dnSize))<0)
			break;
		if (nbRead != recOper->dnSize)
			printf ("C%03d(%s): Partial dn read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, recOper->dnSize);
		if (nbRead > (1500 - sizeof(repconfirm)))
			printf ("C%03d(%s): Read too much %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, 1500 - sizeof(repconfirm));
		cnt=0;
		cctx->nbOpRecv++;
		if(mctx.mode&VERY_VERBOSE)
		{
			printf("C%03d(%s): Rec %s\n",cctx->thrdNum,cctx->slaveName,recOper->dn);
			for(myop=cctx->headListOp->next;myop;myop=myop->next)
				printf("C%03d(%s): IN : %s\n",cctx->thrdNum,cctx->slaveName,myop->dn);
			for(t=cctx->dcOper;t;t=t->next)
				printf("C%03d(%s): LATE : %s\n",cctx->thrdNum,cctx->slaveName,t->dn);
		}
		/*
		 * Do not tell me there was an error during replica...
		 */
		if(recOper->res)
		{
			printf("C%03d(%s): Replica failed, op:%d(%s), dn=\"%s\" res=%d\n",
                 cctx->thrdNum, cctx->slaveName,
                 recOper->type, opDecOper(recOper->type),
                 recOper->dn, recOper->res );
			switch (recOper->res)
			{
				case 32:	cctx->nbRepFail32++	; break;
				case 68:	cctx->nbRepFail68++	; break;
				default:	cctx->nbRepFailX++	; break;
			}
		}
		/*
		 * Is this a late operation?
		 */
		fndlt=0;
		if(cctx->dcOper)
		{
			for (i=1,t = cctx->dcOper;t;i++)
				if ((recOper->type!=t->type) || strcmp(recOper->dn,t->dn))
					t = t->next;
				else
				{
					/*
					 * if this is a single operation: 132456
					 */
					if(t->first==SINGLE)
					{
						/*
						 * error.
						 */
						printf("C%03d(%s): Late replica:   op:%d(%s), dn=\"%s\"\n",
                               cctx->thrdNum, cctx->slaveName,
                               t->type, opDecOper(t->type), t->dn );
						cctx->nbLate++;
					} else if (t->first==MIDDLE)
					{
						/*
						 * Middle of a series : 23546
						 */
						printf("C%03d(%s): Early (%3d)     op:%d(%s), dn=\"%s\"\n",
                               cctx->thrdNum, cctx->slaveName,i,
                               t->type, opDecOper(t->type), t->dn );
						cctx->nbEarly++;
						
					} else if(t->next)
					{
						/*
						 * else maybe we are in a re-corrected situation.
						 * we should receive the next one, now.
						 */
							if(t->next->first!=LAST)
								t->next->first=FIRST;
					}
					cctx->dcOper = thOperFree (cctx->dcOper, t);
					fndlt=1;
					break;
				}
		}
		if(!fndlt)
		{
			/*
			 * See if the operation we received is the same as the head
			 */
			opRead(cctx,1,&myop);
			if (myop != NULL &&
				recOper->type==myop->type &&
				strcmp(recOper->dn,myop->dn) == 0)
			    opNext(cctx,&myop);
			else
			{
				/*
				 * Nope, look for it
				 */
				for(i=2;opRead(cctx,i,&myop)==0;i++)
					if(myop)
					{
						if(recOper->type==myop->type &&
							strcmp(recOper->dn,myop->dn) == 0)
						{
							/*
							 * Skip all between current head and this one
							 */
							printf("C%03d(%s): Early (%3d)     op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, i-1, recOper->type, opDecOper(recOper->type), recOper->dn );
							cctx->nbEarly++;
							opNext(cctx,&myop);
							/*
							 * mark the first of the series as leader
							 */
							cctx->dcOper=thOperAdd(cctx->dcOper,myop,
								i==2?SINGLE:FIRST);
							for(;i>2;i--)
							{
								opNext(cctx,&myop);
								/*
								 * copy up until one before last
								 */
								if(myop)
									thOperAdd(cctx->dcOper,myop,
										i==3?LAST:MIDDLE);
							}
							opNext(cctx,&myop);
							break;
						}
					} else break;
				if(!myop)
				{
					printf("C%03d(%s): Not on list     op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, recOper->type, opDecOper(recOper->type), recOper->dn );
					cctx->nbNotOnList++;
				}
			}
		}
	}
	pfd.events=(POLLIN|POLLPRI);
	pfd.revents=0;
	/*
	 * operations threads still running?
	 */
	for(i=0;i<mctx.nbThreads;i++)
	{							/*JLS 17-11-00*/
	  if (getThreadStatus (&(tctx[i]), &status) < 0)	/*JLS 17-11-00*/
	    break;						/*JLS 17-11-00*/
	  if(status != DEAD)					/*JLS 17-11-00*/
	  {
	    cnt=0;
	    break;
	  }
	}							/*JLS 17-11-00*/
	/*
	 * twice half a second...
	 */
	if(++cnt>timeout*2)
			break;
  }
  if(mctx.mode&VERY_VERBOSE)
	printf("C%03d(%s): Exiting\n",cctx->thrdNum,cctx->slaveName);
  /*
   * Any operation left?
   */
  for(opNext(cctx,&myop);myop;opNext(cctx,&myop))
  {
	printf("Operation %d(%s) still on Queue for %s (%s)\n",myop->type,opDecOper(myop->type),cctx->slaveName,myop->dn);
	cctx->nbStillOnQ++;
  }
  for(t=cctx->dcOper;t;t=t->next)
  {
	printf("Lost op %d(%s) on %s (%s)\n",t->type,opDecOper(t->type),cctx->slaveName,t->dn);
	cctx->nbLostOp++;
  }
  close(cctx->sockfd);
  cctx->status=DEAD;
  pthread_exit(NULL);
}






/* ****************************************************************************
	FUNCTION :	opCheckMain
	PURPOSE :	This function is the main function of the check
			operation threads,
	INPUT :		arg	= NULL
	OUTPUT :	None.
	RETURN :	None.
	DESCRIPTION :
 *****************************************************************************/
void *
opCheckMain (
	void	*arg)
{
  struct sockaddr_in srvsaddr,claddr;
  struct hostent cltaddr; 
#ifdef LINUX
  struct hostent *stupidlinux=NULL;
#endif
#ifdef AIX
  struct hostent_data stupidaix;
#endif
  struct linger lopt;
  uint32_t ipaddr;
  int newfd,sockfd,ncctx,i,err;
  char buffer[128];
  int	 retry;			/* To retry on EINTR */

  /*
   * Initialization
   */

  srvsaddr.sin_addr.s_addr=htonl(INADDR_ANY);
  srvsaddr.sin_family=AF_INET;
  srvsaddr.sin_port=htons(masterPort);

  /*
   * Let's go !!!
   */

  if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  {
	perror("Socket");
	ldcltExit(1);						/*JLS 18-08-00*/
  }
  i=1;
  if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&i,sizeof(int))!=0)
	perror("Sockopt");
  if(bind(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=0)
  {
	perror("Bind");
	ldcltExit(1);						/*JLS 18-08-00*/
  }
  if(listen(sockfd,1)!=0)
	perror("listen");
  for(ncctx=0;;)
  {
	i=sizeof(claddr);
	retry = 1;
	while (retry)
	{
#ifdef AIX
		if ((newfd=accept(sockfd,(struct sockaddr *)&claddr,(unsigned long *)&i))>=0)
#else
		if ((newfd=accept(sockfd,(struct sockaddr *)&claddr,&i))>=0)
#endif
			retry = 0;
		else
			if (errno != EINTR)
			{
				perror("Accept");
				ldcltExit(1);			/*JLS 18-08-00*/
			}
	}
	/*
	 * get client's name
	 */
	ipaddr=ntohl(claddr.sin_addr.s_addr);

#ifdef AIX
	gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
		&stupidaix);
#else
#ifdef LINUX
	 gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
		buffer,128, &stupidlinux, &err); 
#else
#if defined(HPUX) && defined(__LP64__)
	 gethostbyaddr((char*)&ipaddr,sizeof(ipaddr),AF_INET);
#else
	 gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
		buffer,128,&err); 
#endif
#endif
#endif

	i=1;
	if(setsockopt(newfd,IPPROTO_TCP, TCP_NODELAY,(void *)&i,sizeof(int))!=0)
		perror("Nagle");
	/*
	 * Linger: when connection ends, send an RST instead of a FIN
	 * This way the client will have a fail on the first write instead of
	 * the second
	 */
	lopt.l_onoff=1;
	lopt.l_linger=0;
	if(setsockopt(newfd,SOL_SOCKET,SO_LINGER,(void*)&lopt,sizeof(struct linger))<0)
		perror("Linger");
	/*
	 * Search for an empty client slot. If a client reconnects, use the
	 * same slot
	 */
	for(i=0;i<mctx.slavesNb;i++)
	{
		if(cctx[i].calls==0)
		{
			i=ncctx++;
			break;
		}
		if(cctx[i].slaveName&&cctx[i].status==DEAD)
			if(strcmp(cctx[i].slaveName,cltaddr.h_name)==0)
				break;
	}
	if(i>=mctx.slavesNb)
	{
		fprintf (stderr, "ldclt: Too many slaves %s\n",cltaddr.h_name);
		close(newfd);
		continue;
	}

	cctx[i].sockfd=newfd;
	cctx[i].calls++;
	cctx[i].slaveName=strdup(cltaddr.h_name);
	if ((err = pthread_create (&(cctx[i].tid), NULL,
		opCheckLoop, (void *)&(cctx[i]))) != 0)
	{
		fprintf (stderr, "ldclt: %s\n", strerror (err));
		fprintf (stderr, "Error: cannot create thread opCheck for %s\n",
				cltaddr.h_name);
		fflush (stderr);
	}
    else
      mctx.slaveConn = 1;
  } 
  close(sockfd);
}






/* End of file */


--- NEW FILE parser.c ---
#ident "@(#)parser.c	1.5 01/04/11"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		parser.c
	AUTHOR :        Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		19 March 2001
	DESCRIPTION :	
			This file contains the parser functions of ldclt
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
19/03/01 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
21/03/01 | JL Schwing	| 1.2 : Implements variables in "-e object=filename"
---------+--------------+------------------------------------------------------
23/03/01 | JL Schwing	| 1.3 : Implements data file list support in variants.
			| Bug fix : close the file !
			| Implements "-e rdn=value".
---------+--------------+------------------------------------------------------
28/03/01 | JL Schwing	| 1.4 : Support -e commoncounter with -e rdn/object
---------+--------------+------------------------------------------------------
11/04/01 | JL Schwing	| 1.5 : Implement [INCRFROMFILE<NOLOOP>(myfile)]
			| Improved error message.
---------+--------------+------------------------------------------------------
*/


#include <stdio.h>	/* printf(), etc... */
#include <string.h>	/* strcpy(), etc... */
#include <errno.h>	/* errno, etc... */
#include <stdlib.h>	/* malloc(), etc... */
#include <lber.h>	/* ldap C-API BER declarations */
#include <ldap.h>	/* ldap C-API declarations */
#ifdef LDAP_H_FROM_QA_WKA
#include <proto-ldap.h>	/* ldap C-API prototypes */
#endif
#ifndef _WIN32
#include <unistd.h>	/* close(), etc... */
#include <pthread.h>	/* pthreads(), etc... */
#endif

#include "port.h"	/* Portability definitions */
#include "ldclt.h"	/* This tool's include file */
#include "utils.h"	/* Utilities functions */














/* ****************************************************************************
	FUNCTION :	decodeHow
	PURPOSE :	Decode the how field
	INPUT :		how	= field to decode
	OUTPUT :	None.
	RETURN :	-1 if error, how value else.
	DESCRIPTION :
 *****************************************************************************/
int
decodeHow (
	char	*how)
{
  if (mctx.mode & VERY_VERBOSE)
    printf ("decodeHow: how=\"%s\"\n", how);

  if (!strcmp (how, "INCRFROMFILE"))		return (HOW_INCR_FROM_FILE);
  if (!strcmp (how, "INCRFROMFILENOLOOP"))	return (HOW_INCR_FROM_FILE_NL);
  if (!strcmp (how, "INCRN"))			return (HOW_INCR_NB);
  if (!strcmp (how, "INCRNNOLOOP"))		return (HOW_INCR_NB_NOLOOP);
  if (!strcmp (how, "RNDFROMFILE"))		return (HOW_RND_FROM_FILE);
  if (!strcmp (how, "RNDN"))			return (HOW_RND_NUMBER);
  if (!strcmp (how, "RNDS"))			return (HOW_RND_STRING);
  return (-1);
}












/* ****************************************************************************
	FUNCTION :	parseVariant
	PURPOSE :	Parse a variant definition.
	INPUT :		variant	= string to parse
			fname	= file name
			line	= source line
			obj	= object we are parsing and building
	OUTPUT :	field	= field parsed
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
parseVariant (
	char		*variant,
	char		*fname,
	char		*line,
	vers_object	*obj,
	vers_field	*field)
{
  int	 start, end;		/* For the loops */
  char	 how[MAX_FILTER];	/* To parse the variant : */
  char	 first[MAX_FILTER];	/*   how(first)              */
  char	 second[MAX_FILTER];	/*   how(first,second)       */
  char	 third[MAX_FILTER];	/*   how(first,second,third) */
  int	 ret;			/* ldclt_mutex_init() return value */

  if (mctx.mode & VERY_VERBOSE)
    printf ("parseVariant: variant=\"%s\"\n", variant);

  /*
   * Maybe a variable ?
   */
  if (variant[1] == '\0')
  {
    if ((variant[0] < VAR_MIN) || (variant[0] > VAR_MAX))
    {
      fprintf (stderr, "Error: bad variable in %s : \"%s\"\n", fname, line);
      fprintf (stderr, "Error: must be in [%c-%c]\n", VAR_MIN, VAR_MAX);
      return (-1);
    }
    field->how = HOW_VARIABLE;
    field->var = variant[0] - VAR_MIN;
    return (0);
  }

  /*
   * Maybe a variable definition ?
   */
  if (variant[1] != '=')
    field->var = -1;
  else
  {
    if ((variant[0] < VAR_MIN) || (variant[0] > VAR_MAX))
    {
      fprintf (stderr, "Error: bad variable in %s : \"%s\"\n", fname, line);
      fprintf (stderr, "Error: must be in [%c-%c]\n", VAR_MIN, VAR_MAX);
      return (-1);
    }
    field->var = variant[0] - VAR_MIN;
    variant++;	/* Skip variable name */
    variant++;	/* Skip '=' */

    /*
     * We need a variable !
     */
    if (obj->var[field->var] == NULL)
      obj->var[field->var] = (char *) malloc (MAX_FILTER);
  }

  /*
   * Find how definition
   */
  for (end=0 ; (variant[end]!='\0') && (variant[end]!='(') ; end++);
  if (variant[end]=='\0')
  {
    fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
    fprintf (stderr, "Error: missing '('\n");
    return (-1);
  }
  strncpy (how, variant, end);
  how[end] = '\0';

  /*
   * Parse the first parameter
   */
  end++;	/* Skip '(' */
  for (start=end ; (variant[end]!='\0') && (variant[end]!=';') 
					&& (variant[end]!=')') ; end++);
  if (variant[end]=='\0')
  {
    fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
    fprintf (stderr, "Error: missing ')'\n");
    return (-1);
  }
  strncpy (first, variant+start, end-start);
  first[end-start] = '\0';

  /*
   * Parse the second parameter
   */
  if (variant[end] == ')')
    second[0] = '\0';
  else
  {
    end++;	/* Skip ';' */
    for (start=end ; (variant[end]!='\0') && (variant[end]!=';') 
					  && (variant[end]!=')') ; end++);
    if (variant[end]=='\0')
    {
      fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
      fprintf (stderr, "Error: missing ')'\n");
      return (-1);
    }
    strncpy (second, variant+start, end-start);
    second[end-start] = '\0';
  }

  /*
   * Parse the third parameter
   */
  if (variant[end]==')')
    third[0]='\0';
  else
  {
    end++;	/* Skip ';' */
    for (start=end ; (variant[end]!='\0') && (variant[end]!=')') ; end++);
    if (variant[end]=='\0')
    {
      fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
      fprintf (stderr, "Error: missing ')'\n");
      return (-1);
    }
    strncpy (third, variant+start, end-start);
    third[end-start] = '\0';
  }

  /*
   * Analyse it
   * Note : first parameter always exist (detected when parsing) while
   *        second and third may not have been provided by the user.
   */
  switch (field->how = decodeHow (how))
  {
    case HOW_INCR_FROM_FILE:
    case HOW_INCR_FROM_FILE_NL:
    case HOW_RND_FROM_FILE:
	if ((field->dlf = dataListFile (first)) == NULL)
	{
	  fprintf (stderr, "Error : bad file in %s : \"%s\"\n", fname, line);
	  return (-1);
	}

	/*
	 * Useless for HOW_RND_FROM_FILE
	 */
	field->cnt  = 0;
	field->low  = 0;
	field->high = field->dlf->strNb - 1;

	/*
	 * Maybe common counter ?
	 */
	if ((mctx.mode & COMMON_COUNTER) &&
	    ((field->how == HOW_INCR_FROM_FILE) || 
	     (field->how == HOW_INCR_FROM_FILE_NL)))
	{
	  if ((ret = ldclt_mutex_init (&(field->cnt_mutex))) != 0)
	  {
	    fprintf (stderr, "ldclt: %s\n", strerror (ret));
	    fprintf (stderr, "Error: cannot initiate cnt_mutex in %s for %s\n",
						fname, line);
	    fflush (stderr);
	    return (-1);
	  }
	}
	break;
    case HOW_INCR_NB:
    case HOW_INCR_NB_NOLOOP:
    case HOW_RND_NUMBER:
	if (third[0] == '\0')
	{
	  fprintf (stderr, "Error : missing parameters in %s : \"%s\"\n",
				fname, line);
	  return (-1);
	}
	field->cnt  = atoi (first);
	field->low  = atoi (first);
	field->high = atoi (second);
	field->nb   = atoi (third);

	/*
	 * Maybe common counter ?
	 */
	if ((mctx.mode & COMMON_COUNTER) &&
	    ((field->how == HOW_INCR_NB) || (field->how == HOW_INCR_NB_NOLOOP)))
	{
	  if ((ret = ldclt_mutex_init (&(field->cnt_mutex))) != 0)
	  {
	    fprintf (stderr, "ldclt: %s\n", strerror (ret));
	    fprintf (stderr, "Error: cannot initiate cnt_mutex in %s for %s\n",
						fname, line);
	    fflush (stderr);
	    return (-1);
	  }
	}
	break;
    case HOW_RND_STRING:
	field->nb = atoi (first);
	break;
    case -1:
	fprintf (stderr, "Error: illegal keyword \"%s\" in %s : \"%s\"\n", 
					how, fname, line);
	return (-1);
	break;
  }

  return (0);
}













/* ****************************************************************************
	FUNCTION :	parseAttribValue
	PURPOSE :	Parse the right part of attribname: attribvalue.
	INPUT :		fname	= file name
			obj	= object where variables are.
			line	= value to parse.
	OUTPUT :	attrib	= attribute where the value should be stored
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
parseAttribValue (
	char		*fname,
	vers_object	*obj,
	char		*line,
	vers_attribute	*attrib)
{
  char		 variant[MAX_FILTER];	/* To process the variant */
  int		 start, end;		/* For the loops */
  vers_field	*field;			/* To build the fields */

  if (mctx.mode & VERY_VERBOSE)
    printf ("parseAttribValue: line=\"%s\"\n", line);

  /*
   * We will now parse this line for the different fields.
   */
  field = NULL;
  end = start = 0;
  while (line[end]!='\0')
  {
    /*
     * Allocate a new field
     */
    if (field == NULL)
    {
      field         = (vers_field *) malloc (sizeof (vers_field));
      field->next   = NULL;
      attrib->field = field;
    }
    else
    {
      field->next = (vers_field *) malloc (sizeof (vers_field));
      field       = field->next;
      field->next = NULL;
    }

    /*
     * Is it a variant field ?
     */
    if (line[end] == '[')
    {
      /*
       * Extract the variant definition
       */
      end++;	/* Skip '[' */
      for (start=end ; (line[end]!='\0') && (line[end]!=']') ; end++);
      strncpy (variant, line+start, end-start);
      variant[end-start] = '\0';
      if (line[end]=='\0')
      {
	fprintf (stderr, "Error: missing ']' in %s : \"%s\"\n", fname, line);
	return (-1);
      }
      if (parseVariant (variant, fname, line, obj, field) < 0)
	return (-1);
      end++;	/* Skip ']' */

      /*
       * We need to allocate a buffer in this attribute !
       */
      if (attrib->buf == NULL)
      {
	attrib->buf = (char *) malloc (MAX_FILTER);
	if (mctx.mode & VERY_VERBOSE)
	  printf ("parseAttribValue: buffer allocated\n");
      }
    }
    else
    {
      /*
       * It is a constant field. Find the end : [ or \0
       */
      for (start=end ; (line[end]!='\0') && (line[end]!='[') ; end++);
      field->how = HOW_CONSTANT;
      field->cst = (char *) malloc (1+end-start);
      strncpy (field->cst, line+start, end-start);
      field->cst[end-start] = '\0';
    }
  }

  /*
   * Attribute value is parsed !
   */
  return (0);
}












/* ****************************************************************************
	FUNCTION :	parseLine
	PURPOSE :	Parse the given line to find an attribute definition.
	INPUT :		line	= line to parse
			fname	= file name
	OUTPUT :	obj	= object where the attribute should be added
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
parseLine (
	char		*line,
	char		*fname,
	vers_object	*obj)
{
  int	 end;		/* For the loops */

  if (mctx.mode & VERY_VERBOSE)
    printf ("parseLine: line=\"%s\"\n", line);

  /*
   * Empty line ? Comment ?
   * No more place for new attributes ?
   */
  if ((line[0]=='\0') || (line[0]=='#'))
    return (0);
  if (obj->attribsNb == MAX_ATTRIBS)
  {
    fprintf (stderr, "Error: too many attributes in %s, max is %d\n",
			fname, MAX_ATTRIBS);
    return (-1);
  }

  /*
   * Find the attribute name
   *    name:
   */
  for (end=0 ; (line[end]!='\0') && (line[end]!=':') ; end++);
  if (line[end]!=':')
  {
    fprintf (stderr, "Error: can't find attribute name in %s : \"%s\"\n",
			fname, line);
    return (-1);
  }

  /*
   * Initiate the attribute
   */
  obj->attribs[obj->attribsNb].buf  = NULL;
  obj->attribs[obj->attribsNb].src  = strdup (line);
  obj->attribs[obj->attribsNb].name = (char *) malloc (1+end);
  strncpy (obj->attribs[obj->attribsNb].name, line, end);
  obj->attribs[obj->attribsNb].name[end] = '\0';
  for (end++ ; line[end]==' ' ; end++);	/* Skip the leading ' ' */

  /*
   * We will now parse the value of this attribute
   */
  if (parseAttribValue(fname,obj, line+end, &(obj->attribs[obj->attribsNb]))<0)
    return (-1);

  /*
   * Do not forget to increment attributes number !
   */
  obj->attribsNb++;
  return (0);
}










/* ****************************************************************************
	FUNCTION :	readObject
	PURPOSE :	This function will read an object description from the
			file given in argument.
			The object should be already initiated !!!
	INPUT :		None.
	OUTPUT :	obj	= parsed object.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
readObject (
	vers_object	*obj)
{
  FILE	*ifile;			/* The file that contains the object to read */
  char	 line[MAX_FILTER];	/* To read ifile */

  /*
   * Open the file
   */
  ifile = fopen (obj->fname, "r");
  if (ifile == NULL)
  {
    perror (obj->fname);
    fprintf (stderr, "Error: cannot open file \"%s\"\n", obj->fname);
    return (-1);
  }

  /*
   * Process each line of the input file.
   * Reminder : the object is initiated by the calling function !
   */
  while (fgets (line, MAX_FILTER, ifile) != NULL)
  {
    if ((strlen (line) > 0) && (line[strlen(line)-1]=='\n'))
      line[strlen(line)-1] = '\0';
    if (parseLine (line, obj->fname, obj) < 0)
      return (-1);
  }

  /*
   * Do not forget to close the file !
   */
  if (fclose (ifile) != 0)
  {
    perror (obj->fname);
    fprintf (stderr, "Error: cannot fclose file \"%s\"\n", obj->fname);
    return (-1);
  }

  /*
   * End of function
   */
  if (obj->attribsNb == 0)
  {
    fprintf (stderr, "Error: no object found in \"%s\"\n", obj->fname);
    return (-1);
  }
  return (0);
}






/* End of file */


--- NEW FILE port.c ---
#ident "ldclt @(#)port.c	1.2 01/03/14"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
        FILE :		port.c
        AUTHOR :        Jean-Luc SCHWING
        VERSION :       1.0
        DATE :		28 November 2000
        DESCRIPTION :	
			This file contains platform-independant version of 
			common (unix) functions in order to have portable 
			source code for either unix and windows platforms.
			It is greatly inspired from iPlanet DS 5.0 workspace.
 LOCAL :		None.
        HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
28/11/00 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.2 : Lint cleanup.
---------+--------------+------------------------------------------------------
*/


#include <stdio.h>		/* EOF, etc... */

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#else
#include <unistd.h>		/* sleep(), etc... */		/*JLS 14-03-01*/
#include <pthread.h>		/* pthreads(), etc... */
#endif

#include "port.h"

/************************************************************************/
/************************************************************************/
/****************         NT section              ***********************/
/************************************************************************/
/************************************************************************/ 

#ifdef _WIN32

int
ldclt_mutex_init (
	ldclt_mutex_t	*mutex)
{
  InitializeCriticalSection (mutex);
  return (0);
}

int
ldclt_mutex_lock (
	ldclt_mutex_t	*mutex)
{
  EnterCriticalSection(mutex);
  return (0);
}

int
ldclt_mutex_unlock (
	ldclt_mutex_t	*mutex)
{
  LeaveCriticalSection (mutex);
  return (0);
}

void
ldclt_sleep (
	int	 nseconds)
{
  Sleep (1000 * nseconds);
}

int
ldclt_thread_create (
	ldclt_tid	*tid,
	void		*fct,
	void		*param)
{
  CreateThread (NULL, 0, fct, param, 0, tid);
  return (0);
}

long 
lrand48 (void)
{
  return ((rand()<<8)+rand());
}

/*
 * Implements the Unix getopt function for NT systems
 */
char	*optarg;
int	 optind;
int
getopt (
	int	  argc,
	char	**argv,
	char	 *optstring)
{
  static char	**prevArgv = NULL;	/* Memorize argv to parse */
  static int	  inOption;		/* In option parsing ? */
  static int	  cNum;			/* Current char num */
  int		  c;			/* Current char */
  int		  i;			/* Loops */

  /*
   * Initialization - maybe the first time this function is called ?
   */
  if (prevArgv != argv)
  {
    prevArgv = argv;
    optind   = 0;
    inOption = 0;
  }

  /*
   * Maybe we processed the last chars of the option in the previous call
   */
  if (inOption)
  {
    if (argv[optind][cNum] == '\0')
      inOption = 0;
  }

  /*
   * Maybe we should look for '-'
   */
  if (!inOption)
  {
    optind++;				/* Next option */
    if (optind == argc)			/* No more option */
      return (EOF);
    if (argv[optind][0] != '-')		/* Not an option */
      return (EOF);
    if (argv[optind][1] == '\0')	/* Only '-' */
      return (EOF);
    cNum = 1;				/* Next char to process */
    inOption = 0;			/* We are in an option */
  }

  /*
   * See if this is a valid option
   */
  c = argv[optind][cNum];
  for (i=0 ; (i<strlen(optstring)) && (c!=optstring[i]) ; i++);
  if (c != optstring[i])		/* Not an option */
    return ('?');
  cNum++;				/* Next char */

  /*
   * Check if this option requires an argument
   * Note that for the last char of optstring, it is a valid '\0' != ':'
   */
  if (optstring[i+1] != ':')		/* No argument */
    return (c);

  /*
   * Need an argument...
   * The argument is either the end of argv[optind] or argv[++optind]
   */
  if (argv[optind][cNum] == '\0')	/* Must return next argument */
  {
    optind++;				/* Next argument */
    if (optind == argc)			/* There is no next argument */
    {
      printf ("%s: option requires an argument -- %c\n", argv[0], c);
      return ('?');
    }
    optarg   = argv[optind];	/* Set optarg to teh argument argv[] */
    inOption = 0;		/* No more in option... */
    return (c);
  }

  /*
   * Return the end of the current argv[optind]
   */
  optarg   = &(argv[optind][cNum]);	/* End of argv[optind] */
  inOption = 0;				/* No more in option */
  return (c);
}


/*
 * Implement the Unix getsubopt function for NT systems
 */
int
getsubopt(
	char	**optionp,
	char	**tokens,
	char	**valuep)
{
  int	 i;		/* Loops */
  char	*curOpt;	/* Current optionp */

  curOpt = *optionp;	/* Begin of current option */

  /*
   * Find the end of the current option
   */
  for (i=0 ; (curOpt[i]!='\0') && (curOpt[i]!=',') ; i++);
  if (curOpt[i] == '\0')
    *optionp = &(curOpt[i]);
  else
    *optionp = &(curOpt[i+1]);
  curOpt[i] = '\0';		/* Do not forget to end this string */

  /*
   * Find if there is a subvalue for this option
   */
  for (i=0 ; (curOpt[i]!='\0') && (curOpt[i]!='=') ; i++);
  if (curOpt[i] == '\0')
    *valuep = &(curOpt[i]);
  else
    *valuep = &(curOpt[i+1]);
  curOpt[i] = '\0';		/* Do not forget to end this string */

  /*
   * Find if this option is valid...
   */
  for (i=0 ; tokens[i] != NULL ; i++)
    if (!strcmp (curOpt, tokens[i]))
      return (i);

  /*
   * Not found...
   */
  return (-1);
}


#else /* NT 4 */

/************************************************************************/
/************************************************************************/
/****************         Unix section            ***********************/
/************************************************************************/
/************************************************************************/

int
ldclt_mutex_init (
	ldclt_mutex_t	*mutex)
{
  return (pthread_mutex_init (mutex, NULL));
}

int
ldclt_mutex_lock (
	ldclt_mutex_t	 *mutex)
{
  return (pthread_mutex_lock (mutex));
}

int
ldclt_mutex_unlock (
	ldclt_mutex_t	*mutex)
{
  return (pthread_mutex_unlock (mutex));
}

void
ldclt_sleep (
	int	 nseconds)
{
  sleep (nseconds);
}

int
ldclt_thread_create (
	ldclt_tid	*tid,
	void		*(*fct)(void *),
	void		*param)
{
  return (pthread_create (tid, NULL, fct, param));
}

#endif /* _WIN32 */



/* End of file */


--- NEW FILE port.h ---
#ident "ldclt @(#)port.h	1.4 01/04/03"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
        FILE :		port.h
        AUTHOR :        Jean-Luc SCHWING
        VERSION :       1.0
        DATE :		28 November 2000
        DESCRIPTION :	
			This file contains the include (interface) definitions 
			of port.c
 LOCAL :		None.
        HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
28/11/00 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.2 : Port on Linux.
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.3 : Port on HP-UX.
---------+--------------+------------------------------------------------------
03/04/01 | JL Schwing	| 1.4 : Linux large file issue...
---------+--------------+------------------------------------------------------
*/

/*
 * Tuning of the code
 */
#ifdef AIX							/*JLS 01-12-00*/
#define LDCLT_CAST_SIGACTION	1				/*JLS 01-12-00*/
#endif								/*JLS 01-12-00*/

#ifdef HPUX							/*JLS 01-12-00*/
#define LDCLT_CAST_SIGACTION	1				/*JLS 01-12-00*/
#define LDCLT_NO_DLOPEN		1				/*JLS 01-12-00*/
#endif								/*JLS 01-12-00*/

#ifdef LINUX							/*JLS 01-12-00*/
#define LDCLT_CAST_SIGACTION	1				/*JLS 01-12-00*/
#ifndef O_LARGEFILE						/*JLS 03-04-01*/
# define O_LARGEFILE	0100000					/*JLS 03-04-01*/
#endif								/*JLS 03-04-01*/
#endif								/*JLS 01-12-00*/

#ifdef _WIN32							/*JLS 01-12-00*/
#define LDCLT_NO_DLOPEN		1				/*JLS 01-12-00*/
#endif								/*JLS 01-12-00*/


/************************************************************************/
/************************************************************************/
/****************         NT section              ***********************/
/************************************************************************/
/************************************************************************/

#ifdef _WIN32

typedef CRITICAL_SECTION	 ldclt_mutex_t;
typedef DWORD			 ldclt_tid;

extern int	 getopt (int argc, char **argv, char *optstring);
extern int	 getsubopt(char **optionp, char **tokens, char **valuep);
extern long	 lrand48 (void);
extern char	*optarg;
extern int	 optind;

#else /* _WIN32 */

extern int	 getsubopt(char **optionp, char **tokens, char **valuep);

/************************************************************************/
/************************************************************************/
/****************         Unix section            ***********************/
/************************************************************************/
/************************************************************************/

typedef pthread_mutex_t		ldclt_mutex_t;
typedef pthread_t		ldclt_tid;

#endif /* _WIN32 */


/*
 * Portability functions common to all platforms
 */
extern int	ldclt_mutex_init   (ldclt_mutex_t *mutex);
extern int	ldclt_mutex_lock   (ldclt_mutex_t *mutex);
extern int	ldclt_mutex_unlock (ldclt_mutex_t *mutex);
extern void	ldclt_sleep (int nseconds);
extern int	ldclt_thread_create (ldclt_tid *tid, void *(*fct)(void *), void *param);

/* End of file */


--- NEW FILE remote.h ---
/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
        FILE :		remote.h
        AUTHOR :        Jean-Luc SCHWING
        VERSION :       1.0
        DATE :		04 May 1999
        DESCRIPTION :	
			This file contains the definitions used by the remote 
			control module of ldclt.
 LOCAL :		None.
        HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
05/05/99 | F. Pistolesi	| 1.3 : Implements communication with remote part.
---------+--------------+------------------------------------------------------
06/05/99 | JL Schwing	| 1.4 : Port on Solaris 2.5.1
---------+--------------+------------------------------------------------------
*/

/*
 * Network includes
 */

#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef OSF1
#ifndef _UINT32_T
#define _UINT32_T
typedef unsigned long	uint32_t;
#endif /* _UINT32_T */
#else /* OS_RELEASE */
#include <inttypes.h>
#endif /* OS_RELEASE */
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

typedef struct {
	uint32_t	 type,res,dnSize;
	char		 dn[sizeof(uint32_t)];
} repconfirm;

extern int masterPort;

/* End of file */


--- NEW FILE repcheck.c ---
/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include "remote.h"
#include "lber.h"
#include "ldap.h"

enum {ADD,DELETE,MODRDN,MODIFY,RESULT};

typedef struct {
	int conn,op,type;
	char *dn;
	} Optype;

Optype *pendops;
int npend,maxop,connected;
char *ldap_ops[]={"ADD","DEL","MODRDN","MOD ","RESULT",NULL};
int ldap_val[]={LDAP_REQ_ADD,LDAP_REQ_DELETE,LDAP_REQ_MODRDN,LDAP_REQ_MODIFY};

get_op_par(char *s,Optype *op)
{
 char *t;
 int i;

 t=strstr(s,"conn=");
 for(t+=5,op->conn=0;isdigit(*t);t++)
	op->conn=op->conn*10+*t-'0';
 t=strstr(s,"op=");
 for(t+=3,op->op=0;isdigit(*t);t++)
	op->op=op->op*10+*t-'0';
 if(t=strstr(s,"dn="))
	op->dn=strdup(t+3);
}

send_op(char* s,int sfd)
{
 int sz,i;
 Optype tmp;
 repconfirm *result;
 char *t;

 get_op_par(s,&tmp);
 for(i=0;i<maxop;i++)
	if(pendops[i].op==tmp.op && pendops[i].conn==tmp.conn){
		t=strstr(s,"err=");
		sz=strlen(pendops[i].dn);
		result=(repconfirm*)malloc(sizeof(repconfirm)+sz);
		for(t+=4,result->res=0;isdigit(*t);t++)
			result->res=result->res*10+*t-'0';
		result->type=htonl(ldap_val[pendops[i].type]);
		strcpy(result->dn,pendops[i].dn);
		result->dnSize=htonl(sz);
		result->res=htonl(result->res);
		if(write(sfd,result,sizeof(repconfirm)+sz)<=0){
			close(sfd);
			memset(pendops,0,maxop*sizeof(Optype));
			maxop=npend=connected=0;
			return;
			}
		if(i!=maxop)
			pendops[i]=pendops[maxop];
		else memset(pendops+i,0,sizeof(Optype));
		return;
		}
}

main(int argc, char**argv)
{
 int i,port=16000;
 int sockfd;
 static char logline[512];
 char **tmp;
 struct hostent *serveraddr;
 struct sockaddr_in srvsaddr;

 while((i=getopt(argc,argv,"p:"))!=EOF){
	switch(i){
		case 'p': port=atoi(optarg);
			break;
		}
	}
 serveraddr=gethostbyname(argv[optind]);
 srvsaddr.sin_addr.s_addr=htonl(*((u_long*)(serveraddr->h_addr_list[0])));
 srvsaddr.sin_family=AF_INET;
 srvsaddr.sin_port=htons(port);
 maxop=npend=0;
 pendops=(Optype*)malloc(sizeof(Optype)*20);
 sigset(SIGPIPE,SIG_IGN);
 while(gets(logline)){
	 if(!connected){
		if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
			perror(argv[0]);
			exit(1);
			}
		i=1;
		if(setsockopt(sockfd,IPPROTO_TCP, TCP_NODELAY,&i,sizeof(int))!=0)
			perror("Nagle");
		if(connect(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=-1)
			connected=1;
		 else {
			close(sockfd);
			continue;
			}
		}
	for(tmp=ldap_ops,i=0;tmp[i];i++)
		if(strstr(logline,tmp[i]))
			break;
	if(i<RESULT){
		get_op_par(logline,&pendops[maxop]);
		pendops[maxop].type=i;
		if(++maxop>npend)
			npend=maxop;
		if(!(npend%20)){
			pendops=(Optype*)realloc(pendops,sizeof(Optype)*(npend+20));
			memset(pendops+npend,0,sizeof(Optype)*20);
			}
		}
	if(i==RESULT)
		send_op(logline,sockfd);
	}
 close(sockfd);
}



--- NEW FILE repslave.c ---
#ident "@(#)repslave.c	1.15 99/06/09"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
        FILE :		repslave.c
        AUTHOR :        Fabio Pistolesi
        VERSION :       1.0
        DATE :		05 May 1999
        DESCRIPTION :	
			This file contains the implementation of the slave part 
			of ldclt tool. This slave is intended to scan the logs 
			of the ldap server and to communicate the operations 
			logged to the master ldclt, to be checked against the 
			memorized operations performed on the master ldap 
			server.
 LOCAL :		None.
        HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
05/05/99 | F. Pistolesi	| Creation
---------+--------------+------------------------------------------------------
06/05/99 | JL Schwing	| 1.2 : Port on Solaris 2.5.1
---------+--------------+------------------------------------------------------
10/05/99 | F. Pistolesi	| Added multiple filtered servers to send results to.
---------+--------------+------------------------------------------------------
18/05/99 | JL Schwing	| 1.8 : Port on 2.5.1
---------+--------------+------------------------------------------------------
26/05/99 | F. Pistolesi	| 1.10: Bug fix - missing free()
---------+--------------+------------------------------------------------------
27/05/99 | F. Pistolesi	| 1.11: Add new option -d (debug)
---------+--------------+------------------------------------------------------
29/05/99 | F. Pistolesi	| 1.12: Add new option -t (log)
---------+--------------+------------------------------------------------------
09/06/99 | JL Schwing	| 1.14: Bug fix - crash in send_op() if tmp.dn==NULL
---------+--------------+------------------------------------------------------
09/06/99 | F. Pistolesi	| 1.15: Fix the fix above.
---------+--------------+------------------------------------------------------
*/

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <libgen.h>
#if OS_RELEASE == 551
#include <re_comp.h>
#endif
#include "remote.h"
#include "lber.h"
#include "ldap.h"

/*
 * Enumeration for internal list
 */
enum {ADD,DELETE,MODRDN,MODIFY,RESULT,LAST};

/*
 * internal list
 */
typedef struct {
	int conn,op,type;
	char *dn;
	} Optype;

typedef struct {
	int fd;
	char *filter,*hname;
	struct sockaddr_in addr;
	} Towho;

Optype *pendops;
Towho *srvlist;
int npend,maxop,connected,nsrv,debug;
char *ldap_ops[]={"ADD","DEL","MODRDN","MOD ","RESULT","NONE",NULL};
/*
 * To map internal values to LDAP_REQ
 */
int ldap_val[]={LDAP_REQ_ADD,LDAP_REQ_DELETE,LDAP_REQ_MODRDN,LDAP_REQ_MODIFY};

get_op_par(char *s,Optype *op)
{
  char *t;
  int i;

 /*
  * Provided they do not change dsservd's log format, this should work
  * Magic numbers are the length of the lookup string
  */
  t=strstr(s,"conn=");
  for(t+=5,op->conn=0;isdigit(*t);t++)
	op->conn=op->conn*10+*t-'0';
  t=strstr(s,"op=");
  for(t+=3,op->op=0;isdigit(*t);t++)
	op->op=op->op*10+*t-'0';
  if(t=strstr(s,"dn="))
	op->dn=strdup(t+3);
}

open_cnx(struct sockaddr *srv)
{
  int i,sockfd;

  if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  {
	perror("Slave");
	exit(1);
  }
  i=1;
 /*
  * Disable TCP's Nagle algorithm
  */
  if(setsockopt(sockfd,IPPROTO_TCP, TCP_NODELAY,(void *)&i,sizeof(int))!=0)
	perror("Nagle");
  if(connect(sockfd,srv,sizeof(struct sockaddr))!=-1)
	return sockfd;
  else close(sockfd);
  return -1;
}

send_op(char* s)
{
  int sz,i,j,ret;
  Optype tmp;
  repconfirm *result;
  char *t;
  struct pollfd pfd;

  get_op_par(s,&tmp);
  for(i=0;i<maxop;i++)
	/*
	 * got a RESULT string. Try to match with known operations.
	 */
	if(pendops[i].op==tmp.op && pendops[i].conn==tmp.conn)
	{
		sz=strlen(pendops[i].dn);
		result=(repconfirm*)malloc(sizeof(repconfirm)+sz);
		t=strstr(s,"err=");
		for(t+=4,result->res=0;isdigit(*t);t++)
			result->res=result->res*10+*t-'0';
		/*
		 * Build packet
		 */
		result->type=htonl(ldap_val[pendops[i].type]);
		strcpy(result->dn,pendops[i].dn+1);
		sz-=2;
		result->dn[sz]='\0';
		result->dnSize=htonl(sz);
		if(debug)
			printf("Sending %d %d %s\n",ntohl(result->type),result->res,result->dn);
		result->res=htonl(result->res);
		/*
		 * find which filter applies. Note that if no filter applies, no
		 * packets are sent
		 */
		for(j=0;j<nsrv;j++)
		{
			/*
			 * Suppose a NULL filter means everything
			 */
			if(srvlist[j].filter)
				if(regex(srvlist[j].filter,result->dn)==NULL)
					continue;
			/*
			 * try to write. This works if server set SO_LINGER option
			 * with parameters l_onoff=1,l_linger=0. This means terminate
			 * the connection sending an RST instead of FIN, so that
			 * write() will fail on first attempt instead of second.
			 */
			if(write(srvlist[j].fd,result,sizeof(repconfirm)+sz)<=0)
			{
				/*
				 * socket was closed by peer. try again
				 */
				close(srvlist[j].fd);
				if((srvlist[j].fd=connected=open_cnx((struct sockaddr*)&srvlist[j].addr))==-1)
					/*
					 * OK, server disconnected for good
					 */
					continue;
				if((ret=write(srvlist[j].fd,result,sizeof(repconfirm)+sz))<=0)
					puts("Porc!");
			}
		}
		/*
		 * Copy over the operation at the end
		 */
		free(pendops[i].dn);
		maxop--;
		pendops[i]=pendops[maxop];
		free(result);
		break;
	}
  if (tmp.dn != NULL)
    free(tmp.dn);
}

main(int argc, char**argv)
{
  int i,port=16000;
  int sockfd,log=0;
  static char logline[512];
  char **tmp,*hn,*hp,*hf;
  struct hostent *serveraddr;

  while((i=getopt(argc,argv,"tdP:s:"))!=EOF)
  {
	switch(i)
	{
		case 't': log=1;
			  break;
		case 'd': debug=1;
			  break;
		case 'P':
			port=atoi(optarg);
			break;
		case 's':
			/*
			 * pointers to hostname, host port, filter
			 */
			hn=strtok(optarg,",");
			hp=strtok(NULL,",");
			hf=strtok(NULL,",");
			if(hf==NULL&&hp)
				if(*hp<'0' || *hp >'9')
					hf=hp;
			if(hn==NULL||hf==NULL)
			{
				puts("Missing parameter\n");
				break;
			}
			/*
			 * Get master address, just the first.
			 */
			if((serveraddr=gethostbyname(hn))==NULL)
			{
				printf("Unknown host %s\n",hn);
				break;
			}
			srvlist=(Towho*)realloc(srvlist,(nsrv+1)*sizeof(Towho));
			srvlist[nsrv].addr.sin_addr.s_addr=htonl(*((u_long*)(serveraddr->h_addr_list[0])));
			srvlist[nsrv].addr.sin_family=AF_INET;
			srvlist[nsrv].addr.sin_port=htonl((hp==hf?port:atoi(hp)));
			if((srvlist[nsrv].filter=regcmp(hf,NULL))==NULL)
				printf("Wrong REX: %s\n",hf);
			srvlist[nsrv].fd=open_cnx((struct sockaddr*)&srvlist[nsrv].addr);
			srvlist[nsrv].hname=strdup(hn);
			nsrv++;
			break;
	}
  }
  if(!nsrv)
  {
	if(!argv[optind])
	{
		printf("Usage: %s [-td] -P port <hostname>\n\tor %s [-td] -s <host>,[<port>,]<REGEX>\n",argv[0],argv[0]);
		printf("\t-t\tprints input on stdout.\n\t-d\tdebug mode.\n");
		exit(1);
	}
	srvlist=(Towho*)malloc(sizeof(Towho));
	if((serveraddr=gethostbyname(argv[optind]))==NULL)
	{
		printf("Unknown host %s\n",argv[optind]);
		exit(1);
	}
	srvlist[nsrv].addr.sin_addr.s_addr=htonl(*((u_long*)(serveraddr->h_addr_list[0])));
	srvlist[nsrv].addr.sin_family=AF_INET;
	srvlist[nsrv].addr.sin_port=htons(port);
	srvlist[nsrv].filter=NULL;
	srvlist[nsrv].fd=open_cnx((struct sockaddr*)&srvlist[nsrv].addr);
	srvlist[nsrv].hname=strdup(argv[optind]);
	nsrv++;
  }
  maxop=npend=0;
  pendops=(Optype*)malloc(sizeof(Optype)*20);
 /*
  * Ignore SIGPIPE during write()
  */
  sigset(SIGPIPE,SIG_IGN);
  while(gets(logline))
  {
	if(log)
		puts(logline);
	for(tmp=ldap_ops,i=0;tmp[i];i++)
		if(strstr(logline,tmp[i]))
			break;
	if(i<RESULT)
	{
		get_op_par(logline,&pendops[maxop]);
		pendops[maxop].type=i;
		if(++maxop>npend)
			npend=maxop;
		if(!(npend%20))
		{
			pendops=(Optype*)realloc(pendops,sizeof(Optype)*(npend+20));
			memset(pendops+npend,0,sizeof(Optype)*20);
		}
	}
	if(i==RESULT)
		send_op(logline);
  }
}


/* End of file */


--- NEW FILE scalab01.c ---
#ident "ldclt @(#)scalab01.c	1.8 01/05/03"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		scalab01.c
	AUTHOR :	Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		08 January 2001
	DESCRIPTION :	
			This file contains the implmentation of the specific
			scenario scalab01 of ldclt.
			I implement this set of functions in a separate file to
			reduce the interconnection(s) between the main ldclt
			and the add-ons, keeping in mind the possibility to use
			a dynamic load of plugins for a future release.
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
08/01/01 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
12/01/01 | JL Schwing	| 1.2 : Second set of options for -e scalab01
---------+--------------+------------------------------------------------------
29/01/01 | B Kolics	| 1.3 : readAttrValue() uses filter of requested attr
---------+--------------+------------------------------------------------------
01/02/01 | JL Schwing	| 1.4 : Protect against multiple choice of same user.
---------+--------------+------------------------------------------------------
26/02/01 | JL Schwing	| 1.5 : Port on non-solaris platforms...
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.6 : Lint cleanup.
			| Bug fix : forget to set ldap protocol version.
---------+--------------+------------------------------------------------------
26/04/01 | B Kolics     | 1.7 : in case of lock failure, thread is not aborted
---------+--------------+------------------------------------------------------
03/05/01 | B Kolics     | 1.8 : bug fix - forget to release more line.
---------+--------------+------------------------------------------------------
*/



#include <stdio.h>	/* printf(), etc... */
#include <stdlib.h>	/* malloc(), etc... */
#include <string.h>	/* strcpy(), etc... */
#include <errno.h>	/* perror(), etc... */
#ifndef _WIN32
#include <pthread.h>	/* pthreads(), etc... */
#endif

#include <lber.h>	/* ldap C-API BER declarations */
#include <ldap.h>	/* ldap C-API declarations */

#include "port.h"	/* Portability definitions */
#include "ldclt.h"	/* This tool's include file */
#include "utils.h"	/* Utilities functions */
#include "scalab01.h"	/* Scalab01 specific definitions */





/*
 * Private data structures.
 */
scalab01_context	 s1ctx;





/* ****************************************************************************
	FUNCTION :	scalab01_init
	PURPOSE :	Initiates the scalab01 scenario.
	INPUT :		None.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01_init (void)
{
  int	 ret;		/* Return value */

  s1ctx.nbcnx      = 0;		/* No connection yet */
  s1ctx.list       = NULL;	/* No record yet */
  s1ctx.lockingMax = 0;		/* No locking yet */

  /*
   * Initiates mutexes
   */
  if ((ret = ldclt_mutex_init (&(s1ctx.list_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Error: cannot initiate s1ctx.list_mutex\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }
  if ((ret = ldclt_mutex_init (&(s1ctx.locking_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Error: cannot initiate s1ctx.locking_mutex\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }
  if ((ret = ldclt_mutex_init (&(s1ctx.nbcnx_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Error: cannot initiate s1ctx.nbcnx_mutex\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }

  /*
   * No error
   */
  return (0);
}







/* ****************************************************************************
	FUNCTION :	scalab01Lock
	PURPOSE :	Lock for single user trying to connect.
	INPUT :		tttctx	= thread context.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 cannot lock, 1 if could lock.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01Lock (
	thread_context	*tttctx)
{
  int	 i;	/* For the loop */
  int	 ret;	/* Return code */
  int	 res;	/* Result of this function */

  /*
   * Get secure access to the common data structure.
   */
  if ((ret = ldclt_mutex_lock (&(s1ctx.locking_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
		mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Is it locked ?
   */
  res = 1;
  for (i=0 ; i<s1ctx.lockingMax ; i++)
    if ((s1ctx.locking[i] != NULL) && 
	(!strcmp (s1ctx.locking[i], tttctx->bufBindDN)))
    {
      res = 0;
      break;
    }
  if (res == 1)
  {
    for (i=0 ; (i<s1ctx.lockingMax) && (s1ctx.locking[i] != NULL) ; i++);
    if (i == s1ctx.lockingMax)
    {
      if (s1ctx.lockingMax == SCALAB01_MAX_LOCKING)
	res = 0;
      else
	s1ctx.lockingMax++;
    }
    if (res != 0)
      s1ctx.locking[i] = tttctx->bufBindDN;
  }

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(s1ctx.locking_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
			mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  return (res);
}








/* ****************************************************************************
	FUNCTION :	scalab01Unlock
	PURPOSE :	Unlock for single user trying to connect.
	INPUT :		tttctx	= thread context.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01Unlock (
	thread_context	*tttctx)
{
  int	 i;	/* For the loop */
  int	 ret;	/* Return code */

  /*
   * Get secure access to the common data structure.
   */
  if ((ret = ldclt_mutex_lock (&(s1ctx.locking_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
		mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Find the entry and unlock it.
   */
  for (i=0 ; i<s1ctx.lockingMax ; i++)
    if ((s1ctx.locking[i] != NULL) && 
	(!strcmp (s1ctx.locking[i], tttctx->bufBindDN)))
    {
      s1ctx.locking[i] = NULL;
      break;
    }

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(s1ctx.locking_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
			mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  return (0);
}









/* ****************************************************************************
	FUNCTION :	scalab01_modemIncr
	PURPOSE :	Increments the modem nb of cnx
	INPUT :		ident	= thread identifier
	OUTPUT :	None.
	RETURN :	-1 if error
			 0 if no modem available
			 1 if modem available
	DESCRIPTION :
 *****************************************************************************/
int
scalab01_modemIncr (
	char	*ident)
{
  int	 ret;	/* Return value */
  int	 res;	/* Result of this function */

  /*
   * Get secure access to the common data structure.
   */
  if ((ret = ldclt_mutex_lock (&(s1ctx.nbcnx_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
		mctx.pid, ident, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  if (s1ctx.nbcnx >= s1ctx.maxcnxnb)
    res = 0;
  else
  {
    res = 1;
    s1ctx.nbcnx++;
  }

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(s1ctx.nbcnx_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
			mctx.pid, ident, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  return (res);
}


/* ****************************************************************************
	FUNCTION :	scalab01_modemDecr
	PURPOSE :	Decrements the modem nb of cnx
	INPUT :		ident	= thread identifier
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01_modemDecr (
	char	*ident)
{
  int	 ret;	/* Return value */

  /*
   * Get secure access to the common data structure.
   */
  if ((ret = ldclt_mutex_lock (&(s1ctx.nbcnx_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
		mctx.pid, ident, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  s1ctx.nbcnx--;

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(s1ctx.nbcnx_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
			mctx.pid, ident, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  return (0);
}







/* ****************************************************************************
	FUNCTION :	scalab01_addLogin
	PURPOSE :	Add a new user login to the s1ctx structure.
	INPUT :		tttctx	 = thread context.
			dn	 = user's dn.
			duration = duration of the connection.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01_addLogin (
	thread_context	*tttctx,
	char		*dn,
	int		 duration)
{
  int		 ret;	/* Return value */
  isp_user	*new;	/* New entry */
  isp_user	*cur;	/* Current entry */

  /*
   * Create the new record.
   */
  new = (isp_user *) malloc (sizeof (isp_user));
  strcpy (new->dn, dn);
  new->cost = new->counter = duration;
  new->next = NULL;

  /*
   * Get secure access to the common data structure.
   * Note : it should be possible to reduce the "size" of this critical
   *        section but I am not 100% certain this won't mess up all things.
   */
  if ((ret = ldclt_mutex_lock (&(s1ctx.list_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
		mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Maybe this is the first entry of the list ?
   */
  if (s1ctx.list == NULL)
    s1ctx.list = new;
  else
  {
    /*
     * Check with the list's head
     */
    if (s1ctx.list->counter >= duration)
    {
      new->next  = s1ctx.list;
      s1ctx.list = new;
    }
    else
    {
      cur = s1ctx.list;
      while (cur != NULL)
      {
	if (cur->next == NULL)
	{
	  cur->next = new;
	  cur       = NULL; /* Exit loop */
	}
	else
	  if (cur->next->counter >= duration)
	  {
	    new->next = cur->next;
	    cur->next = new;
	    cur       = NULL; /* Exit loop */
	  }
	  else
	    cur = cur->next;
      }
    }
  }

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(s1ctx.list_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
			mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  return (0);
}









/* ****************************************************************************
	FUNCTION :	scalab01_connectSuperuser
	PURPOSE :	Purpose of the fct
	INPUT :		None.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01_connectSuperuser (void)
{
  int	 ret;				/* Return value */
  int	 v2v3;				/* LDAP version used */
  char	 bindDN [MAX_DN_LENGTH];	/* To bind */

  /*
   * Create the LDAP context
   */
#ifdef LDCLTSSL
  /*
   * SSL is enabled ?
   */
  if (mctx.mode & SSL)
  {
    /*
     * LDAP session initialization in SSL mode
     */
    s1ctx.ldapCtx = (LDAP *)(*(mctx.sslctx.ldapssl_init))
			(mctx.hostname, mctx.port, 1);
    if (mctx.mode & VERY_VERBOSE)
      printf ("ldclt[%d]: ctrl: ldapssl_init (%s, %d), ldapCtx=0x%08x\n",
			mctx.pid, mctx.hostname, mctx.port, (unsigned int)s1ctx.ldapCtx);
    if (s1ctx.ldapCtx == NULL)
    {
      printf ("ldclt[%d]: ctrl: Cannot ldapssl_init (%s, %d), errno=%d\n",
			mctx.pid, mctx.hostname, mctx.port, errno);
      fflush (stdout);
      return (-1);
    }
    /*
     * Client authentication is used ?
     */
    if (mctx.mode & CLTAUTH)
    {
      ret = (int)(*(mctx.sslctx.ldapssl_enable_clientauth))
		  (s1ctx.ldapCtx, "", mctx.keydbpin, mctx.cltcertname);
      if (mctx.mode & VERY_VERBOSE)
	printf
	    ("ldclt[%d]: ctrl: After ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
	     mctx.pid, (unsigned int)s1ctx.ldapCtx, mctx.keydbpin, mctx.cltcertname);
      if (ret < 0)
      {
	printf
	    ("ldclt[%d]: ctrl: Cannot ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
	     mctx.pid, (unsigned int)s1ctx.ldapCtx, mctx.keydbpin, mctx.cltcertname);
	ldap_perror(s1ctx.ldapCtx, "ldapssl_enable_clientauth");
	fflush (stdout);
	return (-1);
      }
    }
  }
  else
  {
#endif
    /*
     * Connection initialization in normal, unencrypted mode
     */
    s1ctx.ldapCtx = ldap_init (mctx.hostname, mctx.port);
    if (mctx.mode & VERY_VERBOSE)
      printf ("ldclt[%d]: ctrl: After ldap_init (%s, %d), ldapCtx=0x%08x\n",
		mctx.pid, mctx.hostname, mctx.port, (unsigned int)s1ctx.ldapCtx);
    if (s1ctx.ldapCtx == NULL)
    {
      printf ("ldclt[%d]: ctrl: Cannot ldap_init (%s, %d), errno=%d\n",
		mctx.pid, mctx.hostname, mctx.port, errno);
      fflush (stdout);
      return (-1);
    }
#ifdef LDCLTSSL
  }
#endif

  /*
   * Set the LDAP version and other options...
   */
  if (mctx.mode & LDAP_V2)
    v2v3 = LDAP_VERSION2;
  else
    v2v3 = LDAP_VERSION3;

  ret = ldap_set_option (s1ctx.ldapCtx, LDAP_OPT_PROTOCOL_VERSION, &v2v3);
  if (ret < 0)							/*JLS 14-03-01*/
  {								/*JLS 14-03-01*/
    printf ("ldclt[%d]: ctrl: Cannot ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)\n",
             mctx.pid);
    fflush (stdout);						/*JLS 14-03-01*/
    return (-1);						/*JLS 14-03-01*/
  }								/*JLS 14-03-01*/


  /*
   * Now we could bind
   */
#ifdef LDCLTSSL
  /*
   * for SSL client authentication, SASL BIND is used
   */
  if (mctx.mode & CLTAUTH)
  {
    if (mctx.mode & VERY_VERBOSE)
      printf ("ldclt[%d]: ctrl: Before ldap_sasl_bind_s\n", mctx.pid);
    ret = ldap_sasl_bind_s (s1ctx.ldapCtx, "", "EXTERNAL", NULL, NULL, NULL,
			    NULL);
    if (mctx.mode & VERY_VERBOSE)
      printf ("ldclt[%d]: ctrl: After ldap_sasl_bind_s\n", mctx.pid);
    if (ret != LDAP_SUCCESS)
    {
      printf ("ldclt[%d]: ctrl: Cannot ldap_sasl_bind_s, error=%d (%s)\n",
		mctx.pid, ret, my_ldap_err2string (ret));
      fflush (stdout);
      return (-1);
    }
  }
  else
  {
#endif /* LDCLTSSL */
    strcpy (bindDN, SCALAB01_SUPER_USER_RDN);
    strcat (bindDN, ",");
    strcat (bindDN, mctx.baseDN);
    if (mctx.mode & VERY_VERBOSE)
      printf ("ldclt[%d]: ctrl: Before ldap_simple_bind_s (%s , %s)\n",
		mctx.pid, bindDN, SCALAB01_SUPER_USER_PASSWORD);
    ret = ldap_simple_bind_s (s1ctx.ldapCtx,
		bindDN, SCALAB01_SUPER_USER_PASSWORD);
    if (mctx.mode & VERY_VERBOSE)
      printf ("ldclt[%d]: ctrl: After ldap_simple_bind_s (%s, %s)\n",
		mctx.pid, bindDN, SCALAB01_SUPER_USER_PASSWORD);
    if (ret != LDAP_SUCCESS)
    {
      printf("ldclt[%d]: ctrl: Cannot ldap_simple_bind_s (%s, %s), error=%d (%s)\n",
		mctx.pid, bindDN, SCALAB01_SUPER_USER_PASSWORD,
		ret, my_ldap_err2string (ret));
      fflush (stdout);
      return (-1);
    }
#ifdef LDCLTSSL
  }
#endif

  /*
   * Normal end...
   */
  return (0);
}








/* ****************************************************************************
	FUNCTION :	readAttrValue
	PURPOSE :	This function will ldap_search the given entry for the
			value of the given attribute.
	INPUT :		ident	= thread identifier
			ldapCtx	= LDAP context
			dn	= dn of the entry to process
			attname	= attribute name
	OUTPUT :	value	= attribute value. This buffer must be
				  initiated with enough memory.
				  value[0] == '\0' if not find.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
readAttrValue (
	LDAP	*ldapCtx,
	char	*ident,
	char	*dn,
	char	*attname,
	char	*value)
{
  int		  ret;		/* Return value */
  char		 *attrs[2];	/* Attribute to retrieve */
  LDAPMessage	 *res;		/* LDAP responses */
  LDAPMessage	 *cur;		/* Current message */
  BerElement	 *ber;		/* To decode the response */
  char		 *aname;	/* Current attribute name */
  char		**vals;		/* Attribute value returned */
  char		 *filter;	/* Filter used for searching */

  /*
   * First, ldap_search() the entry.
   */
  attrs[0] = attname;
  attrs[1] = NULL;
  filter = (char *)malloc((4+strlen(attname))*sizeof(char));
  sprintf(filter, "(%s=*)", attname);
  ret = ldap_search_s (ldapCtx, dn, LDAP_SCOPE_BASE,
	filter, attrs, 0, &res);
  if (filter != NULL) free(filter);
  if (ret != LDAP_SUCCESS)
  {
    printf ("ldclt[%d]: %s: Cannot ldap_search (%s in %s), error=%d (%s)\n",
		mctx.pid, ident, attname, dn, ret, my_ldap_err2string (ret));
    fflush (stdout);
    return (-1);
  }

  /*
   * Decode the response
   */
  value[0] = '\0';	/* Not find yet */
  cur  = ldap_first_entry (ldapCtx, res);
  while ((!value[0]) && (cur != NULL))
  {
    aname = ldap_first_attribute (ldapCtx, cur, &ber);
    while ((!value[0]) && (aname != NULL))
    {
      /*
       * We expect this attribute to be single-valued.
       */
      if (!strcmp (aname, attname))
      {
	vals = ldap_get_values (ldapCtx, cur, aname);
	if (vals == NULL)
	{
	  printf ("ldclt[%d]: %s: no value for %s in %s\n",
                   mctx.pid, ident, dn, attname);
	  fflush (stdout);
	  return (-1);
	}
	strcpy (value, vals[0]);
	ldap_value_free (vals);
      }

      /*
       * Next attribute
       */
      ldap_memfree (aname);
      if (!value[0])
	aname = ldap_next_attribute (ldapCtx, cur, ber);
    }

    /*
     * Next entry - shouldn't happen in theory
     */
    if (ber != NULL)
      ldap_ber_free (ber, 0);
    cur = ldap_next_entry (ldapCtx, cur);
  }
  ldap_msgfree (res);	/* Free the response */

  return (0);
}







/* ****************************************************************************
	FUNCTION :	writeAttrValue
	PURPOSE :	This function will ldap_modify the given entry to
			replace the value of the given attribute.
	INPUT :		ident	= thread identifier
			ldapCtx	= LDAP context
			dn	= dn of the entry to process
			attname	= attribute name
			value	= attribute value
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
writeAttrValue (
	LDAP	*ldapCtx,
	char	*ident,
	char	*dn,
	char	*attname,
	char	*value)
{
  int		 ret;		/* Return value */
  LDAPMod	 attribute;	/* To build the attributes */
  LDAPMod	*attrsmod[2];	/* Modify attributes */
  char		*pvalues[2];	/* To build the values list */

  /*
   * Prepear the data to be written
   */
  pvalues[0]           = value;
  pvalues[1]           = NULL;
  attribute.mod_op     = LDAP_MOD_REPLACE;
  attribute.mod_type   = attname;
  attribute.mod_values = pvalues;
  attrsmod[0]          = &attribute;
  attrsmod[1]          = NULL;

  /*
   * Store the data in the directory.
   */
  ret = ldap_modify_ext_s (ldapCtx, dn, attrsmod, NULL, NULL);
  if (ret != LDAP_SUCCESS)
  {
    printf ("ldclt[%d]: %s: Cannot ldap_modify_ext_s (%s in %s), error=%d (%s)\n",
			mctx.pid, ident, attname, dn, ret, my_ldap_err2string (ret));
    fflush (stdout);
    return (-1);
  }

  return (0);
}







/* ****************************************************************************
	FUNCTION :	scalab01_unlock
	PURPOSE :	Unlock the user given in argument.
	INPUT :		entry	= entry to unlock.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
scalab01_unlock (
	isp_user	*user)
{
  int	 account;	/* Accounting value */
  char	 buf[20];	/* To read/write attribute */

  /*
   * Increment accounting counters
   * First, read the current value.
   */
  if (readAttrValue (s1ctx.ldapCtx,"ctrl",user->dn,SCALAB01_ACC_ATTRIB,buf) < 0)
  {
    printf ("ldclt[%d]: ctrl: Cannot read accounting attribute of %s\n",
             mctx.pid, user->dn);
    fflush (stdout);
    return (-1);
  }

  /*
   * If this attribute has no value (doesn't exist) we assume it is 0.
   */
  if (buf[0] != '\0')
    account = atoi (buf);
  else
  {
    printf ("ldclt[%d]: ctrl: No accounting attribute for %s - assume it is 0\n",
             mctx.pid, user->dn);
    fflush (stdout);
    account = 0;
  }

  /*
   * Compute the new value and store it in the directory.
   */
  sprintf (buf, "%d", account + user->cost);
  if (writeAttrValue (s1ctx.ldapCtx,"ctrl",user->dn,SCALAB01_ACC_ATTRIB,buf) <0)
  {
    printf ("ldclt[%d]: ctrl: Cannot write accounting attribute of %s\n",
             mctx.pid, user->dn);
    fflush (stdout);
    return (-1);
  }

  /*
   * Unlock the user
   */
  if (writeAttrValue (s1ctx.ldapCtx, "ctrl", user->dn, 
			SCALAB01_LOCK_ATTRIB, SCALAB01_VAL_UNLOCKED) < 0)
  {
    printf ("ldclt[%d]: ctrl: Cannot write lock (unlock) attribute of %s\n",
             mctx.pid, user->dn);
    fflush (stdout);
    return (-1);
  }
  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: ctrl: entry %s unlocked\n",
             mctx.pid, user->dn);

  /*
   * Decrement modem pool usage...
   */
  if (scalab01_modemDecr ("ctrl") < 0)
    return (-1);

  /*
   * Normal end
   */
  return (0);
}








/* ****************************************************************************
	FUNCTION :	scalab01_control
	PURPOSE :	This function implements the control loop/thread of
			the scalab01 scenario. Its main target is to manage
			the counters of each "connection" and to unlock the
			entry when time is reached.
	INPUT :		None.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
void *
scalab01_control (
	void	*arg)
{
  isp_user	*cur;	/* Current entry */
  isp_user	*head;	/* Head of entries to process */
  int		 ret;	/* Return value */
  int		 nbTot;	/* Total nb entries locked */
  int		 nbU;	/* Number unlocked */

  /*
   * Initialization
   * Failure to connect is a critical error...
   */
  if (scalab01_connectSuperuser () < 0)
    ldcltExit (EXIT_NOBIND);

  /*
   * Main loop
   */
  while (1 /*CONSTCOND*/)					/*JLS 14-03-01*/
  {
    ldclt_sleep (1);	/* Poll the connections every second */
    nbTot = nbU = 0;	/* No entries processed yet */

    /*
     * Get protected access to the entries
     */
    if ((ret = ldclt_mutex_lock (&(s1ctx.list_mutex))) != 0)
    {
      fprintf (stderr, "ldclt[%d]: ctrl: cannot mutex_lock(), error=%d (%s)\n",
		mctx.pid, ret, strerror (ret));
      fflush (stderr);
      ldcltExit (EXIT_OTHER);
    }

    /*
     * Decrement all counters
     */
    for (cur=s1ctx.list ; cur!=NULL ; cur=cur->next)
    {
      cur->counter--;
      nbTot++;
    }

    /*
     * Find the entries to process.
     */
    if ((s1ctx.list == NULL) || (s1ctx.list->counter > 0))
      head = NULL;
    else
    {
      head = cur = s1ctx.list;
      while ((cur != NULL) && (cur->counter == 0))
	cur = cur->next;
      s1ctx.list = cur;
    }

    /*
     * Release mutex
     */
    if ((ret = ldclt_mutex_unlock (&(s1ctx.list_mutex))) != 0)
    {
      fprintf (stderr, "ldclt[%d]: ctrl: cannot mutex_unlock(), error=%d (%s)\n",
		mctx.pid, ret, strerror (ret));
      fflush (stderr);
      ldcltExit (EXIT_OTHER);
    }

    /*
     * Now, we have "head" that points either to NULL or to a list of
     * entries to process.
     * Attention, this list of entries is not terminated by NULL, but
     * we must rather check the field head->next->counter" for the last
     * entry...
     *
     * NOTE : implements this section as a separate thread to keep the
     *        general timer working...
     */
    while (head != NULL)
    {
      if (scalab01_unlock (head) < 0)
      {
	printf ("ldclt[%d]: ctrl: cannot unlock %s\n", mctx.pid, head->dn);
	ldcltExit (EXIT_OTHER);
      }
      nbU++;	/* One more entry unlocked */

      /*
       * Next entry...
       */
      cur = head;
      if (head->next == NULL)
	head = NULL;
      else
	if (head->next->counter != 0)
	  head = NULL;
	else
	  head = head->next;

      free (cur);
    } /* while (head =! NULL) */

    /*
     * Print some stats...
     */
    if (mctx.mode & VERBOSE)
      printf ("ldclt[%d]: ctrl: nb entries unlocked / total : %3d / %5d\n",
               mctx.pid, nbU, nbTot);
  } /* Main loop */

  /*
   * End of thread
   */
  return (arg);
}







/* ****************************************************************************
	FUNCTION :	doScalab01
	PURPOSE :	Implements the client part of the scalab01 scenario.
	INPUT :		tttctx	= this thread context
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
doScalab01 (
	thread_context	*tttctx)
{
  char	 buf[32];	/* To read attributes value */
  int	 duration;	/* Use a variable for trace purpose */
  int	 res;		/* Result of cnx to modem pool */
  int	 doloop;	/* To know if we should loop */

  /*
   * Simulate connection to the modem pool.
   */
  while ((res = scalab01_modemIncr(tttctx->thrdId)) != 1)
    switch (res)
    {
      case 0:
	ldclt_sleep (s1ctx.wait==0?SCALAB01_DEF_WAIT_TIME:rndlim(0,s1ctx.wait));
	break;
      case -1:
	return (-1);
	break;
    }

  /*
   * Connection to the server
   * The function connectToServer() will take care of the various connection/
   * disconnection, bind/unbind/close etc... requested by the user.
   * The cost is one more function call in this application, but the
   * resulting source code will be much more easiest to maintain.
   */
  if (connectToServer (tttctx) < 0)
    return (-1);
  if (!(tttctx->binded))
    return (0);

  /*
   * Check that no other thread is using the same identity...
   */
  doloop = 1;
  while (doloop)
  {
    switch (scalab01Lock (tttctx))
    {
      case 0:
	ldclt_sleep (1);
	break;
      case 1:
	doloop = 0;
	break;
      case -1:
	return (-1);
	break;
    }
  }

  /*
   * Ok, we are now binded. Great ;-)
   * The DN we used to bind is available in tttctx->bufBindDN
   * Read lock attribute
   */
  if (readAttrValue (tttctx->ldapCtx, tttctx->thrdId, tttctx->bufBindDN,
		SCALAB01_LOCK_ATTRIB, buf) < 0)
  {
    printf ("ldclt[%d]: %s: Cannot read lock attribute of %s\n", 
				mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
    fflush (stdout);
    (void) scalab01_modemDecr (tttctx->thrdId);
    return (-1);
  }
  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: %s: entry %s lock read\n",
             mctx.pid, tttctx->thrdId, tttctx->bufBindDN);

  /*
   * If locked, then we cannot login now...
   */
  if (!strcmp (buf, SCALAB01_VAL_LOCKED))
  {
    if (scalab01_modemDecr (tttctx->thrdId) < 0)
      return (-1);
    return (0);
  }

  /*
   * If not locked :
   *  - lock the user
   *  - decide how many times will be connected
   *  - add information to the list of connected
   */
  if (writeAttrValue (tttctx->ldapCtx, tttctx->thrdId, tttctx->bufBindDN,
		SCALAB01_LOCK_ATTRIB, SCALAB01_VAL_LOCKED) < 0)
  {
    printf ("ldclt[%d]: %s: Cannot write lock attribute of %s\n", 
				mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
    fflush (stdout);
    /*
     * It can still happen that two threads write this attribute at the same
     * time, so there can be failure in one of the threads
     * in this case just return
     */
    if (scalab01_modemDecr (tttctx->thrdId) < 0)		/*JLS 03-05-01*/
      return (-1);						/*JLS 03-05-01*/
    return (0);							/*BK  26-04-01*/
  }
  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: %s: entry %s lock written\n",
             mctx.pid, tttctx->thrdId, tttctx->bufBindDN);

  if (scalab01Unlock (tttctx) < 0)
    return (-1);

  duration = rndlim (1, s1ctx.cnxduration);
  if (scalab01_addLogin (tttctx, tttctx->bufBindDN, duration) < 0)
  {
    printf ("ldclt[%d]: %s: Cannot memorize new login of %s\n", 
				mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
    fflush (stdout);
    return (-1);
  }
  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: %s: entry %s login added duration %6d\n",
		mctx.pid, tttctx->thrdId, tttctx->bufBindDN, duration);

  /*
   * Memorize the operation
   */
  if (incrementNbOpers (tttctx) < 0)
    return (-1);

  /*
   * Wait before next operation...
   */
  if (s1ctx.wait > 0)
    ldclt_sleep (rndlim (0,s1ctx.wait));

  /*
   * Unbind
   */
/*
TBC - this is done in the next loop... - cf connectToServer()
*/

  return (0);
}






/* End of file */


--- NEW FILE scalab01.h ---
#ident "ldclt @(#)scalab01.h	1.3 01/03/14"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
        FILE :		scalab01.h
        AUTHOR :        Jean-Luc SCHWING
        VERSION :       1.0
        DATE :		12 January 2001
        DESCRIPTION :	
			This file contains the definitions related to the 
			scenario scalab01 of ldclt.
 LOCAL :		None.
        HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
12/01/01 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
01/02/01 | JL Schwing	| 1.2 : Protect against multiple choice of same user.
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.3 : Lint cleanup.
---------+--------------+------------------------------------------------------
*/


#ifndef SCALAB01_H
#define SCALAB01_H


/*
 * Default values for scalab01
 */
#define SCALAB01_ACC_ATTRIB		"ntUserUnitsPerWeek"
#define SCALAB01_DEF_MAX_CNX		5000
#define SCALAB01_DEF_CNX_DURATION	3600
#define SCALAB01_DEF_WAIT_TIME		10
#define SCALAB01_LOCK_ATTRIB		"ntUserFlags"
#define SCALAB01_SUPER_USER_RDN		"cn=super user"
#define SCALAB01_SUPER_USER_PASSWORD	"super user password"
#define SCALAB01_VAL_LOCKED		"1"
#define SCALAB01_VAL_UNLOCKED		"0"
#define SCALAB01_MAX_LOCKING		4096

/*
 * This structure is intended to memorize the information about
 * the "ISP" users connected.
 * Uses mainly static size data to save malloc()/free() calls.
 */
typedef struct isp_user {
	char		 dn[MAX_DN_LENGTH];	/* User's DN */
	int		 cost;			/* Cnx cost */
	int		 counter;		/* To free it */
	struct isp_user	*next;			/* Next entry */
} isp_user;

/*
 * This is the scalab01 context structure.
 */
typedef struct scalab01_context {
	int		 cnxduration;	/* Max cnx duration */
	LDAP		*ldapCtx;	/* LDAP context */
	isp_user	*list;		/* ISP users list */
	ldclt_mutex_t	 list_mutex;	/* Protect list */
	char		*locking[SCALAB01_MAX_LOCKING];
	ldclt_mutex_t	 locking_mutex;
	int		 lockingMax;
	int		 maxcnxnb;	/* Modem pool size */
	int		 nbcnx;		/* Nb cnx to the modem */
	ldclt_mutex_t	 nbcnx_mutex;	/* Protect nbcnx */
	int		 wait;		/* Retry every this time */
} scalab01_context;

/*
 * Exported functions and structures
 */
extern int		 doScalab01 (thread_context *tttctx);
extern scalab01_context	 s1ctx;
extern void		*scalab01_control (void *);
extern int		 scalab01_init (void);			/*JLS 14-03-01*/

#endif /* SCALAB01_H */

/* End of file */


--- NEW FILE srv.c ---
/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/inttypes.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include "remote.h"
#include "lber.h"
#include "ldap.h"

enum {ADD,DELETE,MODRDN,MODIFY,RESULT};

typedef struct {
	int conn,op,type;
	char *dn;
	} Optype;

Optype *pendops;
int npend=-1,maxop;
char *ldap_ops[]={"ADD","DEL","MODRDN","MOD ","RESULT",NULL};
int ldap_val[]={LDAP_REQ_ADD,LDAP_REQ_DELETE,LDAP_REQ_MODRDN,LDAP_REQ_MODIFY};

print_packet(repconfirm *op)
{
 int i;
 printf("type=%d, res=%d, dnlen=%d, dN: %s\n",op->type,op->res,op->dnSize,op->dn);

}

main(int argc, char**argv)
{
 int i,port=16000;
 int sockfd,newfd;
 static char buff[512];
 char **tmp;
 struct sockaddr_in srvsaddr,claddr;
 struct hostent *cltaddr;
 uint32_t ipaddr;

 while((i=getopt(argc,argv,"p:"))!=EOF){
	switch(i){
		case 'p': port=atoi(optarg);
			break;
		}
	}
 srvsaddr.sin_addr.s_addr=htonl(INADDR_ANY);
 srvsaddr.sin_family=AF_INET;
 srvsaddr.sin_port=htons(port);
 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
	perror("Socket");
	exit(1);
	}
 i=1;
 if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))!=0)
	perror("Sockopt");
 if(bind(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=0){
	perror("Bind");
	exit(1);
	}
 if(listen(sockfd,1)!=0)
	perror("listen");
 for(;;){
	i=sizeof(claddr);
	if((newfd=accept(sockfd,(struct sockaddr *)&claddr,&i))<0){
		perror("Accept");
		exit(1);
		}
	ipaddr=ntohl(claddr.sin_addr.s_addr);
	cltaddr=gethostbyaddr((char*)&ipaddr,sizeof(ipaddr),AF_INET);
	printf("Accepting from %s\n",cltaddr->h_name);
	while(read(newfd,buff,512)>0){
		print_packet((repconfirm*) buff);
		memset(buff,0,512);
		}
	close(newfd);
	}
 close(sockfd);
}



--- NEW FILE threadMain.c ---
#ident "ldclt @(#)threadMain.c	1.40 01/05/04"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		threadMain.c
	AUTHOR :	Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		04 December 1998
	DESCRIPTION :	
			This file implements the main/core part of the 
			threads. The ldap part is in another source file.
 	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
04/12/98 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.2 : Add nb of errors statistics.
---------+--------------+------------------------------------------------------
10/12/98 | JL Schwing	| 1.3 : Implement asynchronous mode.
---------+--------------+------------------------------------------------------
11/12/98 | JL Schwing	| 1.4 : Implement max errors threshold.
			| fflush(stdout) after each printf.
---------+--------------+------------------------------------------------------
14/12/98 | JL Schwing	| 1.5 : Implement "-e close".
			| Add "thread is dead" message.
---------+--------------+------------------------------------------------------
16/12/98 | JL Schwing	| 1.6 : Implement "-e add" and "-e delete".
---------+--------------+------------------------------------------------------
23/12/98 | JL Schwing	| 1.7 : bug fix - crash in msgIdDel().
---------+--------------+------------------------------------------------------
28/12/98 | JL Schwing	| 1.8 : Add tag asyncHit.
---------+--------------+------------------------------------------------------
13/01/99 | JL Schwing	| 1.9 : Implement "-e string".
---------+--------------+------------------------------------------------------
18/01/99 | JL Schwing	| 1.10: Implement "-e randombase".
---------+--------------+------------------------------------------------------
21/01/99 | JL Schwing	| 1.11: Implement "-e ascii".
---------+--------------+------------------------------------------------------
26/02/99 | JL Schwing	| 1.12: Improve strict ascii: reject more characters.
---------+--------------+------------------------------------------------------
26/02/99 | JL Schwing	| 1.13: Quote (aka \) characters rather than reject.
---------+--------------+------------------------------------------------------
04/05/99 | JL Schwing	| 1.14: Modify msgId*() to memorize attribs as well.
---------+--------------+------------------------------------------------------
19/05/99 | JL Schwing	| 1.15: Implement "-e rename".
			| Exit the thread if status==DEAD
---------+--------------+------------------------------------------------------
28/05/99 | JL Schwing	| 1.16: Add new option -W (wait).
---------+--------------+------------------------------------------------------
06/03/00 | JL Schwing	| 1.17: Test malloc() return value.
---------+--------------+------------------------------------------------------
18/08/00 | JL Schwing	| 1.18: Print begin and end dates.
---------+--------------+------------------------------------------------------
25/08/00 | JL Schwing	| 1.19: Implement consistent exit status...
			| Fix some old legacy code.
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| 1.20: Will now use utils.c functions.
---------+--------------+------------------------------------------------------
17/11/00 | JL Schwing	| 1.21: Implement "-e smoothshutdown".
			| Add new functions setThreadStatus() getThreadStatus().
---------+--------------+------------------------------------------------------
21/11/00 | JL Schwing	| 1.22: Implement "-e attreplace=name:mask"
---------+--------------+------------------------------------------------------
29/11/00 | JL Schwing	| 1.23: Port on NT 4.
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.24: Port on Linux.
---------+--------------+------------------------------------------------------
15/12/00 | JL Schwing	| 1.25: Add more trace in VERY_VERBOSE mode.
---------+--------------+------------------------------------------------------
18/12/00 | JL Schwing	| 1.26: Add new exit status EXIT_INIT.
---------+--------------+------------------------------------------------------
05/01/01 | JL Schwing	| 1.27: Implement "-e randombinddn" and associated
			|   "-e randombinddnlow/high"
---------+--------------+------------------------------------------------------
08/01/01 | JL Schwing	| 1.28: Implement "-e scalab01".
---------+--------------+------------------------------------------------------
12/01/01 | JL Schwing	| 1.29: Include scalab01.h
---------+--------------+------------------------------------------------------
05/03/01 | JL Schwing	| 1.30: Bug fix - crash SIGSEGV if no binDN provided.
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.31: Implement "-e commoncounter"
			| Add new function incrementCommonCounter().
---------+--------------+------------------------------------------------------
14/03/01 | JL Schwing	| 1.32: Implement "-e dontsleeponserverdown".
---------+--------------+------------------------------------------------------
15/03/01 | JL Schwing	| 1.33: Implement "-e randomattrlist=name:name:name"
			| Add new function selectRandomAttrList().
---------+--------------+------------------------------------------------------
19/03/01 | JL Schwing	| 1.34: Implement "-e genldif=filename"
---------+--------------+------------------------------------------------------
23/03/01 | JL Schwing	| 1.35: Implements "-e rdn=value".
---------+--------------+------------------------------------------------------
28/03/01 | JL Schwing	| 1.36: Support -e commoncounter with -e rdn/object
			| Add new function incrementCommonCounterObject().
---------+--------------+------------------------------------------------------
02/04/01 | JL Schwing	| 1.37: Bug fix : large files support for -e genldif.
---------+--------------+------------------------------------------------------
11/04/01 | JL Schwing	| 1.38: Implement [INCRFROMFILE<NOLOOP>(myfile)]
---------+--------------+------------------------------------------------------
03/05/01 | JL Schwing	| 1.39: Implement -e randombinddnfromfile=filename.
---------+--------------+------------------------------------------------------
04/05/01 | JL Schwing	| 1.40: Implement -e bindonly.
---------+--------------+------------------------------------------------------
*/

#include <stdio.h>	/* printf(), etc... */
#include <string.h>	/* strerror(), etc... */
#include <stdlib.h>	/* exit(), etc... */
#include <ctype.h>	/* isascii(), etc... */
#include <errno.h>	/* errno, etc... */			/*JLS 06-03-00*/
#include <lber.h>	/* ldap C-API BER declarations */
#include <ldap.h>	/* ldap C-API declarations */
#ifndef _WIN32							/*JLS 29-11-00*/
#include <unistd.h>	/* close(), etc... */
#include <pthread.h>	/* pthreads(), etc... */
#include <signal.h>	/* sigfillset(), etc... */
#endif								/*JLS 29-11-00*/

#include "port.h"	/* Portability definitions */		/*JLS 29-11-00*/
#include "ldclt.h"	/* This tool's include file */
#include "utils.h"	/* Utilities functions */		/*JLS 14-11-00*/
#include "scalab01.h"	/* Scalab01 specific */			/*JLS 12-01-01*/














						/* New */	/*JLS 15-03-01*/
/* ****************************************************************************
	FUNCTION :	selectRandomAttrList
	PURPOSE :	Select a random attr list.
	INPUT :		tttctx	= this thread context
	OUTPUT :	None.
	RETURN :	The random list.
	DESCRIPTION :
 *****************************************************************************/
char **
selectRandomAttrList (
	thread_context	*tttctx)
{
  tttctx->attrlist[0] = mctx.attrlist[rndlim(0,mctx.attrlistNb-1)];
  return (tttctx->attrlist);
}





/* ****************************************************************************
	FUNCTION :	randomString
	PURPOSE :	Return a random string, of length nbDigits.
			The string is returned in tttctx->buf2.
	INPUT :		tttctx	 = thread context.
			nbDigits = number of digits required.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int 
randomString (
	thread_context	*tttctx,
	int		 nbDigits)
{
  rndstr (tttctx->buf2, nbDigits);				/*JLS 14-11-00*/
  return (0);
}







						/* New */	/*JLS 28-03-01*/
/* ****************************************************************************
	FUNCTION :	incrementCommonCounterObject
	PURPOSE :	Purpose of the fct
	INPUT :		tttctx	= thread context
			field	= field to process
	OUTPUT :	None.
	RETURN :	-1 if error or end of loop (no_loop), new value else.
	DESCRIPTION :
 *****************************************************************************/
int
incrementCommonCounterObject (
	thread_context	*tttctx,
	vers_field	*field)
{
  int	 ret;	/* Return value */
  int	 val;	/* New value */

  /*
   * Get mutex
   */
  if ((ret = ldclt_mutex_lock (&(field->cnt_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(field->cnt_mutex), error=%d (%s)\n",
			mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Compute next value
   */
  switch (field->how)
  {
    case HOW_INCR_FROM_FILE:
    case HOW_INCR_NB:
	if (field->cnt <= field->high)	/* Limit not reached */
	{
	  val = field->cnt;
	  field->cnt++;
	}
	else
	{
	  val        = field->low;
	  field->cnt = field->low + 1;
	}
	break;
    case HOW_INCR_FROM_FILE_NL:
    case HOW_INCR_NB_NOLOOP:
	if (field->cnt <= field->high)	/* Limit not reached */
	{
	  val = field->cnt;
	  field->cnt++;
	}
	else
	  val = -1;	/* Exit thread */
	break;
    default:
	printf ("ldclt[%d]: %s: Illegal how=%d in incrementCommonCounterObject()\n",
			mctx.pid, tttctx->thrdId, field->how);
	val = -1;
	break;
  }

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(field->cnt_mutex))) != 0)
  {
    fprintf(stderr,"ldclt[%d]: %s: cannot mutex_unlock(field->cnt_mutex), error=%d (%s)\n",
			mctx.pid, tttctx->thrdId, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Maybe a message to print ?
   */
  if (val < 0)
    printf ("ldclt[%d]: %s: Hit top incrementeal value\n", mctx.pid, tttctx->thrdId);

  return (val);
}






						/* New */	/*JLS 14-03-01*/
/* ****************************************************************************
	FUNCTION :	incrementCommonCounter
	PURPOSE :	Purpose of the fct
	INPUT :		tttctx	= thread context
	OUTPUT :	None.
	RETURN :	-1 if error or end of loop (no_loop), new value else.
	DESCRIPTION :
 *****************************************************************************/
int
incrementCommonCounter (
	thread_context	*tttctx)
{
  int	 ret;	/* Return value */
  int	 val;	/* New value */

  /*
   * Get mutex
   */
  if ((ret = ldclt_mutex_lock (&(mctx.lastVal_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_lock(lastVal_mutex), error=%d (%s)\n",
			mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Compute next value
   */
  if ((mctx.mode & NOLOOP) && (mctx.lastVal == mctx.randomHigh))
    val = -1;
  else
  {
    mctx.lastVal++;
    if (mctx.lastVal > mctx.randomHigh)
    {
      if (mctx.mode & NOLOOP)
	val = -1;
      else
	mctx.lastVal = mctx.randomLow;
    }
    val = mctx.lastVal;
  }

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(mctx.lastVal_mutex))) != 0)
  {
    fprintf(stderr,"ldclt[%d]: T%03d: cannot mutex_unlock(lastVal_mutex), error=%d (%s)\n",
			mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Maybe a message to print ?
   */
  if (val < 0)
    printf ("ldclt[%d]: T%03d: Hit top incrementeal value\n", mctx.pid, tttctx->thrdNum);

  return (val);
}





/* ****************************************************************************
	FUNCTION :	incrementNbOpers
	PURPOSE :	Increment the counters tttctx->nbOpers and
			tttctx->totOpers of the given thread.
	INPUT :		tttctx	= thread context.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int 
incrementNbOpers (
	thread_context	*tttctx)
{
  int	 ret;	/* Return value */

  /*
   * Get mutex
   */
  if ((ret = ldclt_mutex_lock (&(tttctx->nbOpers_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_lock(), error=%d (%s)\n", 
			mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Increment counter
   */
  tttctx->nbOpers++;

  /*
   * Free mutex
   */
  if ((ret = ldclt_mutex_unlock (&(tttctx->nbOpers_mutex))) != 0)
  {
    fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_unlock(), error=%d (%s)\n", 
			mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Increment total and check if max value reached
   */
   tttctx->totOpers++;
   if(tttctx->totalReq > -1) {
     if (tttctx->totOpers >= tttctx->totalReq) {
       if (setThreadStatus(tttctx, MUST_SHUTDOWN) < 0) {
         tttctx->status = DEAD;   /* Force thread to die! */
       }
     }
   }

  return (0);
}







/* ****************************************************************************
	FUNCTION :	ignoreError
	PURPOSE :	Returns true or false depending on the given error
			should be ignored or not (option -I).
			We will sleep() if an error about server down is to be
			ignored.
	INPUT :		err	= error number
	OUTPUT :	None.
	RETURN :	1 if should be ignored, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int 
ignoreError (
	int	 err)
{
  int	 i;
  for (i=0 ; i<mctx.ignErrNb ; i++)
    if (mctx.ignErr[i] == err)
    {								/*JLS 14-03-01*/
      if ((!(mctx.mode & DONT_SLEEP_DOWN)) &&			/*JLS 14-03-01*/
	  ((err == LDAP_SERVER_DOWN) ||				/*JLS 14-03-01*/
	   (err == LDAP_CONNECT_ERROR)))			/*JLS 14-03-01*/
	ldclt_sleep (1);					/*JLS 14-03-01*/
      return (1);
    }								/*JLS 14-03-01*/
  return (0);
}








/* ****************************************************************************
	FUNCTION :	addErrorStat
	PURPOSE :	Add the given error number to the statistics.
	INPUT :		err	= error number
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int 
addErrorStat (
	int	 err)
{
  int	 ret;	/* Return value */

  /*
   * Get mutex
   */
  if ((ret = ldclt_mutex_lock (&(mctx.errors_mutex))) != 0)
  {
    fprintf (stderr, 
		"ldclt[%d]: Cannot mutex_lock(errors_mutex), error=%d (%s)\n", 
		mctx.pid, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Update the counters
   */
  if ((err <= 0) || (err >= MAX_ERROR_NB))
  {
    fprintf (stderr, "ldclt[%d]: Illegal error number %d\n", mctx.pid, err);
    fflush (stderr);
    mctx.errorsBad++;
  }
  else
    mctx.errors[err]++;

  /*
   * Release the mutex
   */
  if ((ret = ldclt_mutex_unlock (&(mctx.errors_mutex))) != 0)
  {
    fprintf (stderr,
		"ldclt[%d]: Cannot mutex_unlock(errors_mutex), error=%d (%s)\n",
		mctx.pid, ret, strerror (ret));
    fflush (stderr);
    return (-1);
  }

  /*
   * Maybe we should ignore this error ?
   */
  if (!(ignoreError (err)))
  {
    /*
     * Ok, we should not ignore this error...
     * Maybe the limit is reached ?
     */
    if ((err <= 0) || (err >= MAX_ERROR_NB))
    {
      if (mctx.errorsBad > mctx.maxErrors)
      {
	printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
	(void) printGlobalStatistics();				/*JLS 25-08-00*/
	fflush (stdout);
	ldclt_sleep (5);
	ldcltExit (EXIT_MAX_ERRORS);				/*JLS 25-08-00*/
      }
    }
    else
      if (mctx.errors[err] > mctx.maxErrors)
      {
	printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
	(void) printGlobalStatistics();				/*JLS 25-08-00*/
	fflush (stdout);
	ldclt_sleep (5);
	ldcltExit (EXIT_MAX_ERRORS);				/*JLS 25-08-00*/
      }
  }

  /*
   * Normal end
   */
  return (0);
}






/* ****************************************************************************
	FUNCTION :	msgIdAdd
	PURPOSE :	Add a new message id to the pending ones.
	INPUT :		tttctx	= thread's context.
			msgid	= message id.
			str	= free string.
			dn	= dn of the entry
			attribs	= attributes
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int 
msgIdAdd (
	thread_context	 *tttctx,
	int		  msgid,
	char		 *str,
	char		 *dn,
	LDAPMod		**attribs)
{
  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: T%03d: msgIdAdd (%d, %s)\n", mctx.pid, tttctx->thrdNum, msgid, str);

  /*
   * Add the new cell
   */
  if (tttctx->firstMsgId == NULL)
  {
    tttctx->firstMsgId = (msgid_cell *) malloc (sizeof (msgid_cell));
    if (tttctx->firstMsgId == NULL)				/*JLS 06-03-00*/
    {								/*JLS 06-03-00*/
      printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->firstMsgId), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, errno, strerror (errno));
      return (-1);						/*JLS 06-03-00*/
    }								/*JLS 06-03-00*/
    tttctx->lastMsgId  = tttctx->firstMsgId;
  }
  else
  {
    tttctx->lastMsgId->next = (msgid_cell *) malloc (sizeof (msgid_cell));
    if (tttctx->lastMsgId->next == NULL)			/*JLS 06-03-00*/
    {								/*JLS 06-03-00*/
      printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->lastMsgId->next), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, errno, strerror (errno));
      return (-1);						/*JLS 06-03-00*/
    }								/*JLS 06-03-00*/
    tttctx->lastMsgId       = tttctx->lastMsgId->next;
  }

  /*
   * Memorize the information
   */
  tttctx->lastMsgId->next  = NULL;
  tttctx->lastMsgId->msgid = msgid;
  strcpy (tttctx->lastMsgId->str, str);
  strcpy (tttctx->lastMsgId->dn, dn);
  tttctx->lastMsgId->attribs = attribs;

  return (0);
}







/* ****************************************************************************
	FUNCTION :	msgIdAttribs
	PURPOSE :	Found the requested message id in the pending list.
	INPUT :		tttctx	= thread's context
			msgid	= message id
	OUTPUT :	None
	RETURN :	The associated attributes, or NULL.
	DESCRIPTION :
 *****************************************************************************/
LDAPMod **
msgIdAttribs (
	thread_context	*tttctx,
	int		 msgid)
{
  msgid_cell	*pt;

  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: T%03d: msgIdAttribs (%d)\n", mctx.pid, tttctx->thrdNum, msgid);

  for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
    if (pt->msgid == msgid)
      return (pt->attribs); 

  return (NULL);
}








/* ****************************************************************************
	FUNCTION :	msgIdDN
	PURPOSE :	Found the requested message id in the pending list.
	INPUT :		tttctx	= thread's context
			msgid	= message id
	OUTPUT :	None
	RETURN :	The associated DN, or NULL.
	DESCRIPTION :
 *****************************************************************************/
char *
msgIdDN (
	thread_context	*tttctx,
	int		 msgid)
{
  msgid_cell	*pt;

  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: T%03d: msgIdDN (%d)\n", mctx.pid, tttctx->thrdNum, msgid);

  for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
    if (pt->msgid == msgid)
      return (pt->dn); 

  return (NULL);
}








/* ****************************************************************************
	FUNCTION :	msgIdStr
	PURPOSE :	Found the requested message id in the pending list.
	INPUT :		tttctx	= thread's context
			msgid	= message id
	OUTPUT :	None
	RETURN :	The associated str, or an error message string.
	DESCRIPTION :
 *****************************************************************************/
char *
msgIdStr (
	thread_context	*tttctx,
	int		 msgid)
{
  msgid_cell	*pt;

  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: T%03d: msgIdStr (%d)\n", mctx.pid, tttctx->thrdNum, msgid);

  for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
    if (pt->msgid == msgid)
      return (pt->str); 

  return ("Error: msgid not found");
}







/* ****************************************************************************
	FUNCTION :	msgIdDel
	PURPOSE :	Delete a message id from the pending ones.
	INPUT :		tttctx	= thread's context
			msgid	= message id.
			freeAttr= true or false depending on freing the attribs
	OUTPUT :	None.
	RETURN :	-1 if not found, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int 
msgIdDel (
	thread_context	*tttctx,
	int		 msgid,
	int		 freeAttr)
{
  msgid_cell	*pt;		/* For the loop */
  msgid_cell	*ptToFree;	/* The cell to free */

  if (mctx.mode & VERY_VERBOSE)
    printf ("ldclt[%d]: T%03d: msgIdDel (%d)\n", mctx.pid, tttctx->thrdNum, msgid);

  /*
   * Make sure there is a list !
   */
  if (tttctx->firstMsgId != NULL)
  {
    /*
     * Maybe it is the first one ?
     */
    if (tttctx->firstMsgId->msgid == msgid)
    {
      ptToFree           = tttctx->firstMsgId;
      tttctx->firstMsgId = tttctx->firstMsgId->next;
      if (tttctx->firstMsgId == NULL)
	tttctx->lastMsgId = NULL;
      free (ptToFree);
      return (0);
    }

    /*
     * Let's go through the whole list
     */
    for (pt = tttctx->firstMsgId ; pt->next != NULL ; pt = pt->next)
      if (pt->next->msgid == msgid)
      {
	/*
	 * Be carrefull if it is the last element of the list
	 */
	if (pt->next->next == NULL)
	  tttctx->lastMsgId = pt;
	ptToFree = pt->next;
	pt->next = ptToFree->next;
	if (freeAttr)
	  if (freeAttrib (ptToFree->attribs) < 0)
	    return (-1);

	/*
	 * Free the pointer itself
	 */
	free (ptToFree);
	return (0);
      }
  }

  /*
   * Not found
   */
  printf ("ldclt[%d]: T%03d: message %d not found.\n", mctx.pid, tttctx->thrdNum, msgid);
  fflush (stdout);
  return (-1);
}








					/* New function */	/*JLS 17-11-00*/
/* ****************************************************************************
	FUNCTION :	getThreadStatus
	PURPOSE :	Get the value of a given thread's status.
	INPUT :		tttctx	= thread context
	OUTPUT :	status	= the thread's status
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
getThreadStatus (
	thread_context	*tttctx,
	int		*status)
{
  int	 ret;	/* Return code */

  if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
  {
    fprintf (stderr, 
		"ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n", 
		mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }
  *status = tttctx->status;
  if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
  {
    fprintf (stderr,
		"ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }

  return (0);
}





					/* New function */	/*JLS 17-11-00*/
/* ****************************************************************************
	FUNCTION :	setThreadStatus
	PURPOSE :	Set the value of a given thread's status.
	INPUT :		tttctx	= thread context
			status	= new status
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
setThreadStatus (
	thread_context	*tttctx,
	int		 status)
{
  int	 ret;	/* Return code */

  if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
  {
    fprintf (stderr, 
		"ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n", 
		mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }
  tttctx->status = status;
  if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
  {
    fprintf (stderr,
		"ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, ret, strerror (ret));
    fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
    fflush (stderr);
    return (-1);
  }

  return (0);
}













/* ****************************************************************************
	FUNCTION :	threadMain
	PURPOSE :	This function is the main function of the client threads
			part of this tool. 
	INPUT :		arg	= this thread's thread_context
	OUTPUT :	None.
	RETURN :	None.
	DESCRIPTION :
 *****************************************************************************/
void *
threadMain (
	void	*arg)
{
  thread_context	*tttctx;	/* This thread's context */
  int			 go = 1;	/* Thread must continue */
  int			 status;	/* Thread's status */	/*JLS 17-11-00*/

  /*
   * Initialization
   */
  tttctx = (thread_context *) arg;
  if (setThreadStatus (tttctx, CREATED) < 0)			/*JLS 17-11-00*/
  {								/*JLS 17-11-00*/
    tttctx->status = DEAD;					/*JLS 17-11-00*/
    return NULL;							/*JLS 17-11-00*/
  }								/*JLS 17-11-00*/
  tttctx->asyncHit   = 0;
  tttctx->binded     = 0;
  tttctx->fd         = -1;
  tttctx->lastVal    = mctx.randomLow-1;
  tttctx->ldapCtx    = NULL;
  tttctx->matcheddnp = NULL;					/*JLS 15-12-00*/
  tttctx->nbOpers    = 0;
  tttctx->totOpers   = 0;
  tttctx->pendingNb  = 0;
  tttctx->firstMsgId = NULL;
  tttctx->lastMsgId  = NULL;

  /*
   * Don't forget the buffers !!
   * This should save time while redoing random values
   */
  if ((mctx.mode & NEED_FILTER) || (mctx.mod2 & M2_GENLDIF))	/*JLS 19-03-01*/
  {
    if (mctx.mod2 & M2_RDN_VALUE)				/*JLS 23-03-01*/
      tttctx->bufFilter = (char *) malloc (MAX_FILTER);		/*JLS 23-03-01*/
    else							/*JLS 23-03-01*/
    {								/*JLS 23-03-01*/
      /*
       * Variable filter ?
       */
      tttctx->bufFilter = (char *) malloc (strlen (mctx.filter) + 1);
      if (tttctx->bufFilter == NULL)				/*JLS 06-03-00*/
      {								/*JLS 06-03-00*/
	printf ("ldclt[%d]: %s: cannot malloc(tttctx->bufFilter), error=%d (%s)\n",
		mctx.pid, tttctx->thrdId, errno, strerror (errno));
	ldcltExit (EXIT_INIT);					/*JLS 18-12-00*/
      }								/*JLS 06-03-00*/
      if (!(mctx.mode & (RANDOM | INCREMENTAL)))
	strcpy (tttctx->bufFilter, mctx.filter);
      else
      {
	tttctx->startRandom = strlen (mctx.randomHead);
	strcpy (tttctx->bufFilter, mctx.randomHead);
	strcpy (&(tttctx->bufFilter[tttctx->startRandom+mctx.randomNbDigit]),
			mctx.randomTail);
	if (mctx.mode & VERY_VERBOSE)
	{
	  printf ("ldclt[%d]: %s: startRandom = %d\n", 
		mctx.pid, tttctx->thrdId, tttctx->startRandom);
	  printf ("ldclt[%d]: %s: randomHead = \"%s\", randomTail = \"%s\"\n",
		mctx.pid, tttctx->thrdId, mctx.randomHead, mctx.randomTail);
	}
      }
    }								/*JLS 23-03-01*/

    /*
     * Variable base DN ?
     */
    tttctx->bufBaseDN = (char *) malloc (strlen (mctx.baseDN) + 1);
    if (tttctx->bufBaseDN == NULL)				/*JLS 06-03-00*/
    {								/*JLS 06-03-00*/
      printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBaseDN), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, errno, strerror (errno));
      ldcltExit (EXIT_INIT);					/*JLS 18-12-00*/
    }								/*JLS 06-03-00*/
    if (!(mctx.mode & RANDOM_BASE))
      strcpy (tttctx->bufBaseDN, mctx.baseDN);
    else
    {
      tttctx->startBaseDN = strlen (mctx.baseDNHead);
      strcpy (tttctx->bufBaseDN, mctx.baseDNHead);
      strcpy (&(tttctx->bufBaseDN[tttctx->startBaseDN+mctx.baseDNNbDigit]),
			mctx.baseDNTail);
    }

    /*
     * Variable bind DN ?
     * Do not forget the random bind password below that is activated
     * at the same time as the random bind DN.
     */
    if (mctx.bindDN != NULL)					/*JLS 05-03-01*/
    {								/*JLS 05-03-01*/
      tttctx->bufBindDN = (char *) malloc (strlen (mctx.bindDN) + 1);
      if (tttctx->bufBindDN == NULL)
      {
	printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBindDN), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, errno, strerror (errno));
	ldcltExit (EXIT_INIT);
      }
      if (!(mctx.mode & RANDOM_BINDDN))
	strcpy (tttctx->bufBindDN, mctx.bindDN);
      else
      {
	tttctx->startBindDN = strlen (mctx.bindDNHead);
	strcpy (tttctx->bufBindDN, mctx.bindDNHead);
	strcpy (&(tttctx->bufBindDN[tttctx->startBindDN+mctx.bindDNNbDigit]),
			mctx.bindDNTail);
      }
    }								/*JLS 05-03-01*/

    /*
     * Variable bind password ?
     * Remember that the random bind password feature is activated
     * by the same option as the random bind DN, but has here its own
     * code section for the ease of coding.
     */
    if (mctx.passwd != NULL)					/*JLS 05-03-01*/
    {								/*JLS 05-03-01*/
      tttctx->bufPasswd = (char *) malloc (strlen (mctx.passwd) + 1);
      if (tttctx->bufPasswd == NULL)
      {
	printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufPasswd), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, errno, strerror (errno));
	ldcltExit (EXIT_INIT);
      }
      if (!(mctx.mode & RANDOM_BINDDN))
	strcpy (tttctx->bufPasswd, mctx.passwd);
      else
      {
	tttctx->startPasswd = strlen (mctx.passwdHead);
	strcpy (tttctx->bufPasswd, mctx.passwdHead);
	strcpy (&(tttctx->bufPasswd[tttctx->startPasswd+mctx.passwdNbDigit]),
			mctx.passwdTail);
      }
    }
  }								/*JLS 05-03-01*/

  /*
   * Bind DN from a file ?
   * The trick (mctx.passwd = "foo bar"; ) is needed to
   * simplify the code, because in many places we check
   * if mctx.passwd exist before sending password.
   */
  if (mctx.mod2 & M2_RNDBINDFILE)				/*JLS 03-05-01*/
  {								/*JLS 03-05-01*/
    tttctx->bufBindDN = (char *) malloc (MAX_DN_LENGTH);	/*JLS 03-05-01*/
    tttctx->bufPasswd = (char *) malloc (MAX_DN_LENGTH);	/*JLS 03-05-01*/
    mctx.passwd = "foo bar"; /* trick... */			/*JLS 03-05-01*/
  }								/*JLS 03-05-01*/

  /*
   * Initiates the attribute replace buffers
   */
  if (mctx.mode & ATTR_REPLACE)			/* New */	/*JLS 21-11-00*/
  {
    tttctx->bufAttrpl = (char *) malloc (strlen (mctx.attrpl) + 1);
    if (tttctx->bufAttrpl == NULL)
    {
      printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufAttrpl), error=%d (%s)\n",
		mctx.pid, tttctx->thrdNum, errno, strerror (errno));
      ldcltExit (EXIT_INIT);					/*JLS 18-12-00*/
    }
    tttctx->startAttrpl = strlen (mctx.attrplHead);
    strcpy (tttctx->bufAttrpl, mctx.attrplHead);
    strcpy (&(tttctx->bufAttrpl[tttctx->startAttrpl+mctx.attrplNbDigit]),
			mctx.attrplTail);
  }

  /*
   * We are ready to go !
   */
  status = RUNNING;						/*JLS 17-11-00*/
  if (setThreadStatus (tttctx, RUNNING) < 0)			/*JLS 17-11-00*/
    status = DEAD;						/*JLS 17-11-00*/

  /*
   * Let's go !
   */
  while (go && (status != DEAD) && (status != MUST_SHUTDOWN))	/*JLS 17-11-00*/
  {
    if (mctx.waitSec > 0)
    {								/*JLS 17-11-00*/
      ldclt_sleep (mctx.waitSec);

      /*
       * Maybe we should shutdown ?
       */
      if (getThreadStatus (tttctx, &status) < 0)		/*JLS 17-11-00*/
	break;							/*JLS 17-11-00*/
      if (status == MUST_SHUTDOWN)				/*JLS 17-11-00*/
	break;							/*JLS 17-11-00*/
    }								/*JLS 17-11-00*/

    /*
     * Do a LDAP request
     */
    if (tttctx->mode & ADD_ENTRIES)
      if (doAddEntry (tttctx) < 0)
      {
	go = 0;
	continue;
      }
    if (tttctx->mode & ATTR_REPLACE)				/*JLS 21-11-00*/
      if (doAttrReplace (tttctx) < 0)				/*JLS 21-11-00*/
      {								/*JLS 21-11-00*/
	go = 0;							/*JLS 21-11-00*/
	continue;						/*JLS 21-11-00*/
      }								/*JLS 21-11-00*/
    if (tttctx->mode & DELETE_ENTRIES)
      if (doDeleteEntry (tttctx) < 0)
      {
	go = 0;
	continue;
      }
    if (mctx.mod2 & M2_BINDONLY)				/*JLS 04-05-01*/
      if (doBindOnly (tttctx) < 0)				/*JLS 04-05-01*/
      {								/*JLS 04-05-01*/
	go = 0;							/*JLS 04-05-01*/
	continue;						/*JLS 04-05-01*/
      }								/*JLS 04-05-01*/
    if (tttctx->mode & EXACT_SEARCH)
      if (doExactSearch (tttctx) < 0)
      {
	go = 0;
	continue;
      }
    if (tttctx->mode & RENAME_ENTRIES)
      if (doRename (tttctx) < 0)
      {
	go = 0;
	continue;
      }

    /*
     * Maybe a specific scenario ?
     */
    if (tttctx->mode & SCALAB01)				/*JLS 08-01-01*/
      if (doScalab01 (tttctx) < 0)				/*JLS 08-01-01*/
      {								/*JLS 08-01-01*/
	go = 0;							/*JLS 08-01-01*/
	continue;						/*JLS 08-01-01*/
      }								/*JLS 08-01-01*/

    /*
     * Maybe genldif mode ?
     */
    if (mctx.mod2 & M2_GENLDIF)					/*JLS 19-03-01*/
      if (doGenldif (tttctx) < 0)				/*JLS 19-03-01*/
      {								/*JLS 19-03-01*/
	ldclt_flush_genldif();					/*JLS 02-04-01*/
	go = 0;							/*JLS 19-03-01*/
	continue;						/*JLS 19-03-01*/
      }								/*JLS 19-03-01*/

    /*
     * Check the thread's status
     */
    if (getThreadStatus (tttctx, &status) < 0)			/*JLS 17-11-00*/
      break;							/*JLS 17-11-00*/
  }

  /*
   * End of thread
   */
  /* [156984] once setting "DEAD", nothing should be done in the context */
  /* moved the dead message above setThreadStatus(DEAD) */
  printf ("ldclt[%d]: T%03d: thread is dead.\n", mctx.pid, tttctx->thrdNum);
  fflush (stdout);
  if (setThreadStatus (tttctx, DEAD) < 0)			/*JLS 17-11-00*/
  {								/*JLS 17-11-00*/
    ldclt_sleep (1);						/*JLS 17-11-00*/
    tttctx->status = DEAD; /* Force it !!! */			/*JLS 17-11-00*/
  }								/*JLS 17-11-00*/
  return (arg);
}


/* End of file */


--- NEW FILE utils.c ---
#ident "ldclt @(#)utils.c	1.4 01/01/11"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		utils.c
	AUTHOR :        Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		14 November 2000
	DESCRIPTION :	
			This file contains the utilities functions that will be 
			used as well by ldclt and by the genldif command, e.g. 
			the random generator functions, etc...
			The main target/reason for creating this file is to be 
			able to easely separate these functions from ldclt's 
			framework and data structures, and thus to provide a 
			kind of library suitable for any command.
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| 1.2 : Port on AIX.
---------+--------------+------------------------------------------------------
16/11/00 | JL Schwing	| 1.3 : lint cleanup.
---------+--------------+------------------------------------------------------
11/01/01 | JL Schwing	| 1.4 : Add new function rndlim().
---------+--------------+------------------------------------------------------
*/

#include "utils.h"	/* Basic definitions for this file */
#include <stdio.h>	/* sprintf(), etc... */
#include <stdlib.h>	/* lrand48(), etc... */
#include <ctype.h>	/* isascii(), etc... */			/*JLS 16-11-00*/
#include <string.h>	/* strerror(), etc... */		/*JLS 14-11-00*/


/*
 * Some global variables...
 */
#ifdef AIX
pthread_mutex_t	 ldcltrand48_mutex;	/* ldcltrand48() */	/*JLS 14-11-00*/
#endif


#ifdef AIX					/* New */	/*JLS 14-11-00*/
/* ****************************************************************************
	FUNCTION :	ldcltrand48
	PURPOSE :	Implement a thread-save version of lrand48()
	INPUT :		None.
	OUTPUT :	None.
	RETURN :	A random value.
	DESCRIPTION :
 *****************************************************************************/
long int
ldcltrand48 (void)
{
  long int	 val;
  int		 ret;

  if ((ret = pthread_mutex_lock (&ldcltrand48_mutex)) != 0)
  {
    fprintf (stderr, 
	"Cannot pthread_mutex_lock(ldcltrand48_mutex), error=%d (%s)\n", 
	ret, strerror (ret));
    fflush (stderr);
    ldcltExit (99);
  }
  val = lrand48();
  if ((ret = pthread_mutex_unlock (&ldcltrand48_mutex)) != 0)
  {
    fprintf (stderr,
	"Cannot pthread_mutex_unlock(ldcltrand48_mutex), error=%d (%s)\n",
	ret, strerror (ret));
    fflush (stderr);
    ldcltExit (99);
  }

  return (val);
}

#else  /* AIX */
#define ldcltrand48()	lrand48()
#endif /* AIX */


/* ****************************************************************************
	FUNCTION :	utilsInit
	PURPOSE :	Initiates the utilities functions.
	INPUT :		None.
	OUTPUT :	None.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int
utilsInit (void)
{
#ifdef AIX							/*JLS 14-11-00*/
  int	 ret;							/*JLS 14-11-00*/

  /*
   * Initiate the mutex that protect ldcltrand48()
   */
  if ((ret = pthread_mutex_init(&ldcltrand48_mutex, NULL)) != 0)/*JLS 14-11-00*/
  {								/*JLS 14-11-00*/
    fprintf (stderr, "ldclt: %s\n", strerror (ret));		/*JLS 14-11-00*/
    fprintf (stderr, 						/*JLS 14-11-00*/
		"Error: cannot initiate ldcltrand48_mutex\n");	/*JLS 14-11-00*/
    fflush (stderr);						/*JLS 14-11-00*/
    return (-1);						/*JLS 14-11-00*/
  }								/*JLS 14-11-00*/
#endif								/*JLS 14-11-00*/

  /*
   * No error
   */
  return (0);
}









/* ****************************************************************************
	FUNCTION :	rndlim
	PURPOSE :	Returns a random number between the given limits.
	INPUT :		low	= low limit
			high	= high limit
	OUTPUT :	None.
	RETURN :	The random value.
	DESCRIPTION :
 *****************************************************************************/
int
rndlim (
	int	 low,
	int	 high)
{
  return (low + ldcltrand48() % (high-low+1));
}









/* ****************************************************************************
	FUNCTION :	rnd
	PURPOSE :	Creates a random number string between the given
			arguments. The string is returned in the buffer.
	INPUT :		low	= low limit
			high	= high limit
			ndigits	= number of digits
	OUTPUT :	buf	= buffer to write the random string. Note that
				  it is generated with fixed number of digits,
				  completed with leading '0'.
	RETURN :	None.
	DESCRIPTION :
 *****************************************************************************/
void
rnd (
	char	*buf,
	int	 low,
	int	 high,
	int	 ndigits)
{
  sprintf (buf, "%0*d", ndigits,
			(int)(low + (ldcltrand48() % (high-low+1))));	/*JLS 14-11-00*/
}






/* ****************************************************************************
	FUNCTION :	rndstr
	PURPOSE :	Return a random string, of length ndigits. The string 
			is returned in the buf.
	INPUT :		ndigits	= number of digits required.
	OUTPUT :	buf	= the buf must be long enough to contain the
				  requested string.
	RETURN :	None.
	DESCRIPTION :
 *****************************************************************************/
void 
rndstr (
	char	*buf,
	int	 ndigits)
{
  unsigned int         rndNum;        /* The random value */
  int                 charNum;        /* Random char in buf */
  int                 byteNum;        /* Byte in rndNum */
  char                 newChar;        /* The new byte as a char */
  char                *rndArray;        /* To cast the rndNum into chars */

  charNum  = 0;
  byteNum  = 4;
  rndArray = (char *)(&rndNum);
  while (charNum < ndigits)
  {
    /*
     * Maybe we should generate a new random number ?
     */
    if (byteNum == 4)
    {
      rndNum  = ldcltrand48();                                        /*JLS 14-11-00*/
      byteNum = 0;
    }

    /*
     * Is it a valid char ?
     */
    newChar = rndArray[byteNum];

    /*
     * The last char must not be a '\' nor a space.
     */
    if (!(((charNum+1) == ndigits) && 
         ((newChar == '\\') || (newChar == ' '))))
    {
      /*
       * First, there are some special characters that have a meaning for
       * LDAP, and thus that must be quoted. What LDAP's rfc1779 means by
       * "to quote" may be translated by "to antislash"
       * Note: we do not check the \ because in this way, it leads to randomly
       *       quote some valid characters.
       */
      if ((newChar == '=') || (newChar == ';') || (newChar == ',') ||
          (newChar == '+') || (newChar == '"') || (newChar == '<') ||
          (newChar == '>') || (newChar == '#'))
      {
        /*
         * Ensure that the previous char is *not* a \ otherwise
         * it will result in a \\, rather than a \,
         * If it is the case, add one more \ to have \\\,
         */
        if ((charNum > 0) && (buf[charNum-1] == '\\'))
        {
          if ((charNum+3) < ndigits)
          {
            buf[charNum++] = '\\';
            buf[charNum++] = '\\';
            buf[charNum++] = newChar;
          }
        }
        else
        {
          if ((charNum+2) < ndigits)
          {
            buf[charNum++] = '\\';
            buf[charNum++] = newChar;
          }
        }
      }
      else
      {
        /*
         * Maybe strict ascii required ?
         */
        if (1)
        {
          if (isascii (newChar) && !iscntrl(newChar))
            buf[charNum++] = newChar;
        }
        else
        {
          if (((newChar >= 0x30) && (newChar <= 0x7a)) ||
              ((newChar >= 0xc0) && (newChar <= 0xf6)))
            buf[charNum++] = newChar;
        }
      }
    }

    /*
     * Next byte of the random value.
     */
    byteNum++;
  }

  /*
   * End of function
   */
  buf[charNum] = '\0';
}







/* End of file */


--- NEW FILE utils.h ---
#ident "ldclt @(#)utils.h	1.3 01/01/11"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
	FILE :		utils.h
	AUTHOR :        Jean-Luc SCHWING
	VERSION :       1.0
	DATE :		14 November 2000
	DESCRIPTION :	
			This files contians the prototypes and other 
			definitions related to utils.c, utilities functions 
			that will be used as well by ldclt and by the genldif 
			command.
	LOCAL :		None.
	HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
14/11/00 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
16/11/00 | JL Schwing	| 1.2 : Fix typo.
---------+--------------+------------------------------------------------------
11/01/01 | JL Schwing	| 1.3 : Add new function rndlim().
---------+--------------+------------------------------------------------------
*/




/*
 * Functions exported by utils.c
 */
extern void	 rnd       (char *buf, int low, int high, int ndigits);
extern int	 rndlim    (int low, int high);
extern void	 rndstr    (char *buf, int ndigits);
extern int	 utilsInit (void);


/* End of file */


--- NEW FILE version.c ---
char *ldcltVersion="4.23";


--- NEW FILE workarounds.c ---
#ident "ldclt @(#)workarounds.c	1.5 00/12/01"

/** 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) 2006 Red Hat, Inc.
 * All rights reserved.
 * END COPYRIGHT BLOCK **/

/*
        FILE :		workarounds.c
        AUTHOR :        Jean-Luc SCHWING
        VERSION :       1.0
        DATE :		15 December 1998
        DESCRIPTION :	
			This file contains special work-arounds targetted to 
			fix, or work-around, the various bugs that may appear 
			in Solaris 2.7 libldap.
 	LOCAL :		None.
        HISTORY :
---------+--------------+------------------------------------------------------
dd/mm/yy | Author	| Comments
---------+--------------+------------------------------------------------------
15/12/98 | JL Schwing	| Creation
---------+--------------+------------------------------------------------------
19/09/00 | JL Schwing	| 1.2: Port on Netscape's libldap. This is realized in
			|   such a way that this library become the default
			|   way so a ifdef for Solaris will be used...
---------+--------------+------------------------------------------------------
16/11/00 | JL Schwing	| 1.3 : lint cleanup.
-----------------------------------------------------------------------------
29/11/00 | JL Schwing	| 1.4 : Port on NT 4.
---------+--------------+------------------------------------------------------
01/12/00 | JL Schwing	| 1.5 : Port on Linux.
---------+--------------+------------------------------------------------------
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	/* exit(), ... */			/*JLS 16-11-00*/
#include "lber.h"
#include "ldap.h"
#ifdef SOLARIS_LIBLDAP						/*JLS 19-09-00*/
#include "ldap-private.h"
#else								/*JLS 19-09-00*/
#ifndef _WIN32							/*JLS 01-12-00*/
#include <pthread.h>						/*JLS 01-12-00*/
#endif								/*JLS 01-12-00*/
#include "port.h"	/* Portability definitions */		/*JLS 29-11-00*/
#include "ldclt.h"						/*JLS 19-09-00*/
#endif								/*JLS 19-09-00*/




/* ****************************************************************************
	FUNCTION :	getFdFromLdapSession
	PURPOSE :	This function is a work-around for the bug 4197228
			that is not expected to be fixed soon...
	INPUT :		ld	= ldap session to process.
	OUTPUT :	fd	= the corresponding fd.
	RETURN :	-1 if error, 0 else.
	DESCRIPTION :
 *****************************************************************************/
int getFdFromLdapSession (
	LDAP	*ld,
	int	*fd)
{
#ifdef SOLARIS_LIBLDAP						/*JLS 19-09-00*/
  *fd = ld->ld_sb.sb_sd;
  return (0);
#else								/*JLS 19-09-00*/
  printf("Error : getFdFromLdapSession() not implemented...\n");/*JLS 19-09-00*/
  exit (EXIT_OTHER);						/*JLS 19-09-00*/
#endif								/*JLS 19-09-00*/
}


/* End of file */




More information about the Fedora-directory-commits mailing list