Frank wrote:
Joe Orton wrote:
On Wed, Dec 06, 2006 at 06:20:55PM +0000, Darryl Miles wrote:
[...]
Is there an API to get the current value ?


Yes, CRYPTO_get_locking_callback/CRYPTO_get_id_callback.
[...]

I already know that this functions exists. But what if my module gets inited before mod_ssl, which doesn't use the get-functions to determine that something is already there? I was in the hope to see a clean general purpose solution. :-)

Your thinking is correct there is a problem. Those OpenSSL functions are not documented in my man page but exist in the library. Yes there is a read-test-write race window by using those APIs alone.


After this long and informative discussion I really think there is need for a ssl_thread_init_if_not_already_done inside Apache. (Besides the correction/removal of OpenSSL's stupid global locking mechanism.)

I disagree I should not need to compile apache mod_core in a way that has to understand the quirks of OpenSSL. So adding a function ssl_thread_init_if_not_already_done() to apache core is too specific to that one problem.

I'm saying its possible to solve a bunch of problems like this in a more generic way. This helps you and the next man.



Maybe there is some (small) re-design of the Apache code needed?

Agreed, something needs to be added. I'm saying there is no need to make it specific to OpenSSL. Serializing the initialization can be made generic such that these objectives are met:

* When building Apache mod_core with minimal functionality it is not necessary to build it with special API function to handle OpenSSL. So we get the co-ordination mechanism by default.

* I can build my mod_ssl or mod_frank at any point later without having to rebuild apache mod_core as well.

* Can provide a generic mechanism which can be used to solve the same problem where a common subordinate library is linked with by a module but is not require by mod_core.

* The overhead of adding the handful of new functions to apache mod_core should low. Subjective but...

* Because the solution is generic it can be reused for other purposes where one module has to co-ordinate with another module at runtime over the use of a shared resource, but due to the modular nature of apache its impossible to tell if/when/what other modules need to co-ordinate their behavior until runtime.

* Only those modules that use OpenSSL directly need to be linked against OpenSSL.

* Only those modules that link with OpenSSL need openssl around at build time. So the helper functions below would be repeated within each mod_xxxx that uses OpenSSL.

Those a rough concerns to address.



All Apache should provide is an accessible keyed namespace to attach arbitrary pieces of memory where the attachment functions provides some thread-safe guarantees. Maybe there is already a mechanism to achieve most of that within apache.

All these functions must be thread-safe with respect to themselves. The key itself could be a string or an integer. Or even both if you wanted to abstract the key, like X11 Xwindows "atoms" work, you lookup/create your key independently and get back a reference which is usually a cardinal integer starting at 1 and then use this api with that (not the key directly).

* void *get(key) this gets the (void *) key value.

* void *attach(key, newdata) this overrides the current key value with an optional exchange (by returning the old value).

* void *attach_smart_exchange(key, newdata) this does an exchange but will only exchange a NULL for non-NULL and non-NULL for NULL. This is used to set without overwriting. It always returns the pre-existing value by checking that value in the context of how you called it you can work out if you were successful or not.


Sample hypothetical usage in self-documenting non compilable code:

struct openssl_init_struct {
        long magic;     /* do versioning here */
        int boolean_flag;
        mutex_t mutex;
} *ois;

ois = calloc_from_global_pool(1, sizeof(openssl_init_struct));
ois->magic = OPENSSL_INIT_STRUCT_V1; /* magic constant */
ois->boolean_flag = FALSE;
mutex_init(&ois->mutex);
/* as first use we lock before attachment */
mutex_lock(&ois->mutex);

const char *label_key = "mylabel_openssl_initialization_serializer"; /* could be integer based key system */

/* This ap_newapi_attach_smart_exchange function is a thread-safe atomic attachment of "mydata" to the global namespace, it will only attach if the current value for the key does not exist or is NULL already, which are essentially treated identically (does not exist vs NULL value) */

void *retval = apache_core_handle->ap_newapi_attach_smart_exchange(label_key, ois);

if(retval == NULL) {
/* we won the attachment, we already locked it and we own that lock, fall thru to code below */
} else {
        free_from_global_pool(ois);     /* FIXME: destruct mutex etc.. properly 
*/

/* we lost, go get the winner, you can optimize this a bit by trying this first before callocing our copy */
        ois  = apache_code_handle->ap_newapi_get(label_key);
        if(ois == NULL) {
/* HUH! Abort! Abort! Or loop around again a few times and ultimately catch fire. */
                exit(1);
        }
        /* ok aquire lock and fall thru */
        mutex_lock(&ois->mutex);
}

/* FIXME: do versioning ois->magic check here to ensure the object we got was what we can handle */
if(ois->boolean_flag != TRUE) {
        CRYPTO_do_stuff_to_init();      /* Do stuff here */

        ois->boolean_flag = TRUE;
}

mutex_unlock(&ois->mutex);
/* we're done */




Then each OpenSSL module user is modified to make used of a common shared initialization helper mechanism outlined above. The above code should not be part of core but of the module that uses openssl.

All Apache needs to provide is the 3 primitive functions to attach, get, get_atomic_exchange and maybe some additional 'deatach' to complete things.


Darryl

Reply via email to