tls_locking.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007 iptelorg GmbH 
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  */
00018 /*
00019  * tls locking and atomic ops related init functions
00020  *
00021  * History:
00022  * --------
00023  *  2007-01-22  created by andrei
00024  */
00033 #include <stdlib.h> /* abort() */
00034 #include <openssl/crypto.h>
00035 #include "../../dprint.h"
00036 #include "../../locking.h"
00037 
00038 static int n_static_locks=0;
00039 static gen_lock_set_t* static_locks=0;
00040 
00041 /* "dynamic" locks */
00042 
00043 struct CRYPTO_dynlock_value{
00044         gen_lock_t lock;
00045 };
00046 
00047 
00048 static struct CRYPTO_dynlock_value* dyn_create_f(const char* file, int line)
00049 {
00050         struct CRYPTO_dynlock_value* l;
00051         
00052         l=shm_malloc(sizeof(struct CRYPTO_dynlock_value));
00053         if (l==0){
00054                 LOG(L_CRIT, "ERROR: tls: dyn_create_f locking callback out of shm."
00055                                 " memory (called from %s:%d)\n", file, line);
00056                 goto error;
00057         }
00058         if (lock_init(&l->lock)==0){
00059                 LOG(L_CRIT, "ERROR: tls: dyn_create_f locking callback: lock "
00060                                 "initialization failed (called from %s:%d)\n", file, line);
00061                 shm_free(l);
00062                 goto error;
00063         }
00064         return l;
00065 error:
00066         return 0;
00067 }
00068 
00069 
00070 
00071 static void dyn_lock_f(int mode, struct CRYPTO_dynlock_value* l,
00072                                                 const char* file, int line)
00073 {
00074         if (l==0){
00075                 LOG(L_CRIT, "BUG: tls: dyn_lock_f locking callback: null lock"
00076                                 " (called from %s:%d)\n", file, line);
00077                 /* try to continue */
00078                 return;
00079         }
00080         if (mode & CRYPTO_LOCK){
00081                 lock_get(&l->lock);
00082         }else{
00083                 lock_release(&l->lock);
00084         }
00085 }
00086 
00087 
00088 
00089 static void dyn_destroy_f(struct CRYPTO_dynlock_value *l,
00090                                                         const char* file, int line)
00091 {
00092         if (l==0){
00093                 LOG(L_CRIT, "BUG: tls: dyn_destroy_f locking callback: null lock"
00094                                 " (called from %s:%d)\n", file, line);
00095                 return;
00096         }
00097         lock_destroy(&l->lock);
00098         shm_free(l);
00099 }
00100 
00101 
00102 
00103 /* normal locking callback */
00104 static void locking_f(int mode, int n, const char* file, int line)
00105 {
00106         if (n<0 || n>=n_static_locks){
00107                 LOG(L_CRIT, "BUG: tls: locking_f (callback): invalid lock number: "
00108                                 " %d (range 0 - %d), called from %s:%d\n",
00109                                 n, n_static_locks, file, line);
00110                 abort(); /* quick crash :-) */
00111         }
00112         if (mode & CRYPTO_LOCK){
00113                 lock_set_get(static_locks, n);
00114         }else{
00115                 lock_set_release(static_locks, n);
00116         }
00117         
00118 }
00119 
00120 
00121 
00122 void tls_destroy_locks()
00123 {
00124         if (static_locks){
00125                 lock_set_destroy(static_locks);
00126                 lock_set_dealloc(static_locks);
00127                 static_locks=0;
00128                 n_static_locks=0;
00129         }
00130 }
00131 
00132 
00133 
00134 /* returns -1 on error, 0 on success */
00135 int tls_init_locks()
00136 {
00137         /* init "static" tls locks */
00138         n_static_locks=CRYPTO_num_locks();
00139         if (n_static_locks<0){
00140                 LOG(L_CRIT, "BUG: tls: tls_init_locking: bad CRYPTO_num_locks %d\n",
00141                                         n_static_locks);
00142                 n_static_locks=0;
00143         }
00144         if (n_static_locks){
00145                 static_locks=lock_set_alloc(n_static_locks);
00146                 if (static_locks==0){
00147                         LOG(L_CRIT, "ERROR: tls_init_locking: could not allocate lockset"
00148                                         " with %d locks\n", n_static_locks);
00149                         goto error;
00150                 }
00151                 if (lock_set_init(static_locks)==0){
00152                         LOG(L_CRIT, "ERROR: tls_init_locking: lock_set_init failed "
00153                                         "(%d locks)\n", n_static_locks);
00154                         lock_set_dealloc(static_locks);
00155                         static_locks=0;
00156                         n_static_locks=0;
00157                         goto error;
00158                 }
00159                 CRYPTO_set_locking_callback(locking_f);
00160         }
00161         /* set "dynamic" locks callbacks */
00162         CRYPTO_set_dynlock_create_callback(dyn_create_f);
00163         CRYPTO_set_dynlock_lock_callback(dyn_lock_f);
00164         CRYPTO_set_dynlock_destroy_callback(dyn_destroy_f);
00165         
00166         /* thread id callback: not needed because ser doesn't use thread and
00167          * openssl already uses getpid() (by default)
00168          * CRYPTO_set_id_callback(id_f);
00169          */
00170         /* atomic add -- since for now we don't have atomic_add
00171          *  (only atomic_inc), fallback to the default use-locks mode
00172          * CRYPTO_set_add_lock_callback(atomic_add_f);
00173          */
00174         
00175         
00176         return 0;
00177 error:
00178         tls_destroy_locks();
00179         return -1;
00180 }