7be7181d8266dfb280f03ba6cb765a872da8483d
[kamailio] / src / modules / cfgutils / cfgutils.c
1 /*
2  * Copyright (C) 2012 Edvina AB
3  * Copyright (C) 2007 1&1 Internet AG
4  * Copyright (C) 2007 BASIS AudioNet GmbH
5  * Copyright (C) 2004 FhG
6  * Copyright (C) 2005-2006 Voice Sistem S.R.L.
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Softwar
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  */
24
25 /**
26  * cfgutils module: various config functions for Kamailio;
27  * it provide functions to make a decision in the script
28  * of the server based on a probability function.
29  * The benefit of this module is the value of the probability function
30  * can be manipulated by external applications such as web interface
31  * or command line tools.
32  * Furthermore it provides some functions to let the server wait a
33  * specific time interval.
34  *
35  * gflags module: global flags; it keeps a bitmap of flags
36  * in shared memory and may be used to change behaviour
37  * of server based on value of the flags. E.g.,
38  *    if (is_gflag("1")) { t_relay_to_udp("10.0.0.1","5060"); }
39  *    else { t_relay_to_udp("10.0.0.2","5060"); }
40  * The benefit of this module is the value of the switch flags
41  * can be manipulated by external applications such as web interface
42  * or command line tools.
43  */
44
45
46 #include "../../core/sr_module.h"
47 #include "../../core/error.h"
48 #include "../../core/pvar.h"
49 #include "../../core/ut.h"
50 #include "../../core/mem/mem.h"
51 #include "../../core/mem/shm_mem.h"
52 #include "../../core/mod_fix.h"
53 #include "../../core/crypto/md5.h"
54 #include "../../core/crypto/md5utils.h"
55 #include "../../core/globals.h"
56 #include "../../core/hashes.h"
57 #include "../../core/locking.h"
58 #include "../../core/route.h"
59 #include "../../core/kemi.h"
60 #include "../../core/rand/kam_rand.h"
61 #include "../../core/rpc.h"
62 #include "../../core/rpc_lookup.h"
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <unistd.h>
68
69 #include "api.h"
70
71 MODULE_VERSION
72
73 static int set_prob(struct sip_msg*, char *, char *);
74 static int reset_prob(struct sip_msg*, char *, char *);
75 static int get_prob(struct sip_msg*, char *, char *);
76 static int rand_event(struct sip_msg*, char *, char *);
77 static int m_sleep(struct sip_msg*, char *, char *);
78 static int m_usleep(struct sip_msg*, char *, char *);
79 static int dbg_abort(struct sip_msg*, char*,char*);
80 static int dbg_pkg_status(struct sip_msg*, char*,char*);
81 static int dbg_shm_status(struct sip_msg*, char*,char*);
82 static int dbg_pkg_summary(struct sip_msg*, char*,char*);
83 static int dbg_shm_summary(struct sip_msg*, char*,char*);
84 static int w_route_exists(struct sip_msg*, char*);
85 static int w_check_route_exists(struct sip_msg*, char*);
86
87 static int set_gflag(struct sip_msg*, char *, char *);
88 static int reset_gflag(struct sip_msg*, char *, char *);
89 static int is_gflag(struct sip_msg*, char *, char *);
90
91 static int w_cfg_lock(struct sip_msg*, char *, char *);
92 static int w_cfg_unlock(struct sip_msg*, char *, char *);
93 static int w_cfg_trylock(struct sip_msg*, char *, char *);
94
95
96 static int pv_get_random_val(struct sip_msg *msg, pv_param_t *param,
97                 pv_value_t *res);
98
99
100 static int fixup_prob( void** param, int param_no);
101 static int fixup_gflags( void** param, int param_no);
102
103 static int fixup_core_hash(void **param, int param_no);
104 static int w_core_hash(struct sip_msg *msg, char *p1, char *p2, char *p3);
105
106 int bind_cfgutils(cfgutils_api_t *api);
107
108 static int mod_init(void);
109 static void mod_destroy(void);
110
111 static int initial_prob = 10;
112 static int *probability = NULL;
113
114 static char config_hash[MD5_LEN];
115 static char* hash_file = NULL;
116
117 static int initial_gflags=0;
118 static unsigned int *gflags=0;
119 static gen_lock_t *gflags_lock = NULL;
120
121 static gen_lock_set_t *_cfg_lock_set = NULL;
122 static unsigned int _cfg_lock_size = 0;
123
124 static cmd_export_t cmds[]={
125         {"rand_set_prob", /* action name as in scripts */
126                 (cmd_function)set_prob,  /* C function name */
127                 1,          /* number of parameters */
128                 fixup_prob, 0,         /* */
129                 /* can be applied to original/failed requests and replies */
130                 ANY_ROUTE},
131         {"rand_reset_prob", (cmd_function)reset_prob, 0, 0, 0,
132                 ANY_ROUTE},
133         {"rand_get_prob",   (cmd_function)get_prob,   0, 0, 0,
134                 ANY_ROUTE},
135         {"rand_event",      (cmd_function)rand_event, 0, 0, 0,
136                 ANY_ROUTE},
137         {"sleep",  (cmd_function)m_sleep,  1, fixup_igp_null, fixup_free_igp_null,
138                 ANY_ROUTE},
139         {"usleep", (cmd_function)m_usleep, 1, fixup_igp_null, fixup_free_igp_null,
140                 ANY_ROUTE},
141         {"abort",      (cmd_function)dbg_abort,        0, 0, 0,
142                 ANY_ROUTE},
143         {"pkg_status", (cmd_function)dbg_pkg_status,   0, 0, 0,
144                 ANY_ROUTE},
145         {"shm_status", (cmd_function)dbg_shm_status,   0, 0, 0,
146                 ANY_ROUTE},
147         {"pkg_summary", (cmd_function)dbg_pkg_summary,   0, 0, 0,
148                 ANY_ROUTE},
149         {"shm_summary", (cmd_function)dbg_shm_summary,   0, 0, 0,
150                 ANY_ROUTE},
151         {"set_gflag",    (cmd_function)set_gflag,   1,   fixup_gflags, 0,
152                 ANY_ROUTE},
153         {"reset_gflag",  (cmd_function)reset_gflag, 1,   fixup_gflags, 0,
154                 ANY_ROUTE},
155         {"is_gflag",     (cmd_function)is_gflag,    1,   fixup_gflags, 0,
156                 ANY_ROUTE},
157         {"lock",         (cmd_function)w_cfg_lock,    1,   fixup_spve_null, 0,
158                 ANY_ROUTE},
159         {"unlock",       (cmd_function)w_cfg_unlock,  1,   fixup_spve_null, 0,
160                 ANY_ROUTE},
161         {"trylock",       (cmd_function)w_cfg_trylock,  1,   fixup_spve_null, 0,
162                 ANY_ROUTE},
163         {"core_hash",    (cmd_function)w_core_hash, 3,   fixup_core_hash, 0,
164                 ANY_ROUTE},
165         {"check_route_exists",    (cmd_function)w_check_route_exists, 1,   fixup_spve_null, fixup_free_spve_null,
166                 ANY_ROUTE},
167         {"route_if_exists",    (cmd_function)w_route_exists, 1,   fixup_spve_null, fixup_free_spve_null,
168                 ANY_ROUTE},
169         {"bind_cfgutils", (cmd_function)bind_cfgutils,  0,
170                 0, 0, 0},
171         {0, 0, 0, 0, 0, 0}
172 };
173
174
175 static param_export_t params[]={
176         {"initial_probability", INT_PARAM, &initial_prob   },
177         {"initial_gflags",      INT_PARAM, &initial_gflags },
178         {"hash_file",           PARAM_STRING, &hash_file      },
179         {"lock_set_size",       INT_PARAM, &_cfg_lock_size },
180         {0,0,0}
181 };
182
183
184
185 static pv_export_t mod_items[] = {
186         { {"RANDOM", sizeof("RANDOM")-1}, PVT_OTHER, pv_get_random_val, 0,
187                 0, 0, 0, 0 },
188         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
189 };
190
191
192 struct module_exports exports = {
193         "cfgutils",          /* module name */
194         DEFAULT_DLFLAGS, /* dlopen flags */
195         cmds,            /* cmd (cfg function) exports */
196         params,          /* param exports */
197         0,               /* RPC method exports */
198         mod_items,       /* pseudo-variables exports */
199         0,               /* response handling function */
200         mod_init,        /* module init function */
201         0,               /* per-child init function */
202         mod_destroy      /* module destroy function */
203 };
204
205 /**************************** fixup functions ******************************/
206 static int fixup_prob( void** param, int param_no)
207 {
208         unsigned int myint = 1000; /* stop if str2int later fail */
209         str param_str;
210
211         /* we only fix the parameter #1 */
212         if (param_no!=1)
213                 return 0;
214
215         param_str.s=(char*) *param;
216         param_str.len=strlen(param_str.s);
217         str2int(&param_str, &myint);
218
219         if (myint > 100) {
220                 LM_ERR("invalid probability <%d>\n", myint);
221                 return E_CFG;
222         }
223
224         pkg_free(*param);
225         *param=(void *)(long)myint;
226         return 0;
227 }
228
229 /**
230  * convert char* to int and do bitwise right-shift
231  * char* must be pkg_alloced and will be freed by the function
232  */
233 static int fixup_gflags( void** param, int param_no)
234 {
235         unsigned int myint;
236         str param_str;
237
238         /* we only fix the parameter #1 */
239         if (param_no!=1)
240                 return 0;
241
242         param_str.s=(char*) *param;
243         param_str.len=strlen(param_str.s);
244
245         if (str2int(&param_str, &myint )<0) {
246                 LM_ERR("bad number <%s>\n", (char *)(*param));
247                 return E_CFG;
248         }
249         if ( myint >= 8*sizeof(*gflags) ) {
250                 LM_ERR("flag <%d> out of "
251                         "range [0..%lu]\n", myint, ((unsigned long)8*sizeof(*gflags))-1 );
252                 return E_CFG;
253         }
254         /* convert from flag index to flag bitmap */
255         myint = 1 << myint;
256         /* success -- change to int */
257         pkg_free(*param);
258         *param=(void *)(long)myint;
259         return 0;
260 }
261
262
263 /************************** module functions **********************************/
264
265 static int set_gflag(struct sip_msg *bar, char *flag, char *foo)
266 {
267         lock_get(gflags_lock);
268         (*gflags) |= (unsigned int)(long)flag;
269         lock_release(gflags_lock);
270         return 1;
271 }
272
273
274 static int reset_gflag(struct sip_msg *bar, char *flag, char *foo)
275 {
276         lock_get(gflags_lock);
277         (*gflags) &= ~ ((unsigned int)(long)flag);
278         lock_release(gflags_lock);
279         return 1;
280 }
281
282
283 static int is_gflag(struct sip_msg *bar, char *flag, char *foo)
284 {
285         return ( (*gflags) & ((unsigned int)(long)flag)) ? 1 : -1;
286 }
287
288
289 void cfgutils_rpc_set_gflag(rpc_t* rpc, void* ctx)
290 {
291         long int flag;
292         if(rpc->scan(ctx, "d", (int*)(&flag))<1) {
293                 LM_WARN("no parameters\n");
294                 rpc->fault(ctx, 500, "Invalid Parameters");
295                 return;
296         }
297         lock_get(gflags_lock);
298         (*gflags) |= flag;
299         lock_release(gflags_lock);
300 }
301
302 void cfgutils_rpc_reset_gflag(rpc_t* rpc, void* ctx)
303 {
304         unsigned int flag;
305         if(rpc->scan(ctx, "d", (int*)(&flag))<1) {
306                 LM_WARN("no parameters\n");
307                 rpc->fault(ctx, 500, "Invalid Parameters");
308                 return;
309         }
310         lock_get(gflags_lock);
311         (*gflags) &= ~ flag;
312         lock_release(gflags_lock);
313 }
314
315 void cfgutils_rpc_is_gflag(rpc_t* rpc, void* ctx)
316 {
317         unsigned int flag;
318         if(rpc->scan(ctx, "d", (int*)(&flag))<1) {
319                 LM_WARN("no parameters\n");
320                 rpc->fault(ctx, 500, "Invalid Parameters");
321                 return;
322         }
323         if (((*gflags) & flag) == flag)
324                 rpc->add(ctx, "s", "TRUE");
325         else
326                 rpc->add(ctx, "s", "FALSE");
327 }
328
329 void cfgutils_rpc_get_gflags(rpc_t* rpc, void* ctx)
330 {
331         unsigned int flags;
332
333         flags = *gflags;
334
335         if (rpc->rpl_printf(ctx, "0x%X (%u)", flags, flags) < 0) {
336                 rpc->fault(ctx, 500, "Faiure building the response");
337                 return;
338         }
339 }
340
341 void cfgutils_rpc_set_prob(rpc_t* rpc, void* ctx)
342 {
343         unsigned int percent;
344
345         if(rpc->scan(ctx, "d", (int*)(&percent))<1) {
346                 LM_WARN("no parameters\n");
347                 rpc->fault(ctx, 500, "Invalid Parameters");
348                 return;
349         }
350         if (percent > 100) {
351                 LM_ERR("incorrect probability <%u>\n", percent);
352                 rpc->fault(ctx, 500, "Invalid Percent");
353                 return;
354         }
355         *probability = percent;
356 }
357
358
359 void cfgutils_rpc_reset_prob(rpc_t* rpc, void* ctx)
360 {
361         *probability = initial_prob;
362 }
363
364 void cfgutils_rpc_get_prob(rpc_t* rpc, void* ctx)
365 {
366         if (rpc->rpl_printf(ctx, "actual probability: %u percent",
367                                 (*probability)) < 0) {
368                 rpc->fault(ctx, 500, "Faiure building the response");
369                 return;
370         }
371 }
372
373 void cfgutils_rpc_get_hash(rpc_t* rpc, void* ctx)
374 {
375         if (rpc->rpl_printf(ctx, "%.*s",
376                                 MD5_LEN, config_hash) < 0) {
377                 rpc->fault(ctx, 500, "Faiure building the response");
378                 return;
379         }
380 }
381
382
383 /*! \brief
384   * Calculate a MD5 digest over a file.
385   * This function assumes 32 bytes in the destination buffer.
386   * \param dest destination
387   * \param file_name file for that the digest should be calculated
388   * \return zero on success, negative on errors
389   */
390 static int MD5File(char *dest, const char *file_name)
391 {
392         MD5_CTX context;
393         FILE *input;
394         unsigned char buffer[32768];
395         unsigned char hash[16];
396         unsigned int counter, size;
397
398         struct stat stats;
399
400         if (!dest || !file_name) {
401                 LM_ERR("invalid parameter value\n");
402                 return -1;
403         }
404
405     if (stat(file_name, &stats) != 0) {
406                 LM_ERR("could not stat file %s\n", file_name);
407                 return -1;
408         }
409         size = stats.st_size;
410
411         MD5Init(&context);
412         if((input = fopen(file_name, "rb")) == NULL) {
413                 LM_ERR("could not open file %s\n", file_name);
414                 return -1;
415         }
416
417         while(size) {
418                 counter = (size > sizeof(buffer)) ? sizeof(buffer) : size;
419                 if ((counter = fread(buffer, 1, counter, input)) <= 0) {
420                         fclose(input);
421                         return -1;
422                 }
423                 U_MD5Update(&context, buffer, counter);
424                 size -= counter;
425         }
426         fclose(input);
427         U_MD5Final(hash, &context);
428
429         string2hex(hash, 16, dest);
430         LM_DBG("MD5 calculated: %.*s for file %s\n", MD5_LEN, dest, file_name);
431
432         return 0;
433 }
434
435
436 void cfgutils_rpc_check_hash(rpc_t* rpc, void* ctx)
437 {
438         char tmp[MD5_LEN];
439         memset(tmp, 0, MD5_LEN);
440
441         if (!hash_file) {
442                 rpc->fault(ctx, 500, "No hash file");
443                 return;
444         }
445
446         if (MD5File(tmp, hash_file) != 0) {
447                 LM_ERR("could not hash the config file");
448                 rpc->fault(ctx, 500, "Failed to hash the file");
449                 return;
450         }
451
452         if (strncmp(config_hash, tmp, MD5_LEN) == 0) {
453                 if (rpc->rpl_printf(ctx, "Identical hash") < 0) {
454                         rpc->fault(ctx, 500, "Faiure building the response");
455                         return;
456                 }
457         } else {
458                 if (rpc->rpl_printf(ctx, "Different hash") < 0) {
459                         rpc->fault(ctx, 500, "Faiure building the response");
460                         return;
461                 }
462         }
463 }
464
465 static const char* cfgutils_rpc_is_gflag_doc[2] = {
466         "Checks if the bits specified by the argument are all set.",
467         0
468 };
469
470
471 static const char* cfgutils_rpc_set_gflag_doc[2] = {
472         "Sets the bits specified by the argument.",
473         0
474 };
475
476
477 static const char* cfgutils_rpc_get_gflags_doc[2] = {
478         "Return the value for global flags.",
479         0
480 };
481
482
483 static const char* cfgutils_rpc_reset_gflag_doc[2] = {
484         "Resets the bits specified by the argument.",
485         0
486 };
487
488 static const char* cfgutils_rpc_set_prob_doc[2] = {
489         "Set the random probability.",
490         0
491 };
492 static const char* cfgutils_rpc_reset_prob_doc[2] = {
493         "Reset the random probability.",
494         0
495 };
496
497 static const char* cfgutils_rpc_get_prob_doc[2] = {
498         "Get the random probability.",
499         0
500 };
501
502 static const char* cfgutils_rpc_get_hash_doc[2] = {
503         "Get config hash value.",
504         0
505 };
506
507 static const char* cfgutils_rpc_check_hash_doc[2] = {
508         "Check config hash value.",
509         0
510 };
511
512 static rpc_export_t rpc_cmds[] = {
513         {"cfgutils.is_gflag", cfgutils_rpc_is_gflag,
514                 cfgutils_rpc_is_gflag_doc, 0},
515         {"cfgutils.set_gflag", cfgutils_rpc_set_gflag,
516                 cfgutils_rpc_set_gflag_doc, 0},
517         {"cfgutils.get_gflags", cfgutils_rpc_get_gflags,
518                 cfgutils_rpc_get_gflags_doc, 0},
519         {"cfgutils.reset_gflag", cfgutils_rpc_reset_gflag,
520                 cfgutils_rpc_reset_gflag_doc, 0},
521         {"cfgutils.rand_set_prob", cfgutils_rpc_set_prob,
522                 cfgutils_rpc_set_prob_doc, 0},
523         {"cfgutils.rand_reset_prob", cfgutils_rpc_reset_prob,
524                 cfgutils_rpc_reset_prob_doc, 0},
525         {"cfgutils.rand_get_prob", cfgutils_rpc_get_prob,
526                 cfgutils_rpc_get_prob_doc, 0},
527         {"cfgutils.get_config_hash", cfgutils_rpc_get_hash,
528                 cfgutils_rpc_get_hash_doc, 0},
529         {"cfgutils.check_config_hash", cfgutils_rpc_check_hash,
530                 cfgutils_rpc_check_hash_doc, 0},
531
532         {0, 0, 0, 0}
533 };
534
535 static int set_prob(struct sip_msg *bar, char *percent_par, char *foo)
536 {
537         *probability=(int)(long)percent_par;
538         return 1;
539 }
540
541 static int ki_rand_set_prob(sip_msg_t *msg, int percent_par)
542 {
543         *probability=percent_par;
544         return 1;
545 }
546
547 static int reset_prob(struct sip_msg *bar, char *percent_par, char *foo)
548 {
549         *probability=initial_prob;
550         return 1;
551 }
552
553 static int ki_rand_reset_prob(sip_msg_t *msg)
554 {
555         *probability=initial_prob;
556         return 1;
557 }
558
559 static int get_prob(struct sip_msg *bar, char *foo1, char *foo2)
560 {
561         return *probability;
562 }
563
564 static int ki_rand_get_prob(sip_msg_t *bar)
565 {
566         return *probability;
567 }
568
569 static int ki_rand_event(sip_msg_t *msg)
570 {
571         double tmp;
572         /* most of the time this will be disabled completly. Tis will also fix the
573          * problem with the corner cases if rand() returned zero or RAND_MAX */
574         if ((*probability) == 0) return -1;
575         if ((*probability) == 100) return 1;
576
577         tmp = ((double) kam_rand() / KAM_RAND_MAX);
578         LM_DBG("generated random %f\n", tmp);
579         if (tmp < ((double) (*probability) / 100)) {
580                 LM_DBG("return true\n");
581                 return 1;
582         }
583         else {
584                 LM_DBG("return false\n");
585                 return -1;
586         }
587 }
588
589 static int rand_event(struct sip_msg *bar, char *foo1, char *foo2)
590 {
591         return ki_rand_event(bar);
592 }
593
594 static int pv_get_random_val(struct sip_msg *msg, pv_param_t *param,
595                 pv_value_t *res)
596 {
597         int n;
598         int l = 0;
599         char *ch;
600
601         if(msg==NULL || res==NULL)
602                 return -1;
603
604         n = kam_rand();
605         ch = int2str(n , &l);
606         res->rs.s = ch;
607         res->rs.len = l;
608         res->ri = n;
609         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
610
611         return 0;
612 }
613
614 static int m_sleep(struct sip_msg *msg, char *time, char *str2)
615 {
616         int s;
617         if(fixup_get_ivalue(msg, (gparam_t*)time, &s)!=0)
618         {
619                 LM_ERR("cannot get time interval value\n");
620                 return -1;
621         }
622         sleep((unsigned int)s);
623         return 1;
624 }
625
626 static int ki_sleep(sip_msg_t* msg, int v)
627 {
628         sleep((unsigned int)v);
629         return 1;
630 }
631
632 static int m_usleep(struct sip_msg *msg, char *time, char *str2)
633 {
634         int s;
635         if(fixup_get_ivalue(msg, (gparam_t*)time, &s)!=0)
636         {
637                 LM_ERR("cannot get time interval value\n");
638                 return -1;
639         }
640         sleep_us((unsigned int)s);
641         return 1;
642 }
643
644 static int ki_usleep(sip_msg_t* msg, int v)
645 {
646         sleep_us((unsigned int)v);
647         return 1;
648 }
649
650 static int dbg_abort(struct sip_msg* msg, char* foo, char* bar)
651 {
652         LM_CRIT("abort called\n");
653         abort();
654         return 0;
655 }
656
657 static int ki_abort(sip_msg_t* msg)
658 {
659         LM_CRIT("abort called\n");
660         abort();
661         return 0;
662 }
663
664 static int dbg_pkg_status(struct sip_msg* msg, char* foo, char* bar)
665 {
666         pkg_status();
667         return 1;
668 }
669
670 static int ki_pkg_status(sip_msg_t* msg)
671 {
672         pkg_status();
673         return 1;
674 }
675
676 static int dbg_shm_status(struct sip_msg* msg, char* foo, char* bar)
677 {
678         shm_status();
679         return 1;
680 }
681
682 static int ki_shm_status(sip_msg_t* msg)
683 {
684         shm_status();
685         return 1;
686 }
687
688 static int dbg_pkg_summary(struct sip_msg* msg, char* foo, char* bar)
689 {
690         pkg_sums();
691         return 1;
692 }
693
694 static int ki_pkg_summary(sip_msg_t* msg)
695 {
696         pkg_sums();
697         return 1;
698 }
699
700 static int dbg_shm_summary(struct sip_msg* msg, char* foo, char* bar)
701 {
702         shm_sums();
703         return 1;
704 }
705
706 static int ki_shm_summary(sip_msg_t* msg)
707 {
708         shm_sums();
709         return 1;
710 }
711
712 static int cfg_lock_helper(str *lkey, int mode)
713 {
714         unsigned int pos;
715
716         if(_cfg_lock_set==NULL) {
717                 LM_ERR("lock set not initialized (attempt to do op: %d on: %.*s) -"
718                                 " see param lock_set_size\n",
719                                 mode, lkey->len, lkey->s);
720                 return -1;
721         }
722         pos = core_case_hash(lkey, 0, _cfg_lock_size);
723
724         LM_DBG("cfg_lock mode %d on %u (%.*s)\n", mode, pos, lkey->len, lkey->s);
725
726         if(mode==0) {
727                 /* Lock */
728                 lock_set_get(_cfg_lock_set, pos);
729         } else if (mode == 1) {
730                 /* Unlock */
731                 lock_set_release(_cfg_lock_set, pos);
732         } else {
733                 int res;
734                 /* Trylock */
735                 res = lock_set_try(_cfg_lock_set, pos);
736                 if (res != 0) {
737                         LM_DBG("Failed to trylock \n");
738                         /* Failed to lock */
739                         return -1;
740                 }
741                 LM_DBG("Succeeded with trylock \n");
742                 /* Succeeded in locking */
743                 return 1;
744         }
745         return 1;
746 }
747
748 static int cfg_lock(sip_msg_t *msg, str *lkey)
749 {
750         return cfg_lock_helper(lkey, 0);
751 }
752
753 static int cfg_unlock(sip_msg_t *msg, str *lkey)
754 {
755         return cfg_lock_helper(lkey, 1);
756 }
757
758 static int cfg_trylock(sip_msg_t *msg, str *lkey)
759 {
760         return cfg_lock_helper(lkey, 2);
761 }
762
763 static int w_cfg_lock_wrapper(struct sip_msg *msg, gparam_p key, int mode)
764 {
765         str s;
766         if(key==NULL) {
767                 return -1;
768         }
769         if(fixup_get_svalue(msg, key, &s)!=0) {
770                 LM_ERR("cannot get first parameter\n");
771                 return -1;
772         }
773         return cfg_lock_helper(&s, mode);
774 }
775
776 static int w_cfg_lock(struct sip_msg *msg, char *key, char *s2)
777 {
778         return w_cfg_lock_wrapper(msg, (gparam_p)key, 0);
779 }
780
781 static int w_cfg_unlock(struct sip_msg *msg, char *key, char *s2)
782 {
783         return w_cfg_lock_wrapper(msg, (gparam_p)key, 1);
784 }
785
786 static int w_cfg_trylock(struct sip_msg *msg, char *key, char *s2)
787 {
788         return w_cfg_lock_wrapper(msg, (gparam_p)key, 2);
789 }
790
791 /*! Check if a route block exists - only request routes
792  */
793 static int w_check_route_exists(struct sip_msg *msg, char *route)
794 {
795         str s;
796
797         if (fixup_get_svalue(msg, (gparam_p) route, &s) != 0)
798         {
799                         LM_ERR("invalid route parameter\n");
800                         return -1;
801         }
802         if (route_lookup(&main_rt, s.s)<0) {
803                 /* not found */
804                 return -1;
805         }
806         return 1;
807 }
808
809 /*! Run a request route block if it exists
810  */
811 static int w_route_exists(struct sip_msg *msg, char *route)
812 {
813         struct run_act_ctx ctx;
814         int newroute, ret;
815         str s;
816
817         if (fixup_get_svalue(msg, (gparam_p) route, &s) != 0) {
818                         LM_ERR("invalid route parameter\n");
819                         return -1;
820         }
821
822         newroute = route_lookup(&main_rt, s.s);
823         if (newroute<0) {
824                 return -1;
825         }
826         init_run_actions_ctx(&ctx);
827         ret=run_actions(&ctx, main_rt.rlist[newroute], msg);
828         if (ctx.run_flags & EXIT_R_F) {
829                 return 0;
830         }
831         return ret;
832 }
833
834 static int mod_init(void)
835 {
836         /* Register RPC commands */
837         if (rpc_register_array(rpc_cmds)!=0) {
838                 LM_ERR("failed to register RPC commands\n");
839                 return -1;
840         }
841
842         if (!hash_file) {
843                 LM_INFO("no hash_file given, disable hash functionality\n");
844         } else {
845                 if (MD5File(config_hash, hash_file) != 0) {
846                         LM_ERR("could not hash the config file");
847                         return -1;
848                 }
849                 LM_DBG("config file hash is %.*s", MD5_LEN, config_hash);
850         }
851
852         if (initial_prob > 100) {
853                 LM_ERR("invalid probability <%d>\n", initial_prob);
854                 return -1;
855         }
856         LM_DBG("initial probability %d percent\n", initial_prob);
857
858         probability=(int *) shm_malloc(sizeof(int));
859
860         if (!probability) {
861                 LM_ERR("no shmem available\n");
862                 return -1;
863         }
864         *probability = initial_prob;
865
866         gflags=(unsigned int *) shm_malloc(sizeof(unsigned int));
867         if (!gflags) {
868                 LM_ERR(" no shmem available\n");
869                 return -1;
870         }
871         *gflags=initial_gflags;
872         gflags_lock = lock_alloc();
873         if (gflags_lock==0) {
874                 LM_ERR("cannot allocate gflgas lock\n");
875                 return -1;
876         }
877         if (lock_init(gflags_lock)==NULL) {
878                 LM_ERR("cannot initiate gflags lock\n");
879                 lock_dealloc(gflags_lock);
880                 return -1;
881         }
882         if(_cfg_lock_size>0) {
883                 if(_cfg_lock_size>14) {
884                         LM_WARN("lock set size too large (%d), making it 14\n",
885                                         _cfg_lock_size);
886                         _cfg_lock_size = 14;
887                 }
888                 _cfg_lock_size = 1<<_cfg_lock_size;
889                 _cfg_lock_set = lock_set_alloc(_cfg_lock_size);
890                 if(_cfg_lock_set==NULL || lock_set_init(_cfg_lock_set)==NULL) {
891                         LM_ERR("cannot initiate lock set\n");
892                         return -1;
893                 }
894         }
895         return 0;
896 }
897
898
899 static void mod_destroy(void)
900 {
901         if (probability)
902                 shm_free(probability);
903         if (gflags)
904                 shm_free(gflags);
905         if (gflags_lock) {
906                 lock_destroy(gflags_lock);
907                 lock_dealloc(gflags_lock);
908         }
909         if(_cfg_lock_set!=NULL)
910         {
911                 lock_set_destroy(_cfg_lock_set);
912                 lock_set_dealloc(_cfg_lock_set);
913                 _cfg_lock_set = NULL;
914         }
915 }
916
917 /**
918  *
919  */
920 int cfgutils_lock(str *lkey)
921 {
922         return cfg_lock_helper(lkey, 0);
923 }
924
925 /**
926  *
927  */
928 int cfgutils_unlock(str *lkey)
929 {
930         return cfg_lock_helper(lkey, 1);
931 }
932
933 static int fixup_core_hash(void **param, int param_no)
934 {
935         if (param_no == 1)
936                 return fixup_spve_null(param, 1);
937         else if (param_no == 2)
938                 return fixup_spve_null(param, 1);
939         else if (param_no == 3)
940                 return fixup_igp_null(param, 1);
941         else
942                 return 0;
943 }
944
945 static int w_core_hash(struct sip_msg *msg, char *p1, char *p2, char *p3)
946 {
947         str s1, s2;
948         int size;
949
950         if (fixup_get_svalue(msg, (gparam_p) p1, &s1) != 0)
951         {
952                 LM_ERR("invalid s1 paramerer\n");
953                 return -1;
954         }
955         if (fixup_get_svalue(msg, (gparam_p) p2, &s2) != 0)
956         {
957                 LM_ERR("invalid s2 paramerer\n");
958                 return -1;
959         }
960         if (fixup_get_ivalue(msg, (gparam_p) p3, &size) != 0)
961         {
962                 LM_ERR("invalid size paramerer\n");
963                 return -1;
964         }
965
966         if (size <= 0) size = 2;
967         else size = 1 << size;
968
969         /* Return value _MUST_ be > 0 */
970         return core_hash(&s1, s2.len ? &s2 : NULL, size) + 1;
971 }
972
973 static int ki_core_hash(sip_msg_t *msg, str *s1, str *s2, int sz)
974 {
975         int size;
976
977         size = sz;
978
979         if (size <= 0) size = 2;
980         else size = 1 << size;
981
982         return core_hash(s1, (s2 && s2->len>0)?s2:NULL, size) + 1;
983 }
984
985 /**
986  * @brief bind functions to CFGUTILS API structure
987  */
988 int bind_cfgutils(cfgutils_api_t *api)
989 {
990         if (!api) {
991                 ERR("Invalid parameter value\n");
992                 return -1;
993         }
994         api->mlock   = cfgutils_lock;
995         api->munlock = cfgutils_unlock;
996
997         return 0;
998 }
999
1000
1001 /**
1002  * KEMI exports
1003  */
1004 /* clang-format off */
1005 static sr_kemi_t sr_kemi_cfgutils_exports[] = {
1006         { str_init("cfgutils"), str_init("lock"),
1007                 SR_KEMIP_INT, cfg_lock,
1008                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1009                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1010         },
1011         { str_init("cfgutils"), str_init("unlock"),
1012                 SR_KEMIP_INT, cfg_unlock,
1013                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1014                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1015         },
1016         { str_init("cfgutils"), str_init("trylock"),
1017                 SR_KEMIP_INT, cfg_trylock,
1018                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1019                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1020         },
1021         { str_init("cfgutils"), str_init("rand_set_prob"),
1022                 SR_KEMIP_INT, ki_rand_set_prob,
1023                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1024                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1025         },
1026         { str_init("cfgutils"), str_init("rand_reset_prob"),
1027                 SR_KEMIP_INT, ki_rand_reset_prob,
1028                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1029                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1030         },
1031         { str_init("cfgutils"), str_init("rand_get_prob"),
1032                 SR_KEMIP_INT, ki_rand_get_prob,
1033                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1034                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1035         },
1036         { str_init("cfgutils"), str_init("rand_event"),
1037                 SR_KEMIP_INT, ki_rand_event,
1038                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1039                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1040         },
1041         { str_init("cfgutils"), str_init("abort"),
1042                 SR_KEMIP_INT, ki_abort,
1043                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1044                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1045         },
1046         { str_init("cfgutils"), str_init("pkg_status"),
1047                 SR_KEMIP_INT, ki_pkg_status,
1048                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1049                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1050         },
1051         { str_init("cfgutils"), str_init("shm_status"),
1052                 SR_KEMIP_INT, ki_shm_status,
1053                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1054                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1055         },
1056         { str_init("cfgutils"), str_init("pkg_summary"),
1057                 SR_KEMIP_INT, ki_pkg_summary,
1058                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1059                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1060         },
1061         { str_init("cfgutils"), str_init("shm_summary"),
1062                 SR_KEMIP_INT, ki_shm_summary,
1063                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1064                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1065         },
1066         { str_init("cfgutils"), str_init("core_hash"),
1067                 SR_KEMIP_INT, ki_core_hash,
1068                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
1069                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1070         },
1071         { str_init("cfgutils"), str_init("sleep"),
1072                 SR_KEMIP_INT, ki_sleep,
1073                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1074                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1075         },
1076         { str_init("cfgutils"), str_init("usleep"),
1077                 SR_KEMIP_INT, ki_usleep,
1078                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1079                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1080         },
1081
1082         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1083 };
1084 /* clang-format on */
1085
1086 /**
1087  *
1088  */
1089 int mod_register(char *path, int *dlflags, void *p1, void *p2)
1090 {
1091         sr_kemi_modules_add(sr_kemi_cfgutils_exports);
1092         return 0;
1093 }