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 73This library implements type-checked dynamic hash tables. 74The hash table entries can be arbitrary structures. 75Usually they consist of key and value fields. 76.Pp 77.Fn lh_<type>_new 78creates a new 79.Vt LHASH_OF(<type>) 80structure to store arbitrary data entries, and provides the hash and 81compare callbacks to be used in organising the table's entries. 82The hash callback takes a pointer to a table entry as its argument 83and returns an unsigned long hash value for its key field. 84The hash value is normally truncated to a power of 2, so make sure that 85your hash function returns well mixed low order bits. 86The compare callback takes two arguments (pointers to two hash table 87entries), and returns 0 if their keys are equal, non-zero otherwise. 88If your hash table will contain items of some particular type and the 89hash and compare callbacks hash and compare these types, then the 90.Fn DECLARE_LHASH_HASH_FN 91and 92.Fn IMPLEMENT_LHASH_COMP_FN 93macros can be used to create callback wrappers of the prototypes 94required by 95.Fn lh_<type>_new . 96These provide per-variable casts before calling the type-specific 97callbacks written by the application author. 98These macros, as well as those used for the doall callbacks, are 99defined 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 136An 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) */ 140unsigned long STUFF_hash(const STUFF *tohash); 141/* Order 'arg1' and 'arg2' (implemented elsewhere) */ 142int stuff_cmp(const STUFF *arg1, const STUFF *arg2); 143/* Create type-safe wrapper functions for use in the LHASH internals */ 144static IMPLEMENT_LHASH_HASH_FN(stuff, STUFF); 145static IMPLEMENT_LHASH_COMP_FN(stuff, STUFF); 146/* ... */ 147int 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 157frees the 158.Vt LHASH_OF(<type>) 159structure 160.Fa table . 161Allocated hash table entries will not be freed; consider using 162.Fn lh_<type>_doall 163to deallocate any remaining entries in the hash table (see below). 164.Pp 165.Fn lh_<type>_insert 166inserts the structure pointed to by 167.Fa data 168into 169.Fa table . 170If there already is an entry with the same key, the old value is 171replaced. 172Note that 173.Fn lh_<type>_insert 174stores pointers, the data are not copied. 175.Pp 176.Fn lh_<type>_delete 177deletes an entry from 178.Fa table . 179.Pp 180.Fn lh_<type>_retrieve 181looks up an entry in 182.Fa table . 183Normally, 184.Fa data 185is a structure with the key field(s) set; the function will return a 186pointer to a fully populated structure. 187.Pp 188.Fn lh_<type>_doall 189will, for every entry in the hash table, call 190.Fa func 191with the data item as its parameter. 192For 193.Fn lh_<type>_doall 194and 195.Fn lh_<type>_doall_arg , 196function pointer casting should be avoided in the callbacks (see 197.Sx NOTES ) 198\(em instead use the declare/implement macros to create type-checked 199wrappers that cast variables prior to calling your type-specific 200callbacks. 201An example of this is illustrated here where the callback is used to 202cleanup resources for items in the hash table prior to the hashtable 203itself being deallocated: 204.Bd -literal -offset 2n 205/* Clean up resources belonging to 'a' (this is implemented elsewhere) */ 206void STUFF_cleanup_doall(STUFF *a); 207/* Implement a prototype-compatible wrapper for "STUFF_cleanup" */ 208IMPLEMENT_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 ... */ 211lh_STUFF_doall(hashtable, LHASH_DOALL_FN(STUFF_cleanup)); 212/* Then the hash table itself can be deallocated */ 213lh_STUFF_free(hashtable); 214.Ed 215.Pp 216When doing this, be careful if you delete entries from the hash table in 217your callbacks: the table may decrease in size, moving the item that you 218are currently on down lower in the hash table \(em this could cause some 219entries to be skipped during the iteration. 220The second best solution to this problem is to set hash->down_load=0 221before you start (which will stop the hash table ever decreasing in 222size). 223The best solution is probably to avoid deleting items from the hash 224table inside a doall callback! 225.Pp 226.Fn lh_<type>_doall_arg 227is the same as 228.Fn lh_<type>_doall 229except that 230.Fa func 231will be called with 232.Fa arg 233as the second argument and 234.Fa func 235should be of type 236.Vt LHASH_DOALL_ARG_FN_TYPE 237(a callback prototype that is passed both the table entry and an extra 238argument). 239As with 240.Fn lh_<type>_doall , 241you can instead choose to declare your callback with a prototype 242matching the types you are dealing with and use the declare/implement 243macros to create compatible wrappers that cast variables before calling 244your type-specific callbacks. 245An example of this is demonstrated here (printing all hash table entries 246to a BIO that is provided by the caller): 247.Bd -literal -offset 2n 248/* Print item 'a' to 'output_bio' (this is implemented elsewhere) */ 249void STUFF_print_doall_arg(const STUFF *a, BIO *output_bio); 250/* Implement a prototype-compatible wrapper for "STUFF_print" */ 251static 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 */ 254lh_STUFF_doall_arg(hashtable, LHASH_DOALL_ARG_FN(STUFF_print), BIO, 255 logging_bio); 256.Ed 257.Pp 258.Fn lh_<type>_error 259can be used to determine if an error occurred in the last operation. 260.Fn lh_<type>_error 261is a macro. 262.Sh RETURN VALUES 263.Fn lh_<type>_new 264returns 265.Dv NULL 266on error, otherwise a pointer to the new 267.Vt LHASH 268structure. 269.Pp 270When a hash table entry is replaced, 271.Fn lh_<type>_insert 272returns the value being replaced. 273.Dv NULL 274is returned on normal operation and on error. 275.Pp 276.Fn lh_<type>_delete 277returns the entry being deleted. 278.Dv NULL 279is returned if there is no such value in the hash table. 280.Pp 281.Fn lh_<type>_retrieve 282returns the hash table entry if it has been found, or 283.Dv NULL 284otherwise. 285.Pp 286.Fn lh_<type>_error 287returns 1 if an error occurred in the last operation, or 0 otherwise. 288.Pp 289.Fn lh_<type>_free , 290.Fn lh_<type>_doall , 291and 292.Fn lh_<type>_doall_arg 293return no values. 294.Sh NOTES 295The various LHASH macros and callback types exist to make it possible to 296write type-checked code without resorting to function-prototype casting 297\(em an evil that makes application code much harder to audit/verify and 298also opens the window of opportunity for stack corruption and other 299hard-to-find bugs. 300It also, apparently, violates ANSI-C. 301.Pp 302The LHASH code regards table entries as constant data. 303As such, it internally represents 304.Fn lh_<type>_insert Ap ed 305items with a 306.Vt const void * 307pointer type. 308This is why callbacks such as those used by 309.Fn lh_<type>_doall 310and 311.Fn lh_<type>_doall_arg 312declare their prototypes with "const", even for the parameters that pass 313back the table items' data pointers \(em for consistency, user-provided 314data is "const" at all times as far as the LHASH code is concerned. 315However, as callers are themselves providing these pointers, they can 316choose whether they too should be treating all such parameters as 317constant. 318.Pp 319As an example, a hash table may be maintained by code that, for 320reasons of encapsulation, has only "const" access to the data being 321indexed in the hash table (i.e. it is returned as "const" from 322elsewhere in their code) \(em in this case the LHASH prototypes are 323appropriate as-is. 324Conversely, if the caller is responsible for the life-time of the data 325in question, then they may well wish to make modifications to table item 326passed back in the 327.Fn lh_<type>_doall 328or 329.Fn lh_<type>_doall_arg 330callbacks (see the "STUFF_cleanup" example above). 331If so, the caller can either cast the "const" away (if they're providing 332the raw callbacks themselves) or use the macros to declare/implement the 333wrapper functions without "const" types. 334.Pp 335Callers that only have "const" access to data they are indexing in a 336table, yet declare callbacks without constant types (or cast the "const" 337away themselves), are therefore creating their own risks/bugs without 338being encouraged to do so by the API. 339On a related note, those auditing code should pay special attention 340to any instances of DECLARE/IMPLEMENT_LHASH_DOALL_[ARG_]_FN macros 341that provide types without any "const" qualifiers. 342.Sh INTERNALS 343The following description is based on the SSLeay documentation: 344.Pp 345The lhash library implements a hash table described in the 346.Em Communications of the ACM 347in 1991. 348What makes this hash table different is that as the table fills, 349the hash table is increased (or decreased) in size via 350.Xr OPENSSL_realloc 3 . 351When a 'resize' is done, instead of all hashes being redistributed over 352twice as many 'buckets', one bucket is split. 353So when an 'expand' is done, there is only a minimal cost to 354redistribute some values. 355Subsequent inserts will cause more single 'bucket' redistributions but 356there will never be a sudden large cost due to redistributing all the 357\&'buckets'. 358.Pp 359The state for a particular hash table is kept in the 360.Vt LHASH 361structure. 362The decision to increase or decrease the hash table size is made 363depending on the 'load' of the hash table. 364The load is the number of items in the hash table divided by the size of 365the hash table. 366The default values are as follows. 367If (hash->up_load < load) => expand. 368if (hash->down_load > load) => contract. 369The 370.Fa up_load 371has a default value of 1 and 372.Fa down_load 373has a default value of 2. 374These numbers can be modified by the application by just playing 375with the 376.Fa up_load 377and 378.Fa down_load 379variables. 380The 'load' is kept in a form which is multiplied by 256. 381So hash->up_load=8*256 will cause a load of 8 to be set. 382.Pp 383If you are interested in performance the field to watch is 384.Fa num_comp_calls . 385The hash library keeps track of the 'hash' value for each item so when a 386lookup is done, the 'hashes' are compared, if there is a match, then a 387full compare is done, and hash->num_comp_calls is incremented. 388If num_comp_calls is not equal to num_delete plus num_retrieve it means 389that your hash function is generating hashes that are the same for 390different values. 391It is probably worth changing your hash function if this is the case 392because even if your hash table has 10 items in a 'bucket', it can be 393searched with 10 394.Vt unsigned long 395compares and 10 linked list traverses. 396This will be much less expensive that 10 calls to your compare function. 397.Pp 398.Fn lh_strhash 399is a demo string hashing function: 400.Pp 401.Dl unsigned long lh_strhash(const char *c); 402.Pp 403Since the LHASH routines would normally be passed structures, this 404routine would not normally be passed to 405.Fn lh_<type>_new , 406rather 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 411The lhash library is available in all versions of SSLeay and OpenSSL. 412.Fn lh_<type>_error 413was added in SSLeay 0.9.1b. 414.Pp 415In OpenSSL 0.9.7, all lhash functions that were passed function pointers 416were 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 , 420and 421.Vt LHASH_DOALL_ARG_FN_TYPE 422became available. 423.Pp 424In OpenSSL 1.0.0, the lhash interface was revamped for even better type 425checking. 426.Sh BUGS 427.Fn lh_<type>_insert 428returns 429.Dv NULL 430both for success and error. 431