/* * $Id: dialog.c 1808 2007-03-10 17:36:19Z bogdan_iancu $ * * dialog module - basic support for dialog tracking * * Copyright (C) 2006 Voice Sistem SRL * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2006-04-14 initial version (bogdan) * 2006-11-28 Added statistic support for the number of early and failed * dialogs. (Jeffrey Magder - SOMA Networks) */ #include #include #include #include "../../sr_module.h" #include "../../dprint.h" #include "../../error.h" #include "../../ut.h" #include "../../items.h" #include "../../script_cb.h" #include "../../mem/mem.h" #include "../tm/tm_load.h" #include "../rr/api.h" #include "../../mi/mi.h" #include "dlg_hash.h" #include "dlg_timer.h" #include "dlg_handlers.h" #include "dlg_load.h" #include "dlg_cb.h" MODULE_VERSION static int mod_init(void); static void mod_destroy(); /* module parameter */ static int dlg_hash_size = 4096; static char* rr_param = "did"; static int dlg_flag = -1; static char* timeout_spec = 0; static int default_timeout = 60 * 60 * 12; /* 12 hours */ static int use_tight_match = 0; /* statistic variables */ int dlg_enable_stats = 1; stat_var *active_dlgs = 0; stat_var *processed_dlgs = 0; stat_var *expired_dlgs = 0; stat_var *failed_dlgs = 0; stat_var *early_dlgs = 0; struct tm_binds d_tmb; struct rr_binds d_rrb; xl_spec_t timeout_avp; static int it_get_dlg_count(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags); static cmd_export_t cmds[]={ {"load_dlg", (cmd_function)load_dlg, 0, 0, 0}, {0,0,0,0,0} }; static param_export_t mod_params[]={ { "enable_stats", INT_PARAM, &dlg_enable_stats }, { "hash_size", INT_PARAM, &dlg_hash_size }, { "rr_param", STR_PARAM, &rr_param }, { "dlg_flag", INT_PARAM, &dlg_flag }, { "timeout_avp", STR_PARAM, &timeout_spec }, { "default_timeout", INT_PARAM, &default_timeout }, { "use_tight_match", INT_PARAM, &use_tight_match }, { 0,0,0 } }; static stat_export_t mod_stats[] = { {"active_dialogs" , STAT_NO_RESET, &active_dlgs }, {"early_dialogs", STAT_NO_RESET, &early_dlgs }, {"processed_dialogs" , 0, &processed_dlgs }, {"expired_dialogs" , 0, &expired_dlgs }, {"failed_dialogs", 0, &failed_dlgs }, {0,0,0} }; static mi_export_t mi_cmds[] = { { "dlg_list", mi_print_dlgs, MI_NO_INPUT_FLAG, 0, 0}, { 0, 0, 0, 0, 0} }; static item_export_t mod_items[] = { { "DLG_count", it_get_dlg_count, 100, {{0, 0}, 0, 0} }, { "DLG_lifetime", it_get_dlg_lifetime, 100, {{0, 0}, 0, 0} }, { "DLG_status", it_get_dlg_status , 100, {{0, 0}, 0, 0} }, { 0, 0, 0, {{0, 0}, 0, 0} } }; struct module_exports exports= { "dialog", /* module's name */ DEFAULT_DLFLAGS, /* dlopen flags */ cmds, /* exported functions */ mod_params, /* param exports */ mod_stats, /* exported statistics */ mi_cmds, /* exported MI functions */ mod_items, /* exported pseudo-variables */ mod_init, /* module initialization function */ 0, /* reply processing function */ mod_destroy, 0 /* per-child init function */ }; int load_dlg( struct dlg_binds *dlgb ) { dlgb->register_dlgcb = register_dlgcb; return 1; } static int it_get_dlg_count(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int n; int l; char *ch; if(msg==NULL || res==NULL) return -1; n = active_dlgs ? get_stat_val(active_dlgs) : 0; l = 0; ch = int2str( n, &l); res->rs.s = ch; res->rs.len = l; res->ri = n; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; return 0; } static int mod_init(void) { unsigned int n; LOG(L_INFO,"Dialog module - initializing\n"); /* param checkings */ if (dlg_flag==-1) { LOG(L_ERR,"ERROR:dialog:mod_init: no dlg flag set!!\n"); return -1; } else if (dlg_flag>MAX_FLAG) { LOG(L_ERR,"ERROR:dialog:mod_init: invalid dlg flag %d!!\n",dlg_flag); return -1; } if (rr_param==0 || rr_param[0]==0) { LOG(L_ERR,"ERROR:dialog:mod_init: empty rr_param!!\n"); return -1; } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) { LOG(L_ERR,"ERROR:dialog:mod_init: rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME); return -1; } if (timeout_spec) { if ( xl_parse_spec(timeout_spec, &timeout_avp, XL_THROW_ERROR |XL_DISABLE_MULTI|XL_DISABLE_COLORS)==0 && (timeout_avp.type!=XL_AVP)){ LOG(L_ERR, "ERROR:dialog:mod_init: malformed or non AVP timeout " "AVP definition in '%s'\n", timeout_spec); return -1; } } if (default_timeout<=0) { LOG(L_ERR,"ERROR:dialog:mod_init: 0 default_timeout not accepted!!\n"); return -1; } /* if statistics are disabled, prevent their registration to core */ if (dlg_enable_stats==0) exports.stats = 0; /* load the TM API */ if (load_tm_api(&d_tmb)!=0) { LOG(L_ERR, "ERROR:dialog:mod_init: can't load TM API\n"); return -1; } /* load RR API also */ if (load_rr_api(&d_rrb)!=0) { LOG(L_ERR, "ERROR:dialog:mod_init: can't load RR API\n"); return -1; } /* register callbacks*/ /* listen for all incoming requests */ if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0 ) <=0 ) { LOG(L_ERR,"ERROR:dialog:mod_init: cannot register TMCB_REQUEST_IN " "callback\n"); return -1; } /* listen for all routed requests */ if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) { LOG(L_ERR,"ERROR:dialog:mod_init: cannot register RR callback\n"); return -1; } if ( register_timer( dlg_timer_routine, 0, 1)<0 ) { LOG(L_ERR,"ERROR:dialog:mod_init: failed to register timer \n"); return -1; } /* init handlers */ init_dlg_handlers( rr_param, dlg_flag, timeout_spec?&timeout_avp:0, default_timeout, use_tight_match); /* init timer */ if (init_dlg_timer(dlg_ontimeout)!=0) { LOG(L_ERR,"ERROR:dialog:mod_init: cannot init timer list\n"); return -1; } /* init callbacks */ if (init_dlg_callbacks()!=0) { LOG(L_ERR,"ERROR:dialog:mod_init: cannot init callbacks\n"); return -1; } /* initialized the hash table */ for( n=0 ; n<(8*sizeof(n)) ; n++) { if (dlg_hash_size==(1< rounding from %d to %d\n", dlg_hash_size, 1<<(n-1)); dlg_hash_size = 1<<(n-1); } } if ( init_dlg_table(dlg_hash_size)<0 ) { LOG(L_ERR,"ERROR:dialog:mod_init: failed to create hash table\n"); return -1; } return 0; } static void mod_destroy() { destroy_dlg_timer(); destroy_dlg_table(); destroy_dlg_callbacks(); destroy_dlg_handlers(); }