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(&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  */
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(&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 
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