dialog.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dialog.c 5641 2009-02-26 21:51:02Z miconda $
00003  *
00004  * dialog module - basic support for dialog tracking
00005  *
00006  * Copyright (C) 2006 Voice Sistem SRL
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2006-04-14 initial version (bogdan)
00027  *  2006-11-28 Added statistic support for the number of early and failed
00028  *              dialogs. (Jeffrey Magder - SOMA Networks) 
00029  *  2007-04-30 added dialog matching without DID (dialog ID), but based only
00030  *              on RFC3261 elements - based on an original patch submitted 
00031  *              by Michel Bensoussan <michel@extricom.com> (bogdan)
00032  *  2007-05-15 added saving dialogs' information to database (ancuta)
00033  *  2007-07-04 added saving dialog cseq, contact, record route 
00034  *              and bind_addresses(sock_info) for caller and callee (ancuta)
00035  *  2008-04-14 added new type of callback to be triggered when dialogs are 
00036  *              loaded from DB (bogdan)
00037  */
00038 
00039 
00040 #include <stdio.h>
00041 #include <string.h>
00042 #include <stdlib.h>
00043 #include <sys/time.h>
00044 
00045 #include "../../sr_module.h"
00046 #include "../../db/db.h"
00047 #include "../../dprint.h"
00048 #include "../../error.h"
00049 #include "../../ut.h"
00050 #include "../../pvar.h"
00051 #include "../../mod_fix.h"
00052 #include "../../script_cb.h"
00053 #include "../../faked_msg.h"
00054 #include "../../mem/mem.h"
00055 #include "../../mi/mi.h"
00056 #include "../tm/tm_load.h"
00057 #include "../rr/api.h"
00058 #include "dlg_hash.h"
00059 #include "dlg_timer.h"
00060 #include "dlg_handlers.h"
00061 #include "dlg_load.h"
00062 #include "dlg_cb.h"
00063 #include "dlg_db_handler.h"
00064 #include "dlg_req_within.h"
00065 #include "dlg_profile.h"
00066 #include "dlg_var.h"
00067 #include "dlg_transfer.h"
00068 
00069 MODULE_VERSION
00070 
00071 
00072 static int mod_init(void);
00073 static int child_init(int rank);
00074 static void mod_destroy(void);
00075 
00076 /* module parameter */
00077 static int dlg_hash_size = 4096;
00078 static char* rr_param = "did";
00079 static int dlg_flag = -1;
00080 static str timeout_spec = {NULL, 0};
00081 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
00082 static int seq_match_mode = SEQ_MATCH_STRICT_ID;
00083 static char* profiles_wv_s = NULL;
00084 static char* profiles_nv_s = NULL;
00085 str dlg_extra_hdrs = {NULL,0};
00086 static int db_fetch_rows = 200;
00087 
00088 str dlg_bridge_controller = {"sip:controller@kamailio.org", 27};
00089 
00090 /* statistic variables */
00091 int dlg_enable_stats = 1;
00092 int active_dlgs_cnt = 0;
00093 int early_dlgs_cnt = 0;
00094 stat_var *active_dlgs = 0;
00095 stat_var *processed_dlgs = 0;
00096 stat_var *expired_dlgs = 0;
00097 stat_var *failed_dlgs = 0;
00098 stat_var *early_dlgs  = 0;
00099 
00100 struct tm_binds d_tmb;
00101 struct rr_binds d_rrb;
00102 pv_spec_t timeout_avp;
00103 
00104 /* db stuff */
00105 static str db_url = str_init(DEFAULT_DB_URL);
00106 static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
00107 
00108 static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
00109       pv_value_t *res);
00110 
00111 /* commands wrappers and fixups */
00112 static int fixup_profile(void** param, int param_no);
00113 static int fixup_get_profile2(void** param, int param_no);
00114 static int fixup_get_profile3(void** param, int param_no);
00115 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
00116 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
00117 static int w_is_in_profile(struct sip_msg*, char*, char*);
00118 static int w_get_profile_size(struct sip_msg*, char*, char*, char*);
00119 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
00120 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
00121 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
00122 static int w_dlg_manage(struct sip_msg*, char*, char*);
00123 static int w_dlg_bye(struct sip_msg*, char*, char*);
00124 static int w_dlg_refer(struct sip_msg*, char*, char*);
00125 static int w_dlg_bridge(struct sip_msg*, char*, char*, char*);
00126 static int fixup_dlg_bye(void** param, int param_no);
00127 static int fixup_dlg_refer(void** param, int param_no);
00128 static int fixup_dlg_bridge(void** param, int param_no);
00129 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
00130 
00131 static cmd_export_t cmds[]={
00132    {"dlg_manage", (cmd_function)w_dlg_manage,            0,0,
00133          0, REQUEST_ROUTE },
00134    {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  1,fixup_profile,
00135          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00136    {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  2,fixup_profile,
00137          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00138    {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  1,fixup_profile,
00139          0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00140    {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  2,fixup_profile,
00141          0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00142    {"is_in_profile", (cmd_function)w_is_in_profile,      1,fixup_profile,
00143          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00144    {"is_in_profile", (cmd_function)w_is_in_profile,      2,fixup_profile,
00145          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00146    {"get_profile_size",(cmd_function)w_get_profile_size, 2,fixup_get_profile2,
00147          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00148    {"get_profile_size",(cmd_function)w_get_profile_size, 3,fixup_get_profile3,
00149          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00150    {"dlg_setflag", (cmd_function)w_dlg_setflag,          1,fixup_igp_null,
00151          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00152    {"dlg_resetflag", (cmd_function)w_dlg_resetflag,      1,fixup_igp_null,
00153          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00154    {"dlg_isflagset", (cmd_function)w_dlg_isflagset,      1,fixup_igp_null,
00155          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00156    {"dlg_bye",(cmd_function)w_dlg_bye,                   1,fixup_dlg_bye,
00157          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00158    {"dlg_refer",(cmd_function)w_dlg_refer,               2,fixup_dlg_refer,
00159          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00160    {"dlg_bridge",(cmd_function)w_dlg_bridge,             3,fixup_dlg_bridge,
00161          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00162    {"dlg_get",(cmd_function)w_dlg_get,                   3,fixup_dlg_bridge,
00163          0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00164    {"load_dlg",  (cmd_function)load_dlg,   0, 0, 0, 0},
00165    {0,0,0,0,0,0}
00166 };
00167 
00168 static param_export_t mod_params[]={
00169    { "enable_stats",          INT_PARAM, &dlg_enable_stats         },
00170    { "hash_size",             INT_PARAM, &dlg_hash_size            },
00171    { "rr_param",              STR_PARAM, &rr_param                 },
00172    { "dlg_flag",              INT_PARAM, &dlg_flag                 },
00173    { "timeout_avp",           STR_PARAM, &timeout_spec.s           },
00174    { "default_timeout",       INT_PARAM, &default_timeout          },
00175    { "dlg_extra_hdrs",        STR_PARAM, &dlg_extra_hdrs.s         },
00176    { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
00177    { "db_url",                STR_PARAM, &db_url.s                 },
00178    { "db_mode",               INT_PARAM, &dlg_db_mode              },
00179    { "table_name",            STR_PARAM, &dialog_table_name        },
00180    { "call_id_column",        STR_PARAM, &call_id_column.s         },
00181    { "from_uri_column",       STR_PARAM, &from_uri_column.s        },
00182    { "from_tag_column",       STR_PARAM, &from_tag_column.s        },
00183    { "to_uri_column",         STR_PARAM, &to_uri_column.s          },
00184    { "to_tag_column",         STR_PARAM, &to_tag_column.s          },
00185    { "h_id_column",           STR_PARAM, &h_id_column.s            },
00186    { "h_entry_column",        STR_PARAM, &h_entry_column.s         },
00187    { "state_column",          STR_PARAM, &state_column.s           },
00188    { "start_time_column",     STR_PARAM, &start_time_column.s      },
00189    { "timeout_column",        STR_PARAM, &timeout_column.s         },
00190    { "to_cseq_column",        STR_PARAM, &to_cseq_column.s         },
00191    { "from_cseq_column",      STR_PARAM, &from_cseq_column.s       },
00192    { "to_route_column",       STR_PARAM, &to_route_column.s        },
00193    { "from_route_column",     STR_PARAM, &from_route_column.s      },
00194    { "to_contact_column",     STR_PARAM, &to_contact_column.s      },
00195    { "from_contact_column",   STR_PARAM, &from_contact_column.s    },
00196    { "to_sock_column",        STR_PARAM, &to_sock_column.s         },
00197    { "from_sock_column",      STR_PARAM, &from_sock_column.s       },
00198    { "sflags_column",         STR_PARAM, &sflags_column.s          },
00199    { "toroute_column",        STR_PARAM, &toroute_column.s         },
00200    { "db_update_period",      INT_PARAM, &db_update_period         },
00201    { "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
00202    { "profiles_with_value",   STR_PARAM, &profiles_wv_s            },
00203    { "profiles_no_value",     STR_PARAM, &profiles_nv_s            },
00204    { "bridge_controller",     STR_PARAM, &dlg_bridge_controller.s  },
00205    { 0,0,0 }
00206 };
00207 
00208 
00209 static stat_export_t mod_stats[] = {
00210    {"active_dialogs" ,     STAT_NO_RESET,  &active_dlgs       },
00211    {"early_dialogs",       STAT_NO_RESET,  &early_dlgs        },
00212    {"processed_dialogs" ,  0,              &processed_dlgs    },
00213    {"expired_dialogs" ,    0,              &expired_dlgs      },
00214    {"failed_dialogs",      0,              &failed_dlgs       },
00215    {0,0,0}
00216 };
00217 
00218 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param);
00219 
00220 static mi_export_t mi_cmds[] = {
00221    { "dlg_list",           mi_print_dlgs,       0,  0,  0},
00222    { "dlg_list_ctx",       mi_print_dlgs_ctx,   0,  0,  0},
00223    { "dlg_end_dlg",        mi_terminate_dlg,    0,  0,  0},
00224    { "profile_get_size",   mi_get_profile,      0,  0,  0},
00225    { "profile_list_dlgs",  mi_profile_list,     0,  0,  0},
00226    { "dlg_bridge",         mi_dlg_bridge,       0,  0,  0},
00227    { 0, 0, 0, 0, 0}
00228 };
00229 
00230 
00231 static pv_export_t mod_items[] = {
00232    { {"DLG_count",  sizeof("DLG_count")-1}, PVT_OTHER,  pv_get_dlg_count,    0,
00233       0, 0, 0, 0 },
00234    { {"DLG_lifetime",sizeof("DLG_lifetime")-1}, PVT_OTHER, pv_get_dlg_lifetime, 0,
00235       0, 0, 0, 0 },
00236    { {"DLG_status",  sizeof("DLG_status")-1}, PVT_OTHER, pv_get_dlg_status, 0,
00237       0, 0, 0, 0 },
00238    { {"dlg_ctx",  sizeof("dlg_ctx")-1}, PVT_OTHER, pv_get_dlg_ctx,
00239       pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
00240    { {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
00241       0, pv_parse_dlg_name, 0, 0, 0 },
00242    { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00243 };
00244 
00245 struct module_exports exports= {
00246    "dialog",        /* module's name */
00247    DEFAULT_DLFLAGS, /* dlopen flags */
00248    cmds,            /* exported functions */
00249    mod_params,      /* param exports */
00250    mod_stats,       /* exported statistics */
00251    mi_cmds,         /* exported MI functions */
00252    mod_items,       /* exported pseudo-variables */
00253    0,               /* extra processes */
00254    mod_init,        /* module initialization function */
00255    0,               /* reply processing function */
00256    mod_destroy,
00257    child_init       /* per-child init function */
00258 };
00259 
00260 
00261 static int fixup_profile(void** param, int param_no)
00262 {
00263    struct dlg_profile_table *profile;
00264    pv_elem_t *model=NULL;
00265    str s;
00266 
00267    s.s = (char*)(*param);
00268    s.len = strlen(s.s);
00269    if(s.len==0) {
00270       LM_ERR("param %d is empty string!\n", param_no);
00271       return E_CFG;
00272    }
00273 
00274    if (param_no==1) {
00275       profile = search_dlg_profile( &s );
00276       if (profile==NULL) {
00277          LM_CRIT("profile <%s> not definited\n",s.s);
00278          return E_CFG;
00279       }
00280       pkg_free(*param);
00281       *param = (void*)profile;
00282       return 0;
00283    } else if (param_no==2) {
00284       if(pv_parse_format(&s ,&model) || model==NULL) {
00285          LM_ERR("wrong format [%s] for value param!\n", s.s);
00286          return E_CFG;
00287       }
00288       *param = (void*)model;
00289    }
00290    return 0;
00291 }
00292 
00293 
00294 static int fixup_get_profile2(void** param, int param_no)
00295 {
00296    pv_spec_t *sp;
00297    int ret;
00298 
00299    if (param_no==1) {
00300       return fixup_profile(param, 1);
00301    } else if (param_no==2) {
00302       ret = fixup_pvar(param);
00303       if (ret<0) return ret;
00304       sp = (pv_spec_t*)(*param);
00305       if (sp->type!=PVT_AVP && sp->type!=PVT_SCRIPTVAR) {
00306          LM_ERR("return must be an AVP or SCRIPT VAR!\n");
00307          return E_SCRIPT;
00308       }
00309    }
00310    return 0;
00311 }
00312 
00313 
00314 static int fixup_get_profile3(void** param, int param_no)
00315 {
00316    if (param_no==1) {
00317       return fixup_profile(param, 1);
00318    } else if (param_no==2) {
00319       return fixup_profile(param, 2);
00320    } else if (param_no==3) {
00321       return fixup_get_profile2( param, 2);
00322    }
00323    return 0;
00324 }
00325 
00326 
00327 
00328 int load_dlg( struct dlg_binds *dlgb )
00329 {
00330    dlgb->register_dlgcb = register_dlgcb;
00331    return 1;
00332 }
00333 
00334 
00335 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
00336       pv_value_t *res)
00337 {
00338    int n;
00339    int l;
00340    char *ch;
00341 
00342    if(msg==NULL || res==NULL)
00343       return -1;
00344 
00345    n = active_dlgs ? get_stat_val(active_dlgs) : 0;
00346    l = 0;
00347    ch = int2str( n, &l);
00348 
00349    res->rs.s = ch;
00350    res->rs.len = l;
00351 
00352    res->ri = n;
00353    res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
00354 
00355    return 0;
00356 }
00357 
00358 
00359 static int mod_init(void)
00360 {
00361    unsigned int n;
00362 
00363    if(faked_msg_init()<0)
00364       return -1;
00365 
00366    if (timeout_spec.s)
00367       timeout_spec.len = strlen(timeout_spec.s);
00368 
00369    dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
00370    db_url.len = strlen(db_url.s);
00371    call_id_column.len = strlen(call_id_column.s);
00372    from_uri_column.len = strlen(from_uri_column.s);
00373    from_tag_column.len = strlen(from_tag_column.s);
00374    to_uri_column.len = strlen(to_uri_column.s);
00375    to_tag_column.len = strlen(to_tag_column.s);
00376    h_id_column.len = strlen(h_id_column.s);
00377    h_entry_column.len = strlen(h_entry_column.s);
00378    state_column.len = strlen(state_column.s);
00379    start_time_column.len = strlen(start_time_column.s);
00380    timeout_column.len = strlen(timeout_column.s);
00381    to_cseq_column.len = strlen(to_cseq_column.s);
00382    from_cseq_column.len = strlen(from_cseq_column.s);
00383    to_route_column.len = strlen(to_route_column.s);
00384    from_route_column.len = strlen(from_route_column.s);
00385    to_contact_column.len = strlen(to_contact_column.s);
00386    from_contact_column.len = strlen(from_contact_column.s);
00387    to_sock_column.len = strlen(to_sock_column.s);
00388    from_sock_column.len = strlen(from_sock_column.s);
00389    sflags_column.len = strlen(sflags_column.s);
00390    toroute_column.len = strlen(toroute_column.s);
00391    dialog_table_name.len = strlen(dialog_table_name.s);
00392 
00393    /* param checkings */
00394    if (dlg_flag==-1) {
00395       LM_ERR("no dlg flag set!!\n");
00396       return -1;
00397    } else if (dlg_flag>MAX_FLAG) {
00398       LM_ERR("invalid dlg flag %d!!\n",dlg_flag);
00399       return -1;
00400    }
00401 
00402    if (rr_param==0 || rr_param[0]==0) {
00403       LM_ERR("empty rr_param!!\n");
00404       return -1;
00405    } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
00406       LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
00407       return -1;
00408    }
00409 
00410    if (timeout_spec.s) {
00411       if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 
00412             && (timeout_avp.type!=PVT_AVP)){
00413          LM_ERR("malformed or non AVP timeout "
00414             "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
00415          return -1;
00416       }
00417    }
00418 
00419    if (default_timeout<=0) {
00420       LM_ERR("0 default_timeout not accepted!!\n");
00421       return -1;
00422    }
00423 
00424    /* update the len of the extra headers */
00425    if (dlg_extra_hdrs.s)
00426       dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
00427 
00428    if (seq_match_mode!=SEQ_MATCH_NO_ID &&
00429    seq_match_mode!=SEQ_MATCH_FALLBACK &&
00430    seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
00431       LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
00432       return -1;
00433    }
00434 
00435    /* if statistics are disabled, prevent their registration to core */
00436    if (dlg_enable_stats==0)
00437       exports.stats = 0;
00438 
00439    /* create profile hashes */
00440    if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
00441       LM_ERR("failed to add profiles without value\n");
00442       return -1;
00443    }
00444    if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
00445       LM_ERR("failed to add profiles with value\n");
00446       return -1;
00447    }
00448 
00449    /* load the TM API */
00450    if (load_tm_api(&d_tmb)!=0) {
00451       LM_ERR("can't load TM API\n");
00452       return -1;
00453    }
00454 
00455    /* load RR API also */
00456    if (load_rr_api(&d_rrb)!=0) {
00457       LM_ERR("can't load RR API\n");
00458       return -1;
00459    }
00460 
00461    /* register callbacks*/
00462    /* listen for all incoming requests  */
00463    if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
00464       LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
00465       return -1;
00466    }
00467 
00468    /* listen for all routed requests  */
00469    if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
00470       LM_ERR("cannot register RR callback\n");
00471       return -1;
00472    }
00473 
00474    if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQ_TYPE_CB,0)<0) {
00475       LM_ERR("cannot regsiter script callback");
00476       return -1;
00477    }
00478    if (register_script_cb(dlg_cfg_cb,
00479             PRE_SCRIPT_CB|REQ_TYPE_CB,0)<0)
00480    {
00481       LM_ERR("cannot regsiter pre-script ctx callback\n");
00482       return -1;
00483    }
00484    if (register_script_cb(dlg_cfg_cb,
00485             POST_SCRIPT_CB|REQ_TYPE_CB,0)<0)
00486    {
00487       LM_ERR("cannot regsiter post-script ctx callback\n");
00488       return -1;
00489    }
00490 
00491    if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
00492       LM_ERR("failed to register timer \n");
00493       return -1;
00494    }
00495 
00496    /* init handlers */
00497    init_dlg_handlers( rr_param, dlg_flag,
00498       timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
00499 
00500    /* init timer */
00501    if (init_dlg_timer(dlg_ontimeout)!=0) {
00502       LM_ERR("cannot init timer list\n");
00503       return -1;
00504    }
00505 
00506    /* initialized the hash table */
00507    for( n=0 ; n<(8*sizeof(n)) ; n++) {
00508       if (dlg_hash_size==(1<<n))
00509          break;
00510       if (dlg_hash_size<(1<<n)) {
00511          LM_WARN("hash_size is not a power "
00512             "of 2 as it should be -> rounding from %d to %d\n",
00513             dlg_hash_size, 1<<(n-1));
00514          dlg_hash_size = 1<<(n-1);
00515       }
00516    }
00517 
00518    if ( init_dlg_table(dlg_hash_size)<0 ) {
00519       LM_ERR("failed to create hash table\n");
00520       return -1;
00521    }
00522 
00523    /* if a database should be used to store the dialogs' information */
00524    if (dlg_db_mode==DB_MODE_NONE) {
00525       db_url.s = 0; db_url.len = 0;
00526    } else {
00527       if (dlg_db_mode!=DB_MODE_REALTIME &&
00528       dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
00529          LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
00530          return -1;
00531       }
00532       if ( !db_url.s || db_url.len==0 ) {
00533          LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
00534          return -1;
00535       }
00536       if (init_dlg_db(&db_url, dlg_hash_size, db_update_period,db_fetch_rows)!=0) {
00537          LM_ERR("failed to initialize the DB support\n");
00538          return -1;
00539       }
00540       run_load_callbacks();
00541    }
00542 
00543    destroy_dlg_callbacks( DLGCB_LOADED );
00544 
00545    return 0;
00546 }
00547 
00548 
00549 static int child_init(int rank)
00550 {
00551    if (rank==1) {
00552       if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
00553       if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
00554    }
00555 
00556    if ( (dlg_db_mode==DB_MODE_REALTIME && (rank>0 || rank==PROC_TIMER)) ||
00557    (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ||
00558    (dlg_db_mode==DB_MODE_DELAYED && (rank==PROC_MAIN || rank==PROC_TIMER ||
00559    rank>0) )){
00560       if ( dlg_connect_db(&db_url) ) {
00561          LM_ERR("failed to connect to database (rank=%d)\n",rank);
00562          return -1;
00563       }
00564    }
00565 
00566    /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
00567     * for the rest of the processes will be the same as DB_MODE_NONE */
00568    if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
00569       dlg_db_mode = DB_MODE_NONE;
00570 
00571    return 0;
00572 }
00573 
00574 
00575 static void mod_destroy(void)
00576 {
00577    if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
00578       dialog_update_db(0, 0);
00579       destroy_dlg_db();
00580    }
00581    /* no DB interaction from now on */
00582    dlg_db_mode = DB_MODE_NONE;
00583    destroy_dlg_table();
00584    destroy_dlg_timer();
00585    destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
00586    destroy_dlg_handlers();
00587    destroy_dlg_profiles();
00588 }
00589 
00590 
00591 
00592 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
00593 {
00594    pv_elem_t *pve;
00595    str val_s;
00596 
00597    pve = (pv_elem_t *)value;
00598 
00599    if (((struct dlg_profile_table*)profile)->has_value) {
00600       if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
00601       val_s.len == 0 || val_s.s == NULL) {
00602          LM_WARN("cannot get string for value\n");
00603          return -1;
00604       }
00605       if ( set_dlg_profile( msg, &val_s,
00606       (struct dlg_profile_table*)profile) < 0 ) {
00607          LM_ERR("failed to set profile");
00608          return -1;
00609       }
00610    } else {
00611       if ( set_dlg_profile( msg, NULL,
00612       (struct dlg_profile_table*)profile) < 0 ) {
00613          LM_ERR("failed to set profile");
00614          return -1;
00615       }
00616    }
00617    return 1;
00618 }
00619 
00620 
00621 
00622 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
00623 {
00624    pv_elem_t *pve;
00625    str val_s;
00626 
00627    pve = (pv_elem_t *)value;
00628 
00629    if (((struct dlg_profile_table*)profile)->has_value) {
00630       if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
00631       val_s.len == 0 || val_s.s == NULL) {
00632          LM_WARN("cannot get string for value\n");
00633          return -1;
00634       }
00635       if ( unset_dlg_profile( msg, &val_s,
00636       (struct dlg_profile_table*)profile) < 0 ) {
00637          LM_ERR("failed to unset profile");
00638          return -1;
00639       }
00640    } else {
00641       if ( unset_dlg_profile( msg, NULL,
00642       (struct dlg_profile_table*)profile) < 0 ) {
00643          LM_ERR("failed to unset profile");
00644          return -1;
00645       }
00646    }
00647    return 1;
00648 }
00649 
00650 
00651 
00652 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
00653 {
00654    pv_elem_t *pve;
00655    str val_s;
00656 
00657    pve = (pv_elem_t *)value;
00658 
00659    if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
00660       if ( pv_printf_s(msg, pve, &val_s)!=0 || 
00661       val_s.len == 0 || val_s.s == NULL) {
00662          LM_WARN("cannot get string for value\n");
00663          return -1;
00664       }
00665       return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
00666          &val_s);
00667    } else {
00668       return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
00669          NULL);
00670    }
00671 }
00672 
00673 
00674 static int w_get_profile_size(struct sip_msg *msg, char *profile, 
00675                                        char *value, char *result)
00676 {
00677    pv_elem_t *pve;
00678    str val_s;
00679    pv_spec_t *sp_dest;
00680    unsigned int size;
00681    pv_value_t val;
00682 
00683    pve = (pv_elem_t *)value;
00684    sp_dest = (pv_spec_t *)result;
00685 
00686    if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
00687       if ( pv_printf_s(msg, pve, &val_s)!=0 || 
00688       val_s.len == 0 || val_s.s == NULL) {
00689          LM_WARN("cannot get string for value\n");
00690          return -1;
00691       }
00692       size = get_profile_size( (struct dlg_profile_table*)profile ,&val_s );
00693    } else {
00694       size = get_profile_size( (struct dlg_profile_table*)profile, NULL );
00695    }
00696 
00697    memset(&val, 0, sizeof(pv_value_t));
00698    val.flags = PV_VAL_INT|PV_TYPE_INT;
00699    val.ri = (int)size;
00700 
00701    if(sp_dest->setf(msg, &sp_dest->pvp, (int)EQ_T, &val)<0)
00702    {
00703       LM_ERR("setting profile PV failed\n");
00704       return -1;
00705    }
00706 
00707    return 1;
00708 }
00709 
00710 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
00711 {
00712    struct dlg_cell *dlg;
00713    int val;
00714 
00715    if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
00716    {
00717       LM_ERR("no flag value\n");
00718       return -1;
00719    }
00720    if(val<0 || val>31)
00721       return -1;
00722    if ( (dlg=dlg_get_ctx_dialog())==NULL )
00723       return -1;
00724 
00725    dlg->sflags |= 1<<val;
00726    return 1;
00727 }
00728 
00729 
00730 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
00731 {
00732    struct dlg_cell *dlg;
00733    int val;
00734 
00735    if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
00736    {
00737       LM_ERR("no flag value\n");
00738       return -1;
00739    }
00740    if(val<0 || val>31)
00741       return -1;
00742 
00743    if ( (dlg=dlg_get_ctx_dialog())==NULL )
00744       return -1;
00745 
00746    dlg->sflags &= ~(1<<val);
00747    return 1;
00748 }
00749 
00750 
00751 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
00752 {
00753    struct dlg_cell *dlg;
00754    int val;
00755 
00756    if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
00757    {
00758       LM_ERR("no flag value\n");
00759       return -1;
00760    }
00761    if(val<0 || val>31)
00762       return -1;
00763 
00764    if ( (dlg=dlg_get_ctx_dialog())==NULL )
00765       return -1;
00766 
00767    return (dlg->sflags&(1<<val))?1:-1;
00768 }
00769 
00770 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
00771 {
00772    str tag;
00773    int backup_mode;
00774 
00775    if( (msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL )
00776    {
00777       LM_ERR("bad TO header\n");
00778       return -1;
00779    }
00780    tag = get_to(msg)->tag_value;
00781    if(tag.s!=0 && tag.len!=0)
00782    {
00783       backup_mode = seq_match_mode;
00784       seq_match_mode = SEQ_MATCH_NO_ID;
00785       dlg_onroute(msg, NULL, NULL);
00786       seq_match_mode = backup_mode;
00787    } else {
00788       if(dlg_new_dialog(msg, 0)!=0)
00789          return -1;
00790    }
00791    return 1;
00792 }
00793 
00794 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
00795 {
00796    struct dlg_cell *dlg;
00797    int n;
00798 
00799    dlg = dlg_get_ctx_dialog();
00800    if(dlg==NULL)
00801       return -1;
00802    
00803    n = (int)(long)side;
00804    if(n==1)
00805    {
00806       if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
00807          return -1;
00808       return 1;
00809    } else if(n==2) {
00810       if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
00811          return -1;
00812       return 1;
00813    } else {
00814       if(dlg_bye_all(dlg, NULL)!=0)
00815          return -1;
00816       return 1;
00817    }
00818 }
00819 
00820 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
00821 {
00822    struct dlg_cell *dlg;
00823    int n;
00824    str st = {0,0};
00825 
00826    dlg = dlg_get_ctx_dialog();
00827    if(dlg==NULL)
00828       return -1;
00829    
00830    n = (int)(long)side;
00831 
00832    if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
00833    {
00834       LM_ERR("unable to get To\n");
00835       return -1;
00836    }
00837    if(st.s==NULL || st.len == 0)
00838    {
00839       LM_ERR("invalid To parameter\n");
00840       return -1;
00841    }
00842    if(n==1)
00843    {
00844       if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
00845          return -1;
00846    } else {
00847       if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
00848          return -1;
00849    }
00850    return 1;
00851 }
00852 
00853 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
00854 {
00855    str sf = {0,0};
00856    str st = {0,0};
00857    str so = {0,0};
00858 
00859    if(from==0 || to==0 || op==0)
00860    {
00861       LM_ERR("invalid parameters\n");
00862       return -1;
00863    }
00864 
00865    if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
00866    {
00867       LM_ERR("unable to get From\n");
00868       return -1;
00869    }
00870    if(sf.s==NULL || sf.len == 0)
00871    {
00872       LM_ERR("invalid From parameter\n");
00873       return -1;
00874    }
00875    if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
00876    {
00877       LM_ERR("unable to get To\n");
00878       return -1;
00879    }
00880    if(st.s==NULL || st.len == 0)
00881    {
00882       LM_ERR("invalid To parameter\n");
00883       return -1;
00884    }
00885    if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
00886    {
00887       LM_ERR("unable to get OP\n");
00888       return -1;
00889    }
00890 
00891    if(dlg_bridge(&sf, &st, &so)!=0)
00892       return -1;
00893    return 1;
00894 }
00895 
00896 
00897 static int fixup_dlg_bye(void** param, int param_no)
00898 {
00899    char *val;
00900    int n = 0;
00901 
00902    if (param_no==1) {
00903       val = (char*)*param;
00904       if (strcasecmp(val,"all")==0) {
00905          n = 0;
00906       } else if (strcasecmp(val,"caller")==0) {
00907          n = 1;
00908       } else if (strcasecmp(val,"callee")==0) {
00909          n = 2;
00910       } else {
00911          LM_ERR("invalid param \"%s\"\n", val);
00912          return E_CFG;
00913       }
00914       pkg_free(*param);
00915       *param=(void*)(long)n;
00916    } else {
00917       LM_ERR("called with parameter != 1\n");
00918       return E_BUG;
00919    }
00920    return 0;
00921 }
00922 
00923 static int fixup_dlg_refer(void** param, int param_no)
00924 {
00925    char *val;
00926    int n = 0;
00927 
00928    if (param_no==1) {
00929       val = (char*)*param;
00930       if (strcasecmp(val,"caller")==0) {
00931          n = 1;
00932       } else if (strcasecmp(val,"callee")==0) {
00933          n = 2;
00934       } else {
00935          LM_ERR("invalid param \"%s\"\n", val);
00936          return E_CFG;
00937       }
00938       pkg_free(*param);
00939       *param=(void*)(long)n;
00940    } else if (param_no==2) {
00941       return fixup_spve_null(param, 1);
00942    } else {
00943       LM_ERR("called with parameter idx %d\n", param_no);
00944       return E_BUG;
00945    }
00946    return 0;
00947 }
00948 
00949 static int fixup_dlg_bridge(void** param, int param_no)
00950 {
00951    if (param_no>=1 && param_no<=3) {
00952       return fixup_spve_null(param, 1);
00953    } else {
00954       LM_ERR("called with parameter idx %d\n", param_no);
00955       return E_BUG;
00956    }
00957    return 0;
00958 }
00959 
00960 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
00961 {
00962    struct dlg_cell *dlg = NULL;
00963    str sc = {0,0};
00964    str sf = {0,0};
00965    str st = {0,0};
00966    unsigned int dir = 0;
00967 
00968    if(ci==0 || ft==0 || tt==0)
00969    {
00970       LM_ERR("invalid parameters\n");
00971       return -1;
00972    }
00973 
00974    if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
00975    {
00976       LM_ERR("unable to get Call-ID\n");
00977       return -1;
00978    }
00979    if(sc.s==NULL || sc.len == 0)
00980    {
00981       LM_ERR("invalid Call-ID parameter\n");
00982       return -1;
00983    }
00984    if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
00985    {
00986       LM_ERR("unable to get From tag\n");
00987       return -1;
00988    }
00989    if(sf.s==NULL || sf.len == 0)
00990    {
00991       LM_ERR("invalid From tag parameter\n");
00992       return -1;
00993    }
00994    if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
00995    {
00996       LM_ERR("unable to get To Tag\n");
00997       return -1;
00998    }
00999    if(st.s==NULL || st.len == 0)
01000    {
01001       LM_ERR("invalid To tag parameter\n");
01002       return -1;
01003    }
01004 
01005    dlg = get_dlg(&sc, &sf, &st, &dir);
01006    if(dlg==NULL)
01007       return -1;
01008    current_dlg_pointer = dlg;
01009    _dlg_ctx.dlg = dlg;
01010    _dlg_ctx.dir = dir;
01011    return 1;
01012 }
01013 
01014 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
01015 {
01016    str from = {0,0};
01017    str to = {0,0};
01018    str op = {0,0};
01019    struct mi_node* node;
01020 
01021    node = cmd_tree->node.kids;
01022    if(node == NULL)
01023       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01024    from = node->value;
01025    if(from.len<=0 || from.s==NULL)
01026    {
01027       LM_ERR("bad From value\n");
01028       return init_mi_tree( 500, "Bad From value", 14);
01029    }
01030 
01031    node = node->next;
01032    if(node == NULL)
01033       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01034    to = node->value;
01035    if(to.len<=0 || to.s == NULL)
01036    {
01037       return init_mi_tree(500, "Bad To value", 12);
01038    }
01039 
01040    node= node->next;
01041    if(node != NULL)
01042    {
01043       op = node->value;
01044       if(op.len<=0 || op.s==NULL)
01045       {
01046          return init_mi_tree(500, "Bad OP value", 12);
01047       }
01048    }
01049 
01050    if(dlg_bridge(&from, &to, &op)!=0)
01051       return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
01052 
01053    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
01054 }
01055 
01056 

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6