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