Return to hash.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") ! 3: * Copyright (C) 2003 Internet Software Consortium. ! 4: * ! 5: * Permission to use, copy, modify, and/or distribute this software for any ! 6: * purpose with or without fee is hereby granted, provided that the above ! 7: * copyright notice and this permission notice appear in all copies. ! 8: * ! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ! 15: * PERFORMANCE OF THIS SOFTWARE. ! 16: */ ! 17: ! 18: /* $Id: hash.c,v 1.13.332.3 2009/05/07 23:47:12 tbox Exp $ */ ! 19: ! 20: /*! \file ! 21: * Some portion of this code was derived from universal hash function ! 22: * libraries of Rice University. ! 23: \section license UH Universal Hashing Library ! 24: ! 25: Copyright ((c)) 2002, Rice University ! 26: All rights reserved. ! 27: ! 28: Redistribution and use in source and binary forms, with or without ! 29: modification, are permitted provided that the following conditions are ! 30: met: ! 31: ! 32: * Redistributions of source code must retain the above copyright ! 33: notice, this list of conditions and the following disclaimer. ! 34: ! 35: * Redistributions in binary form must reproduce the above ! 36: copyright notice, this list of conditions and the following ! 37: disclaimer in the documentation and/or other materials provided ! 38: with the distribution. ! 39: ! 40: * Neither the name of Rice University (RICE) nor the names of its ! 41: contributors may be used to endorse or promote products derived ! 42: from this software without specific prior written permission. ! 43: ! 44: ! 45: This software is provided by RICE and the contributors on an "as is" ! 46: basis, without any representations or warranties of any kind, express ! 47: or implied including, but not limited to, representations or ! 48: warranties of non-infringement, merchantability or fitness for a ! 49: particular purpose. In no event shall RICE or contributors be liable ! 50: for any direct, indirect, incidental, special, exemplary, or ! 51: consequential damages (including, but not limited to, procurement of ! 52: substitute goods or services; loss of use, data, or profits; or ! 53: business interruption) however caused and on any theory of liability, ! 54: whether in contract, strict liability, or tort (including negligence ! 55: or otherwise) arising in any way out of the use of this software, even ! 56: if advised of the possibility of such damage. ! 57: */ ! 58: ! 59: #include <config.h> ! 60: ! 61: #include <isc/entropy.h> ! 62: #include <isc/hash.h> ! 63: #include <isc/mem.h> ! 64: #include <isc/magic.h> ! 65: #include <isc/mutex.h> ! 66: #include <isc/once.h> ! 67: #include <isc/random.h> ! 68: #include <isc/refcount.h> ! 69: #include <isc/string.h> ! 70: #include <isc/util.h> ! 71: ! 72: #define HASH_MAGIC ISC_MAGIC('H', 'a', 's', 'h') ! 73: #define VALID_HASH(h) ISC_MAGIC_VALID((h), HASH_MAGIC) ! 74: ! 75: /*% ! 76: * A large 32-bit prime number that specifies the range of the hash output. ! 77: */ ! 78: #define PRIME32 0xFFFFFFFB /* 2^32 - 5 */ ! 79: ! 80: /*@{*/ ! 81: /*% ! 82: * Types of random seed and hash accumulator. Perhaps they can be system ! 83: * dependent. ! 84: */ ! 85: typedef isc_uint32_t hash_accum_t; ! 86: typedef isc_uint16_t hash_random_t; ! 87: /*@}*/ ! 88: ! 89: /*% isc hash structure */ ! 90: struct isc_hash { ! 91: unsigned int magic; ! 92: isc_mem_t *mctx; ! 93: isc_mutex_t lock; ! 94: isc_boolean_t initialized; ! 95: isc_refcount_t refcnt; ! 96: isc_entropy_t *entropy; /*%< entropy source */ ! 97: unsigned int limit; /*%< upper limit of key length */ ! 98: size_t vectorlen; /*%< size of the vector below */ ! 99: hash_random_t *rndvector; /*%< random vector for universal hashing */ ! 100: }; ! 101: ! 102: static isc_mutex_t createlock; ! 103: static isc_once_t once = ISC_ONCE_INIT; ! 104: static isc_hash_t *hash = NULL; ! 105: ! 106: static unsigned char maptolower[] = { ! 107: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ! 108: 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ! 109: 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ! 110: 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ! 111: 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ! 112: 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ! 113: 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ! 114: 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ! 115: 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, ! 116: 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, ! 117: 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, ! 118: 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, ! 119: 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, ! 120: 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, ! 121: 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, ! 122: 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, ! 123: 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ! 124: 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ! 125: 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ! 126: 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ! 127: 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ! 128: 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, ! 129: 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ! 130: 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, ! 131: 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, ! 132: 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, ! 133: 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, ! 134: 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, ! 135: 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, ! 136: 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ! 137: 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, ! 138: 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff ! 139: }; ! 140: ! 141: isc_result_t ! 142: isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, ! 143: unsigned int limit, isc_hash_t **hctxp) ! 144: { ! 145: isc_result_t result; ! 146: isc_hash_t *hctx; ! 147: size_t vlen; ! 148: hash_random_t *rv; ! 149: hash_accum_t overflow_limit; ! 150: ! 151: REQUIRE(mctx != NULL); ! 152: REQUIRE(hctxp != NULL && *hctxp == NULL); ! 153: ! 154: /* ! 155: * Overflow check. Since our implementation only does a modulo ! 156: * operation at the last stage of hash calculation, the accumulator ! 157: * must not overflow. ! 158: */ ! 159: overflow_limit = ! 160: 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8); ! 161: if (overflow_limit < (limit + 1) * 0xff) ! 162: return (ISC_R_RANGE); ! 163: ! 164: hctx = isc_mem_get(mctx, sizeof(isc_hash_t)); ! 165: if (hctx == NULL) ! 166: return (ISC_R_NOMEMORY); ! 167: ! 168: vlen = sizeof(hash_random_t) * (limit + 1); ! 169: rv = isc_mem_get(mctx, vlen); ! 170: if (rv == NULL) { ! 171: result = ISC_R_NOMEMORY; ! 172: goto errout; ! 173: } ! 174: ! 175: /* ! 176: * We need a lock. ! 177: */ ! 178: result = isc_mutex_init(&hctx->lock); ! 179: if (result != ISC_R_SUCCESS) ! 180: goto errout; ! 181: ! 182: /* ! 183: * From here down, no failures will/can occur. ! 184: */ ! 185: hctx->magic = HASH_MAGIC; ! 186: hctx->mctx = NULL; ! 187: isc_mem_attach(mctx, &hctx->mctx); ! 188: hctx->initialized = ISC_FALSE; ! 189: result = isc_refcount_init(&hctx->refcnt, 1); ! 190: if (result != ISC_R_SUCCESS) ! 191: goto cleanup_lock; ! 192: hctx->entropy = NULL; ! 193: hctx->limit = limit; ! 194: hctx->vectorlen = vlen; ! 195: hctx->rndvector = rv; ! 196: ! 197: if (entropy != NULL) ! 198: isc_entropy_attach(entropy, &hctx->entropy); ! 199: ! 200: *hctxp = hctx; ! 201: return (ISC_R_SUCCESS); ! 202: ! 203: cleanup_lock: ! 204: DESTROYLOCK(&hctx->lock); ! 205: errout: ! 206: isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); ! 207: if (rv != NULL) ! 208: isc_mem_put(mctx, rv, vlen); ! 209: ! 210: return (result); ! 211: } ! 212: ! 213: static void ! 214: initialize_lock(void) { ! 215: RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); ! 216: } ! 217: ! 218: isc_result_t ! 219: isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) { ! 220: isc_result_t result = ISC_R_SUCCESS; ! 221: ! 222: REQUIRE(mctx != NULL); ! 223: INSIST(hash == NULL); ! 224: ! 225: RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS); ! 226: ! 227: LOCK(&createlock); ! 228: ! 229: if (hash == NULL) ! 230: result = isc_hash_ctxcreate(mctx, entropy, limit, &hash); ! 231: ! 232: UNLOCK(&createlock); ! 233: ! 234: return (result); ! 235: } ! 236: ! 237: void ! 238: isc_hash_ctxinit(isc_hash_t *hctx) { ! 239: isc_result_t result; ! 240: ! 241: LOCK(&hctx->lock); ! 242: ! 243: if (hctx->initialized == ISC_TRUE) ! 244: goto out; ! 245: ! 246: if (hctx->entropy) { ! 247: result = isc_entropy_getdata(hctx->entropy, ! 248: hctx->rndvector, hctx->vectorlen, ! 249: NULL, 0); ! 250: INSIST(result == ISC_R_SUCCESS); ! 251: } else { ! 252: isc_uint32_t pr; ! 253: unsigned int i, copylen; ! 254: unsigned char *p; ! 255: ! 256: p = (unsigned char *)hctx->rndvector; ! 257: for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) { ! 258: isc_random_get(&pr); ! 259: if (i + sizeof(pr) <= hctx->vectorlen) ! 260: copylen = sizeof(pr); ! 261: else ! 262: copylen = hctx->vectorlen - i; ! 263: ! 264: memcpy(p, &pr, copylen); ! 265: } ! 266: INSIST(p == (unsigned char *)hctx->rndvector + ! 267: hctx->vectorlen); ! 268: } ! 269: ! 270: hctx->initialized = ISC_TRUE; ! 271: ! 272: out: ! 273: UNLOCK(&hctx->lock); ! 274: } ! 275: ! 276: void ! 277: isc_hash_init() { ! 278: INSIST(hash != NULL && VALID_HASH(hash)); ! 279: ! 280: isc_hash_ctxinit(hash); ! 281: } ! 282: ! 283: void ! 284: isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) { ! 285: REQUIRE(VALID_HASH(hctx)); ! 286: REQUIRE(hctxp != NULL && *hctxp == NULL); ! 287: ! 288: isc_refcount_increment(&hctx->refcnt, NULL); ! 289: *hctxp = hctx; ! 290: } ! 291: ! 292: static void ! 293: destroy(isc_hash_t **hctxp) { ! 294: isc_hash_t *hctx; ! 295: isc_mem_t *mctx; ! 296: ! 297: REQUIRE(hctxp != NULL && *hctxp != NULL); ! 298: hctx = *hctxp; ! 299: *hctxp = NULL; ! 300: ! 301: LOCK(&hctx->lock); ! 302: ! 303: isc_refcount_destroy(&hctx->refcnt); ! 304: ! 305: mctx = hctx->mctx; ! 306: if (hctx->entropy != NULL) ! 307: isc_entropy_detach(&hctx->entropy); ! 308: if (hctx->rndvector != NULL) ! 309: isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen); ! 310: ! 311: UNLOCK(&hctx->lock); ! 312: ! 313: DESTROYLOCK(&hctx->lock); ! 314: ! 315: memset(hctx, 0, sizeof(isc_hash_t)); ! 316: isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); ! 317: isc_mem_detach(&mctx); ! 318: } ! 319: ! 320: void ! 321: isc_hash_ctxdetach(isc_hash_t **hctxp) { ! 322: isc_hash_t *hctx; ! 323: unsigned int refs; ! 324: ! 325: REQUIRE(hctxp != NULL && VALID_HASH(*hctxp)); ! 326: hctx = *hctxp; ! 327: ! 328: isc_refcount_decrement(&hctx->refcnt, &refs); ! 329: if (refs == 0) ! 330: destroy(&hctx); ! 331: ! 332: *hctxp = NULL; ! 333: } ! 334: ! 335: void ! 336: isc_hash_destroy() { ! 337: unsigned int refs; ! 338: ! 339: INSIST(hash != NULL && VALID_HASH(hash)); ! 340: ! 341: isc_refcount_decrement(&hash->refcnt, &refs); ! 342: INSIST(refs == 0); ! 343: ! 344: destroy(&hash); ! 345: } ! 346: ! 347: static inline unsigned int ! 348: hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen, ! 349: isc_boolean_t case_sensitive) ! 350: { ! 351: hash_accum_t partial_sum = 0; ! 352: hash_random_t *p = hctx->rndvector; ! 353: unsigned int i = 0; ! 354: ! 355: /* Make it sure that the hash context is initialized. */ ! 356: if (hctx->initialized == ISC_FALSE) ! 357: isc_hash_ctxinit(hctx); ! 358: ! 359: if (case_sensitive) { ! 360: for (i = 0; i < keylen; i++) ! 361: partial_sum += key[i] * (hash_accum_t)p[i]; ! 362: } else { ! 363: for (i = 0; i < keylen; i++) ! 364: partial_sum += maptolower[key[i]] * (hash_accum_t)p[i]; ! 365: } ! 366: ! 367: partial_sum += p[i]; ! 368: ! 369: return ((unsigned int)(partial_sum % PRIME32)); ! 370: } ! 371: ! 372: unsigned int ! 373: isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key, ! 374: unsigned int keylen, isc_boolean_t case_sensitive) ! 375: { ! 376: REQUIRE(hctx != NULL && VALID_HASH(hctx)); ! 377: REQUIRE(keylen <= hctx->limit); ! 378: ! 379: return (hash_calc(hctx, key, keylen, case_sensitive)); ! 380: } ! 381: ! 382: unsigned int ! 383: isc_hash_calc(const unsigned char *key, unsigned int keylen, ! 384: isc_boolean_t case_sensitive) ! 385: { ! 386: INSIST(hash != NULL && VALID_HASH(hash)); ! 387: REQUIRE(keylen <= hash->limit); ! 388: ! 389: return (hash_calc(hash, key, keylen, case_sensitive)); ! 390: }