--- old/usr/src/cmd/cmd-inet/usr.lib/in.dhcpd/hash.c	2014-10-07 19:19:28.879532173 +0200
+++ /dev/null	2014-10-07 19:19:28.000000000 +0200
@@ -1,579 +0,0 @@
-/*
- * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
- * All rights reserved.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Copyright 1988, 1991 by Carnegie Mellon University
- *
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Carnegie Mellon University not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.
- *
- * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
- * IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- * THIS SOFTWARE.
- */
-
-/*
- * Generalized hash table ADT
- *
- * Provides multiple, dynamically-allocated, variable-sized hash tables on
- * various data and keys.
- *
- * This package attempts to follow some of the coding conventions suggested
- * by Bob Sidebotham and the AFS Clean Code Committee of the
- * Information Technology Center at Carnegie Mellon.
- *
- * Additions for per bucket locking, and configurable dynamic free of
- * unused entries.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/sysmacros.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <assert.h>
-#include <synch.h>
-#include "dhcpd.h"
-#include "hash.h"
-
-/*
- * Hash table size calculation routine.
- *
- * Estimate the size of a hash table based on the expected number of
- * entries, up to a maximum of HASHTABLESIZE.
- */
-static unsigned
-hashi_Hsize(unsigned hint)
-{
-	unsigned f;
-
-	if (hint == 0)				/* Default size. */
-		hint = HASHTABLESIZE;
-	else if (hint < 16)			/* Minimal size. */
-		hint = 16;
-
-	hint /= 4;
-	for (f = 2; f * f <= hint; f++) {	/* Find next largest prime. */
-		if (hint % f == 0) {
-			f = 1;
-			hint++;
-		}
-	}
-	return (MIN(HASHTABLESIZE, hint));
-}
-
-/*
- * Frees an entire linked list of bucket members (used in the
- * open hashing scheme).  Does nothing if the passed pointer is NULL.
- *
- * Returns B_FALSE and members which could not be freed in bucketptr, when
- * force variable is set to B_FALSE, and free_data routine indicates
- * free did not occur.
- */
-static boolean_t
-hashi_FreeMember(hash_member **bucketptr, boolean_t (*free_data)(),
-    boolean_t force)
-{
-	hash_member *prev, *next, *unfree = NULL;
-	boolean_t ret = B_TRUE;
-
-	if (bucketptr) {
-		for (prev = *bucketptr; prev; prev = next) {
-			next = prev->next;
-			prev->next = NULL;
-			if (free_data != NULL) {
-				if ((*free_data)(prev->data, force) ==
-				    B_FALSE) {
-					ret = B_FALSE;
-					prev->next = unfree;
-					unfree = prev;
-				} else {
-					free(prev);
-				}
-			} else
-				free(prev);
-		}
-		*bucketptr = unfree;
-	}
-	return (ret);
-}
-
-/*
- * Dynamic free initialization.
- */
-static void
-hashi_Dinit(hash_tbl *hashtable, hash_member *memberptr)
-{
-	(void) mutex_init(&memberptr->h_mtx, USYNC_THREAD, NULL);
-	memberptr->h_time = time(NULL) + hashtable->dfree_time;
-	memberptr->h_count = 1;
-}
-
-/*
- * Dynamic free reference count increment.
- */
-static void
-hashi_Dhold(hash_member *memberptr)
-{
-	(void) mutex_lock(&memberptr->h_mtx);
-	memberptr->h_count++;
-	(void) mutex_unlock(&memberptr->h_mtx);
-}
-
-/*
- * Dynamic free expired data. Return NULL if memberptr is successfully
- * dynamically freed, otherwise return memberptr.
- */
-static hash_member *
-hashi_Dfree(hash_member *memberptr, boolean_t (*free_data)())
-{
-	hash_member *next;
-
-	next = memberptr->next;
-	memberptr->next = NULL;
-	if (hashi_FreeMember(&memberptr, free_data, B_FALSE) == B_TRUE)
-		memberptr = NULL;
-	else
-		memberptr->next = next;
-	return (memberptr);
-}
-
-/*
- * Hash table initialization routine.
- *
- * This routine creates and intializes a hash table of size "tablesize"
- * entries.  Successful calls return a pointer to the hash table (which must
- * be passed to other hash routines to identify the hash table).  Failed
- * calls return NULL.
- */
-hash_tbl *
-hash_Init(unsigned tablesize, boolean_t (*dfree_data)(), time_t dtime,
-	boolean_t lck)
-{
-	hash_tbl *hashtblptr;
-	unsigned totalsize;
-	unsigned	i;
-
-	tablesize = hashi_Hsize(tablesize);
-
-	totalsize = sizeof (hash_tbl) + (sizeof (hash_bucket) *
-	    (tablesize - 1));
-
-	hashtblptr = (hash_tbl *)smalloc(totalsize);
-
-	hashtblptr->size = tablesize; /* Success! */
-	hashtblptr->bucketnum = 0;
-	hashtblptr->dfree_data = dfree_data;
-	hashtblptr->dfree_lck = lck;
-	hashtblptr->dfree_time = dtime;
-	hashtblptr->table = &hashtblptr->data[0];
-	for (i = 0; i < tablesize; i++) {
-		hashtblptr->table[i].table = hashtblptr;
-		if (lck == B_TRUE) {
-			(void) rwlock_init(&(hashtblptr->table[i].rwlock),
-			    USYNC_THREAD, NULL);
-		}
-	}
-
-	return (hashtblptr);		/* NULL if failure */
-}
-
-/*
- * Generic hash function to calculate a hash code from the given string.
- *
- * For each byte of the string, this function left-shifts the value in an
- * accumulator and then adds the byte into the accumulator.  The contents of
- * the accumulator is returned after the entire string has been processed.
- * It is assumed that this result will be used as the "hashcode" parameter in
- * calls to other functions in this package.  These functions automatically
- * adjust the hashcode for the size of each hashtable.
- *
- * This algorithm probably works best when the hash table size is a prime
- * number.
- *
- * Hopefully, this function is better than the previous one which returned
- * the sum of the squares of all the bytes.  I'm still open to other
- * suggestions for a default hash function.  The programmer is more than
- * welcome to supply his/her own hash function as that is one of the design
- * features of this package.
- */
-static unsigned
-hashi_HashFunction(unsigned char *string, unsigned len)
-{
-	unsigned accum;
-
-	/*
-	 * Special case: allow hash_Delete() to iterate over buckets.
-	 */
-	if (string == NULL)
-		return (len);
-
-	for (accum = 0; len != 0; len--) {
-		accum <<= 1;
-		accum += (unsigned)(*string++ & 0xFF);
-	}
-	return (accum);
-}
-
-/*
- * This routine re-initializes the hash table.  It frees all the allocated
- * memory and resets all bucket pointers to NULL. For the macro hash
- * table, the table will be reused. Other tables (with bucket locks)
- * will be destroyed.
- */
-void
-hash_Reset(hash_tbl *hashtable, boolean_t (*free_data)())
-{
-	hash_bucket	*bucketptr;
-	unsigned	i;
-
-	bucketptr = &((hashtable->table)[0]);
-	for (i = 0; i < hashtable->size; i++) {
-		if (hashtable->dfree_lck == B_TRUE)
-			(void) rw_wrlock(&bucketptr->rwlock);
-		/*
-		 * Unequivocally free member, using the force parameter.
-		 */
-		(void) hashi_FreeMember(&bucketptr->next, free_data, B_TRUE);
-		bucketptr->next = NULL;
-		if (hashtable->dfree_lck == B_TRUE) {
-			(void) rw_unlock(&bucketptr->rwlock);
-			(void) rwlock_destroy(&(bucketptr->rwlock));
-		}
-		bucketptr++;
-	}
-	hashtable->bucketnum = 0;
-}
-
-/*
- * Returns B_TRUE if at least one entry for the given key exists; B_FALSE
- * otherwise. Dynamically free expired data as searched.
- */
-static int
-hashi_Exists(hash_bucket *bucketptr, int (*compare)(), hash_datum *key,
-    boolean_t (*free_data)(), hash_member **prev)
-{
-	hash_member *prevptr = (hash_member *)bucketptr;
-	hash_member *memberptr = bucketptr->next;
-	hash_tbl *hashtable = bucketptr->table;
-	hash_member *next;
-	boolean_t ret = B_FALSE;
-	time_t now = time(NULL);
-
-	while (memberptr != NULL) {
-		/*
-		 * Dynamically free expired data.
-		 */
-		if (free_data != NULL && hashtable->dfree_data != NULL &&
-		    memberptr->h_time < now) {
-			next = memberptr->next;
-			if ((memberptr = hashi_Dfree(memberptr, free_data)) ==
-			    NULL) {
-				prevptr->next = memberptr = next;
-				continue;
-			}
-		}
-
-		/*
-		 * Entry exists, or we are randomly selecting any
-		 * element (compare function is NULL).
-		 */
-		if (compare == NULL || (*compare)(key, memberptr->data)) {
-			ret = B_TRUE;
-			break;
-		} else
-			prevptr = memberptr;
-		memberptr = memberptr->next;
-	}
-
-	if (prev != NULL)
-		*prev = prevptr;
-	return (ret);
-}
-
-/*
- * Returns number of Dynamically freed expired entries.
- */
-static int
-hashi_Expire(hash_bucket *bucketptr, boolean_t (*free_data)())
-{
-	hash_member *prevptr = (hash_member *)bucketptr;
-	hash_member *memberptr = bucketptr->next;
-	hash_tbl *hashtable = bucketptr->table;
-	hash_member *next;
-	int rcount = 0;
-	time_t now = time(NULL);
-
-	while (memberptr) {
-		/*
-		 * Dynamically free expired data.
-		 */
-		if (free_data != NULL && hashtable->dfree_data != NULL &&
-		    memberptr->h_time < now) {
-			next = memberptr->next;
-			if ((memberptr = hashi_Dfree(memberptr, free_data)) ==
-			    NULL) {
-				rcount++;
-				prevptr->next = memberptr = next;
-				continue;
-			}
-		}
-		prevptr = memberptr;
-		memberptr = memberptr->next;
-	}
-	return (rcount);
-}
-
-/*
- * Insert the data item "element" into the hash table using "hashcode"
- * to determine the bucket number, and "compare" and "key" to determine
- * its uniqueness.
- *
- * If the insertion is successful the element is returned.  If a matching entry
- * already exists in the given bucket of the hash table, then NULL is returned,
- * signifying that the entry is already in the table. This happens when some
- * other thread has already inserted the entry.
- */
-void *
-hash_Insert(hash_tbl *hashtable, void *hashdata, unsigned hashlen,
-    int (*compare)(), hash_datum *key, hash_datum *element)
-{
-	hash_member *temp = NULL;
-	hash_bucket *bucketptr;
-	hash_member *prev = NULL;
-	unsigned hashcode = hashi_HashFunction(hashdata, hashlen);
-
-	bucketptr = &((hashtable->table)[hashcode % hashtable->size]);
-	if (hashtable->dfree_lck)
-		(void) rw_wrlock(&bucketptr->rwlock);
-
-	if (hashi_Exists(bucketptr, compare, key, hashtable->dfree_data,
-	    &prev)) {
-		/* Some other thread got there first, so just return */
-		if (hashtable->dfree_lck)
-			(void) rw_unlock(&bucketptr->rwlock);
-		return (NULL);
-	}
-
-	temp = (hash_member *)smalloc(sizeof (hash_member));
-
-	prev->next = temp;
-	temp->data = element;
-	temp->next = NULL;
-
-	/*
-	 * Dynamic free initialization.
-	 */
-	if (hashtable->dfree_data != NULL)
-		hashi_Dinit(hashtable, temp);
-
-	if (hashtable->dfree_lck)
-		(void) rw_unlock(&bucketptr->rwlock);
-
-	return ((void *)temp);
-}
-
-/*
- * Release the reference count on an item. Performance: if item is to be
- * deleted, mark for future dynamic free.
- */
-void
-hash_Rele(void *hashp, boolean_t delete)
-{
-	hash_member *memberptr = (hash_member *)hashp;
-
-	(void) mutex_lock(&memberptr->h_mtx);
-	memberptr->h_count--;
-	assert(memberptr->h_count >= 0);
-	if (delete == B_TRUE)
-		memberptr->h_time = 0;
-	(void) mutex_unlock(&memberptr->h_mtx);
-}
-
-/*
- * Report the reference count on an item.
- */
-int
-hash_Refcount(void *hashp)
-{
-	hash_member *memberptr = (hash_member *)hashp;
-	int ret;
-
-	(void) mutex_lock(&memberptr->h_mtx);
-	ret = memberptr->h_count;
-	(void) mutex_unlock(&memberptr->h_mtx);
-	return (ret);
-}
-
-/*
- * Report the dynamic free time on an item.
- */
-int
-hash_Htime(void *hashp)
-{
-	hash_member *memberptr = (hash_member *)hashp;
-	int ret;
-
-	(void) mutex_lock(&memberptr->h_mtx);
-	ret = memberptr->h_time;
-	(void) mutex_unlock(&memberptr->h_mtx);
-	return (ret);
-}
-
-/*
- * Increase the dynamic free time on an item.
- */
-void
-hash_Age(void *hashp)
-{
-	hash_member *memberptr = (hash_member *)hashp;
-
-	(void) mutex_lock(&memberptr->h_mtx);
-	memberptr->h_time++;
-	(void) mutex_unlock(&memberptr->h_mtx);
-}
-
-/*
- *  Set the dynamic free time on an item.
- */
-void
-hash_Dtime(void *hashp, time_t tm)
-{
-	hash_member *memberptr = (hash_member *)hashp;
-
-	(void) mutex_lock(&memberptr->h_mtx);
-	memberptr->h_time = tm;
-	(void) mutex_unlock(&memberptr->h_mtx);
-}
-
-/*
- * Delete a data item from the hash table using "hashcode"
- * to determine the bucket number, and "compare" and "key" to determine
- * its uniqueness.
- *
- * If the deletion is successful 0 is returned.  If a matching entry
- * does not exist in the given bucket of the hash table, or some other error
- * occurs, -1 is returned and the insertion is not done.
- */
-boolean_t
-hash_Delete(hash_tbl *hashtable, void *hashdata, unsigned hashlen,
-    int (*compare)(), hash_datum *key, boolean_t (*free_data)())
-{
-	hash_member *prev = NULL;
-	hash_member *temp;
-	hash_bucket *bucketptr;
-	unsigned hashcode = hashi_HashFunction(hashdata, hashlen);
-
-	bucketptr = &((hashtable->table)[hashcode % hashtable->size]);
-	if (hashtable->dfree_lck == B_TRUE)
-		(void) rw_wrlock(&bucketptr->rwlock);
-
-	if (hashi_Exists(bucketptr, compare, key, free_data, &prev) ==
-	    B_FALSE || prev == NULL) {
-		if (hashtable->dfree_lck == B_TRUE)
-			(void) rw_unlock(&bucketptr->rwlock);
-		return (B_FALSE); /* Entry does not exist */
-	}
-
-	temp = prev->next;
-	if (temp) {
-		prev->next = temp->next;
-		temp->next = NULL;
-		(void) hashi_FreeMember(&temp, free_data, B_TRUE);
-	} else
-		prev->next = NULL;
-	if (hashtable->dfree_lck == B_TRUE)
-		(void) rw_unlock(&bucketptr->rwlock);
-	return (B_TRUE);
-}
-
-/*
- * Locate and return the data entry associated with the given key.
- *
- * If the data entry is found, a pointer to it is returned.  Otherwise,
- * NULL is returned.
- */
-hash_datum *
-hash_Lookup(hash_tbl *hashtable, void *hashdata, unsigned hashlen,
-    int (*compare)(), hash_datum *key, boolean_t hold)
-{
-	hash_datum *ret = NULL;
-	hash_bucket *bucketptr;
-	hash_member *prev = NULL;
-	unsigned hashcode = hashi_HashFunction(hashdata, hashlen);
-
-	bucketptr = &((hashtable->table)[hashcode % hashtable->size]);
-	if (hashtable->dfree_lck == B_TRUE)
-		(void) rw_wrlock(&bucketptr->rwlock);
-
-	if (hashi_Exists(bucketptr, compare, key, hashtable->dfree_data,
-	    &prev) == B_TRUE) {
-		/*
-		 * Dynamic free increment reference.
-		 */
-		if (hold)
-			hashi_Dhold(prev->next);
-		ret = prev->next->data;
-
-	}
-	if (hashtable->dfree_lck == B_TRUE)
-		(void) rw_unlock(&bucketptr->rwlock);
-	return (ret);
-}
-
-/*
- * Reap expired data items, or a random data item from the hash table.
- */
-void
-hash_Reap(hash_tbl *hashtable, boolean_t (*free_data)())
-{
-	hash_bucket		*bucketptr;
-	int			rcount;
-	unsigned		i;
-
-	bucketptr = &((hashtable->table)[0]);
-	rcount = 0;
-
-	/*
-	 * Walk the buckets, reaping expired clients.
-	 */
-	for (i = 0; i < hashtable->size; i++) {
-		if (hashtable->dfree_lck == B_TRUE)
-			(void) rw_wrlock(&bucketptr->rwlock);
-		rcount += hashi_Expire(bucketptr, hashtable->dfree_data);
-		if (hashtable->dfree_lck == B_TRUE)
-			(void) rw_unlock(&bucketptr->rwlock);
-		bucketptr++;
-	}
-
-	/*
-	 * Nothing to be reaped, delete a random element. Note that
-	 * the unhash_data routine will wait for current references
-	 * before deletion.
-	 */
-	if (rcount == 0) {
-		for (i = 0; i < hashtable->size; i++) {
-			if (hash_Delete(hashtable, NULL, i, NULL, NULL,
-			    free_data) == B_TRUE) {
-				break;
-			}
-		}
-	}
-}
