+
+/* Define the predeclared (but externally opaque) "ERR_FNS" type */
+struct st_ERR_FNS
+ {
+ /* Works on the "error_hash" string table */
+ LHASH_OF(ERR_STRING_DATA) *(*cb_err_get)(int create);
+ void (*cb_err_del)(void);
+ ERR_STRING_DATA *(*cb_err_get_item)(const ERR_STRING_DATA *);
+ ERR_STRING_DATA *(*cb_err_set_item)(ERR_STRING_DATA *);
+ ERR_STRING_DATA *(*cb_err_del_item)(ERR_STRING_DATA *);
+ /* Works on the "thread_hash" error-state table */
+ LHASH_OF(ERR_STATE) *(*cb_thread_get)(int create);
+ void (*cb_thread_release)(LHASH_OF(ERR_STATE) **hash);
+ ERR_STATE *(*cb_thread_get_item)(const ERR_STATE *);
+ ERR_STATE *(*cb_thread_set_item)(ERR_STATE *);
+ void (*cb_thread_del_item)(const ERR_STATE *);
+ /* Returns the next available error "library" numbers */
+ int (*cb_get_next_lib)(void);
+ };
+
+/* Predeclarations of the "err_defaults" functions */
+static LHASH_OF(ERR_STRING_DATA) *int_err_get(int create);
+static void int_err_del(void);
+static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
+static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *);
+static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *);
+static LHASH_OF(ERR_STATE) *int_thread_get(int create);
+static void int_thread_release(LHASH_OF(ERR_STATE) **hash);
+static ERR_STATE *int_thread_get_item(const ERR_STATE *);
+static ERR_STATE *int_thread_set_item(ERR_STATE *);
+static void int_thread_del_item(const ERR_STATE *);
+static int int_err_get_next_lib(void);
+/* The static ERR_FNS table using these defaults functions */
+static const ERR_FNS err_defaults =
+ {
+ int_err_get,
+ int_err_del,
+ int_err_get_item,
+ int_err_set_item,
+ int_err_del_item,
+ int_thread_get,
+ int_thread_release,
+ int_thread_get_item,
+ int_thread_set_item,
+ int_thread_del_item,
+ int_err_get_next_lib
+ };
+
+/* The replacable table of ERR_FNS functions we use at run-time */
+static const ERR_FNS *err_fns = NULL;
+
+/* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */
+#define ERRFN(a) err_fns->cb_##a
+
+/* The internal state used by "err_defaults" - as such, the setting, reading,
+ * creating, and deleting of this data should only be permitted via the
+ * "err_defaults" functions. This way, a linked module can completely defer all
+ * ERR state operation (together with requisite locking) to the implementations
+ * and state in the loading application. */
+static LHASH_OF(ERR_STRING_DATA) *int_error_hash = NULL;
+static LHASH_OF(ERR_STATE) *int_thread_hash = NULL;
+static int int_thread_hash_references = 0;
+static int int_err_library_number= ERR_LIB_USER;
+
+/* Internal function that checks whether "err_fns" is set and if not, sets it to
+ * the defaults. */
+static void err_fns_check(void)
+ {
+ if (err_fns) return;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ if (!err_fns)
+ err_fns = &err_defaults;
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+ }
+
+/* API functions to get or set the underlying ERR functions. */
+
+const ERR_FNS *ERR_get_implementation(void)
+ {
+ err_fns_check();
+ return err_fns;
+ }
+
+int ERR_set_implementation(const ERR_FNS *fns)