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