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