acc_mod.c

Go to the documentation of this file.
00001 /*
00002  * $Id: acc_mod.c 5472 2009-01-14 22:18:08Z miconda $
00003  * 
00004  * Accounting module
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  * Copyright (C) 2006 Voice Sistem SRL
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * History:
00026  * -------
00027  * 2003-03-06: aligned to change in callback names (jiri)
00028  * 2003-03-06: fixed improper sql connection, now from 
00029  *               child_init (jiri)
00030  * 2003-03-11: New module interface (janakj)
00031  * 2003-03-16: flags export parameter added (janakj)
00032  * 2003-04-04  grand acc cleanup (jiri)
00033  * 2003-04-06: Opens database connection in child_init only (janakj)
00034  * 2003-04-24  parameter validation (0 t->uas.request) added (jiri)
00035  * 2003-11-04  multidomain support for mysql introduced (jiri)
00036  * 2003-12-04  global TM callbacks switched to per transaction callbacks
00037  *             (bogdan)
00038  * 2004-06-06  db cleanup: static db_url, calls to acc_db_{bind,init,close)
00039  *             (andrei)
00040  * 2005-05-30  acc_extra patch commited (ramona)
00041  * 2005-06-28  multi leg call support added (bogdan)
00042  * 2006-01-13  detect_direction (for sequential requests) added (bogdan)
00043  * 2006-09-08  flexible multi leg accounting support added (bogdan)
00044  * 2006-09-19  final stage of a masive re-structuring and cleanup (bogdan)
00045  */
00046 
00047 /*! \file
00048  * \ingroup acc
00049  * \brief Acc:: Core module interface
00050  *
00051  * - Module: \ref acc
00052  */
00053 
00054 /*! \defgroup acc ACC :: The Kamailio accounting Module
00055  *            
00056  * The ACC module is used to account transactions information to
00057  *  different backends like syslog, SQL, RADIUS and DIAMETER (beta
00058  *  version).
00059  *            
00060  */ 
00061 
00062 #include <stdio.h>
00063 #include <string.h>
00064 
00065 #include "../../sr_module.h"
00066 #include "../../local_route.h"
00067 #include "../../dprint.h"
00068 #include "../../mem/mem.h"
00069 #include "../tm/tm_load.h"
00070 #include "../rr/api.h"
00071 #include "acc.h"
00072 #include "acc_mod.h"
00073 #include "acc_extra.h"
00074 #include "acc_logic.h"
00075 
00076 #ifdef RAD_ACC
00077 #include "../../radius.h"
00078 #endif
00079 
00080 #ifdef DIAM_ACC
00081 #include "diam_dict.h"
00082 #include "diam_tcp.h"
00083 #endif
00084 
00085 MODULE_VERSION
00086 
00087 struct tm_binds tmb;
00088 struct rr_binds rrb;
00089 
00090 static int mod_init(void);
00091 static void destroy(void);
00092 static int child_init(int rank);
00093 
00094 
00095 /* ----- General purpose variables ----------- */
00096 
00097 /* what would you like to report on */
00098 
00099 int early_media = 0;    /*!< should early media replies (183) be logged ? default==no */
00100 int report_cancels = 0;    /*!< would you like us to report CANCELs from upstream too? */
00101 int report_ack = 0;     /*!< report e2e ACKs too */
00102 int detect_direction = 0;  /*!< detect and correct direction in the sequential requests */
00103 int failed_transaction_flag = -1; /*!< should failed replies (>=3xx) be logged ? default==no */
00104 static char* leg_info_str = 0;   /*!< multi call-leg support */
00105 struct acc_extra *leg_info = 0;
00106 
00107 
00108 /* ----- SYSLOG acc variables ----------- */
00109 /*! \name AccSyslogVariables  Syslog Variables */     
00110 /*@{*/
00111 
00112 int log_flag = -1;
00113 int log_missed_flag = -1;
00114 int log_level = L_NOTICE;  /*!< Syslog: noisiness level logging facilities are used */
00115 int log_facility = LOG_DAEMON;   /*!< Syslog: log facility that is used */
00116 static char * log_facility_str = 0; /*!< Syslog: log facility that is used */
00117 static char *log_extra_str = 0; /*!< Syslog: log extra variables */
00118 struct acc_extra *log_extra = 0; /*!< Log extra attributes */
00119 
00120 /*@}*/
00121 
00122 /* ----- RADIUS acc variables ----------- */
00123 /*! \name AccRadiusVariables  Radius Variables */     
00124 /*@{*/
00125 
00126 #ifdef RAD_ACC
00127 static char *radius_config = 0;
00128 int radius_flag = -1;
00129 int radius_missed_flag = -1;
00130 static int service_type = -1;
00131 void *rh;
00132 /* rad extra variables */
00133 static char *rad_extra_str = 0;
00134 struct acc_extra *rad_extra = 0;
00135 #endif
00136 /*@}*/
00137 
00138 
00139 /* ----- DIAMETER acc variables ----------- */
00140 
00141 /*! \name AccDiamaterVariables  Radius Variables */     
00142 /*@{*/
00143 #ifdef DIAM_ACC
00144 int diameter_flag = -1;
00145 int diameter_missed_flag = -1;
00146 static char *dia_extra_str = 0;     /*!< diameter extra variables */
00147 struct acc_extra *dia_extra = 0;
00148 rd_buf_t *rb;           /*!< buffer used to read from TCP connection*/
00149 char* diameter_client_host="localhost";
00150 int diameter_client_port=3000;
00151 #endif
00152 
00153 /*@}*/
00154 
00155 /* ----- SQL acc variables ----------- */
00156 /*! \name AccSQLVariables  Radius Variables */     
00157 /*@{*/
00158 
00159 #ifdef SQL_ACC
00160 int db_flag = -1;
00161 int db_missed_flag = -1;
00162 static char *db_extra_str = 0;      /*!< db extra variables */
00163 struct acc_extra *db_extra = 0;
00164 static str db_url = {NULL, 0};      /*!< Database url */
00165 str db_table_acc = str_init("acc"); /*!< name of database tables */
00166 str db_table_mc = str_init("missed_calls");
00167 /* names of columns in tables acc/missed calls*/
00168 str acc_method_col     = str_init("method");
00169 str acc_fromtag_col    = str_init("from_tag");
00170 str acc_totag_col      = str_init("to_tag");
00171 str acc_callid_col     = str_init("callid");
00172 str acc_sipcode_col    = str_init("sip_code");
00173 str acc_sipreason_col  = str_init("sip_reason");
00174 str acc_time_col       = str_init("time");
00175 #endif
00176 
00177 /*@}*/
00178 
00179 /* ------------- fixup function --------------- */
00180 static int acc_fixup(void** param, int param_no);
00181 static int free_acc_fixup(void** param, int param_no);
00182 
00183 
00184 static cmd_export_t cmds[] = {
00185    {"acc_log_request", (cmd_function)w_acc_log_request, 1,
00186       acc_fixup, free_acc_fixup,
00187       REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
00188 #ifdef SQL_ACC
00189    {"acc_db_request",  (cmd_function)w_acc_db_request,  2,
00190       acc_fixup, free_acc_fixup,
00191       REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
00192 #endif
00193 #ifdef RAD_ACC
00194    {"acc_rad_request", (cmd_function)w_acc_rad_request, 1,
00195       acc_fixup, free_acc_fixup,
00196       REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
00197 #endif
00198 #ifdef DIAM_ACC
00199    {"acc_diam_request",(cmd_function)w_acc_diam_request,1,
00200       acc_fixup, free_acc_fixup,
00201       REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
00202 #endif
00203    {0, 0, 0, 0, 0, 0}
00204 };
00205 
00206 
00207 
00208 static param_export_t params[] = {
00209    {"early_media",             INT_PARAM, &early_media             },
00210    {"failed_transaction_flag", INT_PARAM, &failed_transaction_flag },
00211    {"report_ack",              INT_PARAM, &report_ack              },
00212    {"report_cancels",          INT_PARAM, &report_cancels          },
00213    {"multi_leg_info",          STR_PARAM, &leg_info_str            },
00214    {"detect_direction",        INT_PARAM, &detect_direction        },
00215    /* syslog specific */
00216    {"log_flag",             INT_PARAM, &log_flag             },
00217    {"log_missed_flag",      INT_PARAM, &log_missed_flag      },
00218    {"log_level",            INT_PARAM, &log_level            },
00219    {"log_facility",         STR_PARAM, &log_facility_str     },
00220    {"log_extra",            STR_PARAM, &log_extra_str        },
00221 #ifdef RAD_ACC
00222    {"radius_config",        STR_PARAM, &radius_config        },
00223    {"radius_flag",          INT_PARAM, &radius_flag          },
00224    {"radius_missed_flag",   INT_PARAM, &radius_missed_flag   },
00225    {"service_type",         INT_PARAM, &service_type         },
00226    {"radius_extra",         STR_PARAM, &rad_extra_str        },
00227 #endif
00228    /* DIAMETER specific */
00229 #ifdef DIAM_ACC
00230    {"diameter_flag",        INT_PARAM, &diameter_flag        },
00231    {"diameter_missed_flag", INT_PARAM, &diameter_missed_flag },
00232    {"diameter_client_host", STR_PARAM, &diameter_client_host },
00233    {"diameter_client_port", INT_PARAM, &diameter_client_port },
00234    {"diameter_extra",       STR_PARAM, &dia_extra_str        },
00235 #endif
00236    /* db-specific */
00237 #ifdef SQL_ACC
00238    {"db_flag",              INT_PARAM, &db_flag              },
00239    {"db_missed_flag",       INT_PARAM, &db_missed_flag       },
00240    {"db_extra",             STR_PARAM, &db_extra_str         },
00241    {"db_url",               STR_PARAM, &db_url.s             },
00242    {"db_table_acc",         STR_PARAM, &db_table_acc.s       },
00243    {"db_table_missed_calls",STR_PARAM, &db_table_mc.s        },
00244    {"acc_method_column",    STR_PARAM, &acc_method_col.s     },
00245    {"acc_from_tag_column",  STR_PARAM, &acc_fromtag_col.s    },
00246    {"acc_to_tag_column",    STR_PARAM, &acc_totag_col.s      },
00247    {"acc_callid_column",    STR_PARAM, &acc_callid_col.s     },
00248    {"acc_sip_code_column",  STR_PARAM, &acc_sipcode_col.s    },
00249    {"acc_sip_reason_column",STR_PARAM, &acc_sipreason_col.s  },
00250    {"acc_time_column",      STR_PARAM, &acc_time_col.s       },
00251 #endif
00252    {0,0,0}
00253 };
00254 
00255 
00256 struct module_exports exports= {
00257    "acc",
00258    DEFAULT_DLFLAGS, /* dlopen flags */
00259    cmds,       /* exported functions */
00260    params,     /* exported params */
00261    0,          /* exported statistics */
00262    0,          /* exported MI functions */
00263    0,          /* exported pseudo-variables */
00264    0,          /* extra processes */
00265    mod_init,   /* initialization module */
00266    0,          /* response function */
00267    destroy,    /* destroy function */
00268    child_init  /* per-child init function */
00269 };
00270 
00271 
00272 
00273 /************************** FIXUP functions ****************************/
00274 
00275 
00276 static int acc_fixup(void** param, int param_no)
00277 {
00278    struct acc_param *accp;
00279    char *p;
00280 
00281    p = (char*)*param;
00282    if (p==0 || p[0]==0) {
00283       LM_ERR("first parameter is empty\n");
00284       return E_SCRIPT;
00285    }
00286 
00287    if (param_no == 1) {
00288       accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
00289       if (!accp) {
00290          LM_ERR("no more pkg mem\n");
00291          return E_OUT_OF_MEM;
00292       }
00293       memset( accp, 0, sizeof(struct acc_param));
00294       accp->reason.s = p;
00295       accp->reason.len = strlen(p);
00296       /* any code? */
00297       if (accp->reason.len>=3 && isdigit((int)p[0])
00298       && isdigit((int)p[1]) && isdigit((int)p[2]) ) {
00299          accp->code = (p[0]-'0')*100 + (p[1]-'0')*10 + (p[2]-'0');
00300          accp->code_s.s = p;
00301          accp->code_s.len = 3;
00302          accp->reason.s += 3;
00303          for( ; isspace((int)accp->reason.s[0]) ; accp->reason.s++ );
00304          accp->reason.len = strlen(accp->reason.s);
00305       }
00306       *param = (void*)accp;
00307 #ifdef SQL_ACC
00308    } else if (param_no == 2) {
00309       /* only for db acc - the table name */
00310       if (db_url.s==0) {
00311          pkg_free(p);
00312          *param = 0;
00313       }
00314 #endif
00315    }
00316    return 0;
00317 }
00318 
00319 static int free_acc_fixup(void** param, int param_no)
00320 {
00321    if(*param)
00322    {
00323       pkg_free(*param);
00324       *param = 0;
00325    }
00326    return 0;
00327 }
00328 
00329 
00330 
00331 /************************** INTERFACE functions ****************************/
00332 
00333 static int mod_lrt_init( void )
00334 {
00335 
00336 #ifdef SQL_ACC
00337    if(db_url.s && acc_db_init_child(&db_url)<0) {
00338       LM_ERR("could not open database connection");
00339       return -1;
00340    }
00341 #endif
00342 
00343    return 0;
00344 }
00345 
00346 static int mod_init( void )
00347 {
00348    lrt_info_t li;
00349    li.init = mod_lrt_init;
00350    li.name = "acc";
00351    if(register_lrt_info(&li)!=0)
00352       return -1;
00353 
00354 #ifdef SQL_ACC
00355    if (db_url.s)
00356       db_url.len = strlen(db_url.s);
00357    db_table_acc.len = strlen(db_table_acc.s);
00358    db_table_mc.len = strlen(db_table_mc.s);
00359    acc_method_col.len = strlen(acc_method_col.s);
00360    acc_fromtag_col.len = strlen(acc_fromtag_col.s);
00361    acc_totag_col.len = strlen(acc_totag_col.s);
00362    acc_callid_col.len = strlen(acc_callid_col.s);
00363    acc_sipcode_col.len = strlen(acc_sipcode_col.s);
00364    acc_sipreason_col.len = strlen(acc_sipreason_col.s);
00365    acc_time_col.len = strlen(acc_time_col.s);
00366 #endif
00367 
00368    if (log_facility_str) {
00369       int tmp = str2facility(log_facility_str);
00370       if (tmp != -1)
00371          log_facility = tmp;
00372       else {
00373          LM_ERR("invalid log facility configured");
00374          return -1;
00375       }
00376    }
00377 
00378    /* ----------- GENERIC INIT SECTION  ----------- */
00379 
00380    if (flag_idx2mask(&failed_transaction_flag)<0)
00381       return -1;
00382 
00383    /* load the TM API */
00384    if (load_tm_api(&tmb)!=0) {
00385       LM_ERR("can't load TM API\n");
00386       return -1;
00387    }
00388 
00389    /* if detect_direction is enabled, load rr also */
00390    if (detect_direction) {
00391       if (load_rr_api(&rrb)!=0) {
00392          LM_ERR("can't load RR API\n");
00393          return -1;
00394       }
00395       /* we need the append_fromtag on in RR */
00396       if (!rrb.append_fromtag) {
00397          LM_ERR("'append_fromtag' RR param is not enabled!"
00398             " - required by 'detect_direction'\n");
00399          return -1;
00400       }
00401    }
00402 
00403    /* listen for all incoming requests  */
00404    if ( tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, acc_onreq, 0, 0 ) <=0 ) {
00405       LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
00406       return -1;
00407    }
00408 
00409    /* init the extra engine */
00410    init_acc_extra();
00411 
00412    /* configure multi-leg accounting */
00413    if (leg_info_str && (leg_info=parse_acc_leg(leg_info_str))==0 ) {
00414       LM_ERR("failed to parse multileg_info param\n");
00415       return -1;
00416    }
00417 
00418    /* ----------- SYSLOG INIT SECTION ----------- */
00419 
00420    /* parse the extra string, if any */
00421    if (log_extra_str && (log_extra=parse_acc_extra(log_extra_str))==0 ) {
00422       LM_ERR("failed to parse log_extra param\n");
00423       return -1;
00424    }
00425 
00426    if (flag_idx2mask(&log_flag)<0)
00427       return -1;
00428 
00429    if (flag_idx2mask(&log_missed_flag)<0)
00430       return -1;
00431 
00432    acc_log_init();
00433 
00434    /* ------------ SQL INIT SECTION ----------- */
00435 
00436 #ifdef SQL_ACC
00437    if (db_url.s && db_url.len > 0) {
00438       /* parse the extra string, if any */
00439       if (db_extra_str && (db_extra=parse_acc_extra(db_extra_str))==0 ) {
00440          LM_ERR("failed to parse db_extra param\n");
00441          return -1;
00442       }
00443       if (acc_db_init(&db_url)<0){
00444          LM_ERR("failed...did you load a database module?\n");
00445          return -1;
00446       }
00447       /* fix the flags */
00448       if (flag_idx2mask(&db_flag)<0)
00449          return -1;
00450       if (flag_idx2mask(&db_missed_flag)<0)
00451          return -1;
00452    } else {
00453       db_flag = 0;
00454       db_missed_flag = 0;
00455    }
00456 #endif
00457 
00458    /* ------------ RADIUS INIT SECTION ----------- */
00459 
00460 #ifdef RAD_ACC
00461    if (radius_config && radius_config[0]) {
00462       /* parse the extra string, if any */
00463       if (rad_extra_str && (rad_extra=parse_acc_extra(rad_extra_str))==0 ) {
00464          LM_ERR("failed to parse rad_extra param\n");
00465          return -1;
00466       }
00467 
00468       /* fix the flags */
00469       if (flag_idx2mask(&radius_flag)<0)
00470          return -1;
00471       if (flag_idx2mask(&radius_missed_flag)<0)
00472          return -1;
00473       if (init_acc_rad( radius_config, service_type)!=0 ) {
00474          LM_ERR("failed to init radius\n");
00475          return -1;
00476       }
00477    } else {
00478       radius_config = 0;
00479       radius_flag = 0;
00480       radius_missed_flag = 0;
00481    }
00482 #endif
00483 
00484    /* ------------ DIAMETER INIT SECTION ----------- */
00485 
00486 #ifdef DIAM_ACC
00487    /* fix the flags */
00488    if (flag_idx2mask(&diameter_flag)<0)
00489       return -1;
00490    if (flag_idx2mask(&diameter_missed_flag)<0)
00491       return -1;
00492 
00493    /* parse the extra string, if any */
00494    if (dia_extra_str && (dia_extra=parse_acc_extra(dia_extra_str))==0 ) {
00495       LM_ERR("failed to parse dia_extra param\n");
00496       return -1;
00497    }
00498 
00499    if (acc_diam_init()!=0) {
00500       LM_ERR("failed to init diameter engine\n");
00501       return -1;
00502    }
00503 
00504 #endif
00505    return 0;
00506 }
00507 
00508 
00509 static int child_init(int rank)
00510 {
00511 #ifdef SQL_ACC
00512    if(db_url.s && acc_db_init_child(&db_url)<0) {
00513       LM_ERR("could not open database connection");
00514       return -1;
00515    }
00516 
00517 #endif
00518 
00519    /* DIAMETER */
00520 #ifdef DIAM_ACC
00521    /* open TCP connection */
00522    LM_DBG("initializing TCP connection\n");
00523 
00524    sockfd = init_mytcp(diameter_client_host, diameter_client_port);
00525    if(sockfd==-1) 
00526    {
00527       LM_ERR("TCP connection not established\n");
00528       return -1;
00529    }
00530 
00531    LM_DBG("a TCP connection was established on sockfd=%d\n", sockfd);
00532 
00533    /* every child with its buffer */
00534    rb = (rd_buf_t*)pkg_malloc(sizeof(rd_buf_t));
00535    if(!rb)
00536    {
00537       LM_DBG("no more pkg memory\n");
00538       return -1;
00539    }
00540    rb->buf = 0;
00541 #endif
00542 
00543    return 0;
00544 }
00545 
00546 
00547 static void destroy(void)
00548 {
00549    if (log_extra)
00550       destroy_extras( log_extra);
00551 #ifdef SQL_ACC
00552    acc_db_close();
00553    if (db_extra)
00554       destroy_extras( db_extra);
00555 #endif
00556 #ifdef RAD_ACC
00557    if (rad_extra)
00558       destroy_extras( rad_extra);
00559 #endif
00560 #ifdef DIAM_ACC
00561    close_tcp_connection(sockfd);
00562    if (dia_extra)
00563       destroy_extras( dia_extra);
00564 #endif
00565 }
00566 

Generated on Thu May 17 12:00:24 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6