00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
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
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;
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
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
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
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",
00316 DEFAULT_DLFLAGS,
00317 cmds,
00318 mod_params,
00319 mod_stats,
00320 mi_cmds,
00321 mod_items,
00322 0,
00323 mod_init,
00324 0,
00325 mod_destroy,
00326 child_init
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
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
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
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
00562 if (dlg_enable_stats==0)
00563 exports.stats = 0;
00564
00565
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
00576 if (load_tm_api(&d_tmb)!=0) {
00577 LM_ERR("can't load TM API\n");
00578 return -1;
00579 }
00580
00581
00582 if (load_rr_api(&d_rrb)!=0) {
00583 LM_ERR("can't load RR API\n");
00584 return -1;
00585 }
00586
00587
00588
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
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
00628 init_dlg_handlers( rr_param, dlg_flag,
00629 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
00630
00631
00632 if (init_dlg_timer(dlg_ontimeout)!=0) {
00633 LM_ERR("cannot init timer list\n");
00634 return -1;
00635 }
00636
00637
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
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
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 ,
00697 dlg_ka_timer_exec, NULL, dlg_ka_timer )<0) {
00698 LM_ERR("failed to start ka timer routine as process\n");
00699 return -1;
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
00718
00719 if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
00720 dlg_db_mode = DB_MODE_NONE;
00721
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
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
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
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
01500 if (profile->has_value==0 || value==NULL) {
01501
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
01508 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
01509
01510 ph=ph->next;
01511 }while(ph!=profile->entries[i].first);
01512 }
01513 lock_release(&profile->lock);
01514 }
01515 } else {
01516
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
01525 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
01526 }
01527
01528 ph=ph->next;
01529 }while(ph!=profile->entries[i].first);
01530 }
01531 lock_release(&profile->lock);
01532 }
01533 }
01534 }
01535
01536
01537
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 };