hashtable.h 12 KB

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