os/ossrv/ssl/libcrypto/src/crypto/lhash/lhash.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* crypto/lhash/lhash.c */
sl@0
     2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
sl@0
     3
 * All rights reserved.
sl@0
     4
 *
sl@0
     5
 * This package is an SSL implementation written
sl@0
     6
 * by Eric Young (eay@cryptsoft.com).
sl@0
     7
 * The implementation was written so as to conform with Netscapes SSL.
sl@0
     8
 * 
sl@0
     9
 * This library is free for commercial and non-commercial use as long as
sl@0
    10
 * the following conditions are aheared to.  The following conditions
sl@0
    11
 * apply to all code found in this distribution, be it the RC4, RSA,
sl@0
    12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
sl@0
    13
 * included with this distribution is covered by the same copyright terms
sl@0
    14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
sl@0
    15
 * 
sl@0
    16
 * Copyright remains Eric Young's, and as such any Copyright notices in
sl@0
    17
 * the code are not to be removed.
sl@0
    18
 * If this package is used in a product, Eric Young should be given attribution
sl@0
    19
 * as the author of the parts of the library used.
sl@0
    20
 * This can be in the form of a textual message at program startup or
sl@0
    21
 * in documentation (online or textual) provided with the package.
sl@0
    22
 * 
sl@0
    23
 * Redistribution and use in source and binary forms, with or without
sl@0
    24
 * modification, are permitted provided that the following conditions
sl@0
    25
 * are met:
sl@0
    26
 * 1. Redistributions of source code must retain the copyright
sl@0
    27
 *    notice, this list of conditions and the following disclaimer.
sl@0
    28
 * 2. Redistributions in binary form must reproduce the above copyright
sl@0
    29
 *    notice, this list of conditions and the following disclaimer in the
sl@0
    30
 *    documentation and/or other materials provided with the distribution.
sl@0
    31
 * 3. All advertising materials mentioning features or use of this software
sl@0
    32
 *    must display the following acknowledgement:
sl@0
    33
 *    "This product includes cryptographic software written by
sl@0
    34
 *     Eric Young (eay@cryptsoft.com)"
sl@0
    35
 *    The word 'cryptographic' can be left out if the rouines from the library
sl@0
    36
 *    being used are not cryptographic related :-).
sl@0
    37
 * 4. If you include any Windows specific code (or a derivative thereof) from 
sl@0
    38
 *    the apps directory (application code) you must include an acknowledgement:
sl@0
    39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
sl@0
    40
 * 
sl@0
    41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
sl@0
    42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0
    43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sl@0
    44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
sl@0
    45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
sl@0
    46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
sl@0
    47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0
    48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
sl@0
    49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
sl@0
    50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
sl@0
    51
 * SUCH DAMAGE.
sl@0
    52
 * 
sl@0
    53
 * The licence and distribution terms for any publically available version or
sl@0
    54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
sl@0
    55
 * copied and put under another distribution licence
sl@0
    56
 * [including the GNU Public Licence.]
sl@0
    57
 */
sl@0
    58
sl@0
    59
