Dynamic Locking Callbacks Multithread Support

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