1 /*
2  * Accounting module
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  * Copyright (C) 2006 Voice Sistem SRL
6  *
7  * This file is part of Kamailio, a free SIP server.
8  *
9  * Kamailio is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * Kamailio is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 /*! \file
26  * \ingroup acc
27  * \brief Acc:: Core module interface
28  *
29  * - Module: \ref acc
30  */
31 
32 /*! \defgroup acc ACC :: The Kamailio accounting Module
33  *
34  * The ACC module is used to account transactions information to
35  *  different backends like syslog, SQL, RADIUS and DIAMETER (beta
36  *  version).
37  *
38  */
39 
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include "../../core/sr_module.h"
44 #include "../../core/dprint.h"
45 #include "../../core/mem/mem.h"
46 #include "../../modules/tm/tm_load.h"
47 #include "../../core/str.h"
48 #include "../../core/mod_fix.h"
49 #include "../../core/kemi.h"
50 #include "../rr/api.h"
51 #include "acc.h"
52 #include "acc_api.h"
53 #include "acc_mod.h"
54 #include "acc_extra.h"
55 #include "acc_logic.h"
56 #include "acc_cdr.h"
57 
58 MODULE_VERSION
59 
60 struct tm_binds tmb;
61 struct rr_binds rrb;
62 
63 static int mod_init(void);
64 static void destroy(void);
65 static int child_init(int rank);
66 
67 
68 /* ----- General purpose variables ----------- */
69 
70 /* what would you like to report on */
71 
72 int early_media = 0;		/*!< should early media replies (183) be logged ? default==no */
73 int report_cancels = 0;		/*!< would you like us to report CANCELs from upstream too? */
74 int report_ack = 0;		/*!< report e2e ACKs too */
75 int detect_direction = 0;	/*!< detect and correct direction in the sequential requests */
76 int failed_transaction_flag = -1; /*!< should failed replies (>=3xx) be logged ? default==no */
77 static char *failed_filter_str = 0;  /* by default, do not filter logging of
78 										failed transactions */
79 unsigned short failed_filter[MAX_FAILED_FILTER_COUNT + 1];
80 static char* leg_info_str = 0;	/*!< multi call-leg support */
81 struct acc_extra *leg_info = 0;
82 int acc_prepare_always = 0; /* prepare the request always for later acc */
83 int acc_prepare_flag = -1; /*!< should the request be prepared for later acc */
84 char *acc_time_format = "%Y-%m-%d %H:%M:%S";
85 int reason_from_hf = 0; /*!< assign reason from reason hf if present */
86 
87 /* ----- time mode variables ------- */
88 /*! \name AccTimeModeVariables  Time Mode Variables */
89 /*@{*/
90 
91 int acc_time_mode  = 0;
92 str acc_time_attr  = str_init("time_attr");
93 str acc_time_exten  = str_init("time_exten");
94 int _acc_clone_msg  = 1;
95 int _acc_cdr_on_failed = 1;
96 
97 /*@}*/
98 
99 /* ----- SYSLOG acc variables ----------- */
100 /*! \name AccSyslogVariables  Syslog Variables */
101 /*@{*/
102 
103 int log_flag = -1;
104 int log_missed_flag = -1;
105 int log_level = L_NOTICE;	/*!< Syslog: noisiness level logging facilities are used */
106 int log_facility = LOG_DAEMON;	/*!< Syslog: log facility that is used */
107 static char * log_facility_str = 0; /*!< Syslog: log facility that is used */
108 static char *log_extra_str = 0; /*!< Syslog: log extra variables */
109 struct acc_extra *log_extra = 0; /*!< Log extra attributes */
110 
111 /*@}*/
112 
113 /* ----- CDR generation variables ------- */
114 /*! \name AccCdrVariables  CDR Variables */
115 /*@{*/
116 
117 int cdr_enable  = 0;
118 int cdr_extra_nullable  = 0;
119 int cdr_log_enable  = 1;
120 int cdr_start_on_confirmed = 0;
121 int cdr_expired_dlg_enable = 0;
122 static char* cdr_facility_str = 0;
123 static char* cdr_log_extra_str = 0;
124 str cdr_skip = {NULL, 0};
125 
126 str cdr_start_str = str_init("start_time");
127 str cdr_end_str = str_init("end_time");
128 str cdr_duration_str = str_init("duration");
129 /* name for db table to store dialog-based cdrs */
130 str acc_cdrs_table = str_init("");
131 
132 /*@}*/
133 
134 /* ----- SQL acc variables ----------- */
135 /*! \name AccSQLVariables  Radius Variables */
136 /*@{*/
137 
138 int db_flag = -1;
139 int db_missed_flag = -1;
140 static char *db_extra_str = 0;		/*!< db extra variables */
141 struct acc_extra *db_extra = 0;
142 static str db_url = {NULL, 0};		/*!< Database url */
143 str db_table_acc = str_init("acc");	/*!< name of database tables */
144 void *db_table_acc_data = NULL;
145 str db_table_mc = str_init("missed_calls");
146 void *db_table_mc_data = NULL;
147 /* names of columns in tables acc/missed calls*/
148 str acc_method_col     = str_init("method");
149 str acc_fromtag_col    = str_init("from_tag");
150 str acc_totag_col      = str_init("to_tag");
151 str acc_callid_col     = str_init("callid");
152 str acc_sipcode_col    = str_init("sip_code");
153 str acc_sipreason_col  = str_init("sip_reason");
154 str acc_time_col       = str_init("time");
155 int acc_db_insert_mode = 0;
156 
157 /*@}*/
158 
159 static int bind_acc(acc_api_t* api);
160 static int acc_register_engine(acc_engine_t *eng);
161 static int acc_init_engines(void);
162 static acc_engine_t *_acc_engines=NULL;
163 static int _acc_module_initialized = 0;
164 
165 static int cdr_register_engine(cdr_engine_t *eng);
166 static int cdr_init_engines(void);
167 static cdr_engine_t *_cdr_engines=NULL;
168 static int cdr_module_initialized = 0;
169 
170 /* ------------- fixup function --------------- */
171 static int acc_fixup(void** param, int param_no);
172 static int free_acc_fixup(void** param, int param_no);
173 
174 /* clang-format off */
175 static cmd_export_t cmds[] = {
176 	{"acc_log_request", (cmd_function)w_acc_log_request, 1,
177 		acc_fixup, free_acc_fixup,
178 		ANY_ROUTE},
179 	{"acc_db_request",  (cmd_function)w_acc_db_request,  2,
180 		acc_fixup, free_acc_fixup,
181 		ANY_ROUTE},
182 	{"acc_request",  (cmd_function)w_acc_request,  2,
183 		fixup_spve_spve, fixup_free_spve_spve,
184 		ANY_ROUTE},
185 	{"bind_acc",    (cmd_function)bind_acc, 0, 0, 0},
186 	{0, 0, 0, 0, 0, 0}
187 };
188 
189 
190 
191 static param_export_t params[] = {
192 	{"early_media",             INT_PARAM, &early_media             },
193 	{"failed_transaction_flag", INT_PARAM, &failed_transaction_flag },
194 	{"failed_filter",           PARAM_STRING, &failed_filter_str       },
195 	{"report_ack",              INT_PARAM, &report_ack              },
196 	{"report_cancels",          INT_PARAM, &report_cancels          },
197 	{"multi_leg_info",          PARAM_STRING, &leg_info_str            },
198 	{"detect_direction",        INT_PARAM, &detect_direction        },
199 	{"acc_prepare_flag",        INT_PARAM, &acc_prepare_flag        },
200 	{"acc_prepare_always",      INT_PARAM, &acc_prepare_always      },
201 	{"reason_from_hf",          INT_PARAM, &reason_from_hf          },
202 	/* syslog specific */
203 	{"log_flag",             INT_PARAM, &log_flag             },
204 	{"log_missed_flag",      INT_PARAM, &log_missed_flag      },
205 	{"log_level",            INT_PARAM, &log_level            },
206 	{"log_facility",         PARAM_STRING, &log_facility_str     },
207 	{"log_extra",            PARAM_STRING, &log_extra_str        },
208 	/* cdr specific */
209 	{"cdr_enable",           INT_PARAM, &cdr_enable                 },
210 	{"cdr_skip",             PARAM_STR, &cdr_skip                   },
211 	{"cdr_log_enable",         INT_PARAM, &cdr_log_enable           },
212 	{"cdr_start_on_confirmed", INT_PARAM, &cdr_start_on_confirmed   },
213 	{"cdr_facility",         PARAM_STRING, &cdr_facility_str           },
214 	{"cdr_extra",            PARAM_STRING, &cdr_log_extra_str          },
215 	{"cdr_extra_nullable",   INT_PARAM, &cdr_extra_nullable            },
216 	{"cdr_start_id",	 PARAM_STR, &cdr_start_str		},
217 	{"cdr_end_id",		 PARAM_STR, &cdr_end_str		},
218 	{"cdr_duration_id",	 PARAM_STR, &cdr_duration_str	},
219 	{"cdr_expired_dlg_enable", INT_PARAM, &cdr_expired_dlg_enable   },
220 	/* db-specific */
221 	{"db_flag",              INT_PARAM, &db_flag            },
222 	{"db_missed_flag",       INT_PARAM, &db_missed_flag     },
223 	{"db_extra",             PARAM_STRING, &db_extra_str    },
224 	{"db_url",               PARAM_STR, &db_url             },
225 	{"db_table_acc",         PARAM_STR, &db_table_acc       },
226 	{"db_table_missed_calls",PARAM_STR, &db_table_mc        },
227 	{"acc_method_column",    PARAM_STR, &acc_method_col     },
228 	{"acc_from_tag_column",  PARAM_STR, &acc_fromtag_col    },
229 	{"acc_to_tag_column",    PARAM_STR, &acc_totag_col      },
230 	{"acc_callid_column",    PARAM_STR, &acc_callid_col     },
231 	{"acc_sip_code_column",  PARAM_STR, &acc_sipcode_col    },
232 	{"acc_sip_reason_column",PARAM_STR, &acc_sipreason_col  },
233 	{"acc_time_column",      PARAM_STR, &acc_time_col       },
234 	{"db_insert_mode",       INT_PARAM, &acc_db_insert_mode },
235 	/* time-mode-specific */
236 	{"time_mode",            INT_PARAM, &acc_time_mode        },
237 	{"time_attr",            PARAM_STR, &acc_time_attr        },
238 	{"time_exten",           PARAM_STR, &acc_time_exten       },
239 	{"cdrs_table",           PARAM_STR, &acc_cdrs_table       },
240 	{"time_format",          PARAM_STRING, &acc_time_format   },
241 	{"clone_msg",            PARAM_INT, &_acc_clone_msg       },
242 	{"cdr_on_failed",        PARAM_INT, &_acc_cdr_on_failed   },
243 	{0,0,0}
244 };
245 
246 
247 struct module_exports exports= {
248 	"acc",
249 	DEFAULT_DLFLAGS, /* dlopen flags */
250 	cmds,            /* exported functions */
251 	params,     	 /* exported params */
252 	0,          	 /* RPC method exports */
253 	0,          	 /* exported pseudo-variables */
254 	0,          	 /* response function */
255 	mod_init,   	 /* initialization module */
256 	child_init,  	 /* per-child init function */
257 	destroy    	 /* destroy function */
258 };
259 /* clang-format on */
260 
261 
262 /************************** FIXUP functions ****************************/
263 
acc_fixup(void ** param,int param_no)264 static int acc_fixup(void** param, int param_no)
265 {
266 	struct acc_param *accp;
267 	char *p;
268 
269 	p = (char*)*param;
270 	if (p==0 || p[0]==0) {
271 		LM_ERR("first parameter is empty\n");
272 		return E_SCRIPT;
273 	}
274 
275 	if (param_no == 1) {
276 		accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
277 		if (!accp) {
278 			PKG_MEM_ERROR;
279 			return E_OUT_OF_MEM;
280 		}
281 		memset( accp, 0, sizeof(struct acc_param));
282 		accp->reason.s = p;
283 		accp->reason.len = strlen(p);
284 		if (strchr(p,PV_MARKER)!=NULL) { /* is a variable $xxxxx */
285 			if (pv_parse_format(&accp->reason, &accp->elem)<0)
286 			{
287 				LM_ERR("bad param 1 - parse format error [%.*s]\n",
288 						accp->reason.len, accp->reason.s);
289 				pkg_free(accp);
290 				return E_UNSPEC;
291 			}
292 		}
293 		else {
294 			if(acc_parse_code(p,accp)<0)
295 			{
296 				LM_ERR("bad param 1 - parse code error\n");
297 				pkg_free(accp);
298 				return E_UNSPEC;
299 			}
300 		}
301 		*param = (void*)accp;
302 	} else if (param_no == 2) {
303 		/* only for db acc - the table name */
304 		if (db_url.s==0) {
305 			pkg_free(p);
306 			*param = 0;
307 		} else {
308 			return fixup_var_pve_str_12(param, 2);
309 		}
310 	}
311 	return 0;
312 }
313 
free_acc_fixup(void ** param,int param_no)314 static int free_acc_fixup(void** param, int param_no)
315 {
316 	if(*param)
317 	{
318 		pkg_free(*param);
319 		*param = 0;
320 	}
321 	return 0;
322 }
323 
324 
325 
326 /************************** INTERFACE functions ****************************/
327 
328 
parse_failed_filter(char * s,unsigned short * failed_filter)329 static int parse_failed_filter(char *s, unsigned short *failed_filter)
330 {
331 	unsigned int n;
332 	char *at;
333 
334 	n = 0;
335 
336 	while (1) {
337 		if (n >= MAX_FAILED_FILTER_COUNT) {
338 			LM_ERR("too many elements in failed_filter\n");
339 			return 0;
340 		}
341 		at = s;
342 		while ((*at >= '0') && (*at <= '9')) at++;
343 		if (at - s != 3) {
344 			LM_ERR("respose code in failed_filter must have 3 digits\n");
345 			return 0;
346 		}
347 		failed_filter[n] = (*s - '0') * 100 + (*(s + 1) - '0') * 10 +
348 			(*(s + 2) - '0');
349 		if (failed_filter[n] < 300) {
350 			LM_ERR("invalid respose code %u in failed_filter\n",
351 					failed_filter[n]);
352 			return 0;
353 		}
354 		LM_DBG("failed_filter %u = %u\n", n, failed_filter[n]);
355 		n++;
356 		failed_filter[n] = 0;
357 		s = at;
358 		if (*s == 0)
359 			return 1;
360 		if (*s != ',') {
361 			LM_ERR("response code is not followed by comma or end of string\n");
362 			return 0;
363 		}
364 		s++;
365 	}
366 }
367 
mod_init(void)368 static int mod_init( void )
369 {
370 	if (db_url.s) {
371 		if(db_url.len<=0) {
372 			db_url.s = NULL;
373 			db_url.len = 0;
374 		}
375 	}
376 	if(db_table_acc.len!=3 || strncmp(db_table_acc.s, "acc", 3)!=0)
377 	{
378 		db_table_acc_data = db_table_acc.s;
379 		if(fixup_var_pve_str_12(&db_table_acc_data, 1)<0)
380 		{
381 			LM_ERR("unable to parse acc table name [%.*s]\n",
382 					db_table_acc.len, db_table_acc.s);
383 			return -1;
384 		} else {
385 			LM_DBG("acc db table initialized to: %s\n", db_table_acc.s);
386 		}
387 	}
388 	if(db_table_mc.len!=12 || strncmp(db_table_mc.s, "missed_calls", 12)!=0)
389 	{
390 		db_table_mc_data = db_table_mc.s;
391 		if(fixup_var_pve_str_12(&db_table_mc_data, 1)<0)
392 		{
393 			LM_ERR("unable to parse mc table name [%.*s]\n",
394 					db_table_mc.len, db_table_mc.s);
395 			return -1;
396 		} else {
397 			LM_DBG("missed calls db table initialized to: %s\n", db_table_mc.s);
398 		}
399 	}
400 
401 	if (log_facility_str) {
402 		int tmp = str2facility(log_facility_str);
403 		if (tmp != -1)
404 			log_facility = tmp;
405 		else {
406 			LM_ERR("invalid log facility configured");
407 			return -1;
408 		}
409 	}
410 
411 	/* ----------- GENERIC INIT SECTION  ----------- */
412 
413 	/* failed transaction handling */
414 	if ((failed_transaction_flag != -1) &&
415 			!flag_in_range(failed_transaction_flag)) {
416 		LM_ERR("failed_transaction_flag set to invalid value\n");
417 		return -1;
418 	}
419 	if (failed_filter_str) {
420 		if (parse_failed_filter(failed_filter_str, failed_filter) == 0) {
421 			LM_ERR("failed to parse failed_filter param\n");
422 			return -1;
423 		}
424 	} else {
425 		failed_filter[0] = 0;
426 	}
427 
428 	/* load the TM API */
429 	if (load_tm_api(&tmb)!=0) {
430 		LM_ERR("can't load TM API\n");
431 		return -1;
432 	}
433 
434 	/* if detect_direction is enabled, load rr also */
435 	if (detect_direction) {
436 		if (load_rr_api(&rrb)!=0) {
437 			LM_ERR("can't load RR API\n");
438 			return -1;
439 		}
440 		/* we need the append_fromtag on in RR */
441 		if (!rrb.append_fromtag) {
442 			LM_ERR("'append_fromtag' RR param is not enabled!"
443 					" - required by 'detect_direction'\n");
444 			return -1;
445 		}
446 	}
447 
448 	/* listen for all incoming requests  */
449 	if ( tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, acc_onreq, 0, 0 ) <=0 ) {
450 		LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
451 		return -1;
452 	}
453 
454 	/* configure multi-leg accounting */
455 	if (leg_info_str && (leg_info=parse_acc_leg(leg_info_str))==0 ) {
456 		LM_ERR("failed to parse multileg_info param\n");
457 		return -1;
458 	}
459 
460 	/* ----------- SYSLOG INIT SECTION ----------- */
461 
462 	/* parse the extra string, if any */
463 	if (log_extra_str && (log_extra=parse_acc_extra(log_extra_str))==0 ) {
464 		LM_ERR("failed to parse log_extra param\n");
465 		return -1;
466 	}
467 
468 	if ((log_flag != -1) && !flag_in_range(log_flag)) {
469 		LM_ERR("log_flag set to invalid value\n");
470 		return -1;
471 	}
472 
473 	if ((log_missed_flag != -1) && !flag_in_range(log_missed_flag)) {
474 		LM_ERR("log_missed_flag set to invalid value\n");
475 		return -1;
476 	}
477 
478 	acc_log_init();
479 
480 	/* ----------- INIT CDR GENERATION ----------- */
481 
482 	if( cdr_enable < 0 || cdr_enable > 1)
483 	{
484 		LM_ERR("cdr_enable is out of range\n");
485 		return -1;
486 	}
487 
488 	if( cdr_extra_nullable < 0 || cdr_extra_nullable > 1)
489 	{
490 		LM_ERR("cdr_extra_nullable is out of range\n");
491 		return -1;
492 	}
493 
494 	if( cdr_expired_dlg_enable < 0 || cdr_expired_dlg_enable > 1)
495 	{
496 		LM_ERR("cdr_expired_dlg_enable is out of range\n");
497 		return -1;
498 	}
499 
500 	if( cdr_enable)
501 	{
502 		if( !cdr_start_str.s || !cdr_end_str.s || !cdr_duration_str.s)
503 		{
504 			LM_ERR( "necessary cdr_parameters are not set\n");
505 			return -1;
506 		}
507 
508 		if( !cdr_start_str.len || !cdr_end_str.len || !cdr_duration_str.len)
509 		{
510 			LM_ERR( "necessary cdr_parameters are empty\n");
511 			return -1;
512 		}
513 
514 
515 		if( set_cdr_extra( cdr_log_extra_str) != 0)
516 		{
517 			LM_ERR( "failed to set cdr extra '%s'\n", cdr_log_extra_str);
518 			return -1;
519 		}
520 
521 		if( cdr_facility_str && set_cdr_facility( cdr_facility_str) != 0)
522 		{
523 			LM_ERR( "failed to set cdr facility '%s'\n", cdr_facility_str);
524 			return -1;
525 		}
526 
527 		if( init_cdr_generation() != 0)
528 		{
529 			LM_ERR("failed to init cdr generation\n");
530 			return -1;
531 		}
532 	}
533 
534 	/* ------------ SQL INIT SECTION ----------- */
535 
536 	if (db_url.s && db_url.len > 0) {
537 		/* parse the extra string, if any */
538 		if (db_extra_str && (db_extra=parse_acc_extra(db_extra_str))==0 ) {
539 			LM_ERR("failed to parse db_extra param\n");
540 			return -1;
541 		}
542 		if (acc_db_init(&db_url)<0){
543 			LM_ERR("failed...did you load a database module?\n");
544 			return -1;
545 		}
546 		/* fix the flags */
547 
548 		if ((db_flag != -1) && !flag_in_range(db_flag)) {
549 			LM_ERR("db_flag set to invalid value\n");
550 			return -1;
551 		}
552 
553 		if ((db_missed_flag != -1) && !flag_in_range(db_missed_flag)) {
554 			LM_ERR("db_missed_flag set to invalid value\n");
555 			return -1;
556 		}
557 	} else {
558 		db_url.s = NULL;
559 		db_url.len = 0;
560 		db_flag = -1;
561 		db_missed_flag = -1;
562 	}
563 
564 	_acc_module_initialized = 1;
565 	if(acc_init_engines()<0) {
566 		LM_ERR("failed to init extra engines\n");
567 		return -1;
568 	}
569 
570 	cdr_module_initialized = 1;
571 	if(cdr_init_engines()<0) {
572 		LM_ERR("failed to init extra engines\n");
573 		return -1;
574 	}
575 
576 	return 0;
577 }
578 
579 
child_init(int rank)580 static int child_init(int rank)
581 {
582 	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
583 		return 0; /* do nothing for the main process */
584 
585 	if(db_url.s && acc_db_init_child(&db_url)<0) {
586 		LM_ERR("could not open database connection");
587 		return -1;
588 	}
589 
590 	return 0;
591 }
592 
593 
destroy(void)594 static void destroy(void)
595 {
596 	if (log_extra)
597 		destroy_extras( log_extra);
598 	acc_db_close();
599 	if (db_extra)
600 		destroy_extras( db_extra);
601 }
602 
603 
604 /**
605  * @brief return leg_info structure
606  */
get_leg_info(void)607 acc_extra_t* get_leg_info(void)
608 {
609 	return leg_info;
610 }
611 
612 /**
613  * @brief bind functions to ACC API structure
614  */
bind_acc(acc_api_t * api)615 static int bind_acc(acc_api_t* api)
616 {
617 	if (!api) {
618 		ERR("Invalid parameter value\n");
619 		return -1;
620 	}
621 
622 	api->register_engine = acc_register_engine;
623 	api->get_leg_info    = get_leg_info;
624 	api->get_core_attrs  = core2strar;
625 	api->get_extra_attrs = extra2strar;
626 	api->get_leg_attrs   = legs2strar;
627 	api->parse_extra     = parse_acc_extra;
628 	api->exec            = acc_api_exec;
629 
630 	if (cdr_enable) {
631 		api->register_cdr_engine = cdr_register_engine;
632 		api->get_core_cdr_attrs  = cdr_core2strar;
633 		api->get_extra_dlg_attrs = extra2strar_dlg_only;
634 		api->exec_cdr            = cdr_api_exec;
635 	}
636 	else {
637 		api->register_cdr_engine = NULL;
638 		api->get_core_cdr_attrs  = NULL;
639 		api->get_extra_dlg_attrs = NULL;
640 		api->exec_cdr            = NULL;
641 	}
642 	return 0;
643 }
644 
645 /**
646  * @brief init an acc engine
647  */
acc_init_engine(acc_engine_t * e)648 static int acc_init_engine(acc_engine_t *e)
649 {
650 	acc_init_info_t ai;
651 
652 	if(_acc_module_initialized==0)
653 		return 0;
654 
655 	if(e->flags & 1)
656 		return 0;
657 
658 	memset(&ai, 0, sizeof(acc_init_info_t));
659 	ai.leg_info = leg_info;
660 	if(e->acc_init(&ai)<0)
661 	{
662 		LM_ERR("failed to initialize extra acc engine\n");
663 		return -1;
664 	}
665 	e->flags |= 1;
666 	return 0;
667 }
668 
669 /**
670  * @brief init registered acc engines
671  */
acc_init_engines(void)672 static int acc_init_engines(void)
673 {
674 	acc_engine_t *e;
675 	e = _acc_engines;
676 	while(e) {
677 		if(acc_init_engine(e)<0)
678 			return -1;
679 		e = e->next;
680 	}
681 	return 0;
682 }
683 
684 /**
685  * @brief register an accounting engine
686  * @return 0 on success, <0 on failure
687  */
acc_register_engine(acc_engine_t * eng)688 static int acc_register_engine(acc_engine_t *eng)
689 {
690 	acc_engine_t *e;
691 
692 	if(eng==NULL)
693 		return -1;
694 	e = (acc_engine_t*)pkg_malloc(sizeof(acc_engine_t));
695 	if(e ==NULL)
696 	{
697 		PKG_MEM_ERROR;
698 		return -1;
699 	}
700 	memcpy(e, eng, sizeof(acc_engine_t));
701 
702 	if(acc_init_engine(e)<0)
703 	{
704 		pkg_free(e);
705 		return -1;
706 	}
707 
708 	e->next = _acc_engines;
709 	_acc_engines = e;
710 	LM_DBG("new acc engine registered: %s\n", e->name);
711 	return 0;
712 }
713 
714 /**
715  * @brief init an acc engine
716  */
cdr_init_engine(cdr_engine_t * e)717 static int cdr_init_engine(cdr_engine_t *e)
718 {
719 	if(cdr_module_initialized==0)
720 		return 0;
721 
722 	if(e->cdr_init()<0)
723 	{
724 		LM_ERR("failed to initialize extra cdr engine\n");
725 		return -1;
726 	}
727 	return 0;
728 }
729 
730 /**
731  * @brief init registered acc engines
732  */
cdr_init_engines(void)733 static int cdr_init_engines(void)
734 {
735 	cdr_engine_t *e;
736 	e = _cdr_engines;
737 	while(e) {
738 		if(cdr_init_engine(e)<0)
739 			return -1;
740 		e = e->next;
741 	}
742 	return 0;
743 }
744 
745 /**
746  * @brief register an accounting engine
747  * @return 0 on success, <0 on failure
748  */
cdr_register_engine(cdr_engine_t * eng)749 static int cdr_register_engine(cdr_engine_t *eng)
750 {
751 	cdr_engine_t *e;
752 
753 	if(eng==NULL)
754 		return -1;
755 	e = (cdr_engine_t*)pkg_malloc(sizeof(cdr_engine_t));
756 	if(e ==NULL)
757 	{
758 		PKG_MEM_ERROR;
759 		return -1;
760 	}
761 	memcpy(e, eng, sizeof(cdr_engine_t));
762 
763 	if(cdr_init_engine(e)<0)
764 	{
765 		pkg_free(e);
766 		return -1;
767 	}
768 
769 	e->next = _cdr_engines;
770 	_cdr_engines = e;
771 	LM_DBG("new acc engine registered: %s\n", e->name);
772 	return 0;
773 }
774 
775 /**
776  *
777  */
acc_api_get_engines(void)778 acc_engine_t *acc_api_get_engines(void)
779 {
780 	return _acc_engines;
781 }
782 
783 /**
784  *
785  */
cdr_api_get_engines(void)786 cdr_engine_t *cdr_api_get_engines(void)
787 {
788 	return _cdr_engines;
789 }
790 
791 /**
792  *
793  */
794 /* clang-format off */
795 static sr_kemi_t sr_kemi_acc_exports[] = {
796 	{ str_init("acc"), str_init("acc_log_request"),
797 		SR_KEMIP_INT, ki_acc_log_request,
798 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
799 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
800 	},
801 	{ str_init("acc"), str_init("acc_db_request"),
802 		SR_KEMIP_INT, ki_acc_db_request,
803 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
804 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
805 	},
806 	{ str_init("acc"), str_init("acc_request"),
807 		SR_KEMIP_INT, ki_acc_request,
808 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
809 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
810 	},
811 
812 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
813 };
814 /* clang-format on */
815 
816 /**
817  *
818  */
mod_register(char * path,int * dlflags,void * p1,void * p2)819 int mod_register(char *path, int *dlflags, void *p1, void *p2)
820 {
821 	sr_kemi_modules_add(sr_kemi_acc_exports);
822 	return 0;
823 }
824