/* Code for dynamic hash table routines
sl@0
    60
 * Author - Eric Young v 2.0
sl@0
    61
 *
sl@0
    62
 * 2.2 eay - added #include "crypto.h" so the memory leak checking code is
sl@0
    63
 *	     present. eay 18-Jun-98
sl@0
    64
 *
sl@0
    65
 * 2.1 eay - Added an 'error in last operation' flag. eay 6-May-98
sl@0
    66
 *
sl@0
    67
 * 2.0 eay - Fixed a bug that occurred when using lh_delete
sl@0
    68
 *	     from inside lh_doall().  As entries were deleted,
sl@0
    69
 *	     the 'table' was 'contract()ed', making some entries
sl@0
    70
 *	     jump from the end of the table to the start, there by
sl@0
    71
 *	     skipping the lh_doall() processing. eay - 4/12/95
sl@0
    72
 *
sl@0
    73
 * 1.9 eay - Fixed a memory leak in lh_free, the LHASH_NODEs
sl@0
    74
 *	     were not being free()ed. 21/11/95
sl@0
    75
 *
sl@0
    76
 * 1.8 eay - Put the stats routines into a separate file, lh_stats.c
sl@0
    77
 *	     19/09/95
sl@0
    78
 *
sl@0
    79
 * 1.7 eay - Removed the fputs() for realloc failures - the code
sl@0
    80
 *           should silently tolerate them.  I have also fixed things
sl@0
    81
 *           lint complained about 04/05/95
sl@0
    82
 *
sl@0
    83
 * 1.6 eay - Fixed an invalid pointers in contract/expand 27/07/92
sl@0
    84
 *
sl@0
    85
 * 1.5 eay - Fixed a misuse of realloc in expand 02/03/1992
sl@0
    86
 *
sl@0
    87
 * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91
sl@0
    88
 *
sl@0
    89
 * 1.3 eay - Fixed a few lint problems 19/3/1991
sl@0
    90
 *
sl@0
    91
 * 1.2 eay - Fixed lh_doall problem 13/3/1991
sl@0
    92
 *
sl@0
    93
 * 1.1 eay - Added lh_doall
sl@0
    94
 *
sl@0
    95
 * 1.0 eay - First version
sl@0
    96
 */
sl@0
    97
#include <stdio.h>
sl@0
    98
#include <string.h>
sl@0
    99
#include <stdlib.h>
sl@0
   100
#include <openssl/crypto.h>
sl@0
   101
#include <openssl/lhash.h>
sl@0
   102
sl@0
   103
const char lh_version[]="lhash" OPENSSL_VERSION_PTEXT;
sl@0
   104
sl@0
   105
#undef MIN_NODES 
sl@0
   106
#define MIN_NODES	16
sl@0
   107
#define UP_LOAD		(2*LH_LOAD_MULT) /* load times 256  (default 2) */
sl@0
   108
#define DOWN_LOAD	(LH_LOAD_MULT)   /* load times 256  (default 1) */
sl@0
   109
sl@0
   110
static void expand(LHASH *lh);
sl@0
   111
static void contract(LHASH *lh);
sl@0
   112
static LHASH_NODE **getrn(LHASH *lh, const void *data, unsigned long *rhash);
sl@0
   113
sl@0
   114
EXPORT_C LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c)
sl@0
   115
	{
sl@0
   116
	LHASH *ret;
sl@0
   117
	int i;
sl@0
   118
sl@0
   119
	if ((ret=(LHASH *)OPENSSL_malloc(sizeof(LHASH))) == NULL)
sl@0
   120
		goto err0;
sl@0
   121
	if ((ret->b=(LHASH_NODE **)OPENSSL_malloc(sizeof(LHASH_NODE *)*MIN_NODES)) == NULL)
sl@0
   122
		goto err1;
sl@0
   123
	for (i=0; i<MIN_NODES; i++)
sl@0
   124
		ret->b[i]=NULL;
sl@0
   125
	ret->comp=((c == NULL)?(LHASH_COMP_FN_TYPE)strcmp:c);
sl@0
   126
	ret->hash=((h == NULL)?(LHASH_HASH_FN_TYPE)lh_strhash:h);
sl@0
   127
	ret->num_nodes=MIN_NODES/2;
sl@0
   128
	ret->num_alloc_nodes=MIN_NODES;
sl@0
   129
	ret->p=0;
sl@0
   130
	ret->pmax=MIN_NODES/2;
sl@0
   131
	ret->up_load=UP_LOAD;
sl@0
   132
	ret->down_load=DOWN_LOAD;
sl@0
   133
	ret->num_items=0;
sl@0
   134
sl@0
   135
	ret->num_expands=0;
sl@0
   136
	ret->num_expand_reallocs=0;
sl@0
   137
	ret->num_contracts=0;
sl@0
   138
	ret->num_contract_reallocs=0;
sl@0
   139
	ret->num_hash_calls=0;
sl@0
   140
	ret->num_comp_calls=0;
sl@0
   141
	ret->num_insert=0;
sl@0
   142
	ret->num_replace=0;
sl@0
   143
	ret->num_delete=0;
sl@0
   144
	ret->num_no_delete=0;
sl@0
   145
	ret->num_retrieve=0;
sl@0
   146
	ret->num_retrieve_miss=0;
sl@0
   147
	ret->num_hash_comps=0;
sl@0
   148
sl@0
   149
	ret->error=0;
sl@0
   150
	return(ret);
sl@0
   151
err1:
sl@0
   152
	OPENSSL_free(ret);
sl@0
   153
err0:
sl@0
   154
	return(NULL);
sl@0
   155
	}
