tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hash.c (5362B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * hash.c
      7 *
      8 * This is merely a couple wrappers around NSPR's PLHashTable, using
      9 * the identity hash and arena-aware allocators.  The reason I did
     10 * this is that hash tables are used in a few places throughout the
     11 * NSS Cryptoki Framework in a fairly stereotyped way, and this allows
     12 * me to pull the commonalities into one place.  Should we ever want
     13 * to change the implementation, it's all right here.
     14 */
     15 
     16 #ifndef CK_T
     17 #include "ck.h"
     18 #endif /* CK_T */
     19 
     20 /*
     21 * nssCKFWHash
     22 *
     23 *  nssCKFWHash_Create
     24 *  nssCKFWHash_Destroy
     25 *  nssCKFWHash_Add
     26 *  nssCKFWHash_Remove
     27 *  nssCKFWHash_Count
     28 *  nssCKFWHash_Exists
     29 *  nssCKFWHash_Lookup
     30 *  nssCKFWHash_Iterate
     31 */
     32 
     33 struct nssCKFWHashStr {
     34    NSSCKFWMutex *mutex;
     35 
     36    /*
     37     * The invariant that mutex protects is:
     38     *   The count accurately reflects the hashtable state.
     39     */
     40 
     41    PLHashTable *plHashTable;
     42    CK_ULONG count;
     43 };
     44 
     45 static PLHashNumber
     46 nss_ckfw_identity_hash(
     47    const void *key)
     48 {
     49    return (PLHashNumber)((char *)key - (char *)NULL);
     50 }
     51 
     52 /*
     53 * nssCKFWHash_Create
     54 *
     55 */
     56 NSS_IMPLEMENT nssCKFWHash *
     57 nssCKFWHash_Create(
     58    NSSCKFWInstance *fwInstance,
     59    NSSArena *arena,
     60    CK_RV *pError)
     61 {
     62    nssCKFWHash *rv;
     63 
     64 #ifdef NSSDEBUG
     65    if (!pError) {
     66        return (nssCKFWHash *)NULL;
     67    }
     68 
     69    if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
     70        *pError = CKR_ARGUMENTS_BAD;
     71        return (nssCKFWHash *)NULL;
     72    }
     73 #endif /* NSSDEBUG */
     74 
     75    rv = nss_ZNEW(arena, nssCKFWHash);
     76    if (!rv) {
     77        *pError = CKR_HOST_MEMORY;
     78        return (nssCKFWHash *)NULL;
     79    }
     80 
     81    rv->mutex = nssCKFWInstance_CreateMutex(fwInstance, arena, pError);
     82    if (!rv->mutex) {
     83        if (CKR_OK == *pError) {
     84            *pError = CKR_GENERAL_ERROR;
     85        }
     86        (void)nss_ZFreeIf(rv);
     87        return (nssCKFWHash *)NULL;
     88    }
     89 
     90    rv->plHashTable = PL_NewHashTable(0, nss_ckfw_identity_hash,
     91                                      PL_CompareValues, PL_CompareValues, &nssArenaHashAllocOps, arena);
     92    if (!rv->plHashTable) {
     93        (void)nssCKFWMutex_Destroy(rv->mutex);
     94        (void)nss_ZFreeIf(rv);
     95        *pError = CKR_HOST_MEMORY;
     96        return (nssCKFWHash *)NULL;
     97    }
     98 
     99    rv->count = 0;
    100 
    101    return rv;
    102 }
    103 
    104 /*
    105 * nssCKFWHash_Destroy
    106 *
    107 */
    108 NSS_IMPLEMENT void
    109 nssCKFWHash_Destroy(
    110    nssCKFWHash *hash)
    111 {
    112    (void)nssCKFWMutex_Destroy(hash->mutex);
    113    PL_HashTableDestroy(hash->plHashTable);
    114    (void)nss_ZFreeIf(hash);
    115 }
    116 
    117 /*
    118 * nssCKFWHash_Add
    119 *
    120 */
    121 NSS_IMPLEMENT CK_RV
    122 nssCKFWHash_Add(
    123    nssCKFWHash *hash,
    124    const void *key,
    125    const void *value)
    126 {
    127    CK_RV error = CKR_OK;
    128    PLHashEntry *he;
    129 
    130    error = nssCKFWMutex_Lock(hash->mutex);
    131    if (CKR_OK != error) {
    132        return error;
    133    }
    134 
    135    he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
    136    if (!he) {
    137        error = CKR_HOST_MEMORY;
    138    } else {
    139        hash->count++;
    140    }
    141 
    142    (void)nssCKFWMutex_Unlock(hash->mutex);
    143 
    144    return error;
    145 }
    146 
    147 /*
    148 * nssCKFWHash_Remove
    149 *
    150 */
    151 NSS_IMPLEMENT void
    152 nssCKFWHash_Remove(
    153    nssCKFWHash *hash,
    154    const void *it)
    155 {
    156    PRBool found;
    157 
    158    if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) {
    159        return;
    160    }
    161 
    162    found = PL_HashTableRemove(hash->plHashTable, it);
    163    if (found) {
    164        hash->count--;
    165    }
    166 
    167    (void)nssCKFWMutex_Unlock(hash->mutex);
    168    return;
    169 }
    170 
    171 /*
    172 * nssCKFWHash_Count
    173 *
    174 */
    175 NSS_IMPLEMENT CK_ULONG
    176 nssCKFWHash_Count(
    177    nssCKFWHash *hash)
    178 {
    179    CK_ULONG count;
    180 
    181    if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) {
    182        return (CK_ULONG)0;
    183    }
    184 
    185    count = hash->count;
    186 
    187    (void)nssCKFWMutex_Unlock(hash->mutex);
    188 
    189    return count;
    190 }
    191 
    192 /*
    193 * nssCKFWHash_Exists
    194 *
    195 */
    196 NSS_IMPLEMENT CK_BBOOL
    197 nssCKFWHash_Exists(
    198    nssCKFWHash *hash,
    199    const void *it)
    200 {
    201    void *value;
    202 
    203    if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) {
    204        return CK_FALSE;
    205    }
    206 
    207    value = PL_HashTableLookup(hash->plHashTable, it);
    208 
    209    (void)nssCKFWMutex_Unlock(hash->mutex);
    210 
    211    if (!value) {
    212        return CK_FALSE;
    213    } else {
    214        return CK_TRUE;
    215    }
    216 }
    217 
    218 /*
    219 * nssCKFWHash_Lookup
    220 *
    221 */
    222 NSS_IMPLEMENT void *
    223 nssCKFWHash_Lookup(
    224    nssCKFWHash *hash,
    225    const void *it)
    226 {
    227    void *rv;
    228 
    229    if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) {
    230        return (void *)NULL;
    231    }
    232 
    233    rv = PL_HashTableLookup(hash->plHashTable, it);
    234 
    235    (void)nssCKFWMutex_Unlock(hash->mutex);
    236 
    237    return rv;
    238 }
    239 
    240 struct arg_str {
    241    nssCKFWHashIterator fcn;
    242    void *closure;
    243 };
    244 
    245 static PRIntn
    246 nss_ckfwhash_enumerator(
    247    PLHashEntry *he,
    248    PRIntn index,
    249    void *arg)
    250 {
    251    struct arg_str *as = (struct arg_str *)arg;
    252    as->fcn(he->key, he->value, as->closure);
    253    return HT_ENUMERATE_NEXT;
    254 }
    255 
    256 /*
    257 * nssCKFWHash_Iterate
    258 *
    259 * NOTE that the iteration function will be called with the hashtable locked.
    260 */
    261 NSS_IMPLEMENT void
    262 nssCKFWHash_Iterate(
    263    nssCKFWHash *hash,
    264    nssCKFWHashIterator fcn,
    265    void *closure)
    266 {
    267    struct arg_str as;
    268    as.fcn = fcn;
    269    as.closure = closure;
    270 
    271    if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) {
    272        return;
    273    }
    274 
    275    PL_HashTableEnumerateEntries(hash->plHashTable, nss_ckfwhash_enumerator, &as);
    276 
    277    (void)nssCKFWMutex_Unlock(hash->mutex);
    278 
    279    return;
    280 }