VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.0g/crypto/lhash/lhash.c@ 69890

Last change on this file since 69890 was 69890, checked in by vboxsync, 7 years ago

Added OpenSSL 1.1.0g with unneeded files removed, otherwise unmodified.
bugref:8070: src/libs maintenance

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1/*
2 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
13#include <openssl/crypto.h>
14#include <openssl/lhash.h>
15#include "lhash_lcl.h"
16
17/*
18 * A hashing implementation that appears to be based on the linear hashing
19 * alogrithm:
20 * https://en.wikipedia.org/wiki/Linear_hashing
21 *
22 * Litwin, Witold (1980), "Linear hashing: A new tool for file and table
23 * addressing", Proc. 6th Conference on Very Large Databases: 212–223
24 * http://hackthology.com/pdfs/Litwin-1980-Linear_Hashing.pdf
25 *
26 * From the wikipedia article "Linear hashing is used in the BDB Berkeley
27 * database system, which in turn is used by many software systems such as
28 * OpenLDAP, using a C implementation derived from the CACM article and first
29 * published on the Usenet in 1988 by Esmond Pitt."
30 *
31 * The CACM paper is available here:
32 * https://pdfs.semanticscholar.org/ff4d/1c5deca6269cc316bfd952172284dbf610ee.pdf
33 */
34
35#undef MIN_NODES
36#define MIN_NODES 16
37#define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */
38#define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */
39
40static int expand(OPENSSL_LHASH *lh);
41static void contract(OPENSSL_LHASH *lh);
42static OPENSSL_LH_NODE **getrn(OPENSSL_LHASH *lh, const void *data, unsigned long *rhash);
43
44OPENSSL_LHASH *OPENSSL_LH_new(OPENSSL_LH_HASHFUNC h, OPENSSL_LH_COMPFUNC c)
45{
46 OPENSSL_LHASH *ret;
47
48 if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
49 return NULL;
50 if ((ret->b = OPENSSL_zalloc(sizeof(*ret->b) * MIN_NODES)) == NULL)
51 goto err;
52 if ((ret->retrieve_stats_lock = CRYPTO_THREAD_lock_new()) == NULL)
53 goto err;
54 ret->comp = ((c == NULL) ? (OPENSSL_LH_COMPFUNC)strcmp : c);
55 ret->hash = ((h == NULL) ? (OPENSSL_LH_HASHFUNC)OPENSSL_LH_strhash : h);
56 ret->num_nodes = MIN_NODES / 2;
57 ret->num_alloc_nodes = MIN_NODES;
58 ret->pmax = MIN_NODES / 2;
59 ret->up_load = UP_LOAD;
60 ret->down_load = DOWN_LOAD;
61 return (ret);
62
63err:
64 OPENSSL_free(ret->b);
65 OPENSSL_free(ret);
66 return NULL;
67}
68
69void OPENSSL_LH_free(OPENSSL_LHASH *lh)
70{
71 unsigned int i;
72 OPENSSL_LH_NODE *n, *nn;
73
74 if (lh == NULL)
75 return;
76
77 for (i = 0; i < lh->num_nodes; i++) {
78 n = lh->b[i];
79 while (n != NULL) {
80 nn = n->next;
81 OPENSSL_free(n);
82 n = nn;
83 }
84 }
85 CRYPTO_THREAD_lock_free(lh->retrieve_stats_lock);
86 OPENSSL_free(lh->b);
87 OPENSSL_free(lh);
88}
89
90void *OPENSSL_LH_insert(OPENSSL_LHASH *lh, void *data)
91{
92 unsigned long hash;
93 OPENSSL_LH_NODE *nn, **rn;
94 void *ret;
95
96 lh->error = 0;
97 if ((lh->up_load <= (lh->num_items * LH_LOAD_MULT / lh->num_nodes)) && !expand(lh))
98 return NULL; /* 'lh->error++' already done in 'expand' */
99
100 rn = getrn(lh, data, &hash);
101
102 if (*rn == NULL) {
103 if ((nn = OPENSSL_malloc(sizeof(*nn))) == NULL) {
104 lh->error++;
105 return (NULL);
106 }
107 nn->data = data;
108 nn->next = NULL;
109 nn->hash = hash;
110 *rn = nn;
111 ret = NULL;
112 lh->num_insert++;
113 lh->num_items++;
114 } else { /* replace same key */
115
116 ret = (*rn)->data;
117 (*rn)->data = data;
118 lh->num_replace++;
119 }
120 return (ret);
121}
122
123void *OPENSSL_LH_delete(OPENSSL_LHASH *lh, const void *data)
124{
125 unsigned long hash;
126 OPENSSL_LH_NODE *nn, **rn;
127 void *ret;
128
129 lh->error = 0;
130 rn = getrn(lh, data, &hash);
131
132 if (*rn == NULL) {
133 lh->num_no_delete++;
134 return (NULL);
135 } else {
136 nn = *rn;
137 *rn = nn->next;
138 ret = nn->data;
139 OPENSSL_free(nn);
140 lh->num_delete++;
141 }
142
143 lh->num_items--;
144 if ((lh->num_nodes > MIN_NODES) &&
145 (lh->down_load >= (lh->num_items * LH_LOAD_MULT / lh->num_nodes)))
146 contract(lh);
147
148 return (ret);
149}
150
151void *OPENSSL_LH_retrieve(OPENSSL_LHASH *lh, const void *data)
152{
153 unsigned long hash;
154 OPENSSL_LH_NODE **rn;
155 void *ret;
156 int scratch;
157
158 lh->error = 0;
159 rn = getrn(lh, data, &hash);
160
161 if (*rn == NULL) {
162 CRYPTO_atomic_add(&lh->num_retrieve_miss, 1, &scratch, lh->retrieve_stats_lock);
163 return NULL;
164 } else {
165 ret = (*rn)->data;
166 CRYPTO_atomic_add(&lh->num_retrieve, 1, &scratch, lh->retrieve_stats_lock);
167 }
168 return ret;
169}
170
171static void doall_util_fn(OPENSSL_LHASH *lh, int use_arg,
172 OPENSSL_LH_DOALL_FUNC func,
173 OPENSSL_LH_DOALL_FUNCARG func_arg, void *arg)
174{
175 int i;
176 OPENSSL_LH_NODE *a, *n;
177
178 if (lh == NULL)
179 return;
180
181 /*
182 * reverse the order so we search from 'top to bottom' We were having
183 * memory leaks otherwise
184 */
185 for (i = lh->num_nodes - 1; i >= 0; i--) {
186 a = lh->b[i];
187 while (a != NULL) {
188 n = a->next;
189 if (use_arg)
190 func_arg(a->data, arg);
191 else
192 func(a->data);
193 a = n;
194 }
195 }
196}
197
198void OPENSSL_LH_doall(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNC func)
199{
200 doall_util_fn(lh, 0, func, (OPENSSL_LH_DOALL_FUNCARG)0, NULL);
201}
202
203void OPENSSL_LH_doall_arg(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNCARG func, void *arg)
204{
205 doall_util_fn(lh, 1, (OPENSSL_LH_DOALL_FUNC)0, func, arg);
206}
207
208static int expand(OPENSSL_LHASH *lh)
209{
210 OPENSSL_LH_NODE **n, **n1, **n2, *np;
211 unsigned int p, pmax, nni, j;
212 unsigned long hash;
213
214 nni = lh->num_alloc_nodes;
215 p = lh->p;
216 pmax = lh->pmax;
217 if (p + 1 >= pmax) {
218 j = nni * 2;
219 n = OPENSSL_realloc(lh->b, sizeof(OPENSSL_LH_NODE *) * j);
220 if (n == NULL) {
221 lh->error++;
222 return 0;
223 }
224 lh->b = n;
225 memset(n + nni, 0, sizeof(*n) * (j - nni));
226 lh->pmax = nni;
227 lh->num_alloc_nodes = j;
228 lh->num_expand_reallocs++;
229 lh->p = 0;
230 } else {
231 lh->p++;
232 }
233
234 lh->num_nodes++;
235 lh->num_expands++;
236 n1 = &(lh->b[p]);
237 n2 = &(lh->b[p + pmax]);
238 *n2 = NULL;
239
240 for (np = *n1; np != NULL;) {
241 hash = np->hash;
242 if ((hash % nni) != p) { /* move it */
243 *n1 = (*n1)->next;
244 np->next = *n2;
245 *n2 = np;
246 } else
247 n1 = &((*n1)->next);
248 np = *n1;
249 }
250
251 return 1;
252}
253
254static void contract(OPENSSL_LHASH *lh)
255{
256 OPENSSL_LH_NODE **n, *n1, *np;
257
258 np = lh->b[lh->p + lh->pmax - 1];
259 lh->b[lh->p + lh->pmax - 1] = NULL; /* 24/07-92 - eay - weird but :-( */
260 if (lh->p == 0) {
261 n = OPENSSL_realloc(lh->b,
262 (unsigned int)(sizeof(OPENSSL_LH_NODE *) * lh->pmax));
263 if (n == NULL) {
264 /* fputs("realloc error in lhash",stderr); */
265 lh->error++;
266 return;
267 }
268 lh->num_contract_reallocs++;
269 lh->num_alloc_nodes /= 2;
270 lh->pmax /= 2;
271 lh->p = lh->pmax - 1;
272 lh->b = n;
273 } else
274 lh->p--;
275
276 lh->num_nodes--;
277 lh->num_contracts++;
278
279 n1 = lh->b[(int)lh->p];
280 if (n1 == NULL)
281 lh->b[(int)lh->p] = np;
282 else {
283 while (n1->next != NULL)
284 n1 = n1->next;
285 n1->next = np;
286 }
287}
288
289static OPENSSL_LH_NODE **getrn(OPENSSL_LHASH *lh,
290 const void *data, unsigned long *rhash)
291{
292 OPENSSL_LH_NODE **ret, *n1;
293 unsigned long hash, nn;
294 OPENSSL_LH_COMPFUNC cf;
295 int scratch;
296
297 hash = (*(lh->hash)) (data);
298 CRYPTO_atomic_add(&lh->num_hash_calls, 1, &scratch, lh->retrieve_stats_lock);
299 *rhash = hash;
300
301 nn = hash % lh->pmax;
302 if (nn < lh->p)
303 nn = hash % lh->num_alloc_nodes;
304
305 cf = lh->comp;
306 ret = &(lh->b[(int)nn]);
307 for (n1 = *ret; n1 != NULL; n1 = n1->next) {
308 CRYPTO_atomic_add(&lh->num_hash_comps, 1, &scratch, lh->retrieve_stats_lock);
309 if (n1->hash != hash) {
310 ret = &(n1->next);
311 continue;
312 }
313 CRYPTO_atomic_add(&lh->num_comp_calls, 1, &scratch, lh->retrieve_stats_lock);
314 if (cf(n1->data, data) == 0)
315 break;
316 ret = &(n1->next);
317 }
318 return (ret);
319}
320
321/*
322 * The following hash seems to work very well on normal text strings no
323 * collisions on /usr/dict/words and it distributes on %2^n quite well, not
324 * as good as MD5, but still good.
325 */
326unsigned long OPENSSL_LH_strhash(const char *c)
327{
328 unsigned long ret = 0;
329 long n;
330 unsigned long v;
331 int r;
332
333 if ((c == NULL) || (*c == '\0'))
334 return (ret);
335/*-
336 unsigned char b[16];
337 MD5(c,strlen(c),b);
338 return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
339*/
340
341 n = 0x100;
342 while (*c) {
343 v = n | (*c);
344 n += 0x100;
345 r = (int)((v >> 2) ^ v) & 0x0f;
346 ret = (ret << r) | (ret >> (32 - r));
347 ret &= 0xFFFFFFFFL;
348 ret ^= v * v;
349 c++;
350 }
351 return ((ret >> 16) ^ ret);
352}
353
354unsigned long OPENSSL_LH_num_items(const OPENSSL_LHASH *lh)
355{
356 return lh ? lh->num_items : 0;
357}
358
359unsigned long OPENSSL_LH_get_down_load(const OPENSSL_LHASH *lh)
360{
361 return lh->down_load;
362}
363
364void OPENSSL_LH_set_down_load(OPENSSL_LHASH *lh, unsigned long down_load)
365{
366 lh->down_load = down_load;
367}
368
369int OPENSSL_LH_error(OPENSSL_LHASH *lh)
370{
371 return lh->error;
372}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette