/src/openssl/include/internal/hashtable.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2024-2026 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 | | |
10 | | #ifndef OPENSSL_HASHTABLE_H |
11 | | #define OPENSSL_HASHTABLE_H |
12 | | #pragma once |
13 | | |
14 | | #include <stddef.h> |
15 | | #include <stdint.h> |
16 | | #include <string.h> |
17 | | #include <openssl/e_os2.h> |
18 | | #include <internal/rcu.h> |
19 | | #include "crypto/context.h" |
20 | | |
21 | | typedef struct ht_internal_st HT; |
22 | | |
23 | | /* |
24 | | * Represents a key to a hashtable |
25 | | */ |
26 | | typedef struct ht_key_header_st { |
27 | | uint64_t cached_hash; |
28 | | size_t keysize; |
29 | | size_t bufsize; |
30 | | uint8_t *keybuf; |
31 | | } HT_KEY; |
32 | | |
33 | | /* |
34 | | * Represents a value in the hash table |
35 | | */ |
36 | | typedef struct ht_value_st { |
37 | | void *value; |
38 | | uintptr_t *type_id; |
39 | | HT_KEY key; |
40 | | } HT_VALUE; |
41 | | |
42 | | /* |
43 | | * Represents a list of values filtered from a hash table |
44 | | */ |
45 | | typedef struct ht_value_list_st { |
46 | | size_t list_len; |
47 | | HT_VALUE **list; |
48 | | } HT_VALUE_LIST; |
49 | | |
50 | | /* |
51 | | * Hashtable configuration |
52 | | */ |
53 | | typedef struct ht_config_st { |
54 | | OSSL_LIB_CTX *ctx; |
55 | | void (*ht_free_fn)(HT_VALUE *obj); |
56 | | uint64_t (*ht_hash_fn)(HT_KEY *key); |
57 | | size_t init_neighborhoods; |
58 | | uint32_t collision_check; |
59 | | uint32_t lockless_reads; |
60 | | uint32_t no_rcu; |
61 | | } HT_CONFIG; |
62 | | |
63 | | /* |
64 | | * Hashtable key rules |
65 | | * Any struct can be used to formulate a hash table key, as long as the |
66 | | * following rules |
67 | | * 1) The first element of the struct defining the key must be an HT_KEY |
68 | | * 2) All struct elements must have a compile time defined length |
69 | | * 3) Pointers can be used, but the value of the pointer, rather than |
70 | | * the contents of the address it points to will be used to compute |
71 | | * the hash |
72 | | * The key definition macros will assist with enforcing these rules |
73 | | */ |
74 | | |
75 | | /* |
76 | | * Starts the definition of a hash table key |
77 | | */ |
78 | | #define HT_START_KEY_DEFN(keyname) \ |
79 | | typedef struct keyname##_st { \ |
80 | | HT_KEY key_header; \ |
81 | | struct { |
82 | | |
83 | | /* |
84 | | * Ends a hash table key definitions |
85 | | */ |
86 | | #define HT_END_KEY_DEFN(keyname) \ |
87 | | } \ |
88 | | keyfields; \ |
89 | | } \ |
90 | | keyname; |
91 | | |
92 | | /* |
93 | | * Defines a field in a hash table key |
94 | | */ |
95 | | #define HT_DEF_KEY_FIELD(name, type) type name; |
96 | | |
97 | | /* |
98 | | * convenience macro to define a static char |
99 | | * array field in a hash table key |
100 | | */ |
101 | | #define HT_DEF_KEY_FIELD_CHAR_ARRAY(name, size) \ |
102 | | HT_DEF_KEY_FIELD(name[size], char) |
103 | | |
104 | | /* |
105 | | * Defines a uint8_t (blob) field in a hash table key |
106 | | */ |
107 | | #define HT_DEF_KEY_FIELD_UINT8T_ARRAY(name, size) \ |
108 | | HT_DEF_KEY_FIELD(name[size], uint8_t) |
109 | | |
110 | | /* |
111 | | * Initializes a key |
112 | | */ |
113 | | #define HT_INIT_KEY(key) \ |
114 | 225k | do { \ |
115 | 225k | memset((key), 0, sizeof(*(key))); \ |
116 | 225k | (key)->key_header.keysize = (key)->key_header.bufsize = (sizeof(*(key)) - sizeof(HT_KEY)); \ |
117 | 225k | (key)->key_header.keybuf = (((uint8_t *)key) + sizeof(HT_KEY)); \ |
118 | 225k | } while (0) |
119 | | |
120 | | /* |
121 | | * Initializes a key as a raw buffer |
122 | | * This operates identically to HT_INIT_KEY |
123 | | * but it treats the provided key as a raw buffer |
124 | | * and iteratively accounts the running amount of |
125 | | * data copied into the key from the caller. |
126 | | * |
127 | | * This MUST be used with the RAW macros below: |
128 | | * HT_COPY_RAW_KEY |
129 | | * HT_COPY_RAW_KEY_CASE |
130 | | */ |
131 | | #define HT_INIT_RAW_KEY(key) \ |
132 | 127k | do { \ |
133 | 127k | HT_INIT_KEY((key)); \ |
134 | 127k | (key)->key_header.keysize = 0; \ |
135 | 127k | } while (0) |
136 | | |
137 | | /* |
138 | | * Helper function to copy raw data into a key |
139 | | * This should not be called independently |
140 | | * use the HT_COPY_RAW_KEY macro instead |
141 | | */ |
142 | | static ossl_inline ossl_unused int ossl_key_raw_copy(HT_KEY *key, const uint8_t *buf, size_t len) |
143 | 0 | { |
144 | 0 | if (key->keysize + len > key->bufsize) |
145 | 0 | return 0; |
146 | 0 | memcpy(&key->keybuf[key->keysize], buf, len); |
147 | 0 | key->keysize += len; |
148 | 0 | return 1; |
149 | 0 | } Unexecuted instantiation: core_namemap.c:ossl_key_raw_copy Unexecuted instantiation: property.c:ossl_key_raw_copy Unexecuted instantiation: by_dir.c:ossl_key_raw_copy Unexecuted instantiation: by_file.c:ossl_key_raw_copy Unexecuted instantiation: by_store.c:ossl_key_raw_copy Unexecuted instantiation: v3_lib.c:ossl_key_raw_copy Unexecuted instantiation: v3_purp.c:ossl_key_raw_copy Unexecuted instantiation: v3_tlsf.c:ossl_key_raw_copy Unexecuted instantiation: v3_utl.c:ossl_key_raw_copy Unexecuted instantiation: x509_att.c:ossl_key_raw_copy Unexecuted instantiation: x509_lu.c:ossl_key_raw_copy Unexecuted instantiation: x509_set.c:ossl_key_raw_copy Unexecuted instantiation: x509_v3.c:ossl_key_raw_copy Unexecuted instantiation: x509_vfy.c:ossl_key_raw_copy Unexecuted instantiation: x509_vpm.c:ossl_key_raw_copy Unexecuted instantiation: x_all.c:ossl_key_raw_copy Unexecuted instantiation: x_attrib.c:ossl_key_raw_copy Unexecuted instantiation: x_crl.c:ossl_key_raw_copy Unexecuted instantiation: x_exten.c:ossl_key_raw_copy Unexecuted instantiation: x_name.c:ossl_key_raw_copy Unexecuted instantiation: hashtable.c:ossl_key_raw_copy Unexecuted instantiation: v3_ac_tgt.c:ossl_key_raw_copy Unexecuted instantiation: v3_addr.c:ossl_key_raw_copy Unexecuted instantiation: v3_asid.c:ossl_key_raw_copy Unexecuted instantiation: v3_battcons.c:ossl_key_raw_copy Unexecuted instantiation: v3_bcons.c:ossl_key_raw_copy Unexecuted instantiation: v3_cpols.c:ossl_key_raw_copy Unexecuted instantiation: v3_crld.c:ossl_key_raw_copy |
150 | | |
151 | | /* |
152 | | * Copy data directly into a key |
153 | | * When initialized with HT_INIT_RAW_KEY, this macro |
154 | | * can be used to copy packed data into a key for hashtable usage |
155 | | * It is advantageous as it limits the amount of data that needs to |
156 | | * be hashed when doing inserts/lookups/deletes, as it tracks how much |
157 | | * key data is actually valid |
158 | | */ |
159 | | #define HT_COPY_RAW_KEY(key, buf, len) ossl_key_raw_copy(key, buf, len) |
160 | | |
161 | | /* |
162 | | * Similar to HT_COPY_RAW_KEY but accepts a character buffer, and copies |
163 | | * data while converting case for case insensitive matches |
164 | | */ |
165 | | #define HT_COPY_RAW_KEY_CASE(key, buf, len) \ |
166 | 127k | do { \ |
167 | 127k | size_t tmplen = (size_t)(len); \ |
168 | 127k | if (tmplen > (key)->bufsize - (key)->keysize) \ |
169 | 127k | tmplen = (key)->bufsize - (key)->keysize; \ |
170 | 127k | ossl_ht_strcase((key), (char *)&((key)->keybuf[(key)->keysize]), buf, tmplen); \ |
171 | 127k | (key)->keysize += tmplen; \ |
172 | 127k | } while (0) |
173 | | |
174 | | #define HT_INIT_KEY_CACHED(key, hash) \ |
175 | 0 | do { \ |
176 | 0 | HT_INIT_KEY((key)); \ |
177 | 0 | (key)->key_header.cached_hash = hash; \ |
178 | 0 | } while (0) |
179 | | |
180 | | #define HT_INIT_KEY_EXTERNAL(key, buf, len) \ |
181 | 97.7k | do { \ |
182 | 97.7k | HT_INIT_KEY((key)); \ |
183 | 97.7k | (key)->key_header.keybuf = (buf); \ |
184 | 97.7k | (key)->key_header.keysize = (len); \ |
185 | 97.7k | } while (0) |
186 | | |
187 | 191 | #define HT_KEY_GET_HASH(key) (key)->key_header.cached_hash |
188 | | |
189 | | /* |
190 | | * Resets a hash table key to a known state |
191 | | */ |
192 | | #define HT_KEY_RESET(key) \ |
193 | | do { \ |
194 | | memset((key)->key_header.keybuf, 0, (key)->key_header.keysize); \ |
195 | | (key)->key_header.cached_hash = 0; \ |
196 | | } while (0) |
197 | | |
198 | | /* |
199 | | * Sets a scalar field in a hash table key |
200 | | */ |
201 | 0 | #define HT_SET_KEY_FIELD(key, member, value) (key)->keyfields.member = value; |
202 | | |
203 | | /* |
204 | | * Sets a string field in a hash table key, preserving |
205 | | * null terminator |
206 | | */ |
207 | | #define HT_SET_KEY_STRING(key, member, value) \ |
208 | | do { \ |
209 | | if ((value) != NULL) \ |
210 | | strncpy((key)->keyfields.member, value, sizeof((key)->keyfields.member) - 1); \ |
211 | | } while (0) |
212 | | |
213 | | /* |
214 | | * This is the same as HT_SET_KEY_STRING, except that it uses |
215 | | * ossl_ht_strcase to make the value being passed case insensitive |
216 | | * This is useful for instances in which we want upper and lower case |
217 | | * key value to hash to the same entry |
218 | | */ |
219 | | #define HT_SET_KEY_STRING_CASE(key, member, value) \ |
220 | | do { \ |
221 | | ossl_ht_strcase(NULL, (key)->keyfields.member, value, sizeof((key)->keyfields.member) - 1); \ |
222 | | } while (0) |
223 | | |
224 | | /* |
225 | | * Same as HT_SET_KEY_STRING but also takes length of the string. |
226 | | */ |
227 | | #define HT_SET_KEY_STRING_N(key, member, value, len) \ |
228 | | do { \ |
229 | | if ((value) != NULL) { \ |
230 | | if (len < sizeof((key)->keyfields.member)) \ |
231 | | strncpy((key)->keyfields.member, value, len); \ |
232 | | else \ |
233 | | strncpy((key)->keyfields.member, value, sizeof((key)->keyfields.member) - 1); \ |
234 | | } \ |
235 | | } while (0) |
236 | | |
237 | | /* Same as HT_SET_KEY_STRING_CASE but also takes length of the string. */ |
238 | | #define HT_SET_KEY_STRING_CASE_N(key, member, value, len) \ |
239 | | do { \ |
240 | | if ((size_t)len < sizeof((key)->keyfields.member)) \ |
241 | | ossl_ht_strcase(NULL, (key)->keyfields.member, value, len); \ |
242 | | else \ |
243 | | ossl_ht_strcase(NULL, (key)->keyfields.member, value, sizeof((key)->keyfields.member) - 1); \ |
244 | | } while (0) |
245 | | |
246 | | /* |
247 | | * Sets a uint8_t (blob) field in a hash table key |
248 | | */ |
249 | | #define HT_SET_KEY_BLOB(key, member, value, len) \ |
250 | | do { \ |
251 | | if (value != NULL) \ |
252 | | memcpy((key)->keyfields.member, value, len); \ |
253 | | } while (0) |
254 | | |
255 | | /* |
256 | | * Converts a defined key type to an HT_KEY |
257 | | */ |
258 | 225k | #define TO_HT_KEY(key) &(key)->key_header |
259 | | |
260 | | /* |
261 | | * Converts an HT_KEY back to its defined |
262 | | * type |
263 | | */ |
264 | | #define FROM_HT_KEY(key, type) (type)(key) |
265 | | |
266 | | /* |
267 | | * Implements the following type safe operations for a hash table |
268 | | * ossl_ht_NAME_TYPE_insert - insert a value to a hash table of type TYPE |
269 | | * ossl_ht_NAME_TYPE_get - gets a value of a specific type from the hash table |
270 | | * ossl_ht_NAME_TYPE_from_value - converts an HT_VALUE to its type |
271 | | * ossl_ht_NAME_TYPE_to_value - converts a TYPE to an HT_VALUE |
272 | | * ossl_ht_NAME_TYPE_type - boolean to detect if a value is of TYPE |
273 | | */ |
274 | | #define IMPLEMENT_HT_VALUE_TYPE_FNS(vtype, name, pfx) \ |
275 | | static uintptr_t name##_##vtype##_id = 0; \ |
276 | | pfx ossl_unused int ossl_ht_##name##_##vtype##_insert(HT *h, HT_KEY *key, \ |
277 | | vtype *data, \ |
278 | | vtype **olddata) \ |
279 | 170 | { \ |
280 | 170 | HT_VALUE inval; \ |
281 | 170 | HT_VALUE *oval = NULL; \ |
282 | 170 | int rc; \ |
283 | 170 | \ |
284 | 170 | inval.value = data; \ |
285 | 170 | inval.type_id = &name##_##vtype##_id; \ |
286 | 170 | rc = ossl_ht_insert(h, key, &inval, olddata == NULL ? NULL : &oval); \ |
287 | 170 | if (oval != NULL) \ |
288 | 170 | *olddata = (vtype *)ossl_ht_inner_value(h, oval); \ |
289 | 170 | return rc; \ |
290 | 170 | } \ |
291 | | \ |
292 | | pfx ossl_unused vtype *ossl_ht_##name##_##vtype##_from_value(HT_VALUE *v) \ |
293 | 97.5k | { \ |
294 | 97.5k | uintptr_t *expect_type = &name##_##vtype##_id; \ |
295 | 97.5k | if (v == NULL) \ |
296 | 97.5k | return NULL; \ |
297 | 97.5k | if (v->type_id != expect_type) \ |
298 | 97.5k | return NULL; \ |
299 | 97.5k | return (vtype *)v->value; \ |
300 | 97.5k | } \ |
301 | | \ |
302 | | pfx ossl_unused vtype *ossl_unused ossl_ht_##name##_##vtype##_get(HT *h, \ |
303 | | HT_KEY *key, \ |
304 | | HT_VALUE **v) \ |
305 | 97.6k | { \ |
306 | 97.6k | HT_VALUE *vv; \ |
307 | 97.6k | vv = ossl_ht_get(h, key); \ |
308 | 97.6k | if (vv == NULL) \ |
309 | 97.6k | return NULL; \ |
310 | 97.6k | *v = ossl_ht_deref_value(h, &vv); \ |
311 | 97.5k | return ossl_ht_##name##_##vtype##_from_value(*v); \ |
312 | 97.6k | } \ |
313 | | \ |
314 | | pfx ossl_unused HT_VALUE *ossl_ht_##name##_##vtype##_to_value(vtype *data, \ |
315 | | HT_VALUE *v) \ |
316 | 0 | { \ |
317 | 0 | v->type_id = &name##_##vtype##_id; \ |
318 | 0 | v->value = data; \ |
319 | 0 | return v; \ |
320 | 0 | } \ |
321 | | \ |
322 | | pfx ossl_unused int ossl_ht_##name##_##vtype##_type(HT_VALUE *h) \ |
323 | 0 | { \ |
324 | 0 | return h->type_id == &name##_##vtype##_id; \ |
325 | 0 | } |
326 | | |
327 | | #define DECLARE_HT_VALUE_TYPE_FNS(vtype, name) \ |
328 | | int ossl_ht_##name##_##vtype##_insert(HT *h, HT_KEY *key, vtype *data, \ |
329 | | vtype **olddata); \ |
330 | | vtype *ossl_ht_##name##_##vtype##_from_value(HT_VALUE *v); \ |
331 | | vtype *ossl_unused ossl_ht_##name##_##vtype##_get(HT *h, \ |
332 | | HT_KEY *key, \ |
333 | | HT_VALUE **v); \ |
334 | | HT_VALUE *ossl_ht_##name##_##vtype##_to_value(vtype *data, HT_VALUE *v); \ |
335 | | int ossl_ht_##name##_##vtype##_type(HT_VALUE *h); |
336 | | |
337 | | /* |
338 | | * Helper function to construct case insensitive keys |
339 | | */ |
340 | | static ossl_inline ossl_unused void ossl_ht_strcase(HT_KEY *key, char *tgt, const char *src, size_t len) |
341 | 127k | { |
342 | 127k | size_t i; |
343 | | #if defined(CHARSET_EBCDIC) && !defined(CHARSET_EBCDIC_TEST) |
344 | | const long int case_adjust = ~0x40; |
345 | | #else |
346 | 127k | const long int case_adjust = ~0x20; |
347 | 127k | #endif |
348 | | |
349 | 127k | if (src == NULL) |
350 | 0 | return; |
351 | | |
352 | | /* |
353 | | * If we're passed a key, we're doing raw key copies |
354 | | * so check that we don't overflow here, and truncate if |
355 | | * we copy more space than we have available |
356 | | */ |
357 | 127k | if (key != NULL && key->keysize + len > key->bufsize) |
358 | 0 | len = (size_t)(key->bufsize - key->keysize); |
359 | | |
360 | 1.08M | for (i = 0; src[i] != '\0' && i < len; i++) |
361 | 961k | tgt[i] = case_adjust & src[i]; |
362 | 127k | } core_namemap.c:ossl_ht_strcase Line | Count | Source | 341 | 127k | { | 342 | 127k | size_t i; | 343 | | #if defined(CHARSET_EBCDIC) && !defined(CHARSET_EBCDIC_TEST) | 344 | | const long int case_adjust = ~0x40; | 345 | | #else | 346 | 127k | const long int case_adjust = ~0x20; | 347 | 127k | #endif | 348 | | | 349 | 127k | if (src == NULL) | 350 | 0 | return; | 351 | | | 352 | | /* | 353 | | * If we're passed a key, we're doing raw key copies | 354 | | * so check that we don't overflow here, and truncate if | 355 | | * we copy more space than we have available | 356 | | */ | 357 | 127k | if (key != NULL && key->keysize + len > key->bufsize) | 358 | 0 | len = (size_t)(key->bufsize - key->keysize); | 359 | | | 360 | 1.08M | for (i = 0; src[i] != '\0' && i < len; i++) | 361 | 961k | tgt[i] = case_adjust & src[i]; | 362 | 127k | } |
Unexecuted instantiation: property.c:ossl_ht_strcase Unexecuted instantiation: by_dir.c:ossl_ht_strcase Unexecuted instantiation: by_file.c:ossl_ht_strcase Unexecuted instantiation: by_store.c:ossl_ht_strcase Unexecuted instantiation: v3_lib.c:ossl_ht_strcase Unexecuted instantiation: v3_purp.c:ossl_ht_strcase Unexecuted instantiation: v3_tlsf.c:ossl_ht_strcase Unexecuted instantiation: v3_utl.c:ossl_ht_strcase Unexecuted instantiation: x509_att.c:ossl_ht_strcase Unexecuted instantiation: x509_lu.c:ossl_ht_strcase Unexecuted instantiation: x509_set.c:ossl_ht_strcase Unexecuted instantiation: x509_v3.c:ossl_ht_strcase Unexecuted instantiation: x509_vfy.c:ossl_ht_strcase Unexecuted instantiation: x509_vpm.c:ossl_ht_strcase Unexecuted instantiation: x_all.c:ossl_ht_strcase Unexecuted instantiation: x_attrib.c:ossl_ht_strcase Unexecuted instantiation: x_crl.c:ossl_ht_strcase Unexecuted instantiation: x_exten.c:ossl_ht_strcase Unexecuted instantiation: x_name.c:ossl_ht_strcase Unexecuted instantiation: hashtable.c:ossl_ht_strcase Unexecuted instantiation: v3_ac_tgt.c:ossl_ht_strcase Unexecuted instantiation: v3_addr.c:ossl_ht_strcase Unexecuted instantiation: v3_asid.c:ossl_ht_strcase Unexecuted instantiation: v3_battcons.c:ossl_ht_strcase Unexecuted instantiation: v3_bcons.c:ossl_ht_strcase Unexecuted instantiation: v3_cpols.c:ossl_ht_strcase Unexecuted instantiation: v3_crld.c:ossl_ht_strcase |
363 | | |
364 | | /* |
365 | | * Create a new hashtable |
366 | | */ |
367 | | HT *ossl_ht_new(const HT_CONFIG *conf); |
368 | | |
369 | | /* |
370 | | * Frees a hash table, potentially freeing all elements |
371 | | */ |
372 | | void ossl_ht_free(HT *htable); |
373 | | |
374 | | /* |
375 | | * Lock the table for reading |
376 | | */ |
377 | | int ossl_ht_read_lock(HT *htable); |
378 | | |
379 | | /* |
380 | | * Lock the table for writing |
381 | | */ |
382 | | void ossl_ht_write_lock(HT *htable); |
383 | | |
384 | | /* |
385 | | * Read unlock |
386 | | */ |
387 | | void ossl_ht_read_unlock(HT *htable); |
388 | | |
389 | | /* |
390 | | * Write unlock |
391 | | */ |
392 | | void ossl_ht_write_unlock(HT *htable); |
393 | | |
394 | | /* |
395 | | * Empties a hash table, potentially freeing all elements |
396 | | */ |
397 | | int ossl_ht_flush(HT *htable); |
398 | | |
399 | | /* |
400 | | * Inserts an element to a hash table, optionally returning |
401 | | * replaced data to caller |
402 | | * Returns 1 if the insert was successful, 0 on duplicate without |
403 | | * replacement, invalid input, or another non-allocation failure, and -1 |
404 | | * on allocation failure or if the table could not be grown. |
405 | | */ |
406 | | int ossl_ht_insert(HT *htable, HT_KEY *key, HT_VALUE *data, |
407 | | HT_VALUE **olddata); |
408 | | |
409 | | /* |
410 | | * Deletes a value from a hash table, based on key |
411 | | * Returns 1 if the key was removed, 0 if they key was not found |
412 | | */ |
413 | | int ossl_ht_delete(HT *htable, HT_KEY *key); |
414 | | |
415 | | /* |
416 | | * Returns number of elements in the hash table |
417 | | */ |
418 | | size_t ossl_ht_count(HT *htable); |
419 | | |
420 | | /* |
421 | | * Iterates over each element in the table. |
422 | | * aborts the loop when cb returns 0 |
423 | | * Contents of elements in the list may be modified during |
424 | | * this traversal, assuming proper thread safety is observed while doing |
425 | | * so (holding the table write lock is sufficient). However, elements of the |
426 | | * table may not be inserted or removed while iterating. |
427 | | */ |
428 | | void ossl_ht_foreach_until(HT *htable, int (*cb)(HT_VALUE *obj, void *arg), |
429 | | void *arg); |
430 | | /* |
431 | | * Returns a list of elements in a hash table based on |
432 | | * filter function return value. Returns NULL on error, |
433 | | * or an HT_VALUE_LIST object on success. Note it is possible |
434 | | * That a list will be returned with 0 entries, if none were found. |
435 | | * The zero length list must still be freed via ossl_ht_value_list_free |
436 | | */ |
437 | | HT_VALUE_LIST *ossl_ht_filter(HT *htable, size_t max_len, |
438 | | int (*filter)(HT_VALUE *obj, void *arg), |
439 | | void *arg); |
440 | | /* |
441 | | * Frees the list returned from ossl_ht_filter |
442 | | */ |
443 | | void ossl_ht_value_list_free(HT_VALUE_LIST *list); |
444 | | |
445 | | /* |
446 | | * Fetches a value from the hash table, based |
447 | | * on key. Returns NULL if the element was not found. |
448 | | */ |
449 | | HT_VALUE *ossl_ht_get(HT *htable, HT_KEY *key); |
450 | | |
451 | | /** |
452 | | * ossl_ht_deref_value - Dereference a value stored in a hash table entry |
453 | | * @h: The hash table handle |
454 | | * @val: Pointer to the value pointer inside the hash table |
455 | | * |
456 | | * This helper returns the actual value stored in a hash table entry, |
457 | | * with awareness of whether the table is configured for RCU (Read-Copy-Update) |
458 | | * safe lookups. |
459 | | * |
460 | | * If the hash table is configured to use RCU lookups, the function |
461 | | * calls ossl_rcu_deref() to safely read the value under RCU protection. |
462 | | * This ensures that the caller sees a consistent pointer in concurrent environments. |
463 | | * |
464 | | * If RCU is not enabled (i.e. `h->config.no_rcu` is true), the function |
465 | | * simply dereferences @val directly. |
466 | | * |
467 | | * Return: |
468 | | * A pointer to the dereferenced hash table value (`HT_VALUE *`), or NULL if |
469 | | * the underlying pointer is NULL. |
470 | | */ |
471 | | HT_VALUE *ossl_ht_deref_value(HT *p, HT_VALUE **val); |
472 | | |
473 | | /** |
474 | | * ossl_ht_inner_value - Extract the user payload from a hash table value |
475 | | * @h: The hash table handle |
476 | | * @v: The hash table value wrapper (HT_VALUE) |
477 | | * |
478 | | * This helper returns the user-provided payload stored inside a |
479 | | * hash table value container. The behavior differs depending on |
480 | | * whether the hash table is configured to use RCU (Read-Copy-Update) |
481 | | * for concurrency control. |
482 | | * |
483 | | * - If RCU is enabled, the function simply returns `v->value` without |
484 | | * modifying or freeing the container. |
485 | | * |
486 | | * - If RCU is disabled the container structure `v` is no longer needed once |
487 | | * the inner pointer has been extracted. In this case, the function frees |
488 | | * `v` and returns the inner `value` pointer directly. |
489 | | * |
490 | | * Return: |
491 | | * A pointer to the user payload (`void *`) contained in the hash table |
492 | | * value wrapper. |
493 | | */ |
494 | | void *ossl_ht_inner_value(HT *h, HT_VALUE *v); |
495 | | |
496 | | #endif |