00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #include <config.h>
00060
00061 #include <isc/entropy.h>
00062 #include <isc/hash.h>
00063 #include <isc/mem.h>
00064 #include <isc/magic.h>
00065 #include <isc/mutex.h>
00066 #include <isc/once.h>
00067 #include <isc/random.h>
00068 #include <isc/refcount.h>
00069 #include <isc/string.h>
00070 #include <isc/util.h>
00071
00072 #define HASH_MAGIC ISC_MAGIC('H', 'a', 's', 'h')
00073 #define VALID_HASH(h) ISC_MAGIC_VALID((h), HASH_MAGIC)
00074
00075
00076
00077
00078 #define PRIME32 0xFFFFFFFB
00079
00080
00081
00082
00083
00084
00085 typedef isc_uint32_t hash_accum_t;
00086 typedef isc_uint16_t hash_random_t;
00087
00088
00089
00090 struct isc_hash {
00091 unsigned int magic;
00092 isc_mem_t *mctx;
00093 isc_mutex_t lock;
00094 isc_boolean_t initialized;
00095 isc_refcount_t refcnt;
00096 isc_entropy_t *entropy;
00097 size_t limit;
00098 size_t vectorlen;
00099 hash_random_t *rndvector;
00100 };
00101
00102 static isc_mutex_t createlock;
00103 static isc_once_t once = ISC_ONCE_INIT;
00104 static isc_hash_t *hash = NULL;
00105
00106 static unsigned char maptolower[] = {
00107 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
00108 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
00109 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
00110 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
00111 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
00112 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
00113 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
00114 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
00115 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
00116 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
00117 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
00118 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
00119 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
00120 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
00121 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
00122 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
00123 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
00124 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
00125 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
00126 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
00127 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
00128 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
00129 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
00130 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
00131 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
00132 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
00133 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
00134 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
00135 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
00136 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
00137 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
00138 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
00139 };
00140
00141 isc_result_t
00142 isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
00143 size_t limit, isc_hash_t **hctxp)
00144 {
00145 isc_result_t result;
00146 isc_hash_t *hctx;
00147 size_t vlen;
00148 hash_random_t *rv;
00149 hash_accum_t overflow_limit;
00150
00151 REQUIRE(mctx != NULL);
00152 REQUIRE(hctxp != NULL && *hctxp == NULL);
00153
00154
00155
00156
00157
00158
00159 overflow_limit =
00160 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
00161 if (overflow_limit < (limit + 1) * 0xff)
00162 return (ISC_R_RANGE);
00163
00164 hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
00165 if (hctx == NULL)
00166 return (ISC_R_NOMEMORY);
00167
00168 vlen = sizeof(hash_random_t) * (limit + 1);
00169 rv = isc_mem_get(mctx, vlen);
00170 if (rv == NULL) {
00171 result = ISC_R_NOMEMORY;
00172 goto errout;
00173 }
00174
00175
00176
00177
00178 result = isc_mutex_init(&hctx->lock);
00179 if (result != ISC_R_SUCCESS)
00180 goto errout;
00181
00182
00183
00184
00185 hctx->magic = HASH_MAGIC;
00186 hctx->mctx = NULL;
00187 isc_mem_attach(mctx, &hctx->mctx);
00188 hctx->initialized = ISC_FALSE;
00189 result = isc_refcount_init(&hctx->refcnt, 1);
00190 if (result != ISC_R_SUCCESS)
00191 goto cleanup_lock;
00192 hctx->entropy = NULL;
00193 hctx->limit = limit;
00194 hctx->vectorlen = vlen;
00195 hctx->rndvector = rv;
00196
00197 if (entropy != NULL)
00198 isc_entropy_attach(entropy, &hctx->entropy);
00199
00200 *hctxp = hctx;
00201 return (ISC_R_SUCCESS);
00202
00203 cleanup_lock:
00204 DESTROYLOCK(&hctx->lock);
00205 errout:
00206 isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
00207 if (rv != NULL)
00208 isc_mem_put(mctx, rv, vlen);
00209
00210 return (result);
00211 }
00212
00213 static void
00214 initialize_lock(void) {
00215 RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
00216 }
00217
00218 isc_result_t
00219 isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
00220 isc_result_t result = ISC_R_SUCCESS;
00221
00222 REQUIRE(mctx != NULL);
00223 INSIST(hash == NULL);
00224
00225 RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
00226
00227 LOCK(&createlock);
00228
00229 if (hash == NULL)
00230 result = isc_hash_ctxcreate(mctx, entropy, limit, &hash);
00231
00232 UNLOCK(&createlock);
00233
00234 return (result);
00235 }
00236
00237 void
00238 isc_hash_ctxinit(isc_hash_t *hctx) {
00239 LOCK(&hctx->lock);
00240
00241 if (hctx->initialized == ISC_TRUE)
00242 goto out;
00243
00244 if (hctx->entropy != NULL) {
00245 isc_result_t result;
00246
00247 result = isc_entropy_getdata(hctx->entropy,
00248 hctx->rndvector,
00249 (unsigned int)hctx->vectorlen,
00250 NULL, 0);
00251 INSIST(result == ISC_R_SUCCESS);
00252 } else {
00253 isc_uint32_t pr;
00254 size_t i, copylen;
00255 unsigned char *p;
00256
00257 p = (unsigned char *)hctx->rndvector;
00258 for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
00259 isc_random_get(&pr);
00260 if (i + sizeof(pr) <= hctx->vectorlen)
00261 copylen = sizeof(pr);
00262 else
00263 copylen = hctx->vectorlen - i;
00264
00265 memmove(p, &pr, copylen);
00266 }
00267 INSIST(p == (unsigned char *)hctx->rndvector +
00268 hctx->vectorlen);
00269 }
00270
00271 hctx->initialized = ISC_TRUE;
00272
00273 out:
00274 UNLOCK(&hctx->lock);
00275 }
00276
00277 void
00278 isc_hash_init(void) {
00279 INSIST(hash != NULL && VALID_HASH(hash));
00280
00281 isc_hash_ctxinit(hash);
00282 }
00283
00284 void
00285 isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
00286 REQUIRE(VALID_HASH(hctx));
00287 REQUIRE(hctxp != NULL && *hctxp == NULL);
00288
00289 isc_refcount_increment(&hctx->refcnt, NULL);
00290 *hctxp = hctx;
00291 }
00292
00293 static void
00294 destroy(isc_hash_t **hctxp) {
00295 isc_hash_t *hctx;
00296 isc_mem_t *mctx;
00297
00298 REQUIRE(hctxp != NULL && *hctxp != NULL);
00299 hctx = *hctxp;
00300 *hctxp = NULL;
00301
00302 LOCK(&hctx->lock);
00303
00304 isc_refcount_destroy(&hctx->refcnt);
00305
00306 mctx = hctx->mctx;
00307 if (hctx->entropy != NULL)
00308 isc_entropy_detach(&hctx->entropy);
00309 if (hctx->rndvector != NULL)
00310 isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
00311
00312 UNLOCK(&hctx->lock);
00313
00314 DESTROYLOCK(&hctx->lock);
00315
00316 memset(hctx, 0, sizeof(isc_hash_t));
00317 isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
00318 isc_mem_detach(&mctx);
00319 }
00320
00321 void
00322 isc_hash_ctxdetach(isc_hash_t **hctxp) {
00323 isc_hash_t *hctx;
00324 unsigned int refs;
00325
00326 REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
00327 hctx = *hctxp;
00328
00329 isc_refcount_decrement(&hctx->refcnt, &refs);
00330 if (refs == 0)
00331 destroy(&hctx);
00332
00333 *hctxp = NULL;
00334 }
00335
00336 void
00337 isc_hash_destroy(void) {
00338 unsigned int refs;
00339
00340 INSIST(hash != NULL && VALID_HASH(hash));
00341
00342 isc_refcount_decrement(&hash->refcnt, &refs);
00343 INSIST(refs == 0);
00344
00345 destroy(&hash);
00346 }
00347
00348 static inline unsigned int
00349 hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
00350 isc_boolean_t case_sensitive)
00351 {
00352 hash_accum_t partial_sum = 0;
00353 hash_random_t *p = hctx->rndvector;
00354 unsigned int i = 0;
00355
00356
00357 if (hctx->initialized == ISC_FALSE)
00358 isc_hash_ctxinit(hctx);
00359
00360 if (case_sensitive) {
00361 for (i = 0; i < keylen; i++)
00362 partial_sum += key[i] * (hash_accum_t)p[i];
00363 } else {
00364 for (i = 0; i < keylen; i++)
00365 partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
00366 }
00367
00368 partial_sum += p[i];
00369
00370 return ((unsigned int)(partial_sum % PRIME32));
00371 }
00372
00373 unsigned int
00374 isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
00375 unsigned int keylen, isc_boolean_t case_sensitive)
00376 {
00377 REQUIRE(hctx != NULL && VALID_HASH(hctx));
00378 REQUIRE(keylen <= hctx->limit);
00379
00380 return (hash_calc(hctx, key, keylen, case_sensitive));
00381 }
00382
00383 unsigned int
00384 isc_hash_calc(const unsigned char *key, unsigned int keylen,
00385 isc_boolean_t case_sensitive)
00386 {
00387 INSIST(hash != NULL && VALID_HASH(hash));
00388 REQUIRE(keylen <= hash->limit);
00389
00390 return (hash_calc(hash, key, keylen, case_sensitive));
00391 }
00392
00393 void
00394 isc__hash_setvec(const isc_uint16_t *vec) {
00395 int i;
00396 hash_random_t *p;
00397
00398 if (hash == NULL)
00399 return;
00400
00401 p = hash->rndvector;
00402 for (i = 0; i < 256; i++) {
00403 p[i] = vec[i];
00404 }
00405 }