cfgutils.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007 1&1 Internet AG
00005  * Copyright (C) 2007 BASIS AudioNet GmbH
00006  * Copyright (C) 2004 FhG
00007  * Copyright (C) 2005-2006 Voice Sistem S.R.L.
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * cfgutils module: random probability functions for openser;
00026  * it provide functions to make a decision in the script
00027  * of the server based on a probability function.
00028  * The benefit of this module is the value of the probability function
00029  * can be manipulated by external applications such as web interface
00030  * or command line tools.
00031  * Furthermore it provides some functions to let the server wait a
00032  * specific time interval.
00033  *
00034  * gflags module: global flags; it keeps a bitmap of flags
00035  * in shared memory and may be used to change behaviour 
00036  * of server based on value of the flags. E.g.,
00037  *    if (is_gflag("1")) { t_relay_to_udp("10.0.0.1","5060"); }
00038  *    else { t_relay_to_udp("10.0.0.2","5060"); }
00039  * The benefit of this module is the value of the switch flags
00040  * can be manipulated by external applications such as web interface
00041  * or command line tools.
00042  */
00043 
00044 
00045 /* FIFO action protocol names */
00046 #define FIFO_SET_PROB   "rand_set_prob"
00047 #define FIFO_RESET_PROB "rand_reset_prob"
00048 #define FIFO_GET_PROB   "rand_get_prob"
00049 #define FIFO_GET_HASH   "get_config_hash"
00050 #define FIFO_CHECK_HASH "check_config_hash"
00051 
00052 /* flag buffer size for FIFO protocool */
00053 #define MAX_FLAG_LEN 12
00054 /* FIFO action protocol names for gflag functionality */
00055 #define FIFO_SET_GFLAG "set_gflag"
00056 #define FIFO_IS_GFLAG "is_gflag"
00057 #define FIFO_RESET_GFLAG "reset_gflag"
00058 #define FIFO_GET_GFLAGS "get_gflags"
00059 
00060 #include "../../sr_module.h"
00061 #include "../../error.h"
00062 #include "../../pvar.h"
00063 #include "../../ut.h"
00064 #include "../../mem/mem.h"
00065 #include "../../mem/shm_mem.h"
00066 #include "../../lib/kmi/mi.h"
00067 #include "../../mod_fix.h"
00068 #include "../../md5.h"
00069 #include "../../md5utils.h"
00070 #include "../../globals.h"
00071 #include "../../hashes.h"
00072 #include "../../locking.h"
00073 #include <stdio.h>
00074 #include <stdlib.h>
00075 #include <sys/types.h>
00076 #include <sys/stat.h>
00077 #include <unistd.h>
00078 
00079 #include "api.h"
00080 
00081 MODULE_VERSION
00082 
00083 static int set_prob(struct sip_msg*, char *, char *);
00084 static int reset_prob(struct sip_msg*, char *, char *);
00085 static int get_prob(struct sip_msg*, char *, char *);
00086 static int rand_event(struct sip_msg*, char *, char *);
00087 static int m_sleep(struct sip_msg*, char *, char *);
00088 static int m_usleep(struct sip_msg*, char *, char *);
00089 static int dbg_abort(struct sip_msg*, char*,char*);
00090 static int dbg_pkg_status(struct sip_msg*, char*,char*);
00091 static int dbg_shm_status(struct sip_msg*, char*,char*);
00092 static int dbg_pkg_summary(struct sip_msg*, char*,char*);
00093 static int dbg_shm_summary(struct sip_msg*, char*,char*);
00094 
00095 static int set_gflag(struct sip_msg*, char *, char *);
00096 static int reset_gflag(struct sip_msg*, char *, char *);
00097 static int is_gflag(struct sip_msg*, char *, char *);
00098 
00099 static int cfg_lock(struct sip_msg*, char *, char *);
00100 static int cfg_unlock(struct sip_msg*, char *, char *);
00101 
00102 static struct mi_root* mi_set_prob(struct mi_root* cmd, void* param );
00103 static struct mi_root* mi_reset_prob(struct mi_root* cmd, void* param );
00104 static struct mi_root* mi_get_prob(struct mi_root* cmd, void* param );
00105 static struct mi_root* mi_get_hash(struct mi_root* cmd, void* param );
00106 static struct mi_root* mi_check_hash(struct mi_root* cmd, void* param );
00107 
00108 static struct mi_root* mi_set_gflag(struct mi_root* cmd, void* param );
00109 static struct mi_root* mi_reset_gflag(struct mi_root* cmd, void* param );
00110 static struct mi_root* mi_is_gflag(struct mi_root* cmd, void* param );
00111 static struct mi_root* mi_get_gflags(struct mi_root* cmd, void* param );
00112 
00113 
00114 static int pv_get_random_val(struct sip_msg *msg, pv_param_t *param,
00115                 pv_value_t *res);
00116 
00117 
00118 static int fixup_prob( void** param, int param_no);
00119 static int fixup_gflags( void** param, int param_no);
00120 
00121 static int fixup_core_hash(void **param, int param_no);
00122 static int w_core_hash(struct sip_msg *msg, char *p1, char *p2, char *p3);
00123 
00124 int bind_cfgutils(cfgutils_api_t *api);
00125 
00126 static int mod_init(void);
00127 static void mod_destroy(void);
00128 
00129 static int initial_prob = 10;
00130 static int *probability;
00131 
00132 static char config_hash[MD5_LEN];
00133 static char* hash_file = NULL;
00134 
00135 static int initial_gflags=0;
00136 static unsigned int *gflags=0;
00137 
00138 static gen_lock_set_t *_cfg_lock_set = NULL;
00139 static unsigned int _cfg_lock_size = 0;
00140 
00141 static cmd_export_t cmds[]={
00142         {"rand_set_prob", /* action name as in scripts */
00143                 (cmd_function)set_prob,  /* C function name */
00144                 1,          /* number of parameters */
00145                 fixup_prob, 0,         /* */
00146                 /* can be applied to original/failed requests and replies */
00147                 ANY_ROUTE},
00148         {"rand_reset_prob", (cmd_function)reset_prob, 0, 0, 0,
00149                 ANY_ROUTE},
00150         {"rand_get_prob",   (cmd_function)get_prob,   0, 0, 0,
00151                 ANY_ROUTE},
00152         {"rand_event",      (cmd_function)rand_event, 0, 0, 0,
00153                 ANY_ROUTE},
00154         {"sleep",  (cmd_function)m_sleep,  1, fixup_uint_null, 0,
00155                 ANY_ROUTE},
00156         {"usleep", (cmd_function)m_usleep, 1, fixup_uint_null, 0,
00157                 ANY_ROUTE},
00158         {"abort",      (cmd_function)dbg_abort,        0, 0, 0,
00159                 ANY_ROUTE},
00160         {"pkg_status", (cmd_function)dbg_pkg_status,   0, 0, 0,
00161                 ANY_ROUTE},
00162         {"shm_status", (cmd_function)dbg_shm_status,   0, 0, 0,
00163                 ANY_ROUTE},
00164         {"pkg_summary", (cmd_function)dbg_pkg_summary,   0, 0, 0,
00165                 ANY_ROUTE},
00166         {"shm_summary", (cmd_function)dbg_shm_summary,   0, 0, 0,
00167                 ANY_ROUTE},
00168         {"set_gflag",    (cmd_function)set_gflag,   1,   fixup_gflags, 0,
00169                 ANY_ROUTE},
00170         {"reset_gflag",  (cmd_function)reset_gflag, 1,   fixup_gflags, 0,
00171                 ANY_ROUTE},
00172         {"is_gflag",     (cmd_function)is_gflag,    1,   fixup_gflags, 0,
00173                 ANY_ROUTE},
00174         {"lock",         (cmd_function)cfg_lock,    1,   fixup_spve_null, 0,
00175                 ANY_ROUTE},
00176         {"unlock",       (cmd_function)cfg_unlock,  1,   fixup_spve_null, 0,
00177                 ANY_ROUTE},
00178         {"core_hash",    (cmd_function)w_core_hash, 3,   fixup_core_hash, 0,
00179                 ANY_ROUTE},
00180         {"bind_cfgutils", (cmd_function)bind_cfgutils,  0,
00181                 0, 0, 0},
00182         {0, 0, 0, 0, 0, 0}
00183 };
00184 
00185 
00186 static param_export_t params[]={ 
00187         {"initial_probability", INT_PARAM, &initial_prob   },
00188         {"initial_gflags",      INT_PARAM, &initial_gflags },
00189         {"hash_file",           STR_PARAM, &hash_file      },
00190         {"lock_set_size",       INT_PARAM, &_cfg_lock_size },
00191         {0,0,0}
00192 };
00193 
00194 
00195 static mi_export_t mi_cmds[] = {
00196         { FIFO_SET_PROB,   mi_set_prob,   0,                 0,  0 },
00197         { FIFO_RESET_PROB, mi_reset_prob, MI_NO_INPUT_FLAG,  0,  0 },
00198         { FIFO_GET_PROB,   mi_get_prob,   MI_NO_INPUT_FLAG,  0,  0 },
00199         { FIFO_GET_HASH,   mi_get_hash,   MI_NO_INPUT_FLAG,  0,  0 },
00200         { FIFO_CHECK_HASH, mi_check_hash, MI_NO_INPUT_FLAG,  0,  0 },
00201         { FIFO_SET_GFLAG,   mi_set_gflag,   0,                 0,  0 },
00202         { FIFO_RESET_GFLAG, mi_reset_gflag, 0,                 0,  0 },
00203         { FIFO_IS_GFLAG,    mi_is_gflag,    0,                 0,  0 },
00204         { FIFO_GET_GFLAGS,  mi_get_gflags,  MI_NO_INPUT_FLAG,  0,  0 },
00205         { 0, 0, 0, 0, 0}
00206 };
00207 
00208 
00209 static pv_export_t mod_items[] = {
00210         { {"RANDOM", sizeof("RANDOM")-1}, PVT_OTHER, pv_get_random_val, 0,
00211                 0, 0, 0, 0 },
00212         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00213 };
00214 
00215 
00216 struct module_exports exports = {
00217         "cfgutils",
00218         DEFAULT_DLFLAGS, /* dlopen flags */
00219         cmds,        /* exported functions */
00220         params,      /* exported parameters */
00221         0,           /* exported statistics */
00222         mi_cmds,     /* exported MI functions */
00223         mod_items,   /* exported pseudo-variables */
00224         0,           /* extra processes */
00225         mod_init,    /* module initialization function */
00226         0,           /* response function*/
00227         mod_destroy, /* destroy function */
00228         0            /* per-child init function */
00229 };
00230 
00231 
00232 /**************************** fixup functions ******************************/
00233 static int fixup_prob( void** param, int param_no)
00234 {
00235         unsigned int myint;
00236         str param_str;
00237 
00238         /* we only fix the parameter #1 */
00239         if (param_no!=1)
00240                 return 0;
00241 
00242         param_str.s=(char*) *param;
00243         param_str.len=strlen(param_str.s);
00244         str2int(&param_str, &myint);
00245 
00246         if (myint > 100) {
00247                 LM_ERR("invalid probability <%d>\n", myint);
00248                 return E_CFG;
00249         }
00250 
00251         pkg_free(*param);
00252         *param=(void *)(long)myint;
00253         return 0;
00254 }
00255 
00260 static int fixup_gflags( void** param, int param_no)
00261 {
00262         unsigned int myint;
00263         str param_str;
00264 
00265         /* we only fix the parameter #1 */
00266         if (param_no!=1)
00267                 return 0;
00268 
00269         param_str.s=(char*) *param;
00270         param_str.len=strlen(param_str.s);
00271 
00272         if (str2int(&param_str, &myint )<0) {
00273                 LM_ERR("bad number <%s>\n", (char *)(*param));
00274                 return E_CFG;
00275         }
00276         if ( myint >= 8*sizeof(*gflags) ) {
00277                 LM_ERR("flag <%d> out of "
00278                         "range [0..%lu]\n", myint, ((unsigned long)8*sizeof(*gflags))-1 );
00279                 return E_CFG;
00280         }
00281         /* convert from flag index to flag bitmap */
00282         myint = 1 << myint;
00283         /* success -- change to int */
00284         pkg_free(*param);
00285         *param=(void *)(long)myint;
00286         return 0;
00287 }
00288 
00289 
00290 /************************** module functions **********************************/
00291 
00292 static int set_gflag(struct sip_msg *bar, char *flag, char *foo) 
00293 {
00294         (*gflags) |= (unsigned int)(long)flag;
00295         return 1;
00296 }
00297 
00298 
00299 static int reset_gflag(struct sip_msg *bar, char *flag, char *foo)
00300 {
00301         (*gflags) &= ~ ((unsigned int)(long)flag);
00302         return 1;
00303 }
00304 
00305 
00306 static int is_gflag(struct sip_msg *bar, char *flag, char *foo)
00307 {
00308         return ( (*gflags) & ((unsigned int)(long)flag)) ? 1 : -1;
00309 }
00310 
00311 
00312 static struct mi_root* mi_set_gflag(struct mi_root* cmd_tree, void* param )
00313 {
00314         unsigned int flag;
00315         struct mi_node* node;
00316 
00317         node = cmd_tree->node.kids;
00318         if(node == NULL)
00319                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00320 
00321         flag = 0;
00322         if( strno2int( &node->value, &flag) <0)
00323                 goto error;
00324         if (!flag) {
00325                 LM_ERR("incorrect flag\n");
00326                 goto error;
00327         }
00328 
00329         (*gflags) |= flag;
00330 
00331         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00332 error:
00333         return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00334 }
00335 
00336 
00337 static struct mi_root*  mi_reset_gflag(struct mi_root* cmd_tree, void* param )
00338 {
00339         unsigned int flag;
00340         struct mi_node* node = NULL;
00341 
00342         node = cmd_tree->node.kids;
00343         if(node == NULL)
00344                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00345 
00346         flag = 0;
00347         if( strno2int( &node->value, &flag) <0)
00348                 goto error;
00349         if (!flag) {
00350                 LM_ERR("incorrect flag\n");
00351                 goto error;
00352         }
00353 
00354         (*gflags) &= ~ flag;
00355 
00356         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00357 error:
00358         return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00359 }
00360 
00361 
00362 static struct mi_root* mi_is_gflag(struct mi_root* cmd_tree, void* param )
00363 {
00364         unsigned int flag;
00365         struct mi_root* rpl_tree = NULL;
00366         struct mi_node* node = NULL;
00367 
00368         node = cmd_tree->node.kids;
00369         if(node == NULL)
00370                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00371 
00372         flag = 0;
00373         if( strno2int( &node->value, &flag) <0)
00374                 goto error_param;
00375         if (!flag) {
00376                 LM_ERR("incorrect flag\n");
00377                 goto error_param;
00378         }
00379 
00380         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00381         if(rpl_tree ==0)
00382                 return 0;
00383 
00384         if( ((*gflags) & flag)== flag )
00385                 node = add_mi_node_child( &rpl_tree->node, 0, 0, 0, "TRUE", 4);
00386         else
00387                 node = add_mi_node_child( &rpl_tree->node, 0, 0, 0, "FALSE", 5);
00388 
00389         if(node == NULL)
00390         {
00391                 LM_ERR("failed to add node\n");
00392                 free_mi_tree(rpl_tree);
00393                 return 0;
00394         }
00395 
00396         return rpl_tree;
00397 error_param:
00398         return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00399 }
00400 
00401 
00402 static struct mi_root*  mi_get_gflags(struct mi_root* cmd_tree, void* param )
00403 {
00404         struct mi_root* rpl_tree= NULL;
00405         struct mi_node* node= NULL;
00406 
00407         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00408         if(rpl_tree == NULL)
00409                 return 0;
00410 
00411         node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "0x%X",(*gflags));
00412         if(node == NULL)
00413                 goto error;
00414 
00415         node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%u",(*gflags));
00416         if(node == NULL)
00417                 goto error;
00418 
00419         return rpl_tree;
00420 error:
00421         free_mi_tree(rpl_tree);
00422         return 0;
00423 }
00424 
00425 
00426 static struct mi_root* mi_set_prob(struct mi_root* cmd, void* param )
00427 {
00428         unsigned int percent;
00429         struct mi_node* node;
00430 
00431         node = cmd->node.kids;
00432         if(node == NULL)
00433                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00434 
00435         if( str2int( &node->value, &percent) <0)
00436                 goto error;
00437         if (percent > 100) {
00438                 LM_ERR("incorrect probability <%u>\n", percent);
00439                 goto error;
00440         }
00441         *probability = percent;
00442         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00443 
00444 error:
00445         return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00446 }
00447 
00448 static struct mi_root* mi_reset_prob(struct mi_root* cmd, void* param )
00449 {
00450 
00451         *probability = initial_prob;
00452         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00453 }
00454 
00455 static struct mi_root* mi_get_prob(struct mi_root* cmd, void* param )
00456 {
00457         struct mi_root* rpl_tree= NULL;
00458         struct mi_node* node= NULL;
00459         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00460         if(rpl_tree == NULL)
00461                 return 0;
00462         node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "actual probability: %u percent\n",(*probability));
00463         if(node == NULL)
00464                 goto error;
00465         
00466         return rpl_tree;
00467 
00468 error:
00469         free_mi_tree(rpl_tree);
00470         return 0;
00471 }
00472 
00473 static struct mi_root* mi_get_hash(struct mi_root* cmd, void* param )
00474 {
00475         struct mi_root* rpl_tree= NULL;
00476         struct mi_node* node= NULL;
00477 
00478         if (!hash_file) {
00479                 LM_INFO("no hash_file given, disable hash functionality\n");
00480                 rpl_tree = init_mi_tree(404, "Functionality disabled\n", 23);
00481         } else {
00482                 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00483                 if(rpl_tree == NULL)
00484                         return 0;
00485                 node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%.*s\n", MD5_LEN, config_hash);
00486                 if(node == NULL)
00487                         goto error;
00488         }
00489         return rpl_tree;
00490 
00491 error:
00492         free_mi_tree(rpl_tree);
00493         return 0;
00494 }
00495 
00496 
00504 static int MD5File(char *dest, const char *file_name)
00505 {
00506         MD5_CTX context;
00507         FILE *input;
00508         unsigned char buffer[32768];
00509         unsigned char hash[16];
00510         unsigned int counter, size;
00511         
00512         struct stat stats;
00513         
00514         if (!dest || !file_name) {
00515                 LM_ERR("invalid parameter value\n");
00516                 return -1;
00517         }
00518 
00519     if (stat(file_name, &stats) != 0) {
00520                 LM_ERR("could not stat file %s\n", file_name);
00521                 return -1;
00522         }
00523         size = stats.st_size;
00524 
00525         MD5Init(&context);
00526         if((input = fopen(file_name, "rb")) == NULL) {
00527                 LM_ERR("could not open file %s\n", file_name);
00528                 return -1;
00529         }
00530 
00531         while(size) {
00532                 counter = (size > sizeof(buffer)) ? sizeof(buffer) : size;
00533                 if ((counter = fread(buffer, 1, counter, input)) <= 0) {
00534                         fclose(input);
00535                         return -1;
00536                 }
00537                 U_MD5Update(&context, buffer, counter);
00538                 size -= counter;
00539         }
00540         fclose(input);
00541         U_MD5Final(hash, &context);
00542 
00543         string2hex(hash, 16, dest);
00544         LM_DBG("MD5 calculated: %.*s for file %s\n", MD5_LEN, dest, file_name);
00545 
00546         return 0;
00547 }
00548 
00549 
00550 static struct mi_root* mi_check_hash(struct mi_root* cmd, void* param )
00551 {
00552         struct mi_root* rpl_tree= NULL;
00553         struct mi_node* node= NULL;
00554         char tmp[MD5_LEN];
00555         memset(tmp, 0, MD5_LEN);
00556 
00557         if (!hash_file) {
00558                 LM_INFO("no hash_file given, disable hash functionality\n");
00559                 rpl_tree = init_mi_tree(404, "Functionality disabled\n", 23);
00560         } else {
00561                 if (MD5File(tmp, hash_file) != 0) {
00562                         LM_ERR("could not hash the config file");
00563                         rpl_tree = init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN );
00564                         return rpl_tree;
00565                 }
00566                 
00567                 if (strncmp(config_hash, tmp, MD5_LEN) == 0) {
00568                         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00569                         if(rpl_tree == NULL)
00570                                 return 0;
00571                         node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "The actual config file hash is identical to the stored one.\n");
00572                 } else {
00573                         rpl_tree = init_mi_tree( 400, "Error", 5 );
00574                         if(rpl_tree == NULL)
00575                                 return 0;
00576                         node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "The actual config file hash is not identical to the stored one.\n");
00577                 }
00578                 if(node == NULL)
00579                         goto error;
00580         }
00581         
00582         return rpl_tree;
00583 
00584 error:
00585         free_mi_tree(rpl_tree);
00586         return 0;
00587 }
00588 
00589 static int set_prob(struct sip_msg *bar, char *percent_par, char *foo) 
00590 {
00591         *probability=(int)(long)percent_par;
00592         return 1;
00593 }
00594         
00595 static int reset_prob(struct sip_msg *bar, char *percent_par, char *foo)
00596 {
00597         *probability=initial_prob;
00598         return 1;
00599 }
00600 
00601 static int get_prob(struct sip_msg *bar, char *foo1, char *foo2)
00602 {
00603         return *probability;
00604 }
00605 
00606 static int rand_event(struct sip_msg *bar, char *foo1, char *foo2)
00607 {
00608         double tmp;
00609         /* most of the time this will be disabled completly. Tis will also fix the
00610          * problem with the corner cases if rand() returned zero or RAND_MAX */
00611         if ((*probability) == 0) return -1;
00612         if ((*probability) == 100) return 1;
00613 
00614         tmp = ((double) rand() / RAND_MAX);
00615         LM_DBG("generated random %f\n", tmp);
00616         if (tmp < ((double) (*probability) / 100)) {
00617                 LM_DBG("return true\n");
00618                 return 1;
00619         }
00620         else {
00621                 LM_DBG("return false\n");
00622                 return -1;
00623         }
00624 }
00625 
00626 static int pv_get_random_val(struct sip_msg *msg, pv_param_t *param,
00627                 pv_value_t *res)
00628 {
00629         int n;
00630         int l = 0;
00631         char *ch;
00632 
00633         if(msg==NULL || res==NULL)
00634                 return -1;
00635 
00636         n = rand();
00637         ch = int2str(n , &l);
00638         res->rs.s = ch;
00639         res->rs.len = l;
00640         res->ri = n;
00641         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
00642 
00643         return 0;
00644 }
00645 
00646 static int m_sleep(struct sip_msg *msg, char *time, char *str2)
00647 {
00648         LM_DBG("sleep %lu seconds\n", (unsigned long)time);
00649         sleep((unsigned int)(unsigned long)time);
00650         return 1;
00651 }
00652 
00653 static int m_usleep(struct sip_msg *msg, char *time, char *str2)
00654 {
00655         LM_DBG("sleep %lu microseconds\n", (unsigned long)time);
00656         sleep_us((unsigned int)(unsigned long)time);
00657         return 1;
00658 }
00659 
00660 static int dbg_abort(struct sip_msg* msg, char* foo, char* bar)
00661 {
00662         LM_CRIT("abort called\n");
00663         abort();
00664         return 0;
00665 }
00666 
00667 static int dbg_pkg_status(struct sip_msg* msg, char* foo, char* bar)
00668 {
00669         pkg_status();
00670         return 1;
00671 }
00672 
00673 static int dbg_shm_status(struct sip_msg* msg, char* foo, char* bar)
00674 {
00675         shm_status();
00676         return 1;
00677 }
00678 
00679 static int dbg_pkg_summary(struct sip_msg* msg, char* foo, char* bar)
00680 {
00681         pkg_sums();
00682         return 1;
00683 }
00684 
00685 static int dbg_shm_summary(struct sip_msg* msg, char* foo, char* bar)
00686 {
00687         shm_sums();
00688         return 1;
00689 }
00690 
00691 int cfg_lock_helper(str *lkey, int mode)
00692 {
00693         unsigned int pos;
00694         pos = core_case_hash(lkey, 0, _cfg_lock_size);
00695         LM_DBG("cfg_lock mode %d on %u\n", mode, pos);
00696         if(mode==0)
00697                 lock_set_get(_cfg_lock_set, pos);
00698         else
00699                 lock_set_release(_cfg_lock_set, pos);
00700         return 1;
00701 }
00702 
00703 int cfg_lock_wrapper(struct sip_msg *msg, gparam_p key, int mode)
00704 {
00705         str s;
00706         if(fixup_get_svalue(msg, key, &s)!=0)
00707         {
00708                 LM_ERR("cannot get first parameter\n");
00709                 return -1;
00710         }
00711         return cfg_lock_helper(&s, mode);
00712 }
00713 
00714 static int cfg_lock(struct sip_msg *msg, char *key, char *s2)
00715 {
00716         if(_cfg_lock_set==NULL || key==NULL)
00717                 return -1;
00718         return cfg_lock_wrapper(msg, (gparam_p)key, 0);
00719 }
00720 
00721 static int cfg_unlock(struct sip_msg *msg, char *key, char *s2)
00722 {
00723         if(_cfg_lock_set==NULL || key==NULL)
00724                 return -1;
00725         return cfg_lock_wrapper(msg, (gparam_p)key, 1);
00726 }
00727 
00728 
00729 static int mod_init(void)
00730 {
00731         if(register_mi_mod(exports.name, mi_cmds)!=0)
00732         {
00733                 LM_ERR("failed to register MI commands\n");
00734                 return -1;
00735         }
00736 
00737         if (!hash_file) {
00738                 LM_INFO("no hash_file given, disable hash functionality\n");
00739         } else {
00740                 if (MD5File(config_hash, hash_file) != 0) {
00741                         LM_ERR("could not hash the config file");
00742                         return -1;
00743                 }
00744                 LM_DBG("config file hash is %.*s", MD5_LEN, config_hash);
00745         }
00746 
00747         if (initial_prob > 100) {
00748                 LM_ERR("invalid probability <%d>\n", initial_prob);
00749                 return -1;
00750         }
00751         LM_DBG("initial probability %d percent\n", initial_prob);
00752 
00753         probability=(int *) shm_malloc(sizeof(int));
00754 
00755         if (!probability) {
00756                 LM_ERR("no shmem available\n");
00757                 return -1;
00758         }
00759         *probability = initial_prob;
00760 
00761         gflags=(unsigned int *) shm_malloc(sizeof(unsigned int));
00762         if (!gflags) {
00763                 LM_ERR(" no shmem available\n");
00764                 return -1;
00765         }
00766         *gflags=initial_gflags;
00767         if(_cfg_lock_size>0 && _cfg_lock_size<=10)
00768         {
00769                 _cfg_lock_size = 1<<_cfg_lock_size;
00770                 _cfg_lock_set = lock_set_alloc(_cfg_lock_size);
00771                 if(_cfg_lock_set==NULL || lock_set_init(_cfg_lock_set)==NULL)
00772                 {
00773                         LM_ERR("cannot initiate lock set\n");
00774                         return -1;
00775                 }
00776         }
00777         return 0;
00778 }
00779 
00780 
00781 static void mod_destroy(void)
00782 {
00783         if (probability)
00784                 shm_free(probability);
00785         if (gflags)
00786                 shm_free(gflags);
00787         if(_cfg_lock_set!=NULL)
00788         {
00789                 lock_set_destroy(_cfg_lock_set);
00790                 lock_set_dealloc(_cfg_lock_set);
00791         }
00792 }
00793 
00797 int cfgutils_lock(str *lkey)
00798 {
00799         return cfg_lock_helper(lkey, 0);
00800 }
00801 
00805 int cfgutils_unlock(str *lkey)
00806 {
00807         return cfg_lock_helper(lkey, 1);
00808 }
00809 
00810 static int fixup_core_hash(void **param, int param_no)
00811 {
00812         if (param_no == 1)
00813                 return fixup_spve_null(param, 1);
00814         else if (param_no == 2)
00815                 return fixup_spve_null(param, 1);
00816         else if (param_no == 3)
00817                 return fixup_igp_null(param, 1);
00818         else
00819                 return 0;
00820 }
00821 
00822 static int w_core_hash(struct sip_msg *msg, char *p1, char *p2, char *p3)
00823 {
00824         str s1, s2;
00825         int size;
00826 
00827         if (fixup_get_svalue(msg, (gparam_p) p1, &s1) != 0)
00828         {
00829                 LM_ERR("invalid s1 paramerer\n");
00830                 return -1;
00831         }
00832         if (fixup_get_svalue(msg, (gparam_p) p2, &s2) != 0)
00833         {
00834                 LM_ERR("invalid s2 paramerer\n");
00835                 return -1;
00836         }
00837         if (fixup_get_ivalue(msg, (gparam_p) p3, &size) != 0)
00838         {
00839                 LM_ERR("invalid size paramerer\n");
00840                 return -1;
00841         }
00842 
00843         if (size <= 0) size = 2;
00844         else size = 1 << size;
00845 
00846         /* Return value _MUST_ be > 0 */
00847         return core_hash(&s1, s2.len ? &s2 : NULL, size) + 1;
00848 }
00849 
00853 int bind_cfgutils(cfgutils_api_t *api)
00854 {
00855         if (!api) {
00856                 ERR("Invalid parameter value\n");
00857                 return -1;
00858         }
00859         api->mlock   = cfgutils_lock;
00860         api->munlock = cfgutils_unlock;
00861 
00862         return 0;
00863 }