sl@0
   156
sl@0
   157
EXPORT_C void lh_free(LHASH *lh)
sl@0
   158
	{
sl@0
   159
	unsigned int i;
sl@0
   160
	LHASH_NODE *n,*nn;
sl@0
   161
sl@0
   162
	if (lh == NULL)
sl@0
   163
	    return;
sl@0
   164
sl@0
   165
	for (i=0; i<lh->num_nodes; i++)
sl@0
   166
		{
sl@0
   167
		n=lh->b[i];
sl@0
   168
		while (n != NULL)
sl@0
   169
			{
sl@0
   170
			nn=n->next;
sl@0
   171
			OPENSSL_free(n);
sl@0
   172
			n=nn;
sl@0
   173
			}
sl@0
   174
		}
sl@0
   175
	OPENSSL_free(lh->b);
sl@0
   176
	OPENSSL_free(lh);
sl@0
   177
	}
sl@0
   178
sl@0
   179
EXPORT_C void *lh_insert(LHASH *lh, void *data)
sl@0
   180
	{
sl@0
   181
	unsigned long hash;
sl@0
   182
	LHASH_NODE *nn,**rn;
sl@0
   183
	void *ret;
sl@0
   184
sl@0
   185
	lh->error=0;
sl@0
   186
	if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))
sl@0
   187
		expand(lh);
sl@0
   188
sl@0
   189
	rn=getrn(lh,data,&hash);
sl@0
   190
sl@0
   191
	if (*rn == NULL)
sl@0
   192
		{
sl@0
   193
		if ((nn=(LHASH_NODE *)OPENSSL_malloc(sizeof(LHASH_NODE))) == NULL)
sl@0
   194
			{
sl@0
   195
			lh->error++;
sl@0
   196
			return(NULL);
sl@0
   197
			}
sl@0
   198
		nn->data=data;
sl@0
   199
		nn->next=NULL;
sl@0
   200
#ifndef OPENSSL_NO_HASH_COMP
sl@0
   201
		nn->hash=hash;
sl@0
   202
#endif
sl@0
   203
		*rn=nn;
sl@0
   204
		ret=NULL;
sl@0
   205
		lh->num_insert++;
sl@0
   206
		lh->num_items++;
sl@0
   207
		}
sl@0
   208
	else /* replace same key */
sl@0
   209
		{
sl@0
   210
		ret= (*rn)->data;
sl@0
   211
		(*rn)->data=data;
sl@0
   212
		lh->num_replace++;
sl@0
   213
		}
sl@0
   214
	return(ret);
sl@0
   215
	}
sl@0
   216
sl@0
   217
