blob: c381acd3a8a872544b6da2980330ec348e469173 [file] [log] [blame]
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef LIST_H
#define LIST_H
/*
* This code is a fairly straightforward hash
* table implementation using Bob Jenkins'
* hash function.
*
* Hash tables are used in OpenVPN to keep track of
* client instances over various key spaces.
*/
/* define this to enable special list test mode */
/*#define LIST_TEST*/
#include "basic.h"
#include "buffer.h"
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
struct hash_element
{
void *value;
const void *key;
unsigned int hash_value;
struct hash_element *next;
};
struct hash_bucket
{
struct hash_element *list;
};
struct hash
{
int n_buckets;
int n_elements;
int mask;
uint32_t iv;
uint32_t (*hash_function)(const void *key, uint32_t iv);
bool (*compare_function)(const void *key1, const void *key2); /* return true if equal */
struct hash_bucket *buckets;
};
struct hash *hash_init(const int n_buckets,
const uint32_t iv,
uint32_t (*hash_function)(const void *key, uint32_t iv),
bool (*compare_function)(const void *key1, const void *key2));
void hash_free(struct hash *hash);
bool hash_add(struct hash *hash, const void *key, void *value, bool replace);
struct hash_element *hash_lookup_fast(struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv);
bool hash_remove_fast(struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv);
void hash_remove_by_value(struct hash *hash, void *value);
struct hash_iterator
{
struct hash *hash;
int bucket_index;
struct hash_bucket *bucket;
struct hash_element *elem;
struct hash_element *last;
bool bucket_marked;
int bucket_index_start;
int bucket_index_end;
};
void hash_iterator_init_range(struct hash *hash,
struct hash_iterator *hi,
int start_bucket,
int end_bucket);
void hash_iterator_init(struct hash *hash, struct hash_iterator *iter);
struct hash_element *hash_iterator_next(struct hash_iterator *hi);
void hash_iterator_delete_element(struct hash_iterator *hi);
void hash_iterator_free(struct hash_iterator *hi);
uint32_t hash_func(const uint8_t *k, uint32_t length, uint32_t initval);
#ifdef LIST_TEST
void list_test(void);
#endif
static inline uint32_t
hash_value(const struct hash *hash, const void *key)
{
return (*hash->hash_function)(key, hash->iv);
}
static inline int
hash_n_elements(const struct hash *hash)
{
return hash->n_elements;
}
static inline int
hash_n_buckets(const struct hash *hash)
{
return hash->n_buckets;
}
static inline struct hash_bucket *
hash_bucket(struct hash *hash, uint32_t hv)
{
return &hash->buckets[hv & hash->mask];
}
static inline void *
hash_lookup(struct hash *hash, const void *key)
{
void *ret = NULL;
struct hash_element *he;
uint32_t hv = hash_value(hash, key);
struct hash_bucket *bucket = &hash->buckets[hv & hash->mask];
he = hash_lookup_fast(hash, bucket, key, hv);
if (he)
{
ret = he->value;
}
return ret;
}
/* NOTE: assumes that key is not a duplicate */
static inline void
hash_add_fast(struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv,
void *value)
{
struct hash_element *he;
ALLOC_OBJ(he, struct hash_element);
he->value = value;
he->key = key;
he->hash_value = hv;
he->next = bucket->list;
bucket->list = he;
++hash->n_elements;
}
static inline bool
hash_remove(struct hash *hash, const void *key)
{
uint32_t hv;
struct hash_bucket *bucket;
bool ret;
hv = hash_value(hash, key);
bucket = &hash->buckets[hv & hash->mask];
ret = hash_remove_fast(hash, bucket, key, hv);
return ret;
}
#endif /* LIST */