dialog.c

00001 /*
00002  * $Id$
00003  *
00004  * dialog module - basic support for dialog tracking
00005  *
00006  * Copyright (C) 2006 Voice Sistem SRL
00007  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
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  *  2006-04-14 initial version (bogdan)
00028  *  2006-11-28 Added statistic support for the number of early and failed
00029  *              dialogs. (Jeffrey Magder - SOMA Networks) 
00030  *  2007-04-30 added dialog matching without DID (dialog ID), but based only
00031  *              on RFC3261 elements - based on an original patch submitted 
00032  *              by Michel Bensoussan <michel@extricom.com> (bogdan)
00033  *  2007-05-15 added saving dialogs' information to database (ancuta)
00034  *  2007-07-04 added saving dialog cseq, contact, record route 
00035  *              and bind_addresses(sock_info) for caller and callee (ancuta)
00036  *  2008-04-14 added new type of callback to be triggered when dialogs are 
00037  *              loaded from DB (bogdan)
00038  *  2010-06-16 added sip-router rpc interface (osas)
00039  */
00040 
00055 #include <stdio.h>
00056 #include <string.h>
00057 #include <stdlib.h>
00058 #include <sys/time.h>
00059 
00060 #include "../../sr_module.h"
00061 #include "../../lib/srdb1/db.h"
00062 #include "../../dprint.h"
00063 #include "../../error.h"
00064 #include "../../ut.h"
00065 #include "../../pvar.h"
00066 #include "../../mod_fix.h"
00067 #include "../../script_cb.h"
00068 #include "../../lib/kcore/faked_msg.h"
00069 #include "../../hashes.h"
00070 #include "../../lib/kcore/kstats_wrapper.h"
00071 #include "../../mem/mem.h"
00072 #include "../../lib/kmi/mi.h"
00073 #include "../../timer_proc.h"
00074 #include "../../lvalue.h"
00075 #include "../../parser/parse_to.h"
00076 #include "../../modules/tm/tm_load.h"
00077 #include "../../rpc_lookup.h"
00078 #include "../rr/api.h"
00079 #include "dlg_hash.h"
00080 #include "dlg_timer.h"
00081 #include "dlg_handlers.h"
00082 #include "dlg_load.h"
00083 #include "dlg_cb.h"
00084 #include "dlg_db_handler.h"
00085 #include "dlg_req_within.h"
00086 #include "dlg_profile.h"
00087 #include "dlg_var.h"
00088 #include "dlg_transfer.h"
00089 
00090 MODULE_VERSION
00091 
00092 
00093 static int mod_init(void);
00094 static int child_init(int rank);
00095 static void mod_destroy(void);
00096 
00097 /* module parameter */
00098 static int dlg_hash_size = 4096;
00099 static char* rr_param = "did";
00100 static int dlg_flag = -1;
00101 static str timeout_spec = {NULL, 0};
00102 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
00103 static int seq_match_mode = SEQ_MATCH_STRICT_ID;
00104 static char* profiles_wv_s = NULL;
00105 static char* profiles_nv_s = NULL;
00106 str dlg_extra_hdrs = {NULL,0};
00107 static int db_fetch_rows = 200;
00108 int initial_cbs_inscript = 1;
00109 int dlg_wait_ack = 1;
00110 
00111 int dlg_event_rt[DLG_EVENTRT_MAX];
00112 
00113 str dlg_bridge_controller = {"sip:controller@kamailio.org", 27};
00114 
00115 str ruri_pvar_param = {"$ru", 3};
00116 pv_elem_t * ruri_param_model = NULL;
00117 
00118 /* statistic variables */
00119 int dlg_enable_stats = 1;
00120 int active_dlgs_cnt = 0;
00121 int early_dlgs_cnt = 0;
00122 int detect_spirals = 1;
00123 int dlg_send_bye = 0;
00124 stat_var *active_dlgs = 0;
00125 stat_var *processed_dlgs = 0;
00126 stat_var *expired_dlgs = 0;
00127 stat_var *failed_dlgs = 0;
00128 stat_var *early_dlgs  = 0;
00129 
00130 struct tm_binds d_tmb;
00131 struct rr_binds d_rrb;
00132 pv_spec_t timeout_avp;
00133 
00134 int dlg_db_mode_param = DB_MODE_NONE;
00135 
00136 str dlg_xavp_cfg = {0};
00137 int dlg_ka_timer = 0;
00138 int dlg_ka_interval = 0;
00139 
00140 /* db stuff */
00141 static str db_url = str_init(DEFAULT_DB_URL);
00142 static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
00143 
00144 static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
00145                 pv_value_t *res);
00146 
00147 void dlg_ka_timer_exec(unsigned int ticks, void* param);
00148 
00149 /* commands wrappers and fixups */
00150 static int fixup_profile(void** param, int param_no);
00151 static int fixup_get_profile2(void** param, int param_no);
00152 static int fixup_get_profile3(void** param, int param_no);
00153 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
00154 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
00155 static int w_is_in_profile(struct sip_msg*, char*, char*);
00156 static int w_get_profile_size2(struct sip_msg*, char*, char*);
00157 static int w_get_profile_size3(struct sip_msg*, char*, char*, char*);
00158 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
00159 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
00160 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
00161 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2);
00162 static int w_dlg_manage(struct sip_msg*, char*, char*);
00163 static int w_dlg_bye(struct sip_msg*, char*, char*);
00164 static int w_dlg_refer(struct sip_msg*, char*, char*);
00165 static int w_dlg_bridge(struct sip_msg*, char*, char*, char*);
00166 static int w_dlg_set_timeout(struct sip_msg*, char*, char*, char*);
00167 static int fixup_dlg_bye(void** param, int param_no);
00168 static int fixup_dlg_refer(void** param, int param_no);
00169 static int fixup_dlg_bridge(void** param, int param_no);
00170 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
00171 static int w_is_known_dlg(struct sip_msg *);
00172 
00173 static cmd_export_t cmds[]={
00174         {"dlg_manage", (cmd_function)w_dlg_manage,            0,0,
00175                         0, REQUEST_ROUTE },
00176         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  1,fixup_profile,
00177                         0, ANY_ROUTE },
00178         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  2,fixup_profile,
00179                         0, ANY_ROUTE },
00180         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  1,fixup_profile,
00181                         0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00182         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  2,fixup_profile,
00183                         0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
00184         {"is_in_profile", (cmd_function)w_is_in_profile,      1,fixup_profile,
00185                         0, ANY_ROUTE },
00186         {"is_in_profile", (cmd_function)w_is_in_profile,      2,fixup_profile,
00187                         0, ANY_ROUTE },
00188         {"get_profile_size",(cmd_function)w_get_profile_size2, 2,fixup_get_profile2,
00189                         0, ANY_ROUTE },
00190         {"get_profile_size",(cmd_function)w_get_profile_size3, 3,fixup_get_profile3,
00191                         0, ANY_ROUTE },
00192         {"dlg_setflag", (cmd_function)w_dlg_setflag,          1,fixup_igp_null,
00193                         0, ANY_ROUTE },
00194         {"dlg_resetflag", (cmd_function)w_dlg_resetflag,      1,fixup_igp_null,
00195                         0, ANY_ROUTE },
00196         {"dlg_isflagset", (cmd_function)w_dlg_isflagset,      1,fixup_igp_null,
00197                         0, ANY_ROUTE },
00198         {"dlg_bye",(cmd_function)w_dlg_bye,                   1,fixup_dlg_bye,
00199                         0, ANY_ROUTE },
00200         {"dlg_refer",(cmd_function)w_dlg_refer,               2,fixup_dlg_refer,
00201                         0, ANY_ROUTE },
00202         {"dlg_bridge",(cmd_function)w_dlg_bridge,             3,fixup_dlg_bridge,
00203                         0, ANY_ROUTE },
00204         {"dlg_get",(cmd_function)w_dlg_get,                   3,fixup_dlg_bridge,
00205                         0, ANY_ROUTE },
00206         {"is_known_dlg", (cmd_function)w_is_known_dlg,        0, NULL,
00207                         0, ANY_ROUTE },
00208         {"dlg_set_timeout", (cmd_function)w_dlg_set_timeout,  1,fixup_igp_null,
00209                         0, ANY_ROUTE },
00210         {"dlg_set_timeout", (cmd_function)w_dlg_set_timeout,  3,fixup_igp_all,
00211                         0, ANY_ROUTE },
00212         {"dlg_set_property", (cmd_function)w_dlg_set_property,1,fixup_spve_null,
00213                         0, ANY_ROUTE },
00214         {"load_dlg",  (cmd_function)load_dlg,   0, 0, 0, 0},
00215         {0,0,0,0,0,0}
00216 };
00217 
00218 static param_export_t mod_params[]={
00219         { "enable_stats",          INT_PARAM, &dlg_enable_stats         },
00220         { "hash_size",             INT_PARAM, &dlg_hash_size            },
00221         { "rr_param",              STR_PARAM, &rr_param                 },
00222         { "dlg_flag",              INT_PARAM, &dlg_flag                 },
00223         { "timeout_avp",           STR_PARAM, &timeout_spec.s           },
00224         { "default_timeout",       INT_PARAM, &default_timeout          },
00225         { "dlg_extra_hdrs",        STR_PARAM, &dlg_extra_hdrs.s         },
00226         { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
00227         { "detect_spirals",        INT_PARAM, &detect_spirals,          },
00228         { "db_url",                STR_PARAM, &db_url.s                 },
00229         { "db_mode",               INT_PARAM, &dlg_db_mode_param        },
00230         { "table_name",            STR_PARAM, &dialog_table_name        },
00231         { "call_id_column",        STR_PARAM, &call_id_column.s         },
00232         { "from_uri_column",       STR_PARAM, &from_uri_column.s        },
00233         { "from_tag_column",       STR_PARAM, &from_tag_column.s        },
00234         { "to_uri_column",         STR_PARAM, &to_uri_column.s          },
00235         { "to_tag_column",         STR_PARAM, &to_tag_column.s          },
00236         { "h_id_column",           STR_PARAM, &h_id_column.s            },
00237         { "h_entry_column",        STR_PARAM, &h_entry_column.s         },
00238         { "state_column",          STR_PARAM, &state_column.s           },
00239         { "start_time_column",     STR_PARAM, &start_time_column.s      },
00240         { "timeout_column",        STR_PARAM, &timeout_column.s         },
00241         { "to_cseq_column",        STR_PARAM, &to_cseq_column.s         },
00242         { "from_cseq_column",      STR_PARAM, &from_cseq_column.s       },
00243         { "to_route_column",       STR_PARAM, &to_route_column.s        },
00244         { "from_route_column",     STR_PARAM, &from_route_column.s      },
00245         { "to_contact_column",     STR_PARAM, &to_contact_column.s      },
00246         { "from_contact_column",   STR_PARAM, &from_contact_column.s    },
00247         { "to_sock_column",        STR_PARAM, &to_sock_column.s         },
00248         { "from_sock_column",      STR_PARAM, &from_sock_column.s       },
00249         { "sflags_column",         STR_PARAM, &sflags_column.s          },
00250         { "toroute_name_column",   STR_PARAM, &toroute_name_column.s    },
00251 
00252         { "vars_table_name",       STR_PARAM, &dialog_vars_table_name   },
00253         { "vars_h_id_column",      STR_PARAM, &vars_h_id_column.s       },
00254         { "vars_h_entry_column",   STR_PARAM, &vars_h_entry_column.s    },
00255         { "vars_key_column",       STR_PARAM, &vars_key_column.s        },
00256         { "vars_value_column",     STR_PARAM, &vars_value_column.s      },
00257 
00258         { "db_update_period",      INT_PARAM, &db_update_period         },
00259         { "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
00260         { "profiles_with_value",   STR_PARAM, &profiles_wv_s            },
00261         { "profiles_no_value",     STR_PARAM, &profiles_nv_s            },
00262         { "bridge_controller",     STR_PARAM, &dlg_bridge_controller.s  },
00263         { "ruri_pvar",             STR_PARAM, &ruri_pvar_param.s        },
00264         { "initial_cbs_inscript",  INT_PARAM, &initial_cbs_inscript     },
00265         { "send_bye",              INT_PARAM, &dlg_send_bye             },
00266         { "wait_ack",              INT_PARAM, &dlg_wait_ack             },
00267         { "xavp_cfg",              STR_PARAM, &dlg_xavp_cfg.s           },
00268         { "ka_timer",              INT_PARAM, &dlg_ka_timer             },
00269         { "ka_interval",           INT_PARAM, &dlg_ka_interval          },
00270         { 0,0,0 }
00271 };
00272 
00273 
00274 static stat_export_t mod_stats[] = {
00275         {"active_dialogs" ,     STAT_NO_RESET,  &active_dlgs       },
00276         {"early_dialogs",       STAT_NO_RESET,  &early_dlgs        },
00277         {"processed_dialogs" ,  0,              &processed_dlgs    },
00278         {"expired_dialogs" ,    0,              &expired_dlgs      },
00279         {"failed_dialogs",      0,              &failed_dlgs       },
00280         {0,0,0}
00281 };
00282 
00283 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param);
00284 
00285 static mi_export_t mi_cmds[] = {
00286         { "dlg_list",           mi_print_dlgs,       0,  0,  0},
00287         { "dlg_list_ctx",       mi_print_dlgs_ctx,   0,  0,  0},
00288         { "dlg_end_dlg",        mi_terminate_dlg,    0,  0,  0},
00289         { "dlg_terminate_dlg",  mi_terminate_dlgs,   0,  0,  0},
00290         { "profile_get_size",   mi_get_profile,      0,  0,  0},
00291         { "profile_list_dlgs",  mi_profile_list,     0,  0,  0},
00292         { "dlg_bridge",         mi_dlg_bridge,       0,  0,  0},
00293         { 0, 0, 0, 0, 0}
00294 };
00295 
00296 static rpc_export_t rpc_methods[];
00297 
00298 static pv_export_t mod_items[] = {
00299         { {"DLG_count",  sizeof("DLG_count")-1}, PVT_OTHER,  pv_get_dlg_count,    0,
00300                 0, 0, 0, 0 },
00301         { {"DLG_lifetime",sizeof("DLG_lifetime")-1}, PVT_OTHER, pv_get_dlg_lifetime, 0,
00302                 0, 0, 0, 0 },
00303         { {"DLG_status",  sizeof("DLG_status")-1}, PVT_OTHER, pv_get_dlg_status, 0,
00304                 0, 0, 0, 0 },
00305         { {"dlg_ctx",  sizeof("dlg_ctx")-1}, PVT_OTHER, pv_get_dlg_ctx,
00306                 pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
00307         { {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
00308                 0, pv_parse_dlg_name, 0, 0, 0 },
00309         { {"dlg_var", sizeof("dlg_var")-1}, PVT_OTHER, pv_get_dlg_variable,
00310                 pv_set_dlg_variable,    pv_parse_dialog_var_name, 0, 0, 0},
00311         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00312 };
00313 
00314 struct module_exports exports= {
00315         "dialog",        /* module's name */
00316         DEFAULT_DLFLAGS, /* dlopen flags */
00317         cmds,            /* exported functions */
00318         mod_params,      /* param exports */
00319         mod_stats,       /* exported statistics */
00320         mi_cmds,         /* exported MI functions */
00321         mod_items,       /* exported pseudo-variables */
00322         0,               /* extra processes */
00323         mod_init,        /* module initialization function */
00324         0,               /* reply processing function */
00325         mod_destroy,
00326         child_init       /* per-child init function */
00327 };
00328 
00329 
00330 static int fixup_profile(void** param, int param_no)
00331 {
00332         struct dlg_profile_table *profile;
00333         pv_elem_t *model=NULL;
00334         str s;
00335 
00336         s.s = (char*)(*param);
00337         s.len = strlen(s.s);
00338         if(s.len==0) {
00339                 LM_ERR("param %d is empty string!\n", param_no);
00340                 return E_CFG;
00341         }
00342 
00343         if (param_no==1) {
00344                 profile = search_dlg_profile( &s );
00345                 if (profile==NULL) {
00346                         LM_CRIT("profile <%s> not definited\n",s.s);
00347                         return E_CFG;
00348                 }
00349                 pkg_free(*param);
00350                 *param = (void*)profile;
00351                 return 0;
00352         } else if (param_no==2) {
00353                 if(pv_parse_format(&s ,&model) || model==NULL) {
00354                         LM_ERR("wrong format [%s] for value param!\n", s.s);
00355                         return E_CFG;
00356                 }
00357                 *param = (void*)model;
00358         }
00359         return 0;
00360 }
00361 
00362 
00363 static int fixup_get_profile2(void** param, int param_no)
00364 {
00365         pv_spec_t *sp;
00366         int ret;
00367 
00368         if (param_no==1) {
00369                 return fixup_profile(param, 1);
00370         } else if (param_no==2) {
00371                 ret = fixup_pvar_null(param, 1);
00372                 if (ret<0) return ret;
00373                 sp = (pv_spec_t*)(*param);
00374                 if (sp->type!=PVT_AVP && sp->type!=PVT_SCRIPTVAR) {
00375                         LM_ERR("return must be an AVP or SCRIPT VAR!\n");
00376                         return E_SCRIPT;
00377                 }
00378         }
00379         return 0;
00380 }
00381 
00382 
00383 static int fixup_get_profile3(void** param, int param_no)
00384 {
00385         if (param_no==1) {
00386                 return fixup_profile(param, 1);
00387         } else if (param_no==2) {
00388                 return fixup_profile(param, 2);
00389         } else if (param_no==3) {
00390                 return fixup_get_profile2( param, 2);
00391         }
00392         return 0;
00393 }
00394 
00395 
00396 
00397 int load_dlg( struct dlg_binds *dlgb )
00398 {
00399         dlgb->register_dlgcb = register_dlgcb;
00400         dlgb->terminate_dlg = dlg_bye_all;
00401         dlgb->set_dlg_var = set_dlg_variable;
00402         dlgb->get_dlg_var = get_dlg_variable;
00403         return 1;
00404 }
00405 
00406 
00407 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
00408                 pv_value_t *res)
00409 {
00410         int n;
00411         int l;
00412         char *ch;
00413 
00414         if(msg==NULL || res==NULL)
00415                 return -1;
00416 
00417         n = active_dlgs ? get_stat_val(active_dlgs) : 0;
00418         l = 0;
00419         ch = int2str( n, &l);
00420 
00421         res->rs.s = ch;
00422         res->rs.len = l;
00423 
00424         res->ri = n;
00425         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
00426 
00427         return 0;
00428 }
00429 
00430 
00431 static int mod_init(void)
00432 {
00433         unsigned int n;
00434 
00435         dlg_event_rt[DLG_EVENTRT_START] = route_lookup(&event_rt, "dialog:start");
00436         dlg_event_rt[DLG_EVENTRT_END] = route_lookup(&event_rt, "dialog:end");
00437         dlg_event_rt[DLG_EVENTRT_FAILED] = route_lookup(&event_rt, "dialog:failed");
00438 
00439 #ifdef STATISTICS
00440         /* register statistics */
00441         if (register_module_stats( exports.name, mod_stats)!=0 ) {
00442                 LM_ERR("failed to register core statistics\n");
00443                 return -1;
00444         }
00445 #endif
00446 
00447         if(register_mi_mod(exports.name, mi_cmds)!=0)
00448         {
00449                 LM_ERR("failed to register MI commands\n");
00450                 return -1;
00451         }
00452 
00453         if (rpc_register_array(rpc_methods)!=0) {
00454                 LM_ERR("failed to register RPC commands\n");
00455                 return -1;
00456         }
00457 
00458         if(faked_msg_init()<0)
00459                 return -1;
00460 
00461         if (timeout_spec.s)
00462                 timeout_spec.len = strlen(timeout_spec.s);
00463 
00464         dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
00465         db_url.len = strlen(db_url.s);
00466         call_id_column.len = strlen(call_id_column.s);
00467         from_uri_column.len = strlen(from_uri_column.s);
00468         from_tag_column.len = strlen(from_tag_column.s);
00469         to_uri_column.len = strlen(to_uri_column.s);
00470         to_tag_column.len = strlen(to_tag_column.s);
00471         h_id_column.len = strlen(h_id_column.s);
00472         h_entry_column.len = strlen(h_entry_column.s);
00473         state_column.len = strlen(state_column.s);
00474         start_time_column.len = strlen(start_time_column.s);
00475         timeout_column.len = strlen(timeout_column.s);
00476         to_cseq_column.len = strlen(to_cseq_column.s);
00477         from_cseq_column.len = strlen(from_cseq_column.s);
00478         to_route_column.len = strlen(to_route_column.s);
00479         from_route_column.len = strlen(from_route_column.s);
00480         to_contact_column.len = strlen(to_contact_column.s);
00481         from_contact_column.len = strlen(from_contact_column.s);
00482         to_sock_column.len = strlen(to_sock_column.s);
00483         from_sock_column.len = strlen(from_sock_column.s);
00484         sflags_column.len = strlen(sflags_column.s);
00485         toroute_name_column.len = strlen(toroute_name_column.s);
00486         dialog_table_name.len = strlen(dialog_table_name.s);
00487 
00488         dialog_vars_table_name.len = strlen(dialog_vars_table_name.s);
00489         vars_h_id_column.len = strlen(vars_h_id_column.s);
00490         vars_h_entry_column.len = strlen(vars_h_entry_column.s);
00491         vars_key_column.len = strlen(vars_key_column.s);
00492         vars_value_column.len = strlen(vars_value_column.s);
00493 
00494         if(dlg_xavp_cfg.s!=NULL)
00495                 dlg_xavp_cfg.len = strlen(dlg_xavp_cfg.s);
00496 
00497         /* param checkings */
00498         if (dlg_flag==-1) {
00499                 LM_ERR("no dlg flag set!!\n");
00500                 return -1;
00501         } else if (dlg_flag>MAX_FLAG) {
00502                 LM_ERR("invalid dlg flag %d!!\n",dlg_flag);
00503                 return -1;
00504         }
00505 
00506         if (rr_param==0 || rr_param[0]==0) {
00507                 LM_ERR("empty rr_param!!\n");
00508                 return -1;
00509         } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
00510                 LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
00511                 return -1;
00512         }
00513 
00514         if (timeout_spec.s) {
00515                 if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 
00516                                 && (timeout_avp.type!=PVT_AVP)){
00517                         LM_ERR("malformed or non AVP timeout "
00518                                 "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
00519                         return -1;
00520                 }
00521         }
00522 
00523         if (default_timeout<=0) {
00524                 LM_ERR("0 default_timeout not accepted!!\n");
00525                 return -1;
00526         }
00527 
00528         if (ruri_pvar_param.s==NULL || *ruri_pvar_param.s=='\0') {
00529                 LM_ERR("invalid r-uri PV string\n");
00530                 return -1;
00531         }
00532         ruri_pvar_param.len = strlen(ruri_pvar_param.s);
00533         if(pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
00534                                 || ruri_param_model==NULL) {
00535                 LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
00536                 return -1;
00537         }
00538 
00539         if (initial_cbs_inscript != 0 && initial_cbs_inscript != 1) {
00540                 LM_ERR("invalid parameter for running initial callbacks in-script"
00541                                 " (must be either 0 or 1)\n");
00542                 return -1;
00543         }
00544 
00545         /* update the len of the extra headers */
00546         if (dlg_extra_hdrs.s)
00547                 dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
00548 
00549         if (seq_match_mode!=SEQ_MATCH_NO_ID &&
00550         seq_match_mode!=SEQ_MATCH_FALLBACK &&
00551         seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
00552                 LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
00553                 return -1;
00554         }
00555 
00556         if (detect_spirals != 0 && detect_spirals != 1) {
00557                 LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
00558                 return -1;
00559         }
00560 
00561         /* if statistics are disabled, prevent their registration to core */
00562         if (dlg_enable_stats==0)
00563                 exports.stats = 0;
00564 
00565         /* create profile hashes */
00566         if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
00567                 LM_ERR("failed to add profiles without value\n");
00568                 return -1;
00569         }
00570         if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
00571                 LM_ERR("failed to add profiles with value\n");
00572                 return -1;
00573         }
00574 
00575         /* load the TM API */
00576         if (load_tm_api(&d_tmb)!=0) {
00577                 LM_ERR("can't load TM API\n");
00578                 return -1;
00579         }
00580 
00581         /* load RR API also */
00582         if (load_rr_api(&d_rrb)!=0) {
00583                 LM_ERR("can't load RR API\n");
00584                 return -1;
00585         }
00586 
00587         /* register callbacks*/
00588         /* listen for all incoming requests  */
00589         if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
00590                 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
00591                 return -1;
00592         }
00593 
00594         /* listen for all routed requests  */
00595         if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
00596                 LM_ERR("cannot register RR callback\n");
00597                 return -1;
00598         }
00599 
00600         if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
00601                 LM_ERR("cannot register script callback");
00602                 return -1;
00603         }
00604         if (register_script_cb(dlg_cfg_cb,
00605                                 PRE_SCRIPT_CB|REQUEST_CB,0)<0)
00606         {
00607                 LM_ERR("cannot register pre-script ctx callback\n");
00608                 return -1;
00609         }
00610         if (register_script_cb(dlg_cfg_cb,
00611                                 POST_SCRIPT_CB|REQUEST_CB,0)<0)
00612         {
00613                 LM_ERR("cannot register post-script ctx callback\n");
00614                 return -1;
00615         }
00616 
00617         if (register_script_cb( spiral_detect_reset, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
00618                 LM_ERR("cannot register req pre-script spiral detection reset callback\n");
00619                 return -1;
00620         }
00621 
00622         if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
00623                 LM_ERR("failed to register timer \n");
00624                 return -1;
00625         }
00626 
00627         /* init handlers */
00628         init_dlg_handlers( rr_param, dlg_flag,
00629                 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
00630 
00631         /* init timer */
00632         if (init_dlg_timer(dlg_ontimeout)!=0) {
00633                 LM_ERR("cannot init timer list\n");
00634                 return -1;
00635         }
00636 
00637         /* sanitize dlg_hash_zie */
00638         if (dlg_hash_size < 1){
00639                 LM_WARN("hash_size is smaller "
00640                                 "then 1  -> rounding from %d to 1\n",
00641                                 dlg_hash_size);
00642                 dlg_hash_size = 1;
00643         }
00644         /* initialized the hash table */
00645         for( n=0 ; n<(8*sizeof(n)) ; n++) {
00646                 if (dlg_hash_size==(1<<n))
00647                         break;
00648                 if (n && dlg_hash_size<(1<<n)) {
00649                         LM_WARN("hash_size is not a power "
00650                                 "of 2 as it should be -> rounding from %d to %d\n",
00651                                 dlg_hash_size, 1<<(n-1));
00652                         dlg_hash_size = 1<<(n-1);
00653                 }
00654         }
00655 
00656         if ( init_dlg_table(dlg_hash_size)<0 ) {
00657                 LM_ERR("failed to create hash table\n");
00658                 return -1;
00659         }
00660 
00661         /* if a database should be used to store the dialogs' information */
00662         dlg_db_mode = dlg_db_mode_param;
00663         if (dlg_db_mode==DB_MODE_NONE) {
00664                 db_url.s = 0; db_url.len = 0;
00665         } else {
00666                 if (dlg_db_mode!=DB_MODE_REALTIME &&
00667                 dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
00668                         LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
00669                         return -1;
00670                 }
00671                 if ( !db_url.s || db_url.len==0 ) {
00672                         LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
00673                         return -1;
00674                 }
00675                 if (init_dlg_db(&db_url, dlg_hash_size, db_update_period,db_fetch_rows)!=0) {
00676                         LM_ERR("failed to initialize the DB support\n");
00677                         return -1;
00678                 }
00679                 run_load_callbacks();
00680         }
00681 
00682         destroy_dlg_callbacks( DLGCB_LOADED );
00683         if(dlg_ka_timer>0 && dlg_ka_interval>0)
00684                 register_sync_timers(1);
00685 
00686         return 0;
00687 }
00688 
00689 
00690 static int child_init(int rank)
00691 {
00692         dlg_db_mode = dlg_db_mode_param;
00693 
00694         if(rank==PROC_MAIN && dlg_ka_timer>0 && dlg_ka_interval>0)
00695         {
00696                 if(fork_sync_timer(PROC_TIMER, "Dialog KA Timer", 1 /*socks flag*/,
00697                                 dlg_ka_timer_exec, NULL, dlg_ka_timer /*sec*/)<0) {
00698                         LM_ERR("failed to start ka timer routine as process\n");
00699                         return -1; /* error */
00700                 }
00701         }
00702 
00703         if (rank==1) {
00704                 if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
00705                 if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
00706         }
00707 
00708         if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
00709         (rank>0 || rank==PROC_TIMER)) ||
00710         (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
00711                 if ( dlg_connect_db(&db_url) ) {
00712                         LM_ERR("failed to connect to database (rank=%d)\n",rank);
00713                         return -1;
00714                 }
00715         }
00716 
00717         /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
00718          * for the rest of the processes will be the same as DB_MODE_NONE */
00719         if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
00720                 dlg_db_mode = DB_MODE_NONE;
00721         /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
00722         if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
00723                         rank==PROC_MAIN)
00724                 dlg_db_mode = DB_MODE_NONE;
00725 
00726         return 0;
00727 }
00728 
00729 
00730 static void mod_destroy(void)
00731 {
00732         if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
00733                 dialog_update_db(0, 0);
00734                 destroy_dlg_db();
00735         }
00736         /* no DB interaction from now on */
00737         dlg_db_mode = DB_MODE_NONE;
00738         destroy_dlg_table();
00739         destroy_dlg_timer();
00740         destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
00741         destroy_dlg_handlers();
00742         destroy_dlg_profiles();
00743 }
00744 
00745 
00746 
00747 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
00748 {
00749         pv_elem_t *pve;
00750         str val_s;
00751 
00752         pve = (pv_elem_t *)value;
00753 
00754         if (((struct dlg_profile_table*)profile)->has_value) {
00755                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
00756                 val_s.len == 0 || val_s.s == NULL) {
00757                         LM_WARN("cannot get string for value\n");
00758                         return -1;
00759                 }
00760                 if ( set_dlg_profile( msg, &val_s,
00761                 (struct dlg_profile_table*)profile) < 0 ) {
00762                         LM_ERR("failed to set profile");
00763                         return -1;
00764                 }
00765         } else {
00766                 if ( set_dlg_profile( msg, NULL,
00767                 (struct dlg_profile_table*)profile) < 0 ) {
00768                         LM_ERR("failed to set profile");
00769                         return -1;
00770                 }
00771         }
00772         return 1;
00773 }
00774 
00775 
00776 
00777 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
00778 {
00779         pv_elem_t *pve;
00780         str val_s;
00781 
00782         pve = (pv_elem_t *)value;
00783 
00784         if (((struct dlg_profile_table*)profile)->has_value) {
00785                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
00786                 val_s.len == 0 || val_s.s == NULL) {
00787                         LM_WARN("cannot get string for value\n");
00788                         return -1;
00789                 }
00790                 if ( unset_dlg_profile( msg, &val_s,
00791                 (struct dlg_profile_table*)profile) < 0 ) {
00792                         LM_ERR("failed to unset profile");
00793                         return -1;
00794                 }
00795         } else {
00796                 if ( unset_dlg_profile( msg, NULL,
00797                 (struct dlg_profile_table*)profile) < 0 ) {
00798                         LM_ERR("failed to unset profile");
00799                         return -1;
00800                 }
00801         }
00802         return 1;
00803 }
00804 
00805 
00806 
00807 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
00808 {
00809         pv_elem_t *pve;
00810         str val_s;
00811 
00812         pve = (pv_elem_t *)value;
00813 
00814         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
00815                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
00816                 val_s.len == 0 || val_s.s == NULL) {
00817                         LM_WARN("cannot get string for value\n");
00818                         return -1;
00819                 }
00820                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
00821                         &val_s);
00822         } else {
00823                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
00824                         NULL);
00825         }
00826 }
00827 
00828 
00832 static int w_get_profile_size3(struct sip_msg *msg, char *profile,
00833                 char *value, char *result)
00834 {
00835         pv_elem_t *pve;
00836         str val_s;
00837         pv_spec_t *sp_dest;
00838         unsigned int size;
00839         pv_value_t val;
00840 
00841         if(result!=NULL)
00842         {
00843                 pve = (pv_elem_t *)value;
00844                 sp_dest = (pv_spec_t *)result;
00845         } else {
00846                 pve = NULL;
00847                 sp_dest = (pv_spec_t *)value;
00848         }
00849         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
00850                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
00851                 val_s.len == 0 || val_s.s == NULL) {
00852                         LM_WARN("cannot get string for value\n");
00853                         return -1;
00854                 }
00855                 size = get_profile_size( (struct dlg_profile_table*)profile, &val_s );
00856         } else {
00857                 size = get_profile_size( (struct dlg_profile_table*)profile, NULL );
00858         }
00859 
00860         memset(&val, 0, sizeof(pv_value_t));
00861         val.flags = PV_VAL_INT|PV_TYPE_INT;
00862         val.ri = (int)size;
00863 
00864         if(sp_dest->setf(msg, &sp_dest->pvp, (int)EQ_T, &val)<0)
00865         {
00866                 LM_ERR("setting profile PV failed\n");
00867                 return -1;
00868         }
00869 
00870         return 1;
00871 }
00872 
00873 
00877 static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result)
00878 {
00879         return w_get_profile_size3(msg, profile, result, NULL);
00880 }
00881 
00882 
00883 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
00884 {
00885         dlg_ctx_t *dctx;
00886         dlg_cell_t *d;
00887         int val;
00888 
00889         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
00890         {
00891                 LM_ERR("no flag value\n");
00892                 return -1;
00893         }
00894         if(val<0 || val>31)
00895                 return -1;
00896         if ( (dctx=dlg_get_dlg_ctx())==NULL )
00897                 return -1;
00898 
00899         dctx->flags |= 1<<val;
00900         d = dlg_get_by_iuid(&dctx->iuid);
00901         if(d!=NULL) {
00902                 d->sflags |= 1<<val;
00903                 dlg_release(d);
00904         }
00905         return 1;
00906 }
00907 
00908 
00909 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
00910 {
00911         dlg_ctx_t *dctx;
00912         dlg_cell_t *d;
00913         int val;
00914 
00915         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
00916         {
00917                 LM_ERR("no flag value\n");
00918                 return -1;
00919         }
00920         if(val<0 || val>31)
00921                 return -1;
00922 
00923         if ( (dctx=dlg_get_dlg_ctx())==NULL )
00924                 return -1;
00925 
00926         dctx->flags &= ~(1<<val);
00927         d = dlg_get_by_iuid(&dctx->iuid);
00928         if(d!=NULL) {
00929                 d->sflags &= ~(1<<val);
00930                 dlg_release(d);
00931         }
00932         return 1;
00933 }
00934 
00935 
00936 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
00937 {
00938         dlg_ctx_t *dctx;
00939         dlg_cell_t *d;
00940         int val;
00941         int ret;
00942 
00943         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
00944         {
00945                 LM_ERR("no flag value\n");
00946                 return -1;
00947         }
00948         if(val<0 || val>31)
00949                 return -1;
00950 
00951         if ( (dctx=dlg_get_dlg_ctx())==NULL )
00952                 return -1;
00953 
00954         d = dlg_get_by_iuid(&dctx->iuid);
00955         if(d!=NULL) {
00956                 ret = (d->sflags&(1<<val))?1:-1;
00957                 dlg_release(d);
00958                 return ret;
00959         }
00960         return (dctx->flags&(1<<val))?1:-1;
00961 }
00962 
00966 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
00967 {
00968         return dlg_manage(msg);
00969 }
00970 
00971 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
00972 {
00973         dlg_cell_t *dlg = NULL;
00974         int n;
00975 
00976         dlg = dlg_get_ctx_dialog();
00977         if(dlg==NULL)
00978                 return -1;
00979         
00980         n = (int)(long)side;
00981         if(n==1)
00982         {
00983                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
00984                         goto error;
00985                 goto done;
00986         } else if(n==2) {
00987                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
00988                         goto error;
00989                 goto done;
00990         } else {
00991                 if(dlg_bye_all(dlg, NULL)!=0)
00992                         goto error;
00993                 goto done;
00994         }
00995 
00996 done:
00997         dlg_release(dlg);
00998         return 1;
00999 
01000 error:
01001         dlg_release(dlg);
01002         return -1;
01003 }
01004 
01005 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
01006 {
01007         dlg_cell_t *dlg;
01008         int n;
01009         str st = {0,0};
01010 
01011         dlg = dlg_get_ctx_dialog();
01012         if(dlg==NULL)
01013                 return -1;
01014         
01015         n = (int)(long)side;
01016 
01017         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
01018         {
01019                 LM_ERR("unable to get To\n");
01020                 goto error;
01021         }
01022         if(st.s==NULL || st.len == 0)
01023         {
01024                 LM_ERR("invalid To parameter\n");
01025                 goto error;
01026         }
01027         if(n==1)
01028         {
01029                 if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
01030                         goto error;
01031         } else {
01032                 if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
01033                         goto error;
01034         }
01035 
01036         dlg_release(dlg);
01037         return 1;
01038 
01039 error:
01040         dlg_release(dlg);
01041         return -1;
01042 }
01043 
01044 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
01045 {
01046         str sf = {0,0};
01047         str st = {0,0};
01048         str so = {0,0};
01049 
01050         if(from==0 || to==0 || op==0)
01051         {
01052                 LM_ERR("invalid parameters\n");
01053                 return -1;
01054         }
01055 
01056         if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
01057         {
01058                 LM_ERR("unable to get From\n");
01059                 return -1;
01060         }
01061         if(sf.s==NULL || sf.len == 0)
01062         {
01063                 LM_ERR("invalid From parameter\n");
01064                 return -1;
01065         }
01066         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
01067         {
01068                 LM_ERR("unable to get To\n");
01069                 return -1;
01070         }
01071         if(st.s==NULL || st.len == 0)
01072         {
01073                 LM_ERR("invalid To parameter\n");
01074                 return -1;
01075         }
01076         if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
01077         {
01078                 LM_ERR("unable to get OP\n");
01079                 return -1;
01080         }
01081 
01082         if(dlg_bridge(&sf, &st, &so)!=0)
01083                 return -1;
01084         return 1;
01085 }
01086 
01090 static int w_dlg_set_timeout(struct sip_msg *msg, char *pto, char *phe, char *phi)
01091 {
01092         int to = 0;
01093         unsigned int he = 0;
01094         unsigned int hi = 0;
01095         dlg_cell_t *dlg = NULL;
01096 
01097         if(fixup_get_ivalue(msg, (gparam_p)pto, &to)!=0)
01098         {
01099                 LM_ERR("no timeout value\n");
01100                 return -1;
01101         }
01102         if(phe!=NULL)
01103         {
01104                 if(fixup_get_ivalue(msg, (gparam_p)phe, (int*)&he)!=0)
01105                 {
01106                         LM_ERR("no hash entry value value\n");
01107                         return -1;
01108                 }
01109                 if(fixup_get_ivalue(msg, (gparam_p)phi, (int*)&hi)!=0)
01110                 {
01111                         LM_ERR("no hash id value value\n");
01112                         return -1;
01113                 }
01114                 dlg = dlg_lookup(he, hi);
01115         } else {
01116                 dlg = dlg_get_msg_dialog(msg);
01117         }
01118 
01119         if(dlg==NULL)
01120         {
01121                 LM_DBG("no dialog found\n");
01122                 return -1;
01123         }
01124 
01125         if(update_dlg_timer(&dlg->tl, to)<0) {
01126                 LM_ERR("failed to update dialog lifetime\n");
01127                 dlg_release(dlg);
01128                 return -1;
01129         }
01130         dlg->lifetime = to;
01131         dlg->dflags |= DLG_FLAG_CHANGED;
01132         dlg_release(dlg);
01133         return 1;
01134 }
01135 
01136 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2)
01137 {
01138         dlg_ctx_t *dctx;
01139         dlg_cell_t *d;
01140         str val;
01141 
01142         if(fixup_get_svalue(msg, (gparam_t*)prop, &val)!=0)
01143         {
01144                 LM_ERR("no property value\n");
01145                 return -1;
01146         }
01147         if(val.len<=0)
01148         {
01149                 LM_ERR("empty property value\n");
01150                 return -1;
01151         }
01152         if ( (dctx=dlg_get_dlg_ctx())==NULL )
01153                 return -1;
01154 
01155         if(val.len==6 && strncmp(val.s, "ka-src", 6)==0) {
01156                 dctx->iflags |= DLG_IFLAG_KA_SRC;
01157                 d = dlg_get_by_iuid(&dctx->iuid);
01158                 if(d!=NULL) {
01159                         d->iflags |= DLG_IFLAG_KA_SRC;
01160                         dlg_release(d);
01161                 }
01162         } else if(val.len==6 && strncmp(val.s, "ka-dst", 6)==0) {
01163                 dctx->iflags |= DLG_IFLAG_KA_DST;
01164                 d = dlg_get_by_iuid(&dctx->iuid);
01165                 if(d!=NULL) {
01166                         d->iflags |= DLG_IFLAG_KA_DST;
01167                         dlg_release(d);
01168                 }
01169         } else {
01170                 LM_ERR("unknown property value [%.*s]\n", val.len, val.s);
01171                 return -1;
01172         }
01173 
01174         return 1;
01175 }
01176 
01177 
01178 void dlg_ka_timer_exec(unsigned int ticks, void* param)
01179 {
01180         dlg_ka_run(ticks);
01181 }
01182 
01183 static int fixup_dlg_bye(void** param, int param_no)
01184 {
01185         char *val;
01186         int n = 0;
01187 
01188         if (param_no==1) {
01189                 val = (char*)*param;
01190                 if (strcasecmp(val,"all")==0) {
01191                         n = 0;
01192                 } else if (strcasecmp(val,"caller")==0) {
01193                         n = 1;
01194                 } else if (strcasecmp(val,"callee")==0) {
01195                         n = 2;
01196                 } else {
01197                         LM_ERR("invalid param \"%s\"\n", val);
01198                         return E_CFG;
01199                 }
01200                 pkg_free(*param);
01201                 *param=(void*)(long)n;
01202         } else {
01203                 LM_ERR("called with parameter != 1\n");
01204                 return E_BUG;
01205         }
01206         return 0;
01207 }
01208 
01209 static int fixup_dlg_refer(void** param, int param_no)
01210 {
01211         char *val;
01212         int n = 0;
01213 
01214         if (param_no==1) {
01215                 val = (char*)*param;
01216                 if (strcasecmp(val,"caller")==0) {
01217                         n = 1;
01218                 } else if (strcasecmp(val,"callee")==0) {
01219                         n = 2;
01220                 } else {
01221                         LM_ERR("invalid param \"%s\"\n", val);
01222                         return E_CFG;
01223                 }
01224                 pkg_free(*param);
01225                 *param=(void*)(long)n;
01226         } else if (param_no==2) {
01227                 return fixup_spve_null(param, 1);
01228         } else {
01229                 LM_ERR("called with parameter idx %d\n", param_no);
01230                 return E_BUG;
01231         }
01232         return 0;
01233 }
01234 
01235 static int fixup_dlg_bridge(void** param, int param_no)
01236 {
01237         if (param_no>=1 && param_no<=3) {
01238                 return fixup_spve_null(param, 1);
01239         } else {
01240                 LM_ERR("called with parameter idx %d\n", param_no);
01241                 return E_BUG;
01242         }
01243         return 0;
01244 }
01245 
01246 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
01247 {
01248         dlg_cell_t *dlg = NULL;
01249         str sc = {0,0};
01250         str sf = {0,0};
01251         str st = {0,0};
01252         unsigned int dir = 0;
01253 
01254         if(ci==0 || ft==0 || tt==0)
01255         {
01256                 LM_ERR("invalid parameters\n");
01257                 return -1;
01258         }
01259 
01260         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
01261         {
01262                 LM_ERR("unable to get Call-ID\n");
01263                 return -1;
01264         }
01265         if(sc.s==NULL || sc.len == 0)
01266         {
01267                 LM_ERR("invalid Call-ID parameter\n");
01268                 return -1;
01269         }
01270         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
01271         {
01272                 LM_ERR("unable to get From tag\n");
01273                 return -1;
01274         }
01275         if(sf.s==NULL || sf.len == 0)
01276         {
01277                 LM_ERR("invalid From tag parameter\n");
01278                 return -1;
01279         }
01280         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
01281         {
01282                 LM_ERR("unable to get To Tag\n");
01283                 return -1;
01284         }
01285         if(st.s==NULL || st.len == 0)
01286         {
01287                 LM_ERR("invalid To tag parameter\n");
01288                 return -1;
01289         }
01290 
01291         dlg = get_dlg(&sc, &sf, &st, &dir);
01292         if(dlg==NULL)
01293                 return -1;
01294     /* set shorcut to dialog internal unique id */
01295         _dlg_ctx.iuid.h_entry = dlg->h_entry;
01296         _dlg_ctx.iuid.h_id = dlg->h_id;
01297         _dlg_ctx.dir = dir;
01298         dlg_release(dlg);
01299         return 1;
01300 }
01301 
01302 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
01303 {
01304         str from = {0,0};
01305         str to = {0,0};
01306         str op = {0,0};
01307         struct mi_node* node;
01308 
01309         node = cmd_tree->node.kids;
01310         if(node == NULL)
01311                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01312         from = node->value;
01313         if(from.len<=0 || from.s==NULL)
01314         {
01315                 LM_ERR("bad From value\n");
01316                 return init_mi_tree( 500, "Bad From value", 14);
01317         }
01318 
01319         node = node->next;
01320         if(node == NULL)
01321                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01322         to = node->value;
01323         if(to.len<=0 || to.s == NULL)
01324         {
01325                 return init_mi_tree(500, "Bad To value", 12);
01326         }
01327 
01328         node= node->next;
01329         if(node != NULL)
01330         {
01331                 op = node->value;
01332                 if(op.len<=0 || op.s==NULL)
01333                 {
01334                         return init_mi_tree(500, "Bad OP value", 12);
01335                 }
01336         }
01337 
01338         if(dlg_bridge(&from, &to, &op)!=0)
01339                 return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
01340 
01341         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
01342 }
01343 
01344 /**************************** RPC functions ******************************/
01354 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, dlg_cell_t *dlg,
01355                 int with_context)
01356 {
01357         rpc_cb_ctx_t rpc_cb;
01358 
01359         rpc->printf(c, "hash:%u:%u state:%u ref_count:%u timestart:%u timeout:%u",
01360                 dlg->h_entry, dlg->h_id, dlg->state, dlg->ref, dlg->start_ts, dlg->tl.timeout);
01361         rpc->printf(c, "\tcallid:%.*s from_tag:%.*s to_tag:%.*s",
01362                 dlg->callid.len, dlg->callid.s,
01363                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
01364                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
01365         rpc->printf(c, "\tfrom_uri:%.*s to_uri:%.*s",
01366                 dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s);
01367         rpc->printf(c, "\tcaller_contact:%.*s caller_cseq:%.*s",
01368                 dlg->contact[DLG_CALLER_LEG].len, dlg->contact[DLG_CALLER_LEG].s,
01369                 dlg->cseq[DLG_CALLER_LEG].len, dlg->cseq[DLG_CALLER_LEG].s);
01370         rpc->printf(c, "\tcaller_route_set: %.*s",
01371                 dlg->route_set[DLG_CALLER_LEG].len, dlg->route_set[DLG_CALLER_LEG].s);
01372         rpc->printf(c, "\tcallee_contact:%.*s callee_cseq:%.*s",
01373                 dlg->contact[DLG_CALLEE_LEG].len, dlg->contact[DLG_CALLEE_LEG].s,
01374                 dlg->cseq[DLG_CALLEE_LEG].len, dlg->cseq[DLG_CALLEE_LEG].s);
01375         rpc->printf(c, "\tcallee_route_set: %.*s",
01376                 dlg->route_set[DLG_CALLEE_LEG].len, dlg->route_set[DLG_CALLEE_LEG].s);
01377         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
01378                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:%.*s",
01379                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
01380                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s);
01381         } else {
01382                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:",
01383                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s);
01384         }
01385         if (with_context) {
01386                 rpc_cb.rpc = rpc;
01387                 rpc_cb.c = c;
01388                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
01389         }
01390 }
01391 
01399 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
01400 {
01401         dlg_cell_t *dlg;
01402         unsigned int i;
01403 
01404         for( i=0 ; i<d_table->size ; i++ ) {
01405                 dlg_lock( d_table, &(d_table->entries[i]) );
01406 
01407                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
01408                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
01409                 }
01410                 dlg_unlock( d_table, &(d_table->entries[i]) );
01411         }
01412 }
01413 
01421 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
01422         str callid, from_tag;
01423         dlg_entry_t *d_entry;
01424         dlg_cell_t *dlg;
01425         unsigned int h_entry;
01426 
01427         if (rpc->scan(c, ".S.S", &callid, &from_tag) < 2) return;
01428 
01429         h_entry = core_hash( &callid, 0, d_table->size);
01430         d_entry = &(d_table->entries[h_entry]);
01431         dlg_lock( d_table, d_entry);
01432         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
01433                 if (match_downstream_dialog( dlg, &callid, &from_tag)==1) {
01434                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
01435                 }
01436         }
01437         dlg_unlock( d_table, d_entry);
01438 }
01439 
01449 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name,
01450                 str *value) {
01451         unsigned int size;
01452         dlg_profile_table_t *profile;
01453 
01454         profile = search_dlg_profile( profile_name );
01455         if (!profile) {
01456                 rpc->printf(c, "Non existing profile:%.*s",
01457                         profile_name->len, profile_name->s);
01458                 return;
01459         }
01460         size = get_profile_size(profile, value);
01461         if (value) {
01462                 rpc->printf(c, "Profile:%.*s => profile:%.*s value:%.*s count:%u",
01463                         profile_name->len, profile_name->s,
01464                         profile->name.len, profile->name.s,
01465                         value->len, value->s, size);
01466                 return;
01467         } else {
01468                 rpc->printf(c, "Profile:%.*s => profile:%.*s value: count:%u",
01469                         profile_name->len, profile_name->s,
01470                         profile->name.len, profile->name.s, size);
01471                 return;
01472         }
01473         return;
01474 }
01475 
01486 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name,
01487                 str *value) {
01488         dlg_profile_table_t *profile;
01489         dlg_profile_hash_t *ph;
01490         unsigned int i;
01491 
01492         profile = search_dlg_profile( profile_name );
01493         if (!profile) {
01494                 rpc->printf(c, "Non existing profile:%.*s",
01495                         profile_name->len, profile_name->s);
01496                 return;
01497         }
01498 
01499         /* go through the hash and print the dialogs */
01500         if (profile->has_value==0 || value==NULL) {
01501                 /* no value */
01502                 lock_get( &profile->lock );
01503                 for ( i=0 ; i< profile->size ; i++ ) {
01504                         ph = profile->entries[i].first;
01505                         if(ph) {
01506                                 do {
01507                                         /* print dialog */
01508                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
01509                                         /* next */
01510                                         ph=ph->next;
01511                                 }while(ph!=profile->entries[i].first);
01512                         }
01513                         lock_release(&profile->lock);
01514                 }
01515         } else {
01516                 /* check for value also */
01517                 lock_get( &profile->lock );
01518                 for ( i=0 ; i< profile->size ; i++ ) {
01519                         ph = profile->entries[i].first;
01520                         if(ph) {
01521                                 do {
01522                                         if ( value->len==ph->value.len &&
01523                                                 memcmp(value->s,ph->value.s,value->len)==0 ) {
01524                                                 /* print dialog */
01525                                                 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
01526                                         }
01527                                         /* next */
01528                                         ph=ph->next;
01529                                 }while(ph!=profile->entries[i].first);
01530                         }
01531                         lock_release(&profile->lock);
01532                 }
01533         }
01534 }
01535 
01536 /*
01537  * Wrapper around is_known_dlg().
01538  */
01539 
01540 static int w_is_known_dlg(sip_msg_t *msg) {
01541         return  is_known_dlg(msg);
01542 }
01543 
01544 static const char *rpc_print_dlgs_doc[2] = {
01545         "Print all dialogs", 0
01546 };
01547 static const char *rpc_print_dlgs_ctx_doc[2] = {
01548         "Print all dialogs with associated context", 0
01549 };
01550 static const char *rpc_print_dlg_doc[2] = {
01551         "Print dialog based on callid and fromtag", 0
01552 };
01553 static const char *rpc_print_dlg_ctx_doc[2] = {
01554         "Print dialog with associated context based on callid and fromtag", 0
01555 };
01556 static const char *rpc_end_dlg_entry_id_doc[2] = {
01557         "End a given dialog based on [h_entry] [h_id]", 0
01558 };
01559 static const char *rpc_profile_get_size_doc[2] = {
01560         "Returns the number of dialogs belonging to a profile", 0
01561 };
01562 static const char *rpc_profile_print_dlgs_doc[2] = {
01563         "Lists all the dialogs belonging to a profile", 0
01564 };
01565 static const char *rpc_dlg_bridge_doc[2] = {
01566         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:\
01567  to, from, [outbound SIP proxy]", 0
01568 };
01569 
01570 
01571 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
01572         internal_rpc_print_dlgs(rpc, c, 0);
01573 }
01574 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
01575         internal_rpc_print_dlgs(rpc, c, 1);
01576 }
01577 static void rpc_print_dlg(rpc_t *rpc, void *c) {
01578         internal_rpc_print_single_dlg(rpc, c, 0);
01579 }
01580 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
01581         internal_rpc_print_single_dlg(rpc, c, 1);
01582 }
01583 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
01584         unsigned int h_entry, h_id;
01585         dlg_cell_t * dlg = NULL;
01586         str rpc_extra_hdrs = {NULL,0};
01587 
01588         if (rpc->scan(c, "ddS", &h_entry, &h_id, &rpc_extra_hdrs) < 2) return;
01589 
01590         dlg = dlg_lookup(h_entry, h_id);
01591         if(dlg){
01592                 dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
01593                 dlg_release(dlg);
01594         }
01595 }
01596 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
01597         str profile_name = {NULL,0};
01598         str value = {NULL,0};
01599 
01600         if (rpc->scan(c, ".S", &profile_name) < 1) return;
01601         if (rpc->scan(c, "*.S", &value) > 0) {
01602                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
01603         } else {
01604                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
01605         }
01606         return;
01607 }
01608 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
01609         str profile_name = {NULL,0};
01610         str value = {NULL,0};
01611 
01612         if (rpc->scan(c, ".S", &profile_name) < 1) return;
01613         if (rpc->scan(c, "*.S", &value) > 0) {
01614                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
01615         } else {
01616                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
01617         }
01618         return;
01619 }
01620 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
01621         str from = {NULL,0};
01622         str to = {NULL,0};
01623         str op = {NULL,0};
01624 
01625         if (rpc->scan(c, "SSS", &from, &to, &op) < 2) return;
01626 
01627         dlg_bridge(&from, &to, &op);
01628 }
01629 
01630 static rpc_export_t rpc_methods[] = {
01631         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, 0},
01632         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, 0},
01633         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
01634         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
01635         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
01636         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
01637         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, 0},
01638         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
01639         {0, 0, 0, 0}
01640 };