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 ******************************/
fixup_prob(void ** param,int param_no)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(¶m_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 */
fixup_gflags(void ** param,int param_no)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(¶m_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
set_gflag(struct sip_msg * bar,char * flag,char * foo)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
reset_gflag(struct sip_msg * bar,char * flag,char * foo)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
is_gflag(struct sip_msg * bar,char * flag,char * foo)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
cfgutils_rpc_set_gflag(rpc_t * rpc,void * ctx)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
cfgutils_rpc_reset_gflag(rpc_t * rpc,void * ctx)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
cfgutils_rpc_is_gflag(rpc_t * rpc,void * ctx)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
cfgutils_rpc_get_gflags(rpc_t * rpc,void * ctx)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
cfgutils_rpc_set_prob(rpc_t * rpc,void * ctx)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
cfgutils_rpc_reset_prob(rpc_t * rpc,void * ctx)359 void cfgutils_rpc_reset_prob(rpc_t* rpc, void* ctx)
360 {
361 *probability = initial_prob;
362 }
363
cfgutils_rpc_get_prob(rpc_t * rpc,void * ctx)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
cfgutils_rpc_get_hash(rpc_t * rpc,void * ctx)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 */
MD5File(char * dest,const char * file_name)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
cfgutils_rpc_check_hash(rpc_t * rpc,void * ctx)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
set_prob(struct sip_msg * bar,char * percent_par,char * foo)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
ki_rand_set_prob(sip_msg_t * msg,int percent_par)541 static int ki_rand_set_prob(sip_msg_t *msg, int percent_par)
542 {
543 *probability=percent_par;
544 return 1;
545 }
546
reset_prob(struct sip_msg * bar,char * percent_par,char * foo)547 static int reset_prob(struct sip_msg *bar, char *percent_par, char *foo)
548 {
549 *probability=initial_prob;
550 return 1;
551 }
552
ki_rand_reset_prob(sip_msg_t * msg)553 static int ki_rand_reset_prob(sip_msg_t *msg)
554 {
555 *probability=initial_prob;
556 return 1;
557 }
558
get_prob(struct sip_msg * bar,char * foo1,char * foo2)559 static int get_prob(struct sip_msg *bar, char *foo1, char *foo2)
560 {
561 return *probability;
562 }
563
ki_rand_get_prob(sip_msg_t * bar)564 static int ki_rand_get_prob(sip_msg_t *bar)
565 {
566 return *probability;
567 }
568
ki_rand_event(sip_msg_t * msg)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
rand_event(struct sip_msg * bar,char * foo1,char * foo2)589 static int rand_event(struct sip_msg *bar, char *foo1, char *foo2)
590 {
591 return ki_rand_event(bar);
592 }
593
pv_get_random_val(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)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
m_sleep(struct sip_msg * msg,char * time,char * str2)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
ki_sleep(sip_msg_t * msg,int v)626 static int ki_sleep(sip_msg_t* msg, int v)
627 {
628 sleep((unsigned int)v);
629 return 1;
630 }
631
m_usleep(struct sip_msg * msg,char * time,char * str2)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
ki_usleep(sip_msg_t * msg,int v)644 static int ki_usleep(sip_msg_t* msg, int v)
645 {
646 sleep_us((unsigned int)v);
647 return 1;
648 }
649
dbg_abort(struct sip_msg * msg,char * foo,char * bar)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
ki_abort(sip_msg_t * msg)657 static int ki_abort(sip_msg_t* msg)
658 {
659 LM_CRIT("abort called\n");
660 abort();
661 return 0;
662 }
663
dbg_pkg_status(struct sip_msg * msg,char * foo,char * bar)664 static int dbg_pkg_status(struct sip_msg* msg, char* foo, char* bar)
665 {
666 pkg_status();
667 return 1;
668 }
669
ki_pkg_status(sip_msg_t * msg)670 static int ki_pkg_status(sip_msg_t* msg)
671 {
672 pkg_status();
673 return 1;
674 }
675
dbg_shm_status(struct sip_msg * msg,char * foo,char * bar)676 static int dbg_shm_status(struct sip_msg* msg, char* foo, char* bar)
677 {
678 shm_status();
679 return 1;
680 }
681
ki_shm_status(sip_msg_t * msg)682 static int ki_shm_status(sip_msg_t* msg)
683 {
684 shm_status();
685 return 1;
686 }
687
dbg_pkg_summary(struct sip_msg * msg,char * foo,char * bar)688 static int dbg_pkg_summary(struct sip_msg* msg, char* foo, char* bar)
689 {
690 pkg_sums();
691 return 1;
692 }
693
ki_pkg_summary(sip_msg_t * msg)694 static int ki_pkg_summary(sip_msg_t* msg)
695 {
696 pkg_sums();
697 return 1;
698 }
699
dbg_shm_summary(struct sip_msg * msg,char * foo,char * bar)700 static int dbg_shm_summary(struct sip_msg* msg, char* foo, char* bar)
701 {
702 shm_sums();
703 return 1;
704 }
705
ki_shm_summary(sip_msg_t * msg)706 static int ki_shm_summary(sip_msg_t* msg)
707 {
708 shm_sums();
709 return 1;
710 }
711
cfg_lock_helper(str * lkey,int mode)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
cfg_lock(sip_msg_t * msg,str * lkey)748 static int cfg_lock(sip_msg_t *msg, str *lkey)
749 {
750 return cfg_lock_helper(lkey, 0);
751 }
752
cfg_unlock(sip_msg_t * msg,str * lkey)753 static int cfg_unlock(sip_msg_t *msg, str *lkey)
754 {
755 return cfg_lock_helper(lkey, 1);
756 }
757
cfg_trylock(sip_msg_t * msg,str * lkey)758 static int cfg_trylock(sip_msg_t *msg, str *lkey)
759 {
760 return cfg_lock_helper(lkey, 2);
761 }
762
w_cfg_lock_wrapper(struct sip_msg * msg,gparam_p key,int mode)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
w_cfg_lock(struct sip_msg * msg,char * key,char * s2)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
w_cfg_unlock(struct sip_msg * msg,char * key,char * s2)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
w_cfg_trylock(struct sip_msg * msg,char * key,char * s2)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 */
ki_check_route_exists(sip_msg_t * msg,str * route)793 static int ki_check_route_exists(sip_msg_t *msg, str *route)
794 {
795 if(route == NULL || route->s == NULL) {
796 return -1;
797 }
798
799 if (route_lookup(&main_rt, route->s)<0) {
800 /* not found */
801 return -1;
802 }
803 return 1;
804 }
805
806 /*! Check if a route block exists - only request routes
807 */
w_check_route_exists(struct sip_msg * msg,char * route)808 static int w_check_route_exists(struct sip_msg *msg, char *route)
809 {
810 str s;
811
812 if (fixup_get_svalue(msg, (gparam_p) route, &s) != 0) {
813 LM_ERR("invalid route parameter\n");
814 return -1;
815 }
816
817 return ki_check_route_exists(msg, &s);
818 }
819
820 /*! Run a request route block if it exists
821 */
ki_route_if_exists(sip_msg_t * msg,str * route)822 static int ki_route_if_exists(sip_msg_t *msg, str *route)
823 {
824 struct run_act_ctx ctx;
825 int newroute, ret;
826
827 if(route == NULL || route->s == NULL) {
828 return -1;
829 }
830
831 newroute = route_lookup(&main_rt, route->s);
832 if (newroute<0) {
833 return -1;
834 }
835
836 init_run_actions_ctx(&ctx);
837 ret=run_actions(&ctx, main_rt.rlist[newroute], msg);
838 if (ctx.run_flags & EXIT_R_F) {
839 return 0;
840 }
841
842 return ret;
843 }
844
845
846 /*! Run a request route block if it exists
847 */
w_route_exists(struct sip_msg * msg,char * route)848 static int w_route_exists(struct sip_msg *msg, char *route)
849 {
850 str s;
851
852 if (fixup_get_svalue(msg, (gparam_p) route, &s) != 0) {
853 LM_ERR("invalid route parameter\n");
854 return -1;
855 }
856
857 return ki_route_if_exists(msg, &s);
858 }
859
mod_init(void)860 static int mod_init(void)
861 {
862 /* Register RPC commands */
863 if (rpc_register_array(rpc_cmds)!=0) {
864 LM_ERR("failed to register RPC commands\n");
865 return -1;
866 }
867
868 if (!hash_file) {
869 LM_INFO("no hash_file given, disable hash functionality\n");
870 } else {
871 if (MD5File(config_hash, hash_file) != 0) {
872 LM_ERR("could not hash the config file");
873 return -1;
874 }
875 LM_DBG("config file hash is %.*s", MD5_LEN, config_hash);
876 }
877
878 if (initial_prob > 100) {
879 LM_ERR("invalid probability <%d>\n", initial_prob);
880 return -1;
881 }
882 LM_DBG("initial probability %d percent\n", initial_prob);
883
884 probability=(int *) shm_malloc(sizeof(int));
885
886 if (!probability) {
887 LM_ERR("no shmem available\n");
888 return -1;
889 }
890 *probability = initial_prob;
891
892 gflags=(unsigned int *) shm_malloc(sizeof(unsigned int));
893 if (!gflags) {
894 LM_ERR(" no shmem available\n");
895 return -1;
896 }
897 *gflags=initial_gflags;
898 gflags_lock = lock_alloc();
899 if (gflags_lock==0) {
900 LM_ERR("cannot allocate gflgas lock\n");
901 return -1;
902 }
903 if (lock_init(gflags_lock)==NULL) {
904 LM_ERR("cannot initiate gflags lock\n");
905 lock_dealloc(gflags_lock);
906 return -1;
907 }
908 if(_cfg_lock_size>0) {
909 if(_cfg_lock_size>14) {
910 LM_WARN("lock set size too large (%d), making it 14\n",
911 _cfg_lock_size);
912 _cfg_lock_size = 14;
913 }
914 _cfg_lock_size = 1<<_cfg_lock_size;
915 _cfg_lock_set = lock_set_alloc(_cfg_lock_size);
916 if(_cfg_lock_set==NULL || lock_set_init(_cfg_lock_set)==NULL) {
917 LM_ERR("cannot initiate lock set\n");
918 return -1;
919 }
920 }
921 return 0;
922 }
923
924
mod_destroy(void)925 static void mod_destroy(void)
926 {
927 if (probability)
928 shm_free(probability);
929 if (gflags)
930 shm_free(gflags);
931 if (gflags_lock) {
932 lock_destroy(gflags_lock);
933 lock_dealloc(gflags_lock);
934 }
935 if(_cfg_lock_set!=NULL)
936 {
937 lock_set_destroy(_cfg_lock_set);
938 lock_set_dealloc(_cfg_lock_set);
939 _cfg_lock_set = NULL;
940 }
941 }
942
943 /**
944 *
945 */
cfgutils_lock(str * lkey)946 int cfgutils_lock(str *lkey)
947 {
948 return cfg_lock_helper(lkey, 0);
949 }
950
951 /**
952 *
953 */
cfgutils_unlock(str * lkey)954 int cfgutils_unlock(str *lkey)
955 {
956 return cfg_lock_helper(lkey, 1);
957 }
958
fixup_core_hash(void ** param,int param_no)959 static int fixup_core_hash(void **param, int param_no)
960 {
961 if (param_no == 1)
962 return fixup_spve_null(param, 1);
963 else if (param_no == 2)
964 return fixup_spve_null(param, 1);
965 else if (param_no == 3)
966 return fixup_igp_null(param, 1);
967 else
968 return 0;
969 }
970
w_core_hash(struct sip_msg * msg,char * p1,char * p2,char * p3)971 static int w_core_hash(struct sip_msg *msg, char *p1, char *p2, char *p3)
972 {
973 str s1, s2;
974 int size;
975
976 if (fixup_get_svalue(msg, (gparam_p) p1, &s1) != 0)
977 {
978 LM_ERR("invalid s1 paramerer\n");
979 return -1;
980 }
981 if (fixup_get_svalue(msg, (gparam_p) p2, &s2) != 0)
982 {
983 LM_ERR("invalid s2 paramerer\n");
984 return -1;
985 }
986 if (fixup_get_ivalue(msg, (gparam_p) p3, &size) != 0)
987 {
988 LM_ERR("invalid size paramerer\n");
989 return -1;
990 }
991
992 if (size <= 0) size = 2;
993 else size = 1 << size;
994
995 /* Return value _MUST_ be > 0 */
996 return core_hash(&s1, s2.len ? &s2 : NULL, size) + 1;
997 }
998
ki_core_hash(sip_msg_t * msg,str * s1,str * s2,int sz)999 static int ki_core_hash(sip_msg_t *msg, str *s1, str *s2, int sz)
1000 {
1001 int size;
1002
1003 size = sz;
1004
1005 if (size <= 0) size = 2;
1006 else size = 1 << size;
1007
1008 return core_hash(s1, (s2 && s2->len>0)?s2:NULL, size) + 1;
1009 }
1010
1011 /**
1012 * @brief bind functions to CFGUTILS API structure
1013 */
bind_cfgutils(cfgutils_api_t * api)1014 int bind_cfgutils(cfgutils_api_t *api)
1015 {
1016 if (!api) {
1017 ERR("Invalid parameter value\n");
1018 return -1;
1019 }
1020 api->mlock = cfgutils_lock;
1021 api->munlock = cfgutils_unlock;
1022
1023 return 0;
1024 }
1025
1026
1027 /**
1028 * KEMI exports
1029 */
1030 /* clang-format off */
1031 static sr_kemi_t sr_kemi_cfgutils_exports[] = {
1032 { str_init("cfgutils"), str_init("lock"),
1033 SR_KEMIP_INT, cfg_lock,
1034 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1035 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1036 },
1037 { str_init("cfgutils"), str_init("unlock"),
1038 SR_KEMIP_INT, cfg_unlock,
1039 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1040 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1041 },
1042 { str_init("cfgutils"), str_init("trylock"),
1043 SR_KEMIP_INT, cfg_trylock,
1044 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1045 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1046 },
1047 { str_init("cfgutils"), str_init("rand_set_prob"),
1048 SR_KEMIP_INT, ki_rand_set_prob,
1049 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1050 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1051 },
1052 { str_init("cfgutils"), str_init("rand_reset_prob"),
1053 SR_KEMIP_INT, ki_rand_reset_prob,
1054 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1055 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1056 },
1057 { str_init("cfgutils"), str_init("rand_get_prob"),
1058 SR_KEMIP_INT, ki_rand_get_prob,
1059 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1060 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1061 },
1062 { str_init("cfgutils"), str_init("rand_event"),
1063 SR_KEMIP_INT, ki_rand_event,
1064 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1065 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1066 },
1067 { str_init("cfgutils"), str_init("abort"),
1068 SR_KEMIP_INT, ki_abort,
1069 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1070 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1071 },
1072 { str_init("cfgutils"), str_init("pkg_status"),
1073 SR_KEMIP_INT, ki_pkg_status,
1074 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1075 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1076 },
1077 { str_init("cfgutils"), str_init("shm_status"),
1078 SR_KEMIP_INT, ki_shm_status,
1079 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1080 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1081 },
1082 { str_init("cfgutils"), str_init("pkg_summary"),
1083 SR_KEMIP_INT, ki_pkg_summary,
1084 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1085 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1086 },
1087 { str_init("cfgutils"), str_init("shm_summary"),
1088 SR_KEMIP_INT, ki_shm_summary,
1089 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1090 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1091 },
1092 { str_init("cfgutils"), str_init("core_hash"),
1093 SR_KEMIP_INT, ki_core_hash,
1094 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
1095 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1096 },
1097 { str_init("cfgutils"), str_init("sleep"),
1098 SR_KEMIP_INT, ki_sleep,
1099 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1100 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1101 },
1102 { str_init("cfgutils"), str_init("usleep"),
1103 SR_KEMIP_INT, ki_usleep,
1104 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1105 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1106 },
1107 { str_init("cfgutils"), str_init("check_route_exists"),
1108 SR_KEMIP_INT, ki_check_route_exists,
1109 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1110 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1111 },
1112 { str_init("cfgutils"), str_init("route_if_exists"),
1113 SR_KEMIP_INT, ki_route_if_exists,
1114 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1115 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1116 },
1117
1118 { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1119 };
1120 /* clang-format on */
1121
1122 /**
1123 *
1124 */
mod_register(char * path,int * dlflags,void * p1,void * p2)1125 int mod_register(char *path, int *dlflags, void *p1, void *p2)
1126 {
1127 sr_kemi_modules_add(sr_kemi_cfgutils_exports);
1128 return 0;
1129 }
1130