diff options
Diffstat (limited to 'src/lib/libcrypto/man/lh_new.3')
| -rw-r--r-- | src/lib/libcrypto/man/lh_new.3 | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/src/lib/libcrypto/man/lh_new.3 b/src/lib/libcrypto/man/lh_new.3 new file mode 100644 index 0000000000..2779cf9202 --- /dev/null +++ b/src/lib/libcrypto/man/lh_new.3 | |||
| @@ -0,0 +1,430 @@ | |||
| 1 | .Dd $Mdocdate: November 12 2015 $ | ||
| 2 | .Dt LH_NEW 3 | ||
| 3 | .Os | ||
| 4 | .Sh NAME | ||
| 5 | .Nm lh_new , | ||
| 6 | .Nm lh_free , | ||
| 7 | .Nm lh_insert , | ||
| 8 | .Nm lh_delete , | ||
| 9 | .Nm lh_retrieve , | ||
| 10 | .Nm lh_doall , | ||
| 11 | .Nm lh_doall_arg , | ||
| 12 | .Nm lh_error | ||
| 13 | .Nd dynamic hash table | ||
| 14 | .Sh SYNOPSIS | ||
| 15 | .In openssl/lhash.h | ||
| 16 | .Fn DECLARE_LHASH_OF <type> | ||
| 17 | .Ft LHASH * | ||
| 18 | .Fn lh_<type>_new void | ||
| 19 | .Ft void | ||
| 20 | .Fo lh_<type>_free | ||
| 21 | .Fa "LHASH_OF(<type>) *table" | ||
| 22 | .Fc | ||
| 23 | .Ft <type> * | ||
| 24 | .Fo lh_<type>_insert | ||
| 25 | .Fa "LHASH_OF(<type>) *table" | ||
| 26 | .Fa "<type> *data" | ||
| 27 | .Fc | ||
| 28 | .Ft <type> * | ||
| 29 | .Fo lh_<type>_delete | ||
| 30 | .Fa "LHASH_OF(<type>) *table" | ||
| 31 | .Fa "<type> *data" | ||
| 32 | .Fc | ||
| 33 | .Ft <type> * | ||
| 34 | .Fo lh_<type>_retrieve | ||
| 35 | .Fa "LHASH_OF<type>) *table" | ||
| 36 | .Fa "<type> *data" | ||
| 37 | .Fc | ||
| 38 | .Ft void | ||
| 39 | .Fo lh_<type>_doall | ||
| 40 | .Fa "LHASH_OF(<type>) *table" | ||
| 41 | .Fa "LHASH_DOALL_FN_TYPE func" | ||
| 42 | .Fc | ||
| 43 | .Ft void | ||
| 44 | .Fo lh_<type>_doall_arg | ||
| 45 | .Fa "LHASH_OF(<type>) *table" | ||
| 46 | .Fa "LHASH_DOALL_ARG_FN_TYPE func" | ||
| 47 | .Fa "<type2>" | ||
| 48 | .Fa "<type2> *arg" | ||
| 49 | .Fc | ||
| 50 | .Ft int | ||
| 51 | .Fo lh_<type>_error | ||
| 52 | .Fa "LHASH_OF(<type>) *table" | ||
| 53 | .Fc | ||
| 54 | .Ft typedef int | ||
| 55 | .Fo (*LHASH_COMP_FN_TYPE) | ||
| 56 | .Fa "const void *" | ||
| 57 | .Fa "const void *" | ||
| 58 | .Fc | ||
| 59 | .Ft typedef unsigned long | ||
| 60 | .Fo (*LHASH_HASH_FN_TYPE) | ||
| 61 | .Fa "const void *" | ||
| 62 | .Fc | ||
| 63 | .Ft typedef void | ||
| 64 | .Fo (*LHASH_DOALL_FN_TYPE) | ||
| 65 | .Fa "const void *" | ||
| 66 | .Fc | ||
| 67 | .Ft typedef void | ||
| 68 | .Fo (*LHASH_DOALL_ARG_FN_TYPE) | ||
| 69 | .Fa "const void *" | ||
| 70 | .Fa "const void *" | ||
| 71 | .Fc | ||
| 72 | .Sh DESCRIPTION | ||
| 73 | This library implements type-checked dynamic hash tables. | ||
| 74 | The hash table entries can be arbitrary structures. | ||
| 75 | Usually they consist of key and value fields. | ||
| 76 | .Pp | ||
| 77 | .Fn lh_<type>_new | ||
| 78 | creates a new | ||
| 79 | .Vt LHASH_OF(<type>) | ||
| 80 | structure to store arbitrary data entries, and provides the hash and | ||
| 81 | compare callbacks to be used in organising the table's entries. | ||
| 82 | The hash callback takes a pointer to a table entry as its argument | ||
| 83 | and returns an unsigned long hash value for its key field. | ||
| 84 | The hash value is normally truncated to a power of 2, so make sure that | ||
| 85 | your hash function returns well mixed low order bits. | ||
| 86 | The compare callback takes two arguments (pointers to two hash table | ||
| 87 | entries), and returns 0 if their keys are equal, non-zero otherwise. | ||
| 88 | If your hash table will contain items of some particular type and the | ||
| 89 | hash and compare callbacks hash and compare these types, then the | ||
| 90 | .Fn DECLARE_LHASH_HASH_FN | ||
| 91 | and | ||
| 92 | .Fn IMPLEMENT_LHASH_COMP_FN | ||
| 93 | macros can be used to create callback wrappers of the prototypes | ||
| 94 | required by | ||
| 95 | .Fn lh_<type>_new . | ||
| 96 | These provide per-variable casts before calling the type-specific | ||
| 97 | callbacks written by the application author. | ||
| 98 | These macros, as well as those used for the doall callbacks, are | ||
| 99 | defined as; | ||
| 100 | .Bd -literal -offset 2n | ||
| 101 | #define DECLARE_LHASH_HASH_FN(name, o_type) \e | ||
| 102 | unsigned long name##_LHASH_HASH(const void *); | ||
| 103 | #define IMPLEMENT_LHASH_HASH_FN(name, o_type) \e | ||
| 104 | unsigned long name##_LHASH_HASH(const void *arg) { \e | ||
| 105 | const o_type *a = arg; \e | ||
| 106 | return name##_hash(a); } | ||
| 107 | #define LHASH_HASH_FN(name) name##_LHASH_HASH | ||
| 108 | |||
| 109 | #define DECLARE_LHASH_COMP_FN(name, o_type) \e | ||
| 110 | int name##_LHASH_COMP(const void *, const void *); | ||
| 111 | #define IMPLEMENT_LHASH_COMP_FN(name, o_type) \e | ||
| 112 | int name##_LHASH_COMP(const void *arg1, const void *arg2) { \e | ||
| 113 | const o_type *a = arg1; \e | ||
| 114 | const o_type *b = arg2; \e | ||
| 115 | return name##_cmp(a,b); } | ||
| 116 | #define LHASH_COMP_FN(name) name##_LHASH_COMP | ||
| 117 | |||
| 118 | #define DECLARE_LHASH_DOALL_FN(name, o_type) \e | ||
| 119 | void name##_LHASH_DOALL(void *); | ||
| 120 | #define IMPLEMENT_LHASH_DOALL_FN(name, o_type) \e | ||
| 121 | void name##_LHASH_DOALL(void *arg) { \e | ||
| 122 | o_type *a = arg; \e | ||
| 123 | name##_doall(a); } | ||
| 124 | #define LHASH_DOALL_FN(name) name##_LHASH_DOALL | ||
| 125 | |||
| 126 | #define DECLARE_LHASH_DOALL_ARG_FN(name, o_type, a_type) \e | ||
| 127 | void name##_LHASH_DOALL_ARG(void *, void *); | ||
| 128 | #define IMPLEMENT_LHASH_DOALL_ARG_FN(name, o_type, a_type) \e | ||
| 129 | void name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \e | ||
| 130 | o_type *a = arg1; \e | ||
| 131 | a_type *b = arg2; \e | ||
| 132 | name##_doall_arg(a, b); } | ||
| 133 | #define LHASH_DOALL_ARG_FN(name) name##_LHASH_DOALL_ARG | ||
| 134 | .Ed | ||
| 135 | .Pp | ||
| 136 | An example of a hash table storing (pointers to) structures of type | ||
| 137 | \&'STUFF' could be defined as follows; | ||
| 138 | .Bd -literal -offset 2n | ||
| 139 | /* Calculate the hash value of 'tohash' (implemented elsewhere) */ | ||
| 140 | unsigned long STUFF_hash(const STUFF *tohash); | ||
| 141 | /* Order 'arg1' and 'arg2' (implemented elsewhere) */ | ||
| 142 | int stuff_cmp(const STUFF *arg1, const STUFF *arg2); | ||
| 143 | /* Create type-safe wrapper functions for use in the LHASH internals */ | ||
| 144 | static IMPLEMENT_LHASH_HASH_FN(stuff, STUFF); | ||
| 145 | static IMPLEMENT_LHASH_COMP_FN(stuff, STUFF); | ||
| 146 | /* ... */ | ||
| 147 | int main(int argc, char *argv[]) { | ||
| 148 | /* Create the new hash table using the hash/compare wrappers */ | ||
| 149 | LHASH_OF(STUFF) *hashtable = | ||
| 150 | lh_STUFF_new(LHASH_HASH_FN(STUFF_hash), | ||
| 151 | LHASH_COMP_FN(STUFF_cmp)); | ||
| 152 | /* ... */ | ||
| 153 | } | ||
| 154 | .Ed | ||
| 155 | .Pp | ||
| 156 | .Fn lh_<type>_free | ||
| 157 | frees the | ||
| 158 | .Vt LHASH_OF(<type>) | ||
| 159 | structure | ||
| 160 | .Fa table . | ||
| 161 | Allocated hash table entries will not be freed; consider using | ||
| 162 | .Fn lh_<type>_doall | ||
| 163 | to deallocate any remaining entries in the hash table (see below). | ||
| 164 | .Pp | ||
| 165 | .Fn lh_<type>_insert | ||
| 166 | inserts the structure pointed to by | ||
| 167 | .Fa data | ||
| 168 | into | ||
| 169 | .Fa table . | ||
| 170 | If there already is an entry with the same key, the old value is | ||
| 171 | replaced. | ||
| 172 | Note that | ||
| 173 | .Fn lh_<type>_insert | ||
| 174 | stores pointers, the data are not copied. | ||
| 175 | .Pp | ||
| 176 | .Fn lh_<type>_delete | ||
| 177 | deletes an entry from | ||
| 178 | .Fa table . | ||
| 179 | .Pp | ||
| 180 | .Fn lh_<type>_retrieve | ||
| 181 | looks up an entry in | ||
| 182 | .Fa table . | ||
| 183 | Normally, | ||
| 184 | .Fa data | ||
| 185 | is a structure with the key field(s) set; the function will return a | ||
| 186 | pointer to a fully populated structure. | ||
| 187 | .Pp | ||
| 188 | .Fn lh_<type>_doall | ||
| 189 | will, for every entry in the hash table, call | ||
| 190 | .Fa func | ||
| 191 | with the data item as its parameter. | ||
| 192 | For | ||
| 193 | .Fn lh_<type>_doall | ||
| 194 | and | ||
| 195 | .Fn lh_<type>_doall_arg , | ||
| 196 | function pointer casting should be avoided in the callbacks (see | ||
| 197 | .Sx NOTES ) | ||
| 198 | \(em instead use the declare/implement macros to create type-checked | ||
| 199 | wrappers that cast variables prior to calling your type-specific | ||
| 200 | callbacks. | ||
| 201 | An example of this is illustrated here where the callback is used to | ||
| 202 | cleanup resources for items in the hash table prior to the hashtable | ||
| 203 | itself being deallocated: | ||
| 204 | .Bd -literal -offset 2n | ||
| 205 | /* Clean up resources belonging to 'a' (this is implemented elsewhere) */ | ||
| 206 | void STUFF_cleanup_doall(STUFF *a); | ||
| 207 | /* Implement a prototype-compatible wrapper for "STUFF_cleanup" */ | ||
| 208 | IMPLEMENT_LHASH_DOALL_FN(STUFF_cleanup, STUFF) | ||
| 209 | /* ... then later in the code ... */ | ||
| 210 | /* So to run "STUFF_cleanup" against all items in a hash table ... */ | ||
| 211 | lh_STUFF_doall(hashtable, LHASH_DOALL_FN(STUFF_cleanup)); | ||
| 212 | /* Then the hash table itself can be deallocated */ | ||
| 213 | lh_STUFF_free(hashtable); | ||
| 214 | .Ed | ||
| 215 | .Pp | ||
| 216 | When doing this, be careful if you delete entries from the hash table in | ||
| 217 | your callbacks: the table may decrease in size, moving the item that you | ||
| 218 | are currently on down lower in the hash table \(em this could cause some | ||
| 219 | entries to be skipped during the iteration. | ||
| 220 | The second best solution to this problem is to set hash->down_load=0 | ||
| 221 | before you start (which will stop the hash table ever decreasing in | ||
| 222 | size). | ||
| 223 | The best solution is probably to avoid deleting items from the hash | ||
| 224 | table inside a doall callback! | ||
| 225 | .Pp | ||
| 226 | .Fn lh_<type>_doall_arg | ||
| 227 | is the same as | ||
| 228 | .Fn lh_<type>_doall | ||
| 229 | except that | ||
| 230 | .Fa func | ||
| 231 | will be called with | ||
| 232 | .Fa arg | ||
| 233 | as the second argument and | ||
| 234 | .Fa func | ||
| 235 | should be of type | ||
| 236 | .Vt LHASH_DOALL_ARG_FN_TYPE | ||
| 237 | (a callback prototype that is passed both the table entry and an extra | ||
| 238 | argument). | ||
| 239 | As with | ||
| 240 | .Fn lh_<type>_doall , | ||
| 241 | you can instead choose to declare your callback with a prototype | ||
| 242 | matching the types you are dealing with and use the declare/implement | ||
| 243 | macros to create compatible wrappers that cast variables before calling | ||
| 244 | your type-specific callbacks. | ||
| 245 | An example of this is demonstrated here (printing all hash table entries | ||
| 246 | to a BIO that is provided by the caller): | ||
| 247 | .Bd -literal -offset 2n | ||
| 248 | /* Print item 'a' to 'output_bio' (this is implemented elsewhere) */ | ||
| 249 | void STUFF_print_doall_arg(const STUFF *a, BIO *output_bio); | ||
| 250 | /* Implement a prototype-compatible wrapper for "STUFF_print" */ | ||
| 251 | static IMPLEMENT_LHASH_DOALL_ARG_FN(STUFF, const STUFF, BIO) | ||
| 252 | /* ... then later in the code ... */ | ||
| 253 | /* Print out the entire hashtable to a particular BIO */ | ||
| 254 | lh_STUFF_doall_arg(hashtable, LHASH_DOALL_ARG_FN(STUFF_print), BIO, | ||
| 255 | logging_bio); | ||
| 256 | .Ed | ||
| 257 | .Pp | ||
| 258 | .Fn lh_<type>_error | ||
| 259 | can be used to determine if an error occurred in the last operation. | ||
| 260 | .Fn lh_<type>_error | ||
| 261 | is a macro. | ||
| 262 | .Sh RETURN VALUES | ||
| 263 | .Fn lh_<type>_new | ||
| 264 | returns | ||
| 265 | .Dv NULL | ||
| 266 | on error, otherwise a pointer to the new | ||
| 267 | .Vt LHASH | ||
| 268 | structure. | ||
| 269 | .Pp | ||
| 270 | When a hash table entry is replaced, | ||
| 271 | .Fn lh_<type>_insert | ||
| 272 | returns the value being replaced. | ||
| 273 | .Dv NULL | ||
| 274 | is returned on normal operation and on error. | ||
| 275 | .Pp | ||
| 276 | .Fn lh_<type>_delete | ||
| 277 | returns the entry being deleted. | ||
| 278 | .Dv NULL | ||
| 279 | is returned if there is no such value in the hash table. | ||
| 280 | .Pp | ||
| 281 | .Fn lh_<type>_retrieve | ||
| 282 | returns the hash table entry if it has been found, or | ||
| 283 | .Dv NULL | ||
| 284 | otherwise. | ||
| 285 | .Pp | ||
| 286 | .Fn lh_<type>_error | ||
| 287 | returns 1 if an error occurred in the last operation, or 0 otherwise. | ||
| 288 | .Pp | ||
| 289 | .Fn lh_<type>_free , | ||
| 290 | .Fn lh_<type>_doall , | ||
| 291 | and | ||
| 292 | .Fn lh_<type>_doall_arg | ||
| 293 | return no values. | ||
| 294 | .Sh NOTES | ||
| 295 | The various LHASH macros and callback types exist to make it possible to | ||
| 296 | write type-checked code without resorting to function-prototype casting | ||
| 297 | \(em an evil that makes application code much harder to audit/verify and | ||
| 298 | also opens the window of opportunity for stack corruption and other | ||
| 299 | hard-to-find bugs. | ||
| 300 | It also, apparently, violates ANSI-C. | ||
| 301 | .Pp | ||
| 302 | The LHASH code regards table entries as constant data. | ||
| 303 | As such, it internally represents | ||
| 304 | .Fn lh_<type>_insert Ap ed | ||
| 305 | items with a | ||
| 306 | .Vt const void * | ||
| 307 | pointer type. | ||
| 308 | This is why callbacks such as those used by | ||
| 309 | .Fn lh_<type>_doall | ||
| 310 | and | ||
| 311 | .Fn lh_<type>_doall_arg | ||
| 312 | declare their prototypes with "const", even for the parameters that pass | ||
| 313 | back the table items' data pointers \(em for consistency, user-provided | ||
| 314 | data is "const" at all times as far as the LHASH code is concerned. | ||
| 315 | However, as callers are themselves providing these pointers, they can | ||
| 316 | choose whether they too should be treating all such parameters as | ||
| 317 | constant. | ||
| 318 | .Pp | ||
| 319 | As an example, a hash table may be maintained by code that, for | ||
| 320 | reasons of encapsulation, has only "const" access to the data being | ||
| 321 | indexed in the hash table (i.e. it is returned as "const" from | ||
| 322 | elsewhere in their code) \(em in this case the LHASH prototypes are | ||
| 323 | appropriate as-is. | ||
| 324 | Conversely, if the caller is responsible for the life-time of the data | ||
| 325 | in question, then they may well wish to make modifications to table item | ||
| 326 | passed back in the | ||
| 327 | .Fn lh_<type>_doall | ||
| 328 | or | ||
| 329 | .Fn lh_<type>_doall_arg | ||
| 330 | callbacks (see the "STUFF_cleanup" example above). | ||
| 331 | If so, the caller can either cast the "const" away (if they're providing | ||
| 332 | the raw callbacks themselves) or use the macros to declare/implement the | ||
| 333 | wrapper functions without "const" types. | ||
| 334 | .Pp | ||
| 335 | Callers that only have "const" access to data they are indexing in a | ||
| 336 | table, yet declare callbacks without constant types (or cast the "const" | ||
| 337 | away themselves), are therefore creating their own risks/bugs without | ||
| 338 | being encouraged to do so by the API. | ||
| 339 | On a related note, those auditing code should pay special attention | ||
| 340 | to any instances of DECLARE/IMPLEMENT_LHASH_DOALL_[ARG_]_FN macros | ||
| 341 | that provide types without any "const" qualifiers. | ||
| 342 | .Sh INTERNALS | ||
| 343 | The following description is based on the SSLeay documentation: | ||
| 344 | .Pp | ||
| 345 | The lhash library implements a hash table described in the | ||
| 346 | .Em Communications of the ACM | ||
| 347 | in 1991. | ||
| 348 | What makes this hash table different is that as the table fills, | ||
| 349 | the hash table is increased (or decreased) in size via | ||
| 350 | .Xr OPENSSL_realloc 3 . | ||
| 351 | When a 'resize' is done, instead of all hashes being redistributed over | ||
| 352 | twice as many 'buckets', one bucket is split. | ||
| 353 | So when an 'expand' is done, there is only a minimal cost to | ||
| 354 | redistribute some values. | ||
| 355 | Subsequent inserts will cause more single 'bucket' redistributions but | ||
| 356 | there will never be a sudden large cost due to redistributing all the | ||
| 357 | \&'buckets'. | ||
| 358 | .Pp | ||
| 359 | The state for a particular hash table is kept in the | ||
| 360 | .Vt LHASH | ||
| 361 | structure. | ||
| 362 | The decision to increase or decrease the hash table size is made | ||
| 363 | depending on the 'load' of the hash table. | ||
| 364 | The load is the number of items in the hash table divided by the size of | ||
| 365 | the hash table. | ||
| 366 | The default values are as follows. | ||
| 367 | If (hash->up_load < load) => expand. | ||
| 368 | if (hash->down_load > load) => contract. | ||
| 369 | The | ||
| 370 | .Fa up_load | ||
| 371 | has a default value of 1 and | ||
| 372 | .Fa down_load | ||
| 373 | has a default value of 2. | ||
| 374 | These numbers can be modified by the application by just playing | ||
| 375 | with the | ||
| 376 | .Fa up_load | ||
| 377 | and | ||
| 378 | .Fa down_load | ||
| 379 | variables. | ||
| 380 | The 'load' is kept in a form which is multiplied by 256. | ||
| 381 | So hash->up_load=8*256 will cause a load of 8 to be set. | ||
| 382 | .Pp | ||
| 383 | If you are interested in performance the field to watch is | ||
| 384 | .Fa num_comp_calls . | ||
| 385 | The hash library keeps track of the 'hash' value for each item so when a | ||
| 386 | lookup is done, the 'hashes' are compared, if there is a match, then a | ||
| 387 | full compare is done, and hash->num_comp_calls is incremented. | ||
| 388 | If num_comp_calls is not equal to num_delete plus num_retrieve it means | ||
| 389 | that your hash function is generating hashes that are the same for | ||
| 390 | different values. | ||
| 391 | It is probably worth changing your hash function if this is the case | ||
| 392 | because even if your hash table has 10 items in a 'bucket', it can be | ||
| 393 | searched with 10 | ||
| 394 | .Vt unsigned long | ||
| 395 | compares and 10 linked list traverses. | ||
| 396 | This will be much less expensive that 10 calls to your compare function. | ||
| 397 | .Pp | ||
| 398 | .Fn lh_strhash | ||
| 399 | is a demo string hashing function: | ||
| 400 | .Pp | ||
| 401 | .Dl unsigned long lh_strhash(const char *c); | ||
| 402 | .Pp | ||
| 403 | Since the LHASH routines would normally be passed structures, this | ||
| 404 | routine would not normally be passed to | ||
| 405 | .Fn lh_<type>_new , | ||
| 406 | rather it would be used in the function passed to | ||
| 407 | .Fn lh_<type>_new . | ||
| 408 | .Sh SEE ALSO | ||
| 409 | .Xr lh_stats 3 | ||
| 410 | .Sh HISTORY | ||
| 411 | The lhash library is available in all versions of SSLeay and OpenSSL. | ||
| 412 | .Fn lh_<type>_error | ||
| 413 | was added in SSLeay 0.9.1b. | ||
| 414 | .Pp | ||
| 415 | In OpenSSL 0.9.7, all lhash functions that were passed function pointers | ||
| 416 | were changed for better type safety, and the function types | ||
| 417 | .Vt LHASH_COMP_FN_TYPE , | ||
| 418 | .Vt LHASH_HASH_FN_TYPE , | ||
| 419 | .Vt LHASH_DOALL_FN_TYPE , | ||
| 420 | and | ||
| 421 | .Vt LHASH_DOALL_ARG_FN_TYPE | ||
| 422 | became available. | ||
| 423 | .Pp | ||
| 424 | In OpenSSL 1.0.0, the lhash interface was revamped for even better type | ||
| 425 | checking. | ||
| 426 | .Sh BUGS | ||
| 427 | .Fn lh_<type>_insert | ||
| 428 | returns | ||
| 429 | .Dv NULL | ||
| 430 | both for success and error. | ||