EXPORT_C void *lh_delete(LHASH *lh, const void *data)
sl@0
   218
	{
sl@0
   219
	unsigned long hash;
sl@0
   220
	LHASH_NODE *nn,**rn;
sl@0
   221
	void *ret;
sl@0
   222
sl@0
   223
	lh->error=0;
sl@0
   224
	rn=getrn(lh,data,&hash);
sl@0
   225
sl@0
   226
	if (*rn == NULL)
sl@0
   227
		{
sl@0
   228
		lh->num_no_delete++;
sl@0
   229
		return(NULL);
sl@0
   230
		}
sl@0
   231
	else
sl@0
   232
		{
sl@0
   233
		nn= *rn;
sl@0
   234
		*rn=nn->next;
sl@0
   235
		ret=nn->data;
sl@0
   236
		OPENSSL_free(nn);
sl@0
   237
		lh->num_delete++;
sl@0
   238
		}
sl@0
   239
sl@0
   240
	lh->num_items--;
sl@0
   241
	if ((lh->num_nodes > MIN_NODES) &&
sl@0
   242
		(lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)))
sl@0
   243
		contract(lh);
sl@0
   244
sl@0
   245
	return(ret);
sl@0
   246
	}
sl@0
   247
sl@0
   248
EXPORT_C void *lh_retrieve(LHASH *lh, const void *data)
sl@0
   249
	{
sl@0
   250
	unsigned long hash;
sl@0
   251
	LHASH_NODE **rn;
sl@0
   252
	void *ret;
sl@0
   253
sl@0
   254
	lh->error=0;
sl@0
   255
	rn=getrn(lh,data,&hash);
sl@0
   256
sl@0
   257
	if (*rn == NULL)
sl@0
   258
		{
sl@0
   259
		lh->num_retrieve_miss++;
sl@0
   260
		return(NULL);
sl@0
   261
		}
sl@0
   262
	else
sl@0
   263
		{
sl@0
   264
		ret= (*rn)->data;
sl@0
   265
		lh->num_retrieve++;
sl@0
   266
		}
sl@0
   267
	return(ret);
sl@0
   268
	}
sl@0
   269
sl@0
   270
static void doall_util_fn(LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func,
sl@0
   271
			  LHASH_DOALL_ARG_FN_TYPE func_arg, void *arg)
sl@0
   272
	{
sl@0
   273
	int i;
sl@0
   274
	LHASH_NODE *a,*n;
sl@0
   275
sl@0
   276
	/* reverse the order so we search from 'top to bottom'
sl@0
   277
	 * We were having memory leaks otherwise */
sl@0
   278
	for (i=lh->num_nodes-1; i>=0; i--)
sl@0
   279
		{
sl@0
   280
		a=lh->b[i];
sl@0
   281
		while (a != NULL)
sl@0
   282
			{
sl@0
   283
			/* 28/05/91 - eay - n added so items can be deleted
sl@0
   284
			 * via lh_doall */
sl@0
   285
			n=a->next;
sl@0
   286
			if(use_arg)
sl@0
   287
				func_arg(a->data,arg);
sl@0
   288
			else
sl@0
   289
				func(a->data);
sl@0
   290
			a=n;
sl@0
   291
			}
sl@0
   292
		}
sl@0
   293
	}
sl@0
   294
sl@0
   295
EXPORT_C void lh_doall(LHASH *lh, LHASH_DOALL_FN_TYPE func)
sl@0
   296
	{
sl@0
   297
	doall_util_fn(lh, 0, func, (LHASH_DOALL_ARG_FN_TYPE)0, NULL);
sl@0
   298
	}
sl@0
   299
sl@0
   300
EXPORT_C void lh_doall_arg(LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg)
sl@0
   301
	{
sl@0
   302
	doall_util_fn(lh, 1, (LHASH_DOALL_FN_TYPE)0, func, arg);
sl@0
   303
	}
sl@0
   304
sl@0
   305
