hashtable.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (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. #ifndef OPENSSL_HASHTABLE_H
  10. # define OPENSSL_HASHTABLE_H
  11. # pragma once
  12. #include <stddef.h>
  13. #include <stdint.h>
  14. #include <openssl/e_os2.h>
  15. #include <internal/rcu.h>
  16. #include "crypto/context.h"
  17. typedef struct ht_internal_st HT;
  18. /*
  19. * Represents a value in the hash table
  20. */
  21. typedef struct ht_value_st {
  22. void *value;
  23. uintptr_t *type_id;
  24. } HT_VALUE;
  25. /*
  26. * Represents a list of values filtered from a hash table
  27. */
  28. typedef struct ht_value_list_st {
  29. size_t list_len;
  30. HT_VALUE **list;
  31. } HT_VALUE_LIST;
  32. /*
  33. * Hashtable configuration
  34. */
  35. typedef struct ht_config_st {
  36. OSSL_LIB_CTX *ctx;
  37. void (*ht_free_fn)(HT_VALUE *obj);
  38. uint64_t (*ht_hash_fn)(uint8_t *key, size_t keylen);
  39. uint32_t init_neighborhoods;
  40. } HT_CONFIG;
  41. /*
  42. * Key value for a hash lookup
  43. */
  44. typedef struct ht_key_header_st {
  45. size_t keysize;
  46. uint8_t *keybuf;
  47. } HT_KEY;
  48. /*
  49. * Hashtable key rules
  50. * Any struct can be used to formulate a hash table key, as long as the
  51. * following rules
  52. * 1) The first element of the struct defining the key must be an HT_KEY
  53. * 2) All struct elements must have a compile time defined length
  54. * 3) Pointers can be used, but the value of the pointer, rather than
  55. * the contents of the address it points to will be used to compute
  56. * the hash
  57. * The key definition macros will assist with enforcing these rules
  58. */
  59. /*
  60. * Starts the definition of a hash table key
  61. */
  62. #define HT_START_KEY_DEFN(keyname) \
  63. typedef struct keyname##_st { \
  64. HT_KEY key_header; \
  65. struct {
  66. /*
  67. * Ends a hash table key definitions
  68. */
  69. #define HT_END_KEY_DEFN(keyname) \
  70. } keyfields; \
  71. } keyname;
  72. /*
  73. * Defines a field in a hash table key
  74. */
  75. #define HT_DEF_KEY_FIELD(name, type) type name;
  76. /*
  77. * convenience macro to define a static char
  78. * array field in a hash table key
  79. */
  80. #define HT_DEF_KEY_FIELD_CHAR_ARRAY(name, size) \
  81. HT_DEF_KEY_FIELD(name[size], char)
  82. /*
  83. * Defines a uint8_t (blob) field in a hash table key
  84. */
  85. #define HT_DEF_KEY_FIELD_UINT8T_ARRAY(name, size) \
  86. HT_DEF_KEY_FIELD(name[size], uint8_t)
  87. /*
  88. * Initializes a key
  89. */
  90. #define HT_INIT_KEY(key) do { \
  91. memset((key), 0, sizeof(*(key))); \
  92. (key)->key_header.keysize = (sizeof(*(key)) - sizeof(HT_KEY)); \
  93. (key)->key_header.keybuf = (((uint8_t *)key) + sizeof(HT_KEY)); \
  94. } while(0)
  95. /*
  96. * Resets a hash table key to a known state
  97. */
  98. #define HT_KEY_RESET(key) memset((key)->key_header.keybuf, 0, (key)->key_header.keysize)
  99. /*
  100. * Sets a scalar field in a hash table key
  101. */
  102. #define HT_SET_KEY_FIELD(key, member, value) (key)->keyfields.member = value;
  103. /*
  104. * Sets a string field in a hash table key, preserving
  105. * null terminator
  106. */
  107. #define HT_SET_KEY_STRING(key, member, value) do { \
  108. if ((value) != NULL) \
  109. strncpy((key)->keyfields.member, value, sizeof((key)->keyfields.member) - 1); \
  110. } while(0)
  111. /*
  112. * This is the same as HT_SET_KEY_STRING, except that it uses
  113. * ossl_ht_strcase to make the value being passed case insensitive
  114. * This is useful for instances in which we want upper and lower case
  115. * key value to hash to the same entry
  116. */
  117. #define HT_SET_KEY_STRING_CASE(key, member, value) do { \
  118. ossl_ht_strcase((key)->keyfields.member, value, sizeof((key)->keyfields.member) -1); \
  119. } while(0)
  120. /*
  121. * Sets a uint8_t (blob) field in a hash table key
  122. */
  123. #define HT_SET_KEY_BLOB(key, member, value, len) do { \
  124. if (value != NULL) \
  125. memcpy((key)->keyfields.member, value, len); \
  126. } while(0)
  127. /*
  128. * Converts a defined key type to an HT_KEY
  129. */
  130. #define TO_HT_KEY(key) &(key)->key_header
  131. /*
  132. * Converts an HT_KEY back to its defined
  133. * type
  134. */
  135. #define FROM_HT_KEY(key, type) (type)(key)
  136. /*
  137. * Implements the following type safe operations for a hash table
  138. * ossl_ht_NAME_TYPE_insert - insert a value to a hash table of type TYPE
  139. * ossl_ht_NAME_TYPE_get - gets a value of a specific type from the hash table
  140. * ossl_ht_NAME_TYPE_from_value - converts an HT_VALUE to its type
  141. * ossl_ht_NAME_TYPE_to_value - converts a TYPE to an HT_VALUE
  142. * ossl_ht_NAME_TYPE_type - boolean to detect if a value is of TYPE
  143. */
  144. #define IMPLEMENT_HT_VALUE_TYPE_FNS(vtype, name, pfx) \
  145. static uintptr_t name##_##vtype##_id = 0; \
  146. pfx ossl_unused int ossl_ht_##name##_##vtype##_insert(HT *h, HT_KEY *key, \
  147. vtype *data, \
  148. vtype **olddata) { \
  149. HT_VALUE inval; \
  150. HT_VALUE *oval = NULL; \
  151. int rc; \
  152. \
  153. inval.value = data; \
  154. inval.type_id = &name##_##vtype##_id; \
  155. rc = ossl_ht_insert(h, key, &inval, olddata == NULL ? NULL : &oval); \
  156. if (oval != NULL) \
  157. *olddata = (vtype *)oval->value; \
  158. return rc; \
  159. } \
  160. \
  161. pfx ossl_unused vtype *ossl_ht_##name##_##vtype##_from_value(HT_VALUE *v) \
  162. { \
  163. uintptr_t *expect_type = &name##_##vtype##_id; \
  164. if (v == NULL) \
  165. return NULL; \
  166. if (v->type_id != expect_type) \
  167. return NULL; \
  168. return (vtype *)v->value; \
  169. } \
  170. \
  171. pfx ossl_unused vtype *ossl_unused ossl_ht_##name##_##vtype##_get(HT *h, \
  172. HT_KEY *key, \
  173. HT_VALUE **v)\
  174. { \
  175. HT_VALUE *vv; \
  176. vv = ossl_ht_get(h, key); \
  177. if (vv == NULL) \
  178. return NULL; \
  179. *v = ossl_rcu_deref(&vv); \
  180. return ossl_ht_##name##_##vtype##_from_value(*v); \
  181. } \
  182. \
  183. pfx ossl_unused HT_VALUE *ossl_ht_##name##_##vtype##_to_value(vtype *data, \
  184. HT_VALUE *v) \
  185. { \
  186. v->type_id = &name##_##vtype##_id; \
  187. v->value = data; \
  188. return v; \
  189. } \
  190. \
  191. pfx ossl_unused int ossl_ht_##name##_##vtype##_type(HT_VALUE *h) \
  192. { \
  193. return h->type_id == &name##_##vtype##_id; \
  194. }
  195. #define DECLARE_HT_VALUE_TYPE_FNS(vtype, name) \
  196. int ossl_ht_##name##_##vtype##_insert(HT *h, HT_KEY *key, vtype *data, \
  197. vtype **olddata); \
  198. vtype *ossl_ht_##name##_##vtype##_from_value(HT_VALUE *v); \
  199. vtype *ossl_unused ossl_ht_##name##_##vtype##_get(HT *h, \
  200. HT_KEY *key, \
  201. HT_VALUE **v); \
  202. HT_VALUE *ossl_ht_##name##_##vtype##_to_value(vtype *data, HT_VALUE *v); \
  203. int ossl_ht_##name##_##vtype##_type(HT_VALUE *h); \
  204. /*
  205. * Helper function to construct case insensitive keys
  206. */
  207. static void ossl_unused ossl_ht_strcase(char *tgt, const char *src, int len)
  208. {
  209. int i;
  210. #if defined(CHARSET_EBCDIC) && !defined(CHARSET_EBCDIC_TEST)
  211. const long int case_adjust = ~0x40;
  212. #else
  213. const long int case_adjust = ~0x20;
  214. #endif
  215. if (src == NULL)
  216. return;
  217. for (i = 0; src[i] != '\0' && i < len; i++)
  218. tgt[i] = case_adjust & src[i];
  219. }
  220. /*
  221. * Create a new hashtable
  222. */
  223. HT *ossl_ht_new(HT_CONFIG *conf);
  224. /*
  225. * Frees a hash table, potentially freeing all elements
  226. */
  227. void ossl_ht_free(HT *htable);
  228. /*
  229. * Lock the table for reading
  230. */
  231. void ossl_ht_read_lock(HT *htable);
  232. /*
  233. * Lock the table for writing
  234. */
  235. void ossl_ht_write_lock(HT *htable);
  236. /*
  237. * Read unlock
  238. */
  239. void ossl_ht_read_unlock(HT *htable);
  240. /*
  241. * Write unlock
  242. */
  243. void ossl_ht_write_unlock (HT *htable);
  244. /*
  245. * Empties a hash table, potentially freeing all elements
  246. */
  247. int ossl_ht_flush(HT *htable);
  248. /*
  249. * Inserts an element to a hash table, optionally returning
  250. * replaced data to caller
  251. * Returns 1 if the insert was successful, 0 on error
  252. */
  253. int ossl_ht_insert(HT *htable, HT_KEY *key, HT_VALUE *data,
  254. HT_VALUE **olddata);
  255. /*
  256. * Deletes a value from a hash table, based on key
  257. * Returns 1 if the key was removed, 0 if they key was not found
  258. */
  259. int ossl_ht_delete(HT *htable, HT_KEY *key);
  260. /*
  261. * Returns number of elements in the hash table
  262. */
  263. size_t ossl_ht_count(HT *htable);
  264. /*
  265. * Iterates over each element in the table.
  266. * aborts the loop when cb returns 0
  267. * Contents of elements in the list may be modified during
  268. * this traversal, assuming proper thread safety is observed while doing
  269. * so (holding the table write lock is sufficient). However, elements of the
  270. * table may not be inserted or removed while iterating.
  271. */
  272. void ossl_ht_foreach_until(HT *htable, int (*cb)(HT_VALUE *obj, void *arg),
  273. void *arg);
  274. /*
  275. * Returns a list of elements in a hash table based on
  276. * filter function return value. Returns NULL on error,
  277. * or an HT_VALUE_LIST object on success. Note it is possible
  278. * That a list will be returned with 0 entries, if none were found.
  279. * The zero length list must still be freed via ossl_ht_value_list_free
  280. */
  281. HT_VALUE_LIST *ossl_ht_filter(HT *htable, size_t max_len,
  282. int (*filter)(HT_VALUE *obj, void *arg),
  283. void *arg);
  284. /*
  285. * Frees the list returned from ossl_ht_filter
  286. */
  287. void ossl_ht_value_list_free(HT_VALUE_LIST *list);
  288. /*
  289. * Fetches a value from the hash table, based
  290. * on key. Returns NULL if the element was not found.
  291. */
  292. HT_VALUE *ossl_ht_get(HT *htable, HT_KEY *key);
  293. #endif