63
CRYPTO_set_locking_callbackNULL; for i = 0; i CRYPTO_num_locks; i++
MUTEX_CLEANUPmutex_buf[i]; freemutex_buf;
mutex_buf = NULL; return 1;
}
To use these static locking functions, we need to make one function call before our program starts threads or calls OpenSSL functions, and we must call
THREAD_setup
, which returns 1 normally and 0 if it is unable to allocate the memory required to hold the mutexes. In our example code, we
do make a potentially unsafe assumption that the initialization of each individual mutex will succeed. You may wish to add additional error handling code to your programs. Once weve called
THREAD_setup
and it returns successfully, we can safely make calls into OpenSSL from multiple threads. After our programs threads are finished, or if we are done using OpenSSL, we
should call
THREAD_cleanup
to reclaim any memory used for the mutex structures.
4.1.2 Dynamic Locking Callbacks
The dynamic locking mechanism requires a data structure
CRYPTO_dynlock_value
and three callback functions. The structure is meant to hold the data necessary for the mutex, and the
three functions correspond to the operations for creation, lockingunlocking, and destruction. As with the static locking mechanism, we must also tell OpenSSL about the callback functions so that
it knows to call them when appropriate.
The first thing that we must do is define the
CRYPTO_dynlock_value
structure. Well be building on the static locking support that we built in
Example 4-1 , so we can use the same
platform-dependent macros that we defined already. For our purposes, this structure will be quite simple, containing only one member:
struct CRYPTO_dynlock_value {
MUTEX_TYPE mutex; };
The first callback function that we need to define is used to create a new mutex that OpenSSL will be able to use to protect a data structure. Memory must be allocated for the structure, and the
structure should have any necessary initialization performed on it. The newly created and initialized mutex should be returned in a released state from the function. The callback is defined
like this:
struct CRYPTO_dynlock_value dyn_create_functionconst char file, int line;
file The name of the source file requesting that the mutex be created. It is intended to aid in
debugging and is usually supplied by the
_ _FILE_ _
preprocessor macro. line
The source line number requesting that the mutex be created. Like the
file
argument, it is also intended to aid in debugging, and it is usually supplied by the
_ _LINE_ _
preprocessor macro.
64
The next callback function is used for acquiring or releasing a mutex. It behaves almost identically to the corresponding static locking mechanisms callback, which performs the same operation. It is
defined like this:
void dyn_lock_functionint mode, struct CRYPTO_dynlock_value mutex, const char file, int line;
mode Determines the action that the locking function should take. When the
CRYPTO_LOCK
flag is set, the lock should be acquired; otherwise, it should be released. mutex
The mutex that should be either acquired or released. It will never be
NULL
and will always be created and initialized by the mutex creation callback first.
file
T
he name of the source file requesting that the locking operation take place. It is intended to aid in debugging and is usually supplied by the
_ _FILE_ _
preprocessor macro. line
The source line number requesting that the locking operation take place. Like the
file
argument, it is also intended to aid in debugging, and it is usually supplied by the
_ _LINE_ _
preprocessor macro. The third and final callback function is used to destroy a mutex that OpenSSL no longer requires.
It should perform any platform-dependent destruction of the mutex and free any memory that was allocated for the
CRYPTO_dynlock_value
structure. It is defined like this:
void dyn_destroy_functionstruct CRYPTO_dynlock_value mutex, const char file, int line;
mutex The mutex that should be destroyed. It will never be
NULL
and will always have first been created and initialized by the mutex creation callback.
file The name of the source file requesting that the mutex be destroyed. It is intended to aid in
debugging and is usually supplied by the
_ _FILE_ _
preprocessor macro. line
The source line number requesting that the mutex be destroyed. Like the
file
argument, it is also intended to aid in debugging, and it is usually supplied by the
_ _LINE_ _
preprocessor macro. Using the static locking mechanisms code from
Example 4-1 , we can easily build a dynamic
locking mechanism implementation. Example 4-2
shows an implementation of the three dynamic locking callback functions. It also includes new versions of the
THREAD_setup
and
THREAD_cleanup
functions extended to support the dynamic locking mechanism in addition to
65
the static locking mechanism. The modifications to these two functions are simply to make the appropriate OpenSSL library calls to install and remove the dynamic locking callback functions.
Example 4-2. E xtensions to the library to support the dynamic locking mechanism
struct CRYPTO_dynlock_value {
MUTEX_TYPE mutex; };
static struct CRYPTO_dynlock_value dyn_create_functionconst char file, int line
{ struct CRYPTO_dynlock_value value;
value = struct CRYPTO_dynlock_value mallocsizeof struct CRYPTO_dynlock_value;
if value return NULL;
MUTEX_SETUPvalue-mutex; return value;
} static void dyn_lock_functionint mode, struct CRYPTO_dynlock_value l,
const char file, int line {
if mode CRYPTO_LOCK MUTEX_LOCKl-mutex;
else MUTEX_UNLOCKl-mutex;
} static void dyn_destroy_functionstruct CRYPTO_dynlock_value l,
const char file, int line {
MUTEX_CLEANUPl-mutex; freel;
} int THREAD_setupvoid
{ int i;
mutex_buf = MUTEX_TYPE mallocCRYPTO_num_locks sizeofMUTEX_TYPE;
if mutex_buf return 0;
for i = 0; i CRYPTO_num_locks; i++ MUTEX_SETUPmutex_buf[i];
CRYPTO_set_id_callbackid_function; CRYPTO_set_locking_callbacklocking_function;
The following three CRYPTO_... functions are the OpenSSL functions for registering the callbacks we implemented above
CRYPTO_set_dynlock_create_callbackdyn_create_function; CRYPTO_set_dynlock_lock_callbackdyn_lock_function;
CRYPTO_set_dynlock_destroy_callbackdyn_destroy_function; return 1;
} int THREAD_cleanupvoid
{ int i;
if mutex_buf return 0;
66
CRYPTO_set_id_callbackNULL; CRYPTO_set_locking_callbackNULL;
CRYPTO_set_dynlock_create_callbackNULL; CRYPTO_set_dynlock_lock_callbackNULL;
CRYPTO_set_dynlock_destroy_callbackNULL; for i = 0; i CRYPTO_num_locks; i++
MUTEX_CLEANUPmutex_buf[i]; freemutex_buf;
mutex_buf = NULL; return 1;
}
4.2 Internal Error Handling