static void expand(LHASH *lh)
sl@0
   306
	{
sl@0
   307
	LHASH_NODE **n,**n1,**n2,*np;
sl@0
   308
	unsigned int p,i,j;
sl@0
   309
	unsigned long hash,nni;
sl@0
   310
sl@0
   311
	lh->num_nodes++;
sl@0
   312
	lh->num_expands++;
sl@0
   313
	p=(int)lh->p++;
sl@0
   314
	n1= &(lh->b[p]);
sl@0
   315
	n2= &(lh->b[p+(int)lh->pmax]);
sl@0
   316
	*n2=NULL;        /* 27/07/92 - eay - undefined pointer bug */
sl@0
   317
	nni=lh->num_alloc_nodes;
sl@0
   318
	
sl@0
   319
	for (np= *n1; np != NULL; )
sl@0
   320
		{
sl@0
   321
#ifndef OPENSSL_NO_HASH_COMP
sl@0
   322
		hash=np->hash;
sl@0
   323
#else
sl@0
   324
		hash=lh->hash(np->data);
sl@0
   325
		lh->num_hash_calls++;
sl@0
   326
#endif
sl@0
   327
		if ((hash%nni) != p)
sl@0
   328
			{ /* move it */
sl@0
   329
			*n1= (*n1)->next;
sl@0
   330
			np->next= *n2;
sl@0
   331
			*n2=np;
sl@0
   332
			}
sl@0
   333
		else
sl@0
   334
			n1= &((*n1)->next);
sl@0
   335
		np= *n1;
sl@0
   336
		}
sl@0
   337
sl@0
   338
	if ((lh->p) >= lh->pmax)
sl@0
   339
		{
sl@0
   340
		j=(int)lh->num_alloc_nodes*2;
sl@0
   341
		n=(LHASH_NODE **)OPENSSL_realloc(lh->b,
sl@0
   342
			(int)(sizeof(LHASH_NODE *)*j));
sl@0
   343
		if (n == NULL)
sl@0
   344
			{
sl@0
   345
/*			fputs("realloc error in lhash",stderr); */
sl@0
   346
			lh->error++;
sl@0
   347
			lh->p=0;
sl@0
   348
			return;
sl@0
   349
			}
sl@0
   350
		/* else */
sl@0
   351
		for (i=(int)lh->num_alloc_nodes; i<j; i++)/* 26/02/92 eay */
sl@0
   352
			n[i]=NULL;			  /* 02/03/92 eay */
sl@0
   353
		lh->pmax=lh->num_alloc_nodes;
sl@0
   354
		lh->num_alloc_nodes=j;
sl@0
   355
		lh->num_expand_reallocs++;
sl@0
   356
		lh->p=0;
sl@0
   357
		lh->b=n;
sl@0
   358
		}
sl@0
   359
	}
sl@0
   360
sl@0
   361
static void contract(LHASH *lh)
sl@0
   362
	{
sl@0
   363
	LHASH_NODE **n,*n1,*np;
sl@0
   364
sl@0
   365
	np=lh->b[lh->p+lh->pmax-1];
sl@0
   366
	lh->b[lh->p+lh->pmax-1]=NULL; /* 24/07-92 - eay - weird but :-( */
sl@0
   367
	if (lh->p == 0)
sl@0
   368
		{
sl@0
   369
		n=(LHASH_NODE **)OPENSSL_realloc(lh->b,
sl@0
   370
			(unsigned int)(sizeof(LHASH_NODE *)*lh->pmax));
sl@0
   371
		if (n == NULL)
sl@0
   372
			{
sl@0
   373
/*			fputs("realloc error in lhash",stderr); */
sl@0
   374
			lh->error++;
sl@0
   375
			return;
sl@0
   376
			}
sl@0
   377
		lh->num_contract_reallocs++;
sl@0
   378
		lh->num_alloc_nodes/=2;
sl@0
   379
		lh->pmax/=2;
sl@0
   380
		lh->p=lh->pmax-1;
sl@0
   381
		lh->b=n;
sl@0
   382
		}
sl@0
   383
	else
sl@0
   384
		lh->p--;
sl@0
   385
sl@0
   386
	lh->num_nodes--;
sl@0
   387
	lh->num_contracts++;
sl@0
   388
sl@0
   389
	n1=lh->b[(int)lh->p];
sl@0
   390
	if (n1 == NULL)
sl@0
   391
		lh->b[(int)lh->p]=np;
sl@0
   392
	else
sl@0
   393
		{
sl@0
   394
		while (n1->next != NULL)
sl@0
   395
			n1=n1->next;
sl@0
   396
		n1->next=np;
sl@0
   397
		}
sl@0
   398
	}
sl@0
   399
sl@0
   400
static LHASH_NODE **getrn(LHASH *lh, const void *data, unsigned long *rhash)
sl@0
   401
	{
sl@0
   402
	LHASH_NODE **ret,*n1;
sl@0
   403
	unsigned long hash,nn;
sl@0
   404
	LHASH_COMP_FN_TYPE cf;
sl@0
   405
sl@0
   406
	hash=(*(lh->hash))(data);
sl@0
   407
	lh->num_hash_calls++;
sl@0
   408
	*rhash=hash;
sl@0
   409
sl@0
   410
	nn=hash%lh->pmax;
sl@0
   411
	if (nn < lh->p)
sl@0
   412
		nn=hash%lh->num_alloc_nodes;
sl@0
   413
sl@0
   414
	cf=lh->comp;
sl@0
   415
	ret= &(lh->b[(int)nn]);
sl@0
   416
	for (n1= *ret; n1 != NULL; n1=n1->next)
sl@0
   417
		{
sl@0
   418
#ifndef OPENSSL_NO_HASH_COMP
sl@0
   419
		lh->num_hash_comps++;
sl@0
   420
		if (n1->hash != hash)
sl@0
   421
			{
sl@0
   422
			ret= &(n1->next);
sl@0
   423
			continue;
sl@0
   424
			}
sl@0
   425
#endif
sl@0
   426
		lh->num_comp_calls++;
sl@0
   427
		if(cf(n1->data,data) == 0)
sl@0
   428
			break;
sl@0
   429
		ret= &(n1->next);
sl@0
   430
		}
sl@0
   431
	return(ret);
sl@0
   432
	}
sl@0
   433
sl@0
   434
/* The following hash seems to work very well on normal text strings
sl@0
   435
 * no collisions on /usr/dict/words and it distributes on %2^n quite
sl@0
   436
 * well, not as good as MD5, but still good.
sl@0
   437
 */
sl@0
   438
EXPORT_C unsigned long lh_strhash(const char *c)
sl@0
   439
	{
sl@0
   440
	unsigned long ret=0;
sl@0
   441
	long n;
sl@0
   442
	unsigned long v;
sl@0
   443
	int r;
sl@0
   444
sl@0
   445
	if ((c == NULL) || (*c == '\0'))
sl@0
   446
		return(ret);
sl@0
   447
/*
sl@0
   448
	unsigned char b[16];
sl@0
   449
	MD5(c,strlen(c),b);
sl@0
   450
	return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24)); 
sl@0
   451
*/
sl@0
   452
sl@0
   453
	n=0x100;
sl@0
   454
	while (*c)
sl@0
   455
		{
sl@0
   456
		v=n|(*c);
sl@0
   457
		n+=0x100;
sl@0
   458
		r= (int)((v>>2)^v)&0x0f;
sl@0
   459
		ret=(ret<<r)|(ret>>(32-r));
sl@0
   460
		ret&=0xFFFFFFFFL;
sl@0
   461
		ret^=v*v;
sl@0
   462
		c++;
sl@0
   463
		}
sl@0
   464
	return((ret>>16)^ret);
sl@0
   465
	}
sl@0
   466
sl@0
   467
EXPORT_C unsigned long lh_num_items(const LHASH *lh)
sl@0
   468
	{
sl@0
   469
	return lh ? lh->num_items : 0;
sl@0
   470
	}