00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00062 #include <stdio.h>
00063 #include <string.h>
00064
00065 #include "../../sr_module.h"
00066 #include "../../dprint.h"
00067 #include "../../mem/mem.h"
00068 #include "../../modules/tm/tm_load.h"
00069 #include "../../str.h"
00070 #include "../rr/api.h"
00071 #include "acc.h"
00072 #include "acc_api.h"
00073 #include "acc_mod.h"
00074 #include "acc_extra.h"
00075 #include "acc_logic.h"
00076 #include "acc_cdr.h"
00077
00078 #ifdef RAD_ACC
00079 #include "../../lib/kcore/radius.h"
00080 #endif
00081
00082 #ifdef DIAM_ACC
00083 #include "diam_dict.h"
00084 #include "diam_tcp.h"
00085 #endif
00086
00087 MODULE_VERSION
00088
00089 struct tm_binds tmb;
00090 struct rr_binds rrb;
00091
00092 static int mod_init(void);
00093 static void destroy(void);
00094 static int child_init(int rank);
00095
00096
00097
00098
00099
00100
00101 int early_media = 0;
00102 int report_cancels = 0;
00103 int report_ack = 0;
00104 int detect_direction = 0;
00105 int failed_transaction_flag = -1;
00106 static char *failed_filter_str = 0;
00107
00108 unsigned short failed_filter[MAX_FAILED_FILTER_COUNT + 1];
00109 static char* leg_info_str = 0;
00110 struct acc_extra *leg_info = 0;
00111 int acc_prepare_flag = -1;
00114
00117
00118 int log_flag = -1;
00119 int log_missed_flag = -1;
00120 int log_level = L_NOTICE;
00121 int log_facility = LOG_DAEMON;
00122 static char * log_facility_str = 0;
00123 static char *log_extra_str = 0;
00124 struct acc_extra *log_extra = 0;
00127
00128
00131
00132 int cdr_enable = 0;
00133 int cdr_start_on_confirmed = 0;
00134 static char* cdr_facility_str = 0;
00135 static char* cdr_log_extra_str = 0;
00136
00137 str cdr_start_str = str_init("st");
00138 str cdr_end_str = str_init("et");
00139 str cdr_duration_str = str_init("d");
00140
00143
00146
00147 #ifdef RAD_ACC
00148 static char *radius_config = 0;
00149 int radius_flag = -1;
00150 int radius_missed_flag = -1;
00151 static int service_type = -1;
00152 void *rh;
00153
00154 static char *rad_extra_str = 0;
00155 struct acc_extra *rad_extra = 0;
00156 #endif
00157
00160
00161
00164 #ifdef DIAM_ACC
00165 int diameter_flag = -1;
00166 int diameter_missed_flag = -1;
00167 static char *dia_extra_str = 0;
00168 struct acc_extra *dia_extra = 0;
00169 rd_buf_t *rb;
00170 char* diameter_client_host="localhost";
00171 int diameter_client_port=3000;
00172 #endif
00173
00176
00179
00180 #ifdef SQL_ACC
00181 int db_flag = -1;
00182 int db_missed_flag = -1;
00183 static char *db_extra_str = 0;
00184 struct acc_extra *db_extra = 0;
00185 static str db_url = {NULL, 0};
00186 str db_table_acc = str_init("acc");
00187 str db_table_mc = str_init("missed_calls");
00188
00189 str acc_method_col = str_init("method");
00190 str acc_fromtag_col = str_init("from_tag");
00191 str acc_totag_col = str_init("to_tag");
00192 str acc_callid_col = str_init("callid");
00193 str acc_sipcode_col = str_init("sip_code");
00194 str acc_sipreason_col = str_init("sip_reason");
00195 str acc_time_col = str_init("time");
00196 int acc_db_insert_mode = 0;
00197 #endif
00198
00201 static int bind_acc(acc_api_t* api);
00202 static int acc_register_engine(acc_engine_t *eng);
00203 static int acc_init_engines(void);
00204 static acc_engine_t *_acc_engines=NULL;
00205 static int _acc_module_initialized = 0;
00206
00207
00208 static int acc_fixup(void** param, int param_no);
00209 static int free_acc_fixup(void** param, int param_no);
00210
00211
00212 static cmd_export_t cmds[] = {
00213 {"acc_log_request", (cmd_function)w_acc_log_request, 1,
00214 acc_fixup, free_acc_fixup,
00215 ANY_ROUTE},
00216 #ifdef SQL_ACC
00217 {"acc_db_request", (cmd_function)w_acc_db_request, 2,
00218 acc_fixup, free_acc_fixup,
00219 ANY_ROUTE},
00220 #endif
00221 #ifdef RAD_ACC
00222 {"acc_rad_request", (cmd_function)w_acc_rad_request, 1,
00223 acc_fixup, free_acc_fixup,
00224 ANY_ROUTE},
00225 #endif
00226 #ifdef DIAM_ACC
00227 {"acc_diam_request",(cmd_function)w_acc_diam_request,1,
00228 acc_fixup, free_acc_fixup,
00229 ANY_ROUTE},
00230 #endif
00231 {"bind_acc", (cmd_function)bind_acc, 0, 0, 0},
00232 {0, 0, 0, 0, 0, 0}
00233 };
00234
00235
00236
00237 static param_export_t params[] = {
00238 {"early_media", INT_PARAM, &early_media },
00239 {"failed_transaction_flag", INT_PARAM, &failed_transaction_flag },
00240 {"failed_filter", STR_PARAM, &failed_filter_str },
00241 {"report_ack", INT_PARAM, &report_ack },
00242 {"report_cancels", INT_PARAM, &report_cancels },
00243 {"multi_leg_info", STR_PARAM, &leg_info_str },
00244 {"detect_direction", INT_PARAM, &detect_direction },
00245 {"acc_prepare_flag", INT_PARAM, &acc_prepare_flag },
00246
00247 {"log_flag", INT_PARAM, &log_flag },
00248 {"log_missed_flag", INT_PARAM, &log_missed_flag },
00249 {"log_level", INT_PARAM, &log_level },
00250 {"log_facility", STR_PARAM, &log_facility_str },
00251 {"log_extra", STR_PARAM, &log_extra_str },
00252
00253 {"cdr_enable", INT_PARAM, &cdr_enable },
00254 {"cdr_start_on_confirmed", INT_PARAM, &cdr_start_on_confirmed },
00255 {"cdr_facility", STR_PARAM, &cdr_facility_str },
00256 {"cdr_extra", STR_PARAM, &cdr_log_extra_str },
00257 {"cdr_start_id", STR_PARAM, &cdr_start_str.s },
00258 {"cdr_end_id", STR_PARAM, &cdr_end_str.s },
00259 {"cdr_duration_id", STR_PARAM, &cdr_duration_str.s },
00260 #ifdef RAD_ACC
00261 {"radius_config", STR_PARAM, &radius_config },
00262 {"radius_flag", INT_PARAM, &radius_flag },
00263 {"radius_missed_flag", INT_PARAM, &radius_missed_flag },
00264 {"service_type", INT_PARAM, &service_type },
00265 {"radius_extra", STR_PARAM, &rad_extra_str },
00266 #endif
00267
00268 #ifdef DIAM_ACC
00269 {"diameter_flag", INT_PARAM, &diameter_flag },
00270 {"diameter_missed_flag", INT_PARAM, &diameter_missed_flag },
00271 {"diameter_client_host", STR_PARAM, &diameter_client_host },
00272 {"diameter_client_port", INT_PARAM, &diameter_client_port },
00273 {"diameter_extra", STR_PARAM, &dia_extra_str },
00274 #endif
00275
00276 #ifdef SQL_ACC
00277 {"db_flag", INT_PARAM, &db_flag },
00278 {"db_missed_flag", INT_PARAM, &db_missed_flag },
00279 {"db_extra", STR_PARAM, &db_extra_str },
00280 {"db_url", STR_PARAM, &db_url.s },
00281 {"db_table_acc", STR_PARAM, &db_table_acc.s },
00282 {"db_table_missed_calls",STR_PARAM, &db_table_mc.s },
00283 {"acc_method_column", STR_PARAM, &acc_method_col.s },
00284 {"acc_from_tag_column", STR_PARAM, &acc_fromtag_col.s },
00285 {"acc_to_tag_column", STR_PARAM, &acc_totag_col.s },
00286 {"acc_callid_column", STR_PARAM, &acc_callid_col.s },
00287 {"acc_sip_code_column", STR_PARAM, &acc_sipcode_col.s },
00288 {"acc_sip_reason_column",STR_PARAM, &acc_sipreason_col.s },
00289 {"acc_time_column", STR_PARAM, &acc_time_col.s },
00290 {"db_insert_mode", INT_PARAM, &acc_db_insert_mode },
00291 #endif
00292 {0,0,0}
00293 };
00294
00295
00296 struct module_exports exports= {
00297 "acc",
00298 DEFAULT_DLFLAGS,
00299 cmds,
00300 params,
00301 0,
00302 0,
00303 0,
00304 0,
00305 mod_init,
00306 0,
00307 destroy,
00308 child_init
00309 };
00310
00311
00312
00313
00314
00315
00316 static int acc_fixup(void** param, int param_no)
00317 {
00318 struct acc_param *accp;
00319 char *p;
00320
00321 p = (char*)*param;
00322 if (p==0 || p[0]==0) {
00323 LM_ERR("first parameter is empty\n");
00324 return E_SCRIPT;
00325 }
00326
00327 if (param_no == 1) {
00328 accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
00329 if (!accp) {
00330 LM_ERR("no more pkg mem\n");
00331 return E_OUT_OF_MEM;
00332 }
00333 memset( accp, 0, sizeof(struct acc_param));
00334 accp->reason.s = p;
00335 accp->reason.len = strlen(p);
00336
00337 if (accp->reason.len>=3 && isdigit((int)p[0])
00338 && isdigit((int)p[1]) && isdigit((int)p[2]) ) {
00339 accp->code = (p[0]-'0')*100 + (p[1]-'0')*10 + (p[2]-'0');
00340 accp->code_s.s = p;
00341 accp->code_s.len = 3;
00342 accp->reason.s += 3;
00343 for( ; isspace((int)accp->reason.s[0]) ; accp->reason.s++ );
00344 accp->reason.len = strlen(accp->reason.s);
00345 }
00346 *param = (void*)accp;
00347 #ifdef SQL_ACC
00348 } else if (param_no == 2) {
00349
00350 if (db_url.s==0) {
00351 pkg_free(p);
00352 *param = 0;
00353 }
00354 #endif
00355 }
00356 return 0;
00357 }
00358
00359 static int free_acc_fixup(void** param, int param_no)
00360 {
00361 if(*param)
00362 {
00363 pkg_free(*param);
00364 *param = 0;
00365 }
00366 return 0;
00367 }
00368
00369
00370
00371
00372
00373
00374 static int parse_failed_filter(char *s, unsigned short *failed_filter)
00375 {
00376 unsigned int n;
00377 char *at;
00378
00379 n = 0;
00380
00381 while (1) {
00382 if (n >= MAX_FAILED_FILTER_COUNT) {
00383 LM_ERR("too many elements in failed_filter\n");
00384 return 0;
00385 }
00386 at = s;
00387 while ((*at >= '0') && (*at <= '9')) at++;
00388 if (at - s != 3) {
00389 LM_ERR("respose code in failed_filter must have 3 digits\n");
00390 return 0;
00391 }
00392 failed_filter[n] = (*s - '0') * 100 + (*(s + 1) - '0') * 10 +
00393 (*(s + 2) - '0');
00394 if (failed_filter[n] < 300) {
00395 LM_ERR("invalid respose code %u in failed_filter\n",
00396 failed_filter[n]);
00397 return 0;
00398 }
00399 LM_DBG("failed_filter %u = %u\n", n, failed_filter[n]);
00400 n++;
00401 failed_filter[n] = 0;
00402 s = at;
00403 if (*s == 0)
00404 return 1;
00405 if (*s != ',') {
00406 LM_ERR("response code is not followed by comma or end of string\n");
00407 return 0;
00408 }
00409 s++;
00410 }
00411 }
00412
00413 static int mod_init( void )
00414 {
00415 #ifdef SQL_ACC
00416 if (db_url.s) {
00417 db_url.len = strlen(db_url.s);
00418 if(db_url.len<=0) {
00419 db_url.s = NULL;
00420 db_url.len = 0;
00421 }
00422 }
00423 db_table_acc.len = strlen(db_table_acc.s);
00424 db_table_mc.len = strlen(db_table_mc.s);
00425 acc_method_col.len = strlen(acc_method_col.s);
00426 acc_fromtag_col.len = strlen(acc_fromtag_col.s);
00427 acc_totag_col.len = strlen(acc_totag_col.s);
00428 acc_callid_col.len = strlen(acc_callid_col.s);
00429 acc_sipcode_col.len = strlen(acc_sipcode_col.s);
00430 acc_sipreason_col.len = strlen(acc_sipreason_col.s);
00431 acc_time_col.len = strlen(acc_time_col.s);
00432 #endif
00433
00434 if (log_facility_str) {
00435 int tmp = str2facility(log_facility_str);
00436 if (tmp != -1)
00437 log_facility = tmp;
00438 else {
00439 LM_ERR("invalid log facility configured");
00440 return -1;
00441 }
00442 }
00443
00444
00445
00446
00447 if ((failed_transaction_flag != -1) &&
00448 !flag_in_range(failed_transaction_flag)) {
00449 LM_ERR("failed_transaction_flag set to invalid value\n");
00450 return -1;
00451 }
00452 if (failed_filter_str) {
00453 if (parse_failed_filter(failed_filter_str, failed_filter) == 0) {
00454 LM_ERR("failed to parse failed_filter param\n");
00455 return -1;
00456 }
00457 } else {
00458 failed_filter[0] = 0;
00459 }
00460
00461
00462 if (load_tm_api(&tmb)!=0) {
00463 LM_ERR("can't load TM API\n");
00464 return -1;
00465 }
00466
00467
00468 if (detect_direction) {
00469 if (load_rr_api(&rrb)!=0) {
00470 LM_ERR("can't load RR API\n");
00471 return -1;
00472 }
00473
00474 if (!rrb.append_fromtag) {
00475 LM_ERR("'append_fromtag' RR param is not enabled!"
00476 " - required by 'detect_direction'\n");
00477 return -1;
00478 }
00479 }
00480
00481
00482 if ( tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, acc_onreq, 0, 0 ) <=0 ) {
00483 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
00484 return -1;
00485 }
00486
00487
00488 init_acc_extra();
00489
00490
00491 if (leg_info_str && (leg_info=parse_acc_leg(leg_info_str))==0 ) {
00492 LM_ERR("failed to parse multileg_info param\n");
00493 return -1;
00494 }
00495
00496
00497
00498
00499 if (log_extra_str && (log_extra=parse_acc_extra(log_extra_str))==0 ) {
00500 LM_ERR("failed to parse log_extra param\n");
00501 return -1;
00502 }
00503
00504 if ((log_flag != -1) && !flag_in_range(log_flag)) {
00505 LM_ERR("log_flag set to invalid value\n");
00506 return -1;
00507 }
00508
00509 if ((log_missed_flag != -1) && !flag_in_range(log_missed_flag)) {
00510 LM_ERR("log_missed_flag set to invalid value\n");
00511 return -1;
00512 }
00513
00514 acc_log_init();
00515
00516
00517
00518 if( cdr_enable < 0 || cdr_enable > 1)
00519 {
00520 LM_ERR("cdr_enable is out of range\n");
00521 return -1;
00522 }
00523
00524 if( cdr_enable)
00525 {
00526 if( !cdr_start_str.s || !cdr_end_str.s || !cdr_duration_str.s)
00527 {
00528 LM_ERR( "necessary cdr_parameters are not set\n");
00529 return -1;
00530 }
00531
00532 cdr_start_str.len = strlen(cdr_start_str.s);
00533 cdr_end_str.len = strlen(cdr_end_str.s);
00534 cdr_duration_str.len = strlen(cdr_duration_str.s);
00535
00536 if( !cdr_start_str.len || !cdr_end_str.len || !cdr_duration_str.len)
00537 {
00538 LM_ERR( "necessary cdr_parameters are empty\n");
00539 return -1;
00540 }
00541
00542
00543 if( set_cdr_extra( cdr_log_extra_str) != 0)
00544 {
00545 LM_ERR( "failed to set cdr extra '%s'\n", cdr_log_extra_str);
00546 return -1;
00547 }
00548
00549 if( cdr_facility_str && set_cdr_facility( cdr_facility_str) != 0)
00550 {
00551 LM_ERR( "failed to set cdr facility '%s'\n", cdr_facility_str);
00552 return -1;
00553 }
00554
00555 if( init_cdr_generation() != 0)
00556 {
00557 LM_ERR("failed to init cdr generation\n");
00558 return -1;
00559 }
00560 }
00561
00562
00563
00564 #ifdef SQL_ACC
00565 if (db_url.s && db_url.len > 0) {
00566
00567 if (db_extra_str && (db_extra=parse_acc_extra(db_extra_str))==0 ) {
00568 LM_ERR("failed to parse db_extra param\n");
00569 return -1;
00570 }
00571 if (acc_db_init(&db_url)<0){
00572 LM_ERR("failed...did you load a database module?\n");
00573 return -1;
00574 }
00575
00576
00577 if ((db_flag != -1) && !flag_in_range(db_flag)) {
00578 LM_ERR("db_flag set to invalid value\n");
00579 return -1;
00580 }
00581
00582 if ((db_missed_flag != -1) && !flag_in_range(db_missed_flag)) {
00583 LM_ERR("db_missed_flag set to invalid value\n");
00584 return -1;
00585 }
00586 } else {
00587 db_url.s = NULL;
00588 db_url.len = 0;
00589 db_flag = -1;
00590 db_missed_flag = -1;
00591 }
00592 #endif
00593
00594
00595
00596 #ifdef RAD_ACC
00597 if (radius_config && radius_config[0]) {
00598
00599 if (rad_extra_str && (rad_extra=parse_acc_extra(rad_extra_str))==0 ) {
00600 LM_ERR("failed to parse rad_extra param\n");
00601 return -1;
00602 }
00603
00604
00605 if ((radius_flag != -1) && !flag_in_range(radius_flag)) {
00606 LM_ERR("radius_flag set to invalid value\n");
00607 return -1;
00608 }
00609
00610 if ((radius_missed_flag != -1) && !flag_in_range(radius_missed_flag)) {
00611 LM_ERR("radius_missed_flag set to invalid value\n");
00612 return -1;
00613 }
00614
00615 if (init_acc_rad( radius_config, service_type)!=0 ) {
00616 LM_ERR("failed to init radius\n");
00617 return -1;
00618 }
00619 } else {
00620 radius_config = 0;
00621 radius_flag = -1;
00622 radius_missed_flag = -1;
00623 }
00624 #endif
00625
00626
00627
00628 #ifdef DIAM_ACC
00629
00630 if (flag_idx2mask(&diameter_flag)<0)
00631 return -1;
00632 if (flag_idx2mask(&diameter_missed_flag)<0)
00633 return -1;
00634
00635
00636 if (dia_extra_str && (dia_extra=parse_acc_extra(dia_extra_str))==0 ) {
00637 LM_ERR("failed to parse dia_extra param\n");
00638 return -1;
00639 }
00640
00641 if (acc_diam_init()!=0) {
00642 LM_ERR("failed to init diameter engine\n");
00643 return -1;
00644 }
00645
00646 #endif
00647
00648 _acc_module_initialized = 1;
00649 if(acc_init_engines()<0) {
00650 LM_ERR("failed to init extra engines\n");
00651 return -1;
00652 }
00653
00654 return 0;
00655 }
00656
00657
00658 static int child_init(int rank)
00659 {
00660 if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00661 return 0;
00662
00663 #ifdef SQL_ACC
00664 if(db_url.s && acc_db_init_child(&db_url)<0) {
00665 LM_ERR("could not open database connection");
00666 return -1;
00667 }
00668
00669 #endif
00670
00671
00672 #ifdef DIAM_ACC
00673
00674 LM_DBG("initializing TCP connection\n");
00675
00676 sockfd = init_mytcp(diameter_client_host, diameter_client_port);
00677 if(sockfd==-1)
00678 {
00679 LM_ERR("TCP connection not established\n");
00680 return -1;
00681 }
00682
00683 LM_DBG("a TCP connection was established on sockfd=%d\n", sockfd);
00684
00685
00686 rb = (rd_buf_t*)pkg_malloc(sizeof(rd_buf_t));
00687 if(!rb)
00688 {
00689 LM_DBG("no more pkg memory\n");
00690 return -1;
00691 }
00692 rb->buf = 0;
00693 #endif
00694
00695 return 0;
00696 }
00697
00698
00699 static void destroy(void)
00700 {
00701 if (log_extra)
00702 destroy_extras( log_extra);
00703 #ifdef SQL_ACC
00704 acc_db_close();
00705 if (db_extra)
00706 destroy_extras( db_extra);
00707 #endif
00708 #ifdef RAD_ACC
00709 if (rad_extra)
00710 destroy_extras( rad_extra);
00711 #endif
00712 #ifdef DIAM_ACC
00713 close_tcp_connection(sockfd);
00714 if (dia_extra)
00715 destroy_extras( dia_extra);
00716 #endif
00717 }
00718
00719
00723 acc_extra_t* get_leg_info(void)
00724 {
00725 return leg_info;
00726 }
00727
00731 static int bind_acc(acc_api_t* api)
00732 {
00733 if (!api) {
00734 ERR("Invalid parameter value\n");
00735 return -1;
00736 }
00737
00738 api->register_engine = acc_register_engine;
00739 api->get_leg_info = get_leg_info;
00740 api->get_core_attrs = core2strar;
00741 api->get_extra_attrs = extra2strar;
00742 api->get_leg_attrs = legs2strar;
00743 api->parse_extra = parse_acc_extra;
00744 api->exec = acc_api_exec;
00745 return 0;
00746 }
00747
00751 static int acc_init_engine(acc_engine_t *e)
00752 {
00753 acc_init_info_t ai;
00754
00755 if(_acc_module_initialized==0)
00756 return 0;
00757
00758 if(e->flags & 1)
00759 return 0;
00760
00761 memset(&ai, 0, sizeof(acc_init_info_t));
00762 ai.leg_info = leg_info;
00763 if(e->acc_init(&ai)<0)
00764 {
00765 LM_ERR("failed to initialize extra acc engine\n");
00766 return -1;
00767 }
00768 e->flags |= 1;
00769 return 0;
00770 }
00771
00775 static int acc_init_engines(void)
00776 {
00777 acc_engine_t *e;
00778 e = _acc_engines;
00779 while(e) {
00780 if(acc_init_engine(e)<0)
00781 return -1;
00782 e = e->next;
00783 }
00784 return 0;
00785 }
00786
00791 static int acc_register_engine(acc_engine_t *eng)
00792 {
00793 acc_engine_t *e;
00794
00795 if(eng==NULL)
00796 return -1;
00797 e = (acc_engine_t*)pkg_malloc(sizeof(acc_engine_t));
00798 if(e ==NULL)
00799 {
00800 LM_ERR("no more pkg\n");
00801 return -1;
00802 }
00803 memcpy(e, eng, sizeof(acc_engine_t));
00804
00805 if(acc_init_engine(e)<0)
00806 return -1;
00807
00808 e->next = _acc_engines;
00809 _acc_engines = e;
00810 LM_DBG("new acc engine registered: %s\n", e->name);
00811 return 0;
00812 }
00813
00817 acc_engine_t *acc_api_get_engines(void)
00818 {
00819 return _acc_engines;
00820 }
00821