/*
* $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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#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<<n))
break;
if (dlg_hash_size<(1<<n)) {
LOG(L_WARN,"WARNING:dialog:mod_init: hash_size is not a power "
"of 2 as it should be -> 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();
}
syntax highlighted by Code2HTML, v. 0.9.1