core: new core event for received datagrams
[sip-router] / modules_k / dialog / dialog.c
1 /*
2  * $Id$
3  *
4  * dialog module - basic support for dialog tracking
5  *
6  * Copyright (C) 2006 Voice Sistem SRL
7  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
8  *
9  * This file is part of Kamailio, a free SIP server.
10  *
11  * Kamailio is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * Kamailio is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License 
22  * along with this program; if not, write to the Free Software 
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * History:
26  * --------
27  *  2006-04-14 initial version (bogdan)
28  *  2006-11-28 Added statistic support for the number of early and failed
29  *              dialogs. (Jeffrey Magder - SOMA Networks) 
30  *  2007-04-30 added dialog matching without DID (dialog ID), but based only
31  *              on RFC3261 elements - based on an original patch submitted 
32  *              by Michel Bensoussan <michel@extricom.com> (bogdan)
33  *  2007-05-15 added saving dialogs' information to database (ancuta)
34  *  2007-07-04 added saving dialog cseq, contact, record route 
35  *              and bind_addresses(sock_info) for caller and callee (ancuta)
36  *  2008-04-14 added new type of callback to be triggered when dialogs are 
37  *              loaded from DB (bogdan)
38  *  2010-06-16 added sip-router rpc interface (osas)
39  */
40
41 /**
42  * @defgroup dialog dialog :: Kamailio dialog module
43  * @brief Kamailio dialog module
44  *
45  * The dialog module provides dialog awareness to the Kamailio proxy. Its
46  * functionality is to keep track of the current dialogs, to offer
47  * information about them (like how many dialogs are active) or to manage
48  * them. The module exports several functions that could be used directly
49  * from scripts.
50  * The module, via an internal API, also provide the foundation to build
51  * on top of it more complex dialog-based functionalities via other
52  * Kamailio modules.                       
53  */
54
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <sys/time.h>
59
60 #include "../../sr_module.h"
61 #include "../../lib/srdb1/db.h"
62 #include "../../dprint.h"
63 #include "../../error.h"
64 #include "../../ut.h"
65 #include "../../pvar.h"
66 #include "../../mod_fix.h"
67 #include "../../script_cb.h"
68 #include "../../lib/kcore/faked_msg.h"
69 #include "../../lib/kcore/hash_func.h"
70 #include "../../lib/kcore/kstats_wrapper.h"
71 #include "../../mem/mem.h"
72 #include "../../lib/kmi/mi.h"
73 #include "../../lvalue.h"
74 #include "../../parser/parse_to.h"
75 #include "../../modules/tm/tm_load.h"
76 #include "../../rpc_lookup.h"
77 #include "../rr/api.h"
78 #include "dlg_hash.h"
79 #include "dlg_timer.h"
80 #include "dlg_handlers.h"
81 #include "dlg_load.h"
82 #include "dlg_cb.h"
83 #include "dlg_db_handler.h"
84 #include "dlg_req_within.h"
85 #include "dlg_profile.h"
86 #include "dlg_var.h"
87 #include "dlg_transfer.h"
88
89 MODULE_VERSION
90
91
92 static int mod_init(void);
93 static int child_init(int rank);
94 static void mod_destroy(void);
95
96 /* module parameter */
97 static int dlg_hash_size = 4096;
98 static char* rr_param = "did";
99 static int dlg_flag = -1;
100 static str timeout_spec = {NULL, 0};
101 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
102 static int seq_match_mode = SEQ_MATCH_STRICT_ID;
103 static char* profiles_wv_s = NULL;
104 static char* profiles_nv_s = NULL;
105 str dlg_extra_hdrs = {NULL,0};
106 static int db_fetch_rows = 200;
107
108 str dlg_bridge_controller = {"sip:controller@kamailio.org", 27};
109
110 str ruri_pvar_param = {"$ru", 3};
111 pv_elem_t * ruri_param_model = NULL;
112
113 /* statistic variables */
114 int dlg_enable_stats = 1;
115 int active_dlgs_cnt = 0;
116 int early_dlgs_cnt = 0;
117 int detect_spirals = 1;
118 stat_var *active_dlgs = 0;
119 stat_var *processed_dlgs = 0;
120 stat_var *expired_dlgs = 0;
121 stat_var *failed_dlgs = 0;
122 stat_var *early_dlgs  = 0;
123
124 struct tm_binds d_tmb;
125 struct rr_binds d_rrb;
126 pv_spec_t timeout_avp;
127
128 int dlg_db_mode_param = DB_MODE_NONE;
129
130 /* db stuff */
131 static str db_url = str_init(DEFAULT_DB_URL);
132 static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
133
134 static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
135                 pv_value_t *res);
136
137 /* commands wrappers and fixups */
138 static int fixup_profile(void** param, int param_no);
139 static int fixup_get_profile2(void** param, int param_no);
140 static int fixup_get_profile3(void** param, int param_no);
141 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
142 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
143 static int w_is_in_profile(struct sip_msg*, char*, char*);
144 static int w_get_profile_size2(struct sip_msg*, char*, char*);
145 static int w_get_profile_size3(struct sip_msg*, char*, char*, char*);
146 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
147 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
148 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
149 static int w_dlg_manage(struct sip_msg*, char*, char*);
150 static int w_dlg_bye(struct sip_msg*, char*, char*);
151 static int w_dlg_refer(struct sip_msg*, char*, char*);
152 static int w_dlg_bridge(struct sip_msg*, char*, char*, char*);
153 static int fixup_dlg_bye(void** param, int param_no);
154 static int fixup_dlg_refer(void** param, int param_no);
155 static int fixup_dlg_bridge(void** param, int param_no);
156 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
157 static int w_is_known_dlg(struct sip_msg *);
158
159 static cmd_export_t cmds[]={
160         {"dlg_manage", (cmd_function)w_dlg_manage,            0,0,
161                         0, REQUEST_ROUTE },
162         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  1,fixup_profile,
163                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
164         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  2,fixup_profile,
165                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
166         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  1,fixup_profile,
167                         0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
168         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  2,fixup_profile,
169                         0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
170         {"is_in_profile", (cmd_function)w_is_in_profile,      1,fixup_profile,
171                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
172         {"is_in_profile", (cmd_function)w_is_in_profile,      2,fixup_profile,
173                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
174         {"get_profile_size",(cmd_function)w_get_profile_size2, 2,fixup_get_profile2,
175                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
176         {"get_profile_size",(cmd_function)w_get_profile_size3, 3,fixup_get_profile3,
177                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
178         {"dlg_setflag", (cmd_function)w_dlg_setflag,          1,fixup_igp_null,
179                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
180         {"dlg_resetflag", (cmd_function)w_dlg_resetflag,      1,fixup_igp_null,
181                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
182         {"dlg_isflagset", (cmd_function)w_dlg_isflagset,      1,fixup_igp_null,
183                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
184         {"dlg_bye",(cmd_function)w_dlg_bye,                   1,fixup_dlg_bye,
185                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
186         {"dlg_refer",(cmd_function)w_dlg_refer,               2,fixup_dlg_refer,
187                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
188         {"dlg_bridge",(cmd_function)w_dlg_bridge,             3,fixup_dlg_bridge,
189                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
190         {"dlg_get",(cmd_function)w_dlg_get,                   3,fixup_dlg_bridge,
191                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
192         {"is_known_dlg", (cmd_function)w_is_known_dlg,        0, NULL,
193                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
194         {"load_dlg",  (cmd_function)load_dlg,   0, 0, 0, 0},
195         {0,0,0,0,0,0}
196 };
197
198 static param_export_t mod_params[]={
199         { "enable_stats",          INT_PARAM, &dlg_enable_stats         },
200         { "hash_size",             INT_PARAM, &dlg_hash_size            },
201         { "rr_param",              STR_PARAM, &rr_param                 },
202         { "dlg_flag",              INT_PARAM, &dlg_flag                 },
203         { "timeout_avp",           STR_PARAM, &timeout_spec.s           },
204         { "default_timeout",       INT_PARAM, &default_timeout          },
205         { "dlg_extra_hdrs",        STR_PARAM, &dlg_extra_hdrs.s         },
206         { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
207         { "detect_spirals",        INT_PARAM, &detect_spirals,          },
208         { "db_url",                STR_PARAM, &db_url.s                 },
209         { "db_mode",               INT_PARAM, &dlg_db_mode_param        },
210         { "table_name",            STR_PARAM, &dialog_table_name        },
211         { "call_id_column",        STR_PARAM, &call_id_column.s         },
212         { "from_uri_column",       STR_PARAM, &from_uri_column.s        },
213         { "from_tag_column",       STR_PARAM, &from_tag_column.s        },
214         { "to_uri_column",         STR_PARAM, &to_uri_column.s          },
215         { "to_tag_column",         STR_PARAM, &to_tag_column.s          },
216         { "h_id_column",           STR_PARAM, &h_id_column.s            },
217         { "h_entry_column",        STR_PARAM, &h_entry_column.s         },
218         { "state_column",          STR_PARAM, &state_column.s           },
219         { "start_time_column",     STR_PARAM, &start_time_column.s      },
220         { "timeout_column",        STR_PARAM, &timeout_column.s         },
221         { "to_cseq_column",        STR_PARAM, &to_cseq_column.s         },
222         { "from_cseq_column",      STR_PARAM, &from_cseq_column.s       },
223         { "to_route_column",       STR_PARAM, &to_route_column.s        },
224         { "from_route_column",     STR_PARAM, &from_route_column.s      },
225         { "to_contact_column",     STR_PARAM, &to_contact_column.s      },
226         { "from_contact_column",   STR_PARAM, &from_contact_column.s    },
227         { "to_sock_column",        STR_PARAM, &to_sock_column.s         },
228         { "from_sock_column",      STR_PARAM, &from_sock_column.s       },
229         { "sflags_column",         STR_PARAM, &sflags_column.s          },
230         { "toroute_name_column",   STR_PARAM, &toroute_name_column.s    },
231
232         { "vars_table_name",       STR_PARAM, &dialog_vars_table_name   },
233         { "vars_h_id_column",      STR_PARAM, &vars_h_id_column.s       },
234         { "vars_h_entry_column",   STR_PARAM, &vars_h_entry_column.s    },
235         { "vars_key_column",       STR_PARAM, &vars_key_column.s        },
236         { "vars_value_column",     STR_PARAM, &vars_value_column.s      },
237
238         { "db_update_period",      INT_PARAM, &db_update_period         },
239         { "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
240         { "profiles_with_value",   STR_PARAM, &profiles_wv_s            },
241         { "profiles_no_value",     STR_PARAM, &profiles_nv_s            },
242         { "bridge_controller",     STR_PARAM, &dlg_bridge_controller.s  },
243         { "ruri_pvar",             STR_PARAM, &ruri_pvar_param.s        },
244         { 0,0,0 }
245 };
246
247
248 static stat_export_t mod_stats[] = {
249         {"active_dialogs" ,     STAT_NO_RESET,  &active_dlgs       },
250         {"early_dialogs",       STAT_NO_RESET,  &early_dlgs        },
251         {"processed_dialogs" ,  0,              &processed_dlgs    },
252         {"expired_dialogs" ,    0,              &expired_dlgs      },
253         {"failed_dialogs",      0,              &failed_dlgs       },
254         {0,0,0}
255 };
256
257 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param);
258
259 static mi_export_t mi_cmds[] = {
260         { "dlg_list",           mi_print_dlgs,       0,  0,  0},
261         { "dlg_list_ctx",       mi_print_dlgs_ctx,   0,  0,  0},
262         { "dlg_end_dlg",        mi_terminate_dlg,    0,  0,  0},
263         { "dlg_terminate_dlg",  mi_terminate_dlgs,   0,  0,  0},
264         { "profile_get_size",   mi_get_profile,      0,  0,  0},
265         { "profile_list_dlgs",  mi_profile_list,     0,  0,  0},
266         { "dlg_bridge",         mi_dlg_bridge,       0,  0,  0},
267         { 0, 0, 0, 0, 0}
268 };
269
270 static rpc_export_t rpc_methods[];
271
272 static pv_export_t mod_items[] = {
273         { {"DLG_count",  sizeof("DLG_count")-1}, PVT_OTHER,  pv_get_dlg_count,    0,
274                 0, 0, 0, 0 },
275         { {"DLG_lifetime",sizeof("DLG_lifetime")-1}, PVT_OTHER, pv_get_dlg_lifetime, 0,
276                 0, 0, 0, 0 },
277         { {"DLG_status",  sizeof("DLG_status")-1}, PVT_OTHER, pv_get_dlg_status, 0,
278                 0, 0, 0, 0 },
279         { {"dlg_ctx",  sizeof("dlg_ctx")-1}, PVT_OTHER, pv_get_dlg_ctx,
280                 pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
281         { {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
282                 0, pv_parse_dlg_name, 0, 0, 0 },
283         { {"dlg_var", sizeof("dlg_var")-1}, PVT_OTHER, pv_get_dlg_variable,
284                 pv_set_dlg_variable,    pv_parse_dialog_var_name, 0, 0, 0},
285         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
286 };
287
288 struct module_exports exports= {
289         "dialog",        /* module's name */
290         DEFAULT_DLFLAGS, /* dlopen flags */
291         cmds,            /* exported functions */
292         mod_params,      /* param exports */
293         mod_stats,       /* exported statistics */
294         mi_cmds,         /* exported MI functions */
295         mod_items,       /* exported pseudo-variables */
296         0,               /* extra processes */
297         mod_init,        /* module initialization function */
298         0,               /* reply processing function */
299         mod_destroy,
300         child_init       /* per-child init function */
301 };
302
303
304 static int fixup_profile(void** param, int param_no)
305 {
306         struct dlg_profile_table *profile;
307         pv_elem_t *model=NULL;
308         str s;
309
310         s.s = (char*)(*param);
311         s.len = strlen(s.s);
312         if(s.len==0) {
313                 LM_ERR("param %d is empty string!\n", param_no);
314                 return E_CFG;
315         }
316
317         if (param_no==1) {
318                 profile = search_dlg_profile( &s );
319                 if (profile==NULL) {
320                         LM_CRIT("profile <%s> not definited\n",s.s);
321                         return E_CFG;
322                 }
323                 pkg_free(*param);
324                 *param = (void*)profile;
325                 return 0;
326         } else if (param_no==2) {
327                 if(pv_parse_format(&s ,&model) || model==NULL) {
328                         LM_ERR("wrong format [%s] for value param!\n", s.s);
329                         return E_CFG;
330                 }
331                 *param = (void*)model;
332         }
333         return 0;
334 }
335
336
337 static int fixup_get_profile2(void** param, int param_no)
338 {
339         pv_spec_t *sp;
340         int ret;
341
342         if (param_no==1) {
343                 return fixup_profile(param, 1);
344         } else if (param_no==2) {
345                 ret = fixup_pvar_null(param, 1);
346                 if (ret<0) return ret;
347                 sp = (pv_spec_t*)(*param);
348                 if (sp->type!=PVT_AVP && sp->type!=PVT_SCRIPTVAR) {
349                         LM_ERR("return must be an AVP or SCRIPT VAR!\n");
350                         return E_SCRIPT;
351                 }
352         }
353         return 0;
354 }
355
356
357 static int fixup_get_profile3(void** param, int param_no)
358 {
359         if (param_no==1) {
360                 return fixup_profile(param, 1);
361         } else if (param_no==2) {
362                 return fixup_profile(param, 2);
363         } else if (param_no==3) {
364                 return fixup_get_profile2( param, 2);
365         }
366         return 0;
367 }
368
369
370
371 int load_dlg( struct dlg_binds *dlgb )
372 {
373         dlgb->register_dlgcb = register_dlgcb;
374         dlgb->terminate_dlg = dlg_bye_all;
375         return 1;
376 }
377
378
379 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
380                 pv_value_t *res)
381 {
382         int n;
383         int l;
384         char *ch;
385
386         if(msg==NULL || res==NULL)
387                 return -1;
388
389         n = active_dlgs ? get_stat_val(active_dlgs) : 0;
390         l = 0;
391         ch = int2str( n, &l);
392
393         res->rs.s = ch;
394         res->rs.len = l;
395
396         res->ri = n;
397         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
398
399         return 0;
400 }
401
402
403 static int mod_init(void)
404 {
405         unsigned int n;
406
407
408 #ifdef STATISTICS
409         /* register statistics */
410         if (register_module_stats( exports.name, mod_stats)!=0 ) {
411                 LM_ERR("failed to register core statistics\n");
412                 return -1;
413         }
414 #endif
415
416         if(register_mi_mod(exports.name, mi_cmds)!=0)
417         {
418                 LM_ERR("failed to register MI commands\n");
419                 return -1;
420         }
421
422         if (rpc_register_array(rpc_methods)!=0) {
423                 LM_ERR("failed to register RPC commands\n");
424                 return -1;
425         }
426
427         if(faked_msg_init()<0)
428                 return -1;
429
430         if (timeout_spec.s)
431                 timeout_spec.len = strlen(timeout_spec.s);
432
433         dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
434         db_url.len = strlen(db_url.s);
435         call_id_column.len = strlen(call_id_column.s);
436         from_uri_column.len = strlen(from_uri_column.s);
437         from_tag_column.len = strlen(from_tag_column.s);
438         to_uri_column.len = strlen(to_uri_column.s);
439         to_tag_column.len = strlen(to_tag_column.s);
440         h_id_column.len = strlen(h_id_column.s);
441         h_entry_column.len = strlen(h_entry_column.s);
442         state_column.len = strlen(state_column.s);
443         start_time_column.len = strlen(start_time_column.s);
444         timeout_column.len = strlen(timeout_column.s);
445         to_cseq_column.len = strlen(to_cseq_column.s);
446         from_cseq_column.len = strlen(from_cseq_column.s);
447         to_route_column.len = strlen(to_route_column.s);
448         from_route_column.len = strlen(from_route_column.s);
449         to_contact_column.len = strlen(to_contact_column.s);
450         from_contact_column.len = strlen(from_contact_column.s);
451         to_sock_column.len = strlen(to_sock_column.s);
452         from_sock_column.len = strlen(from_sock_column.s);
453         sflags_column.len = strlen(sflags_column.s);
454         toroute_name_column.len = strlen(toroute_name_column.s);
455         dialog_table_name.len = strlen(dialog_table_name.s);
456
457         dialog_vars_table_name.len = strlen(dialog_vars_table_name.s);
458         vars_h_id_column.len = strlen(vars_h_id_column.s);
459         vars_h_entry_column.len = strlen(vars_h_entry_column.s);
460         vars_key_column.len = strlen(vars_key_column.s);
461         vars_value_column.len = strlen(vars_value_column.s);
462
463         /* param checkings */
464         if (dlg_flag==-1) {
465                 LM_ERR("no dlg flag set!!\n");
466                 return -1;
467         } else if (dlg_flag>MAX_FLAG) {
468                 LM_ERR("invalid dlg flag %d!!\n",dlg_flag);
469                 return -1;
470         }
471
472         if (rr_param==0 || rr_param[0]==0) {
473                 LM_ERR("empty rr_param!!\n");
474                 return -1;
475         } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
476                 LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
477                 return -1;
478         }
479
480         if (timeout_spec.s) {
481                 if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 
482                                 && (timeout_avp.type!=PVT_AVP)){
483                         LM_ERR("malformed or non AVP timeout "
484                                 "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
485                         return -1;
486                 }
487         }
488
489         if (default_timeout<=0) {
490                 LM_ERR("0 default_timeout not accepted!!\n");
491                 return -1;
492         }
493
494         if (ruri_pvar_param.s==NULL || *ruri_pvar_param.s=='\0') {
495                 LM_ERR("invalid r-uri PV string\n");
496                 return -1;
497         }
498         ruri_pvar_param.len = strlen(ruri_pvar_param.s);
499         if(pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
500                                 || ruri_param_model==NULL) {
501                 LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
502                 return -1;
503         }
504
505         /* update the len of the extra headers */
506         if (dlg_extra_hdrs.s)
507                 dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
508
509         if (seq_match_mode!=SEQ_MATCH_NO_ID &&
510         seq_match_mode!=SEQ_MATCH_FALLBACK &&
511         seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
512                 LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
513                 return -1;
514         }
515
516         if (detect_spirals != 0 && detect_spirals != 1) {
517                 LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
518                 return -1;
519         }
520
521         /* if statistics are disabled, prevent their registration to core */
522         if (dlg_enable_stats==0)
523                 exports.stats = 0;
524
525         /* create profile hashes */
526         if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
527                 LM_ERR("failed to add profiles without value\n");
528                 return -1;
529         }
530         if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
531                 LM_ERR("failed to add profiles with value\n");
532                 return -1;
533         }
534
535         /* load the TM API */
536         if (load_tm_api(&d_tmb)!=0) {
537                 LM_ERR("can't load TM API\n");
538                 return -1;
539         }
540
541         /* load RR API also */
542         if (load_rr_api(&d_rrb)!=0) {
543                 LM_ERR("can't load RR API\n");
544                 return -1;
545         }
546
547         /* register callbacks*/
548         /* listen for all incoming requests  */
549         if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
550                 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
551                 return -1;
552         }
553
554         /* listen for all routed requests  */
555         if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
556                 LM_ERR("cannot register RR callback\n");
557                 return -1;
558         }
559
560         if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
561                 LM_ERR("cannot regsiter script callback");
562                 return -1;
563         }
564         if (register_script_cb(dlg_cfg_cb,
565                                 PRE_SCRIPT_CB|REQUEST_CB,0)<0)
566         {
567                 LM_ERR("cannot regsiter pre-script ctx callback\n");
568                 return -1;
569         }
570         if (register_script_cb(dlg_cfg_cb,
571                                 POST_SCRIPT_CB|REQUEST_CB,0)<0)
572         {
573                 LM_ERR("cannot regsiter post-script ctx callback\n");
574                 return -1;
575         }
576
577         if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
578                 LM_ERR("failed to register timer \n");
579                 return -1;
580         }
581
582         /* init handlers */
583         init_dlg_handlers( rr_param, dlg_flag,
584                 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
585
586         /* init timer */
587         if (init_dlg_timer(dlg_ontimeout)!=0) {
588                 LM_ERR("cannot init timer list\n");
589                 return -1;
590         }
591
592         /* initialized the hash table */
593         for( n=0 ; n<(8*sizeof(n)) ; n++) {
594                 if (dlg_hash_size==(1<<n))
595                         break;
596                 if (dlg_hash_size<(1<<n)) {
597                         LM_WARN("hash_size is not a power "
598                                 "of 2 as it should be -> rounding from %d to %d\n",
599                                 dlg_hash_size, 1<<(n-1));
600                         dlg_hash_size = 1<<(n-1);
601                 }
602         }
603
604         if ( init_dlg_table(dlg_hash_size)<0 ) {
605                 LM_ERR("failed to create hash table\n");
606                 return -1;
607         }
608
609         /* if a database should be used to store the dialogs' information */
610         dlg_db_mode = dlg_db_mode_param;
611         if (dlg_db_mode==DB_MODE_NONE) {
612                 db_url.s = 0; db_url.len = 0;
613         } else {
614                 if (dlg_db_mode!=DB_MODE_REALTIME &&
615                 dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
616                         LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
617                         return -1;
618                 }
619                 if ( !db_url.s || db_url.len==0 ) {
620                         LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
621                         return -1;
622                 }
623                 if (init_dlg_db(&db_url, dlg_hash_size, db_update_period,db_fetch_rows)!=0) {
624                         LM_ERR("failed to initialize the DB support\n");
625                         return -1;
626                 }
627                 run_load_callbacks();
628         }
629
630         destroy_dlg_callbacks( DLGCB_LOADED );
631
632         return 0;
633 }
634
635
636 static int child_init(int rank)
637 {
638         dlg_db_mode = dlg_db_mode_param;
639
640         if (rank==1) {
641                 if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
642                 if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
643         }
644
645         if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
646         (rank>0 || rank==PROC_TIMER)) ||
647         (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
648                 if ( dlg_connect_db(&db_url) ) {
649                         LM_ERR("failed to connect to database (rank=%d)\n",rank);
650                         return -1;
651                 }
652         }
653
654         /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
655          * for the rest of the processes will be the same as DB_MODE_NONE */
656         if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
657                 dlg_db_mode = DB_MODE_NONE;
658         /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
659         if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
660                         rank==PROC_MAIN)
661                 dlg_db_mode = DB_MODE_NONE;
662
663         return 0;
664 }
665
666
667 static void mod_destroy(void)
668 {
669         if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
670                 dialog_update_db(0, 0);
671                 destroy_dlg_db();
672         }
673         /* no DB interaction from now on */
674         dlg_db_mode = DB_MODE_NONE;
675         destroy_dlg_table();
676         destroy_dlg_timer();
677         destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
678         destroy_dlg_handlers();
679         destroy_dlg_profiles();
680 }
681
682
683
684 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
685 {
686         pv_elem_t *pve;
687         str val_s;
688
689         pve = (pv_elem_t *)value;
690
691         if (((struct dlg_profile_table*)profile)->has_value) {
692                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
693                 val_s.len == 0 || val_s.s == NULL) {
694                         LM_WARN("cannot get string for value\n");
695                         return -1;
696                 }
697                 if ( set_dlg_profile( msg, &val_s,
698                 (struct dlg_profile_table*)profile) < 0 ) {
699                         LM_ERR("failed to set profile");
700                         return -1;
701                 }
702         } else {
703                 if ( set_dlg_profile( msg, NULL,
704                 (struct dlg_profile_table*)profile) < 0 ) {
705                         LM_ERR("failed to set profile");
706                         return -1;
707                 }
708         }
709         return 1;
710 }
711
712
713
714 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
715 {
716         pv_elem_t *pve;
717         str val_s;
718
719         pve = (pv_elem_t *)value;
720
721         if (((struct dlg_profile_table*)profile)->has_value) {
722                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
723                 val_s.len == 0 || val_s.s == NULL) {
724                         LM_WARN("cannot get string for value\n");
725                         return -1;
726                 }
727                 if ( unset_dlg_profile( msg, &val_s,
728                 (struct dlg_profile_table*)profile) < 0 ) {
729                         LM_ERR("failed to unset profile");
730                         return -1;
731                 }
732         } else {
733                 if ( unset_dlg_profile( msg, NULL,
734                 (struct dlg_profile_table*)profile) < 0 ) {
735                         LM_ERR("failed to unset profile");
736                         return -1;
737                 }
738         }
739         return 1;
740 }
741
742
743
744 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
745 {
746         pv_elem_t *pve;
747         str val_s;
748
749         pve = (pv_elem_t *)value;
750
751         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
752                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
753                 val_s.len == 0 || val_s.s == NULL) {
754                         LM_WARN("cannot get string for value\n");
755                         return -1;
756                 }
757                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
758                         &val_s);
759         } else {
760                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
761                         NULL);
762         }
763 }
764
765
766 /**
767  * get dynamic name profile size
768  */
769 static int w_get_profile_size3(struct sip_msg *msg, char *profile,
770                 char *value, char *result)
771 {
772         pv_elem_t *pve;
773         str val_s;
774         pv_spec_t *sp_dest;
775         unsigned int size;
776         pv_value_t val;
777
778         if(result!=NULL)
779         {
780                 pve = (pv_elem_t *)value;
781                 sp_dest = (pv_spec_t *)result;
782         } else {
783                 pve = NULL;
784                 sp_dest = (pv_spec_t *)value;
785         }
786         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
787                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
788                 val_s.len == 0 || val_s.s == NULL) {
789                         LM_WARN("cannot get string for value\n");
790                         return -1;
791                 }
792                 size = get_profile_size( (struct dlg_profile_table*)profile, &val_s );
793         } else {
794                 size = get_profile_size( (struct dlg_profile_table*)profile, NULL );
795         }
796
797         memset(&val, 0, sizeof(pv_value_t));
798         val.flags = PV_VAL_INT|PV_TYPE_INT;
799         val.ri = (int)size;
800
801         if(sp_dest->setf(msg, &sp_dest->pvp, (int)EQ_T, &val)<0)
802         {
803                 LM_ERR("setting profile PV failed\n");
804                 return -1;
805         }
806
807         return 1;
808 }
809
810
811 /**
812  * get static name profile size
813  */
814 static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result)
815 {
816         return w_get_profile_size3(msg, profile, result, NULL);
817 }
818
819
820 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
821 {
822         dlg_ctx_t *dctx;
823         int val;
824
825         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
826         {
827                 LM_ERR("no flag value\n");
828                 return -1;
829         }
830         if(val<0 || val>31)
831                 return -1;
832         if ( (dctx=dlg_get_dlg_ctx())==NULL )
833                 return -1;
834
835         dctx->flags |= 1<<val;
836         if(dctx->dlg)
837                 dctx->dlg->sflags |= 1<<val;
838         return 1;
839 }
840
841
842 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
843 {
844         dlg_ctx_t *dctx;
845         int val;
846
847         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
848         {
849                 LM_ERR("no flag value\n");
850                 return -1;
851         }
852         if(val<0 || val>31)
853                 return -1;
854
855         if ( (dctx=dlg_get_dlg_ctx())==NULL )
856                 return -1;
857
858         dctx->flags &= ~(1<<val);
859         if(dctx->dlg)
860                 dctx->dlg->sflags &= ~(1<<val);
861         return 1;
862 }
863
864
865 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
866 {
867         dlg_ctx_t *dctx;
868         int val;
869
870         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
871         {
872                 LM_ERR("no flag value\n");
873                 return -1;
874         }
875         if(val<0 || val>31)
876                 return -1;
877
878         if ( (dctx=dlg_get_dlg_ctx())==NULL )
879                 return -1;
880
881         if(dctx->dlg)
882                 return (dctx->dlg->sflags&(1<<val))?1:-1;
883         return (dctx->flags&(1<<val))?1:-1;
884 }
885
886 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
887 {
888         str tag;
889         int backup_mode;
890
891         if( (msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL )
892         {
893                 LM_ERR("bad TO header\n");
894                 return -1;
895         }
896         tag = get_to(msg)->tag_value;
897         if(tag.s!=0 && tag.len!=0)
898         {
899                 backup_mode = seq_match_mode;
900                 seq_match_mode = SEQ_MATCH_NO_ID;
901                 dlg_onroute(msg, NULL, NULL);
902                 seq_match_mode = backup_mode;
903         } else {
904                 if(dlg_new_dialog(msg, 0)!=0)
905                         return -1;
906         }
907         return 1;
908 }
909
910 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
911 {
912         struct dlg_cell *dlg;
913         int n;
914
915         dlg = dlg_get_ctx_dialog();
916         if(dlg==NULL)
917                 return -1;
918         
919         n = (int)(long)side;
920         if(n==1)
921         {
922                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
923                         return -1;
924                 return 1;
925         } else if(n==2) {
926                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
927                         return -1;
928                 return 1;
929         } else {
930                 if(dlg_bye_all(dlg, NULL)!=0)
931                         return -1;
932                 return 1;
933         }
934 }
935
936 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
937 {
938         struct dlg_cell *dlg;
939         int n;
940         str st = {0,0};
941
942         dlg = dlg_get_ctx_dialog();
943         if(dlg==NULL)
944                 return -1;
945         
946         n = (int)(long)side;
947
948         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
949         {
950                 LM_ERR("unable to get To\n");
951                 return -1;
952         }
953         if(st.s==NULL || st.len == 0)
954         {
955                 LM_ERR("invalid To parameter\n");
956                 return -1;
957         }
958         if(n==1)
959         {
960                 if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
961                         return -1;
962         } else {
963                 if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
964                         return -1;
965         }
966         return 1;
967 }
968
969 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
970 {
971         str sf = {0,0};
972         str st = {0,0};
973         str so = {0,0};
974
975         if(from==0 || to==0 || op==0)
976         {
977                 LM_ERR("invalid parameters\n");
978                 return -1;
979         }
980
981         if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
982         {
983                 LM_ERR("unable to get From\n");
984                 return -1;
985         }
986         if(sf.s==NULL || sf.len == 0)
987         {
988                 LM_ERR("invalid From parameter\n");
989                 return -1;
990         }
991         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
992         {
993                 LM_ERR("unable to get To\n");
994                 return -1;
995         }
996         if(st.s==NULL || st.len == 0)
997         {
998                 LM_ERR("invalid To parameter\n");
999                 return -1;
1000         }
1001         if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
1002         {
1003                 LM_ERR("unable to get OP\n");
1004                 return -1;
1005         }
1006
1007         if(dlg_bridge(&sf, &st, &so)!=0)
1008                 return -1;
1009         return 1;
1010 }
1011
1012
1013 static int fixup_dlg_bye(void** param, int param_no)
1014 {
1015         char *val;
1016         int n = 0;
1017
1018         if (param_no==1) {
1019                 val = (char*)*param;
1020                 if (strcasecmp(val,"all")==0) {
1021                         n = 0;
1022                 } else if (strcasecmp(val,"caller")==0) {
1023                         n = 1;
1024                 } else if (strcasecmp(val,"callee")==0) {
1025                         n = 2;
1026                 } else {
1027                         LM_ERR("invalid param \"%s\"\n", val);
1028                         return E_CFG;
1029                 }
1030                 pkg_free(*param);
1031                 *param=(void*)(long)n;
1032         } else {
1033                 LM_ERR("called with parameter != 1\n");
1034                 return E_BUG;
1035         }
1036         return 0;
1037 }
1038
1039 static int fixup_dlg_refer(void** param, int param_no)
1040 {
1041         char *val;
1042         int n = 0;
1043
1044         if (param_no==1) {
1045                 val = (char*)*param;
1046                 if (strcasecmp(val,"caller")==0) {
1047                         n = 1;
1048                 } else if (strcasecmp(val,"callee")==0) {
1049                         n = 2;
1050                 } else {
1051                         LM_ERR("invalid param \"%s\"\n", val);
1052                         return E_CFG;
1053                 }
1054                 pkg_free(*param);
1055                 *param=(void*)(long)n;
1056         } else if (param_no==2) {
1057                 return fixup_spve_null(param, 1);
1058         } else {
1059                 LM_ERR("called with parameter idx %d\n", param_no);
1060                 return E_BUG;
1061         }
1062         return 0;
1063 }
1064
1065 static int fixup_dlg_bridge(void** param, int param_no)
1066 {
1067         if (param_no>=1 && param_no<=3) {
1068                 return fixup_spve_null(param, 1);
1069         } else {
1070                 LM_ERR("called with parameter idx %d\n", param_no);
1071                 return E_BUG;
1072         }
1073         return 0;
1074 }
1075
1076 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
1077 {
1078         struct dlg_cell *dlg = NULL;
1079         str sc = {0,0};
1080         str sf = {0,0};
1081         str st = {0,0};
1082         unsigned int dir = 0;
1083
1084         if(ci==0 || ft==0 || tt==0)
1085         {
1086                 LM_ERR("invalid parameters\n");
1087                 return -1;
1088         }
1089
1090         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
1091         {
1092                 LM_ERR("unable to get Call-ID\n");
1093                 return -1;
1094         }
1095         if(sc.s==NULL || sc.len == 0)
1096         {
1097                 LM_ERR("invalid Call-ID parameter\n");
1098                 return -1;
1099         }
1100         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
1101         {
1102                 LM_ERR("unable to get From tag\n");
1103                 return -1;
1104         }
1105         if(sf.s==NULL || sf.len == 0)
1106         {
1107                 LM_ERR("invalid From tag parameter\n");
1108                 return -1;
1109         }
1110         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
1111         {
1112                 LM_ERR("unable to get To Tag\n");
1113                 return -1;
1114         }
1115         if(st.s==NULL || st.len == 0)
1116         {
1117                 LM_ERR("invalid To tag parameter\n");
1118                 return -1;
1119         }
1120
1121         dlg = get_dlg(&sc, &sf, &st, &dir, NULL);
1122         if(dlg==NULL)
1123                 return -1;
1124         current_dlg_pointer = dlg;
1125         _dlg_ctx.dlg = dlg;
1126         _dlg_ctx.dir = dir;
1127         return 1;
1128 }
1129
1130 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
1131 {
1132         str from = {0,0};
1133         str to = {0,0};
1134         str op = {0,0};
1135         struct mi_node* node;
1136
1137         node = cmd_tree->node.kids;
1138         if(node == NULL)
1139                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1140         from = node->value;
1141         if(from.len<=0 || from.s==NULL)
1142         {
1143                 LM_ERR("bad From value\n");
1144                 return init_mi_tree( 500, "Bad From value", 14);
1145         }
1146
1147         node = node->next;
1148         if(node == NULL)
1149                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1150         to = node->value;
1151         if(to.len<=0 || to.s == NULL)
1152         {
1153                 return init_mi_tree(500, "Bad To value", 12);
1154         }
1155
1156         node= node->next;
1157         if(node != NULL)
1158         {
1159                 op = node->value;
1160                 if(op.len<=0 || op.s==NULL)
1161                 {
1162                         return init_mi_tree(500, "Bad OP value", 12);
1163                 }
1164         }
1165
1166         if(dlg_bridge(&from, &to, &op)!=0)
1167                 return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
1168
1169         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
1170 }
1171
1172 /**************************** RPC functions ******************************/
1173 /*!
1174  * \brief Helper method that outputs a dialog via the RPC interface
1175  * \see rpc_print_dlg
1176  * \param rpc RPC node that should be filled
1177  * \param c RPC void pointer
1178  * \param dlg printed dialog
1179  * \param with_context if 1 then the dialog context will be also printed
1180  * \return 0 on success, -1 on failure
1181  */
1182 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, struct dlg_cell *dlg, int with_context)
1183 {
1184         rpc_cb_ctx_t rpc_cb;
1185
1186         rpc->printf(c, "hash:%u:%u state:%u timestart:%u timeout:%u",
1187                 dlg->h_entry, dlg->h_id, dlg->state, dlg->start_ts, dlg->tl.timeout);
1188         rpc->printf(c, "\tcallid:%.*s from_tag:%.*s to_tag:%.*s",
1189                 dlg->callid.len, dlg->callid.s,
1190                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
1191                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
1192         rpc->printf(c, "\tfrom_uri:%.*s to_uri:%.*s",
1193                 dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s);
1194         rpc->printf(c, "\tcaller_contact:%.*s caller_cseq:%.*s",
1195                 dlg->contact[DLG_CALLER_LEG].len, dlg->contact[DLG_CALLER_LEG].s,
1196                 dlg->cseq[DLG_CALLER_LEG].len, dlg->cseq[DLG_CALLER_LEG].s);
1197         rpc->printf(c, "\tcaller_route_set: %.*s",
1198                 dlg->route_set[DLG_CALLER_LEG].len, dlg->route_set[DLG_CALLER_LEG].s);
1199         rpc->printf(c, "\tcallee_contact:%.*s callee_cseq:%.*s",
1200                 dlg->contact[DLG_CALLEE_LEG].len, dlg->contact[DLG_CALLEE_LEG].s,
1201                 dlg->cseq[DLG_CALLEE_LEG].len, dlg->cseq[DLG_CALLEE_LEG].s);
1202         rpc->printf(c, "\tcallee_route_set: %.*s",
1203                 dlg->route_set[DLG_CALLEE_LEG].len, dlg->route_set[DLG_CALLEE_LEG].s);
1204         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
1205                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:%.*s",
1206                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
1207                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s);
1208         } else {
1209                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:",
1210                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s);
1211         }
1212         if (with_context) {
1213                 rpc_cb.rpc = rpc;
1214                 rpc_cb.c = c;
1215                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
1216         }
1217 }
1218
1219 /*!
1220  * \brief Helper function that outputs all dialogs via the RPC interface
1221  * \see rpc_print_dlgs
1222  * \param rpc RPC node that should be filled
1223  * \param c RPC void pointer
1224  * \param with_context if 1 then the dialog context will be also printed
1225  */
1226 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
1227 {
1228         struct dlg_cell *dlg;
1229         unsigned int i;
1230
1231         for( i=0 ; i<d_table->size ; i++ ) {
1232                 dlg_lock( d_table, &(d_table->entries[i]) );
1233
1234                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
1235                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1236                 }
1237                 dlg_unlock( d_table, &(d_table->entries[i]) );
1238         }
1239 }
1240
1241 /*!
1242  * \brief Helper function that outputs a dialog via the RPC interface
1243  * \see rpc_print_dlgs
1244  * \param rpc RPC node that should be filled
1245  * \param c RPC void pointer
1246  * \param with_context if 1 then the dialog context will be also printed
1247  */
1248 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
1249         str callid, from_tag;
1250         struct dlg_entry *d_entry;
1251         struct dlg_cell *dlg;
1252         unsigned int h_entry;
1253
1254         if (rpc->scan(c, ".S.S", &callid, &from_tag) < 2) return;
1255
1256         h_entry = core_hash( &callid, 0, d_table->size);
1257         d_entry = &(d_table->entries[h_entry]);
1258         dlg_lock( d_table, d_entry);
1259         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
1260                 if (match_downstream_dialog( dlg, &callid, &from_tag)==1) {
1261                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1262                 }
1263         }
1264         dlg_unlock( d_table, d_entry);
1265 }
1266
1267 /*!
1268  * \brief Helper function that outputs the size of a given profile via the RPC interface
1269  * \see rpc_profile_get_size
1270  * \see rpc_profile_w_value_get_size
1271  * \param rpc RPC node that should be filled
1272  * \param c RPC void pointer
1273  * \param profile_name the given profile
1274  * \param value the given profile value
1275  */
1276 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name, str *value) {
1277         unsigned int size;
1278         struct dlg_profile_table *profile;
1279
1280         profile = search_dlg_profile( profile_name );
1281         if (!profile) {
1282                 rpc->printf(c, "Non existing profile:%.*s",
1283                         profile_name->len, profile_name->s);
1284                 return;
1285         }
1286         size = get_profile_size(profile, value);
1287         if (value) {
1288                 rpc->printf(c, "Profile:%.*s => profile:%.*s value:%.*s count:%u",
1289                         profile_name->len, profile_name->s,
1290                         profile->name.len, profile->name.s,
1291                         value->len, value->s, size);
1292                 return;
1293         } else {
1294                 rpc->printf(c, "Profile:%.*s => profile:%.*s value: count:%u",
1295                         profile_name->len, profile_name->s,
1296                         profile->name.len, profile->name.s, size);
1297                 return;
1298         }
1299         return;
1300 }
1301
1302 /*!
1303  * \brief Helper function that outputs the dialogs belonging to a given profile via the RPC interface
1304  * \see rpc_profile_print_dlgs
1305  * \see rpc_profile_w_value_print_dlgs
1306  * \param rpc RPC node that should be filled
1307  * \param c RPC void pointer
1308  * \param profile_name the given profile
1309  * \param value the given profile value
1310  * \param with_context if 1 then the dialog context will be also printed
1311  */
1312 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name, str *value) {
1313         struct dlg_profile_table *profile;
1314         struct dlg_profile_hash *ph;
1315         unsigned int i;
1316
1317         profile = search_dlg_profile( profile_name );
1318         if (!profile) {
1319                 rpc->printf(c, "Non existing profile:%.*s",
1320                         profile_name->len, profile_name->s);
1321                 return;
1322         }
1323
1324         /* go through the hash and print the dialogs */
1325         if (profile->has_value==0 || value==NULL) {
1326                 /* no value */
1327                 lock_get( &profile->lock );
1328                 for ( i=0 ; i< profile->size ; i++ ) {
1329                         ph = profile->entries[i].first;
1330                         if(ph) {
1331                                 do {
1332                                         /* print dialog */
1333                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1334                                         /* next */
1335                                         ph=ph->next;
1336                                 }while(ph!=profile->entries[i].first);
1337                         }
1338                         lock_release(&profile->lock);
1339                 }
1340         } else {
1341                 /* check for value also */
1342                 lock_get( &profile->lock );
1343                 for ( i=0 ; i< profile->size ; i++ ) {
1344                         ph = profile->entries[i].first;
1345                         if(ph) {
1346                                 do {
1347                                         if ( value->len==ph->value.len &&
1348                                                 memcmp(value->s,ph->value.s,value->len)==0 ) {
1349                                                 /* print dialog */
1350                                                 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1351                                         }
1352                                         /* next */
1353                                         ph=ph->next;
1354                                 }while(ph!=profile->entries[i].first);
1355                         }
1356                         lock_release(&profile->lock);
1357                 }
1358         }
1359 }
1360
1361 /*
1362  * Wrapper around is_known_dlg().
1363  */
1364
1365 static int w_is_known_dlg(struct sip_msg *msg) {
1366         return  is_known_dlg(msg);
1367 }
1368
1369 static const char *rpc_print_dlgs_doc[2] = {
1370         "Print all dialogs", 0
1371 };
1372 static const char *rpc_print_dlgs_ctx_doc[2] = {
1373         "Print all dialogs with associated context", 0
1374 };
1375 static const char *rpc_print_dlg_doc[2] = {
1376         "Print dialog based on callid and fromtag", 0
1377 };
1378 static const char *rpc_print_dlg_ctx_doc[2] = {
1379         "Print dialog with associated context based on callid and fromtag", 0
1380 };
1381 static const char *rpc_end_dlg_entry_id_doc[2] = {
1382         "End a given dialog based on [h_entry] [h_id]", 0
1383 };
1384 static const char *rpc_profile_get_size_doc[2] = {
1385         "Returns the number of dialogs belonging to a profile", 0
1386 };
1387 static const char *rpc_profile_print_dlgs_doc[2] = {
1388         "Lists all the dialogs belonging to a profile", 0
1389 };
1390 static const char *rpc_dlg_bridge_doc[2] = {
1391         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:\
1392  to, from, [outbound SIP proxy]", 0
1393 };
1394
1395
1396 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
1397         internal_rpc_print_dlgs(rpc, c, 0);
1398 }
1399 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
1400         internal_rpc_print_dlgs(rpc, c, 1);
1401 }
1402 static void rpc_print_dlg(rpc_t *rpc, void *c) {
1403         internal_rpc_print_single_dlg(rpc, c, 0);
1404 }
1405 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
1406         internal_rpc_print_single_dlg(rpc, c, 1);
1407 }
1408 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
1409         unsigned int h_entry, h_id;
1410         struct dlg_cell * dlg = NULL;
1411         str rpc_extra_hdrs = {NULL,0};
1412
1413         if (rpc->scan(c, "ddS", &h_entry, &h_id, &rpc_extra_hdrs) < 2) return;
1414
1415         dlg = lookup_dlg(h_entry, h_id, NULL);
1416         if(dlg){
1417                 dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
1418                 unref_dlg(dlg, 1);
1419         }
1420 }
1421 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
1422         str profile_name = {NULL,0};
1423         str value = {NULL,0};
1424
1425         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1426         if (rpc->scan(c, "*.S", &value) > 0) {
1427                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
1428         } else {
1429                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
1430         }
1431         return;
1432 }
1433 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
1434         str profile_name = {NULL,0};
1435         str value = {NULL,0};
1436
1437         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1438         if (rpc->scan(c, "*.S", &value) > 0) {
1439                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
1440         } else {
1441                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
1442         }
1443         return;
1444 }
1445 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
1446         str from = {NULL,0};
1447         str to = {NULL,0};
1448         str op = {NULL,0};
1449
1450         if (rpc->scan(c, "SSS", &from, &to, &op) < 2) return;
1451
1452         dlg_bridge(&from, &to, &op);
1453 }
1454
1455 static rpc_export_t rpc_methods[] = {
1456         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, 0},
1457         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, 0},
1458         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
1459         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
1460         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
1461         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
1462         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, 0},
1463         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
1464         {0, 0, 0, 0}
1465 };