123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- .\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35)
- .\"
- .\" Standard preamble:
- .\" ========================================================================
- .de Sp \" Vertical space (when we can't use .PP)
- .if t .sp .5v
- .if n .sp
- ..
- .de Vb \" Begin verbatim text
- .ft CW
- .nf
- .ne \\$1
- ..
- .de Ve \" End verbatim text
- .ft R
- .fi
- ..
- .\" Set up some character translations and predefined strings. \*(-- will
- .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
- .\" double quote, and \*(R" will give a right double quote. \*(C+ will
- .\" give a nicer C++. Capital omega is used to do unbreakable dashes and
- .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
- .\" nothing in troff, for use with C<>.
- .tr \(*W-
- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
- .ie n \{\
- . ds -- \(*W-
- . ds PI pi
- . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
- . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
- . ds L" ""
- . ds R" ""
- . ds C` ""
- . ds C' ""
- 'br\}
- .el\{\
- . ds -- \|\(em\|
- . ds PI \(*p
- . ds L" ``
- . ds R" ''
- . ds C`
- . ds C'
- 'br\}
- .\"
- .\" Escape single quotes in literal strings from groff's Unicode transform.
- .ie \n(.g .ds Aq \(aq
- .el .ds Aq '
- .\"
- .\" If the F register is >0, we'll generate index entries on stderr for
- .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
- .\" entries marked with X<> in POD. Of course, you'll have to process the
- .\" output yourself in some meaningful fashion.
- .\"
- .\" Avoid warning from groff about undefined register 'F'.
- .de IX
- ..
- .if !\nF .nr F 0
- .if \nF>0 \{\
- . de IX
- . tm Index:\\$1\t\\n%\t"\\$2"
- ..
- . if !\nF==2 \{\
- . nr % 0
- . nr F 2
- . \}
- .\}
- .\"
- .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
- .\" Fear. Run. Save yourself. No user-serviceable parts.
- . \" fudge factors for nroff and troff
- .if n \{\
- . ds #H 0
- . ds #V .8m
- . ds #F .3m
- . ds #[ \f1
- . ds #] \fP
- .\}
- .if t \{\
- . ds #H ((1u-(\\\\n(.fu%2u))*.13m)
- . ds #V .6m
- . ds #F 0
- . ds #[ \&
- . ds #] \&
- .\}
- . \" simple accents for nroff and troff
- .if n \{\
- . ds ' \&
- . ds ` \&
- . ds ^ \&
- . ds , \&
- . ds ~ ~
- . ds /
- .\}
- .if t \{\
- . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
- . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
- . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
- . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
- . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
- . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
- .\}
- . \" troff and (daisy-wheel) nroff accents
- .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
- .ds 8 \h'\*(#H'\(*b\h'-\*(#H'
- .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
- .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
- .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
- .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
- .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
- .ds ae a\h'-(\w'a'u*4/10)'e
- .ds Ae A\h'-(\w'A'u*4/10)'E
- . \" corrections for vroff
- .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
- .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
- . \" for low resolution devices (crt and lpr)
- .if \n(.H>23 .if \n(.V>19 \
- \{\
- . ds : e
- . ds 8 ss
- . ds o a
- . ds d- d\h'-1'\(ga
- . ds D- D\h'-1'\(hy
- . ds th \o'bp'
- . ds Th \o'LP'
- . ds ae ae
- . ds Ae AE
- .\}
- .rm #[ #] #H #V #F C
- .\" ========================================================================
- .\"
- .IX Title "lhash 3"
- .TH lhash 3 "2019-09-12" "1.0.2g" "OpenSSL"
- .\" For nroff, turn off justification. Always turn off hyphenation; it makes
- .\" way too many mistakes in technical documents.
- .if n .ad l
- .nh
- .SH "NAME"
- lh_new, lh_free, lh_insert, lh_delete, lh_retrieve, lh_doall, lh_doall_arg, lh_error \- dynamic hash table
- .SH "SYNOPSIS"
- .IX Header "SYNOPSIS"
- .Vb 1
- \& #include <openssl/lhash.h>
- \&
- \& DECLARE_LHASH_OF(<type>);
- \&
- \& LHASH *lh_<type>_new();
- \& void lh_<type>_free(LHASH_OF(<type> *table);
- \&
- \& <type> *lh_<type>_insert(LHASH_OF(<type> *table, <type> *data);
- \& <type> *lh_<type>_delete(LHASH_OF(<type> *table, <type> *data);
- \& <type> *lh_retrieve(LHASH_OF<type> *table, <type> *data);
- \&
- \& void lh_<type>_doall(LHASH_OF(<type> *table, LHASH_DOALL_FN_TYPE func);
- \& void lh_<type>_doall_arg(LHASH_OF(<type> *table, LHASH_DOALL_ARG_FN_TYPE func,
- \& <type2>, <type2> *arg);
- \&
- \& int lh_<type>_error(LHASH_OF(<type> *table);
- \&
- \& typedef int (*LHASH_COMP_FN_TYPE)(const void *, const void *);
- \& typedef unsigned long (*LHASH_HASH_FN_TYPE)(const void *);
- \& typedef void (*LHASH_DOALL_FN_TYPE)(const void *);
- \& typedef void (*LHASH_DOALL_ARG_FN_TYPE)(const void *, const void *);
- .Ve
- .SH "DESCRIPTION"
- .IX Header "DESCRIPTION"
- This library implements type-checked dynamic hash tables. The hash
- table entries can be arbitrary structures. Usually they consist of key
- and value fields.
- .PP
- lh_<type>\fI_new()\fR creates a new \fB\s-1LHASH_OF\s0(<type\fR> structure to store
- arbitrary data entries, and provides the 'hash' and 'compare'
- callbacks to be used in organising the table's entries. The \fBhash\fR
- callback takes a pointer to a table entry as its argument and returns
- an unsigned long hash value for its key field. The hash value is
- normally truncated to a power of 2, so make sure that your hash
- function returns well mixed low order bits. The \fBcompare\fR callback
- takes two arguments (pointers to two hash table entries), and returns
- 0 if their keys are equal, non-zero otherwise. If your hash table
- will contain items of some particular type and the \fBhash\fR and
- \&\fBcompare\fR callbacks hash/compare these types, then the
- \&\fB\s-1DECLARE_LHASH_HASH_FN\s0\fR and \fB\s-1IMPLEMENT_LHASH_COMP_FN\s0\fR macros can be
- used to create callback wrappers of the prototypes required by
- lh_<type>\fI_new()\fR. These provide per-variable casts before calling the
- type-specific callbacks written by the application author. These
- macros, as well as those used for the \*(L"doall\*(R" callbacks, are defined
- as;
- .PP
- .Vb 7
- \& #define DECLARE_LHASH_HASH_FN(name, o_type) \e
- \& unsigned long name##_LHASH_HASH(const void *);
- \& #define IMPLEMENT_LHASH_HASH_FN(name, o_type) \e
- \& unsigned long name##_LHASH_HASH(const void *arg) { \e
- \& const o_type *a = arg; \e
- \& return name##_hash(a); }
- \& #define LHASH_HASH_FN(name) name##_LHASH_HASH
- \&
- \& #define DECLARE_LHASH_COMP_FN(name, o_type) \e
- \& int name##_LHASH_COMP(const void *, const void *);
- \& #define IMPLEMENT_LHASH_COMP_FN(name, o_type) \e
- \& int name##_LHASH_COMP(const void *arg1, const void *arg2) { \e
- \& const o_type *a = arg1; \e
- \& const o_type *b = arg2; \e
- \& return name##_cmp(a,b); }
- \& #define LHASH_COMP_FN(name) name##_LHASH_COMP
- \&
- \& #define DECLARE_LHASH_DOALL_FN(name, o_type) \e
- \& void name##_LHASH_DOALL(void *);
- \& #define IMPLEMENT_LHASH_DOALL_FN(name, o_type) \e
- \& void name##_LHASH_DOALL(void *arg) { \e
- \& o_type *a = arg; \e
- \& name##_doall(a); }
- \& #define LHASH_DOALL_FN(name) name##_LHASH_DOALL
- \&
- \& #define DECLARE_LHASH_DOALL_ARG_FN(name, o_type, a_type) \e
- \& void name##_LHASH_DOALL_ARG(void *, void *);
- \& #define IMPLEMENT_LHASH_DOALL_ARG_FN(name, o_type, a_type) \e
- \& void name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \e
- \& o_type *a = arg1; \e
- \& a_type *b = arg2; \e
- \& name##_doall_arg(a, b); }
- \& #define LHASH_DOALL_ARG_FN(name) name##_LHASH_DOALL_ARG
- \&
- \& An example of a hash table storing (pointers to) structures of type \*(AqSTUFF\*(Aq
- \& could be defined as follows;
- \&
- \& /* Calculates the hash value of \*(Aqtohash\*(Aq (implemented elsewhere) */
- \& unsigned long STUFF_hash(const STUFF *tohash);
- \& /* Orders \*(Aqarg1\*(Aq and \*(Aqarg2\*(Aq (implemented elsewhere) */
- \& int stuff_cmp(const STUFF *arg1, const STUFF *arg2);
- \& /* Create the type\-safe wrapper functions for use in the LHASH internals */
- \& static IMPLEMENT_LHASH_HASH_FN(stuff, STUFF);
- \& static IMPLEMENT_LHASH_COMP_FN(stuff, STUFF);
- \& /* ... */
- \& int main(int argc, char *argv[]) {
- \& /* Create the new hash table using the hash/compare wrappers */
- \& LHASH_OF(STUFF) *hashtable = lh_STUFF_new(LHASH_HASH_FN(STUFF_hash),
- \& LHASH_COMP_FN(STUFF_cmp));
- \& /* ... */
- \& }
- .Ve
- .PP
- lh_<type>\fI_free()\fR frees the \fB\s-1LHASH_OF\s0(<type\fR> structure
- \&\fBtable\fR. Allocated hash table entries will not be freed; consider
- using lh_<type>\fI_doall()\fR to deallocate any remaining entries in the
- hash table (see below).
- .PP
- lh_<type>\fI_insert()\fR inserts the structure pointed to by \fBdata\fR into
- \&\fBtable\fR. If there already is an entry with the same key, the old
- value is replaced. Note that lh_<type>\fI_insert()\fR stores pointers, the
- data are not copied.
- .PP
- lh_<type>\fI_delete()\fR deletes an entry from \fBtable\fR.
- .PP
- lh_<type>\fI_retrieve()\fR looks up an entry in \fBtable\fR. Normally, \fBdata\fR
- is a structure with the key field(s) set; the function will return a
- pointer to a fully populated structure.
- .PP
- lh_<type>\fI_doall()\fR will, for every entry in the hash table, call
- \&\fBfunc\fR with the data item as its parameter. For lh_<type>\fI_doall()\fR
- and lh_<type>\fI_doall_arg()\fR, function pointer casting should be avoided
- in the callbacks (see \fB\s-1NOTE\s0\fR) \- instead use the declare/implement
- macros to create type-checked wrappers that cast variables prior to
- calling your type-specific callbacks. An example of this is
- illustrated here where the callback is used to cleanup resources for
- items in the hash table prior to the hashtable itself being
- deallocated:
- .PP
- .Vb 9
- \& /* Cleans up resources belonging to \*(Aqa\*(Aq (this is implemented elsewhere) */
- \& void STUFF_cleanup_doall(STUFF *a);
- \& /* Implement a prototype\-compatible wrapper for "STUFF_cleanup" */
- \& IMPLEMENT_LHASH_DOALL_FN(STUFF_cleanup, STUFF)
- \& /* ... then later in the code ... */
- \& /* So to run "STUFF_cleanup" against all items in a hash table ... */
- \& lh_STUFF_doall(hashtable, LHASH_DOALL_FN(STUFF_cleanup));
- \& /* Then the hash table itself can be deallocated */
- \& lh_STUFF_free(hashtable);
- .Ve
- .PP
- When doing this, be careful if you delete entries from the hash table
- in your callbacks: the table may decrease in size, moving the item
- that you are currently on down lower in the hash table \- this could
- cause some entries to be skipped during the iteration. The second
- best solution to this problem is to set hash\->down_load=0 before
- you start (which will stop the hash table ever decreasing in size).
- The best solution is probably to avoid deleting items from the hash
- table inside a \*(L"doall\*(R" callback!
- .PP
- lh_<type>\fI_doall_arg()\fR is the same as lh_<type>\fI_doall()\fR except that
- \&\fBfunc\fR will be called with \fBarg\fR as the second argument and \fBfunc\fR
- should be of type \fB\s-1LHASH_DOALL_ARG_FN_TYPE\s0\fR (a callback prototype
- that is passed both the table entry and an extra argument). As with
- \&\fIlh_doall()\fR, you can instead choose to declare your callback with a
- prototype matching the types you are dealing with and use the
- declare/implement macros to create compatible wrappers that cast
- variables before calling your type-specific callbacks. An example of
- this is demonstrated here (printing all hash table entries to a \s-1BIO\s0
- that is provided by the caller):
- .PP
- .Vb 8
- \& /* Prints item \*(Aqa\*(Aq to \*(Aqoutput_bio\*(Aq (this is implemented elsewhere) */
- \& void STUFF_print_doall_arg(const STUFF *a, BIO *output_bio);
- \& /* Implement a prototype\-compatible wrapper for "STUFF_print" */
- \& static IMPLEMENT_LHASH_DOALL_ARG_FN(STUFF, const STUFF, BIO)
- \& /* ... then later in the code ... */
- \& /* Print out the entire hashtable to a particular BIO */
- \& lh_STUFF_doall_arg(hashtable, LHASH_DOALL_ARG_FN(STUFF_print), BIO,
- \& logging_bio);
- .Ve
- .PP
- lh_<type>\fI_error()\fR can be used to determine if an error occurred in the last
- operation. lh_<type>\fI_error()\fR is a macro.
- .SH "RETURN VALUES"
- .IX Header "RETURN VALUES"
- lh_<type>\fI_new()\fR returns \fB\s-1NULL\s0\fR on error, otherwise a pointer to the new
- \&\fB\s-1LHASH\s0\fR structure.
- .PP
- When a hash table entry is replaced, lh_<type>\fI_insert()\fR returns the value
- being replaced. \fB\s-1NULL\s0\fR is returned on normal operation and on error.
- .PP
- lh_<type>\fI_delete()\fR returns the entry being deleted. \fB\s-1NULL\s0\fR is returned if
- there is no such value in the hash table.
- .PP
- lh_<type>\fI_retrieve()\fR returns the hash table entry if it has been found,
- \&\fB\s-1NULL\s0\fR otherwise.
- .PP
- lh_<type>\fI_error()\fR returns 1 if an error occurred in the last operation, 0
- otherwise.
- .PP
- lh_<type>\fI_free()\fR, lh_<type>\fI_doall()\fR and lh_<type>\fI_doall_arg()\fR return no values.
- .SH "NOTE"
- .IX Header "NOTE"
- The various \s-1LHASH\s0 macros and callback types exist to make it possible
- to write type-checked code without resorting to function-prototype
- casting \- an evil that makes application code much harder to
- audit/verify and also opens the window of opportunity for stack
- corruption and other hard-to-find bugs. It also, apparently, violates
- ANSI-C.
- .PP
- The \s-1LHASH\s0 code regards table entries as constant data. As such, it
- internally represents \fIlh_insert()\fR'd items with a \*(L"const void *\*(R"
- pointer type. This is why callbacks such as those used by \fIlh_doall()\fR
- and \fIlh_doall_arg()\fR declare their prototypes with \*(L"const\*(R", even for the
- parameters that pass back the table items' data pointers \- for
- consistency, user-provided data is \*(L"const\*(R" at all times as far as the
- \&\s-1LHASH\s0 code is concerned. However, as callers are themselves providing
- these pointers, they can choose whether they too should be treating
- all such parameters as constant.
- .PP
- As an example, a hash table may be maintained by code that, for
- reasons of encapsulation, has only \*(L"const\*(R" access to the data being
- indexed in the hash table (ie. it is returned as \*(L"const\*(R" from
- elsewhere in their code) \- in this case the \s-1LHASH\s0 prototypes are
- appropriate as-is. Conversely, if the caller is responsible for the
- life-time of the data in question, then they may well wish to make
- modifications to table item passed back in the \fIlh_doall()\fR or
- \&\fIlh_doall_arg()\fR callbacks (see the \*(L"STUFF_cleanup\*(R" example above). If
- so, the caller can either cast the \*(L"const\*(R" away (if they're providing
- the raw callbacks themselves) or use the macros to declare/implement
- the wrapper functions without \*(L"const\*(R" types.
- .PP
- Callers that only have \*(L"const\*(R" access to data they're indexing in a
- table, yet declare callbacks without constant types (or cast the
- \&\*(L"const\*(R" away themselves), are therefore creating their own risks/bugs
- without being encouraged to do so by the \s-1API.\s0 On a related note,
- those auditing code should pay special attention to any instances of
- DECLARE/IMPLEMENT_LHASH_DOALL_[\s-1ARG_\s0]_FN macros that provide types
- without any \*(L"const\*(R" qualifiers.
- .SH "BUGS"
- .IX Header "BUGS"
- lh_<type>\fI_insert()\fR returns \fB\s-1NULL\s0\fR both for success and error.
- .SH "INTERNALS"
- .IX Header "INTERNALS"
- The following description is based on the SSLeay documentation:
- .PP
- The \fBlhash\fR library implements a hash table described in the
- \&\fICommunications of the \s-1ACM\s0\fR in 1991. What makes this hash table
- different is that as the table fills, the hash table is increased (or
- decreased) in size via \fIOPENSSL_realloc()\fR. When a 'resize' is done, instead of
- all hashes being redistributed over twice as many 'buckets', one
- bucket is split. So when an 'expand' is done, there is only a minimal
- cost to redistribute some values. Subsequent inserts will cause more
- single 'bucket' redistributions but there will never be a sudden large
- cost due to redistributing all the 'buckets'.
- .PP
- The state for a particular hash table is kept in the \fB\s-1LHASH\s0\fR structure.
- The decision to increase or decrease the hash table size is made
- depending on the 'load' of the hash table. The load is the number of
- items in the hash table divided by the size of the hash table. The
- default values are as follows. If (hash\->up_load < load) =>
- expand. if (hash\->down_load > load) => contract. The
- \&\fBup_load\fR has a default value of 1 and \fBdown_load\fR has a default value
- of 2. These numbers can be modified by the application by just
- playing with the \fBup_load\fR and \fBdown_load\fR variables. The 'load' is
- kept in a form which is multiplied by 256. So
- hash\->up_load=8*256; will cause a load of 8 to be set.
- .PP
- If you are interested in performance the field to watch is
- num_comp_calls. The hash library keeps track of the 'hash' value for
- each item so when a lookup is done, the 'hashes' are compared, if
- there is a match, then a full compare is done, and
- hash\->num_comp_calls is incremented. If num_comp_calls is not equal
- to num_delete plus num_retrieve it means that your hash function is
- generating hashes that are the same for different values. It is
- probably worth changing your hash function if this is the case because
- even if your hash table has 10 items in a 'bucket', it can be searched
- with 10 \fBunsigned long\fR compares and 10 linked list traverses. This
- will be much less expensive that 10 calls to your compare function.
- .PP
- \&\fIlh_strhash()\fR is a demo string hashing function:
- .PP
- .Vb 1
- \& unsigned long lh_strhash(const char *c);
- .Ve
- .PP
- Since the \fB\s-1LHASH\s0\fR routines would normally be passed structures, this
- routine would not normally be passed to lh_<type>\fI_new()\fR, rather it would be
- used in the function passed to lh_<type>\fI_new()\fR.
- .SH "SEE ALSO"
- .IX Header "SEE ALSO"
- \&\fIlh_stats\fR\|(3)
- .SH "HISTORY"
- .IX Header "HISTORY"
- The \fBlhash\fR library is available in all versions of SSLeay and OpenSSL.
- \&\fIlh_error()\fR was added in SSLeay 0.9.1b.
- .PP
- This manpage is derived from the SSLeay documentation.
- .PP
- In OpenSSL 0.9.7, all lhash functions that were passed function pointers
- were changed for better type safety, and the function types \s-1LHASH_COMP_FN_TYPE,
- LHASH_HASH_FN_TYPE, LHASH_DOALL_FN_TYPE\s0 and \s-1LHASH_DOALL_ARG_FN_TYPE\s0
- became available.
- .PP
- In OpenSSL 1.0.0, the lhash interface was revamped for even better
- type checking.
|