all: updated FSF address in GPL text
[sip-router] / modules / 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 "../../hashes.h"
70 #include "../../lib/kcore/kstats_wrapper.h"
71 #include "../../mem/mem.h"
72 #include "../../lib/kmi/mi.h"
73 #include "../../timer_proc.h"
74 #include "../../lvalue.h"
75 #include "../../parser/parse_to.h"
76 #include "../../modules/tm/tm_load.h"
77 #include "../../rpc_lookup.h"
78 #include "../rr/api.h"
79 #include "dlg_hash.h"
80 #include "dlg_timer.h"
81 #include "dlg_handlers.h"
82 #include "dlg_load.h"
83 #include "dlg_cb.h"
84 #include "dlg_db_handler.h"
85 #include "dlg_req_within.h"
86 #include "dlg_profile.h"
87 #include "dlg_var.h"
88 #include "dlg_transfer.h"
89
90 MODULE_VERSION
91
92
93 #define RPC_DATE_BUF_LEN 21
94
95 static int mod_init(void);
96 static int child_init(int rank);
97 static void mod_destroy(void);
98
99 /* module parameter */
100 static int dlg_hash_size = 4096;
101 static char* rr_param = "did";
102 static int dlg_flag = -1;
103 static str timeout_spec = {NULL, 0};
104 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
105 static int seq_match_mode = SEQ_MATCH_STRICT_ID;
106 static char* profiles_wv_s = NULL;
107 static char* profiles_nv_s = NULL;
108 str dlg_extra_hdrs = {NULL,0};
109 static int db_fetch_rows = 200;
110 int initial_cbs_inscript = 1;
111 int dlg_wait_ack = 1;
112
113 int dlg_event_rt[DLG_EVENTRT_MAX];
114
115 str dlg_bridge_controller = {"sip:controller@kamailio.org", 27};
116
117 str dlg_bridge_contact = {"sip:controller@kamailio.org:5060", 32};
118
119 str ruri_pvar_param = {"$ru", 3};
120 pv_elem_t * ruri_param_model = NULL;
121
122 /* statistic variables */
123 int dlg_enable_stats = 1;
124 int active_dlgs_cnt = 0;
125 int early_dlgs_cnt = 0;
126 int detect_spirals = 1;
127 int dlg_send_bye = 0;
128 int dlg_timeout_noreset = 0;
129 stat_var *active_dlgs = 0;
130 stat_var *processed_dlgs = 0;
131 stat_var *expired_dlgs = 0;
132 stat_var *failed_dlgs = 0;
133 stat_var *early_dlgs  = 0;
134
135 struct tm_binds d_tmb;
136 struct rr_binds d_rrb;
137 pv_spec_t timeout_avp;
138
139 int dlg_db_mode_param = DB_MODE_NONE;
140
141 str dlg_xavp_cfg = {0};
142 int dlg_ka_timer = 0;
143 int dlg_ka_interval = 0;
144 int dlg_clean_timer = 90;
145
146 /* db stuff */
147 static str db_url = str_init(DEFAULT_DB_URL);
148 static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
149
150 static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
151                 pv_value_t *res);
152
153 void dlg_ka_timer_exec(unsigned int ticks, void* param);
154 void dlg_clean_timer_exec(unsigned int ticks, void* param);
155
156 /* commands wrappers and fixups */
157 static int fixup_profile(void** param, int param_no);
158 static int fixup_get_profile2(void** param, int param_no);
159 static int fixup_get_profile3(void** param, int param_no);
160 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
161 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
162 static int w_is_in_profile(struct sip_msg*, char*, char*);
163 static int w_get_profile_size2(struct sip_msg*, char*, char*);
164 static int w_get_profile_size3(struct sip_msg*, char*, char*, char*);
165 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
166 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
167 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
168 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2);
169 static int w_dlg_manage(struct sip_msg*, char*, char*);
170 static int w_dlg_bye(struct sip_msg*, char*, char*);
171 static int w_dlg_refer(struct sip_msg*, char*, char*);
172 static int w_dlg_bridge(struct sip_msg*, char*, char*, char*);
173 static int w_dlg_set_timeout(struct sip_msg*, char*, char*, char*);
174 static int w_dlg_set_timeout_by_profile2(struct sip_msg *, char *, char *);
175 static int w_dlg_set_timeout_by_profile3(struct sip_msg *, char *, char *, 
176                                         char *);
177 static int fixup_dlg_bye(void** param, int param_no);
178 static int fixup_dlg_refer(void** param, int param_no);
179 static int fixup_dlg_bridge(void** param, int param_no);
180 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
181 static int w_is_known_dlg(struct sip_msg *);
182
183 static cmd_export_t cmds[]={
184         {"dlg_manage", (cmd_function)w_dlg_manage,            0,0,
185                         0, REQUEST_ROUTE },
186         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  1,fixup_profile,
187                         0, ANY_ROUTE },
188         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  2,fixup_profile,
189                         0, ANY_ROUTE },
190         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  1,fixup_profile,
191                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
192         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  2,fixup_profile,
193                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
194         {"is_in_profile", (cmd_function)w_is_in_profile,      1,fixup_profile,
195                         0, ANY_ROUTE },
196         {"is_in_profile", (cmd_function)w_is_in_profile,      2,fixup_profile,
197                         0, ANY_ROUTE },
198         {"get_profile_size",(cmd_function)w_get_profile_size2, 2,fixup_get_profile2,
199                         0, ANY_ROUTE },
200         {"get_profile_size",(cmd_function)w_get_profile_size3, 3,fixup_get_profile3,
201                         0, ANY_ROUTE },
202         {"dlg_setflag", (cmd_function)w_dlg_setflag,          1,fixup_igp_null,
203                         0, ANY_ROUTE },
204         {"dlg_resetflag", (cmd_function)w_dlg_resetflag,      1,fixup_igp_null,
205                         0, ANY_ROUTE },
206         {"dlg_isflagset", (cmd_function)w_dlg_isflagset,      1,fixup_igp_null,
207                         0, ANY_ROUTE },
208         {"dlg_bye",(cmd_function)w_dlg_bye,                   1,fixup_dlg_bye,
209                         0, ANY_ROUTE },
210         {"dlg_refer",(cmd_function)w_dlg_refer,               2,fixup_dlg_refer,
211                         0, ANY_ROUTE },
212         {"dlg_bridge",(cmd_function)w_dlg_bridge,             3,fixup_dlg_bridge,
213                         0, ANY_ROUTE },
214         {"dlg_get",(cmd_function)w_dlg_get,                   3,fixup_dlg_bridge,
215                         0, ANY_ROUTE },
216         {"is_known_dlg", (cmd_function)w_is_known_dlg,        0, NULL,
217                         0, ANY_ROUTE },
218         {"dlg_set_timeout", (cmd_function)w_dlg_set_timeout,  1,fixup_igp_null,
219                         0, ANY_ROUTE },
220         {"dlg_set_timeout", (cmd_function)w_dlg_set_timeout,  3,fixup_igp_all,
221                         0, ANY_ROUTE },
222         {"dlg_set_timeout_by_profile", 
223                 (cmd_function) w_dlg_set_timeout_by_profile2, 2, fixup_profile,
224                         0, ANY_ROUTE },
225         {"dlg_set_timeout_by_profile", 
226                 (cmd_function) w_dlg_set_timeout_by_profile3, 3, fixup_profile,
227                         0, ANY_ROUTE },
228         {"dlg_set_property", (cmd_function)w_dlg_set_property,1,fixup_spve_null,
229                         0, ANY_ROUTE },
230         {"load_dlg",  (cmd_function)load_dlg,   0, 0, 0, 0},
231         {0,0,0,0,0,0}
232 };
233
234 static param_export_t mod_params[]={
235         { "enable_stats",          INT_PARAM, &dlg_enable_stats         },
236         { "hash_size",             INT_PARAM, &dlg_hash_size            },
237         { "rr_param",              STR_PARAM, &rr_param                 },
238         { "dlg_flag",              INT_PARAM, &dlg_flag                 },
239         { "timeout_avp",           STR_PARAM, &timeout_spec.s           },
240         { "default_timeout",       INT_PARAM, &default_timeout          },
241         { "dlg_extra_hdrs",        STR_PARAM, &dlg_extra_hdrs.s         },
242         { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
243         { "detect_spirals",        INT_PARAM, &detect_spirals,          },
244         { "db_url",                STR_PARAM, &db_url.s                 },
245         { "db_mode",               INT_PARAM, &dlg_db_mode_param        },
246         { "table_name",            STR_PARAM, &dialog_table_name        },
247         { "call_id_column",        STR_PARAM, &call_id_column.s         },
248         { "from_uri_column",       STR_PARAM, &from_uri_column.s        },
249         { "from_tag_column",       STR_PARAM, &from_tag_column.s        },
250         { "to_uri_column",         STR_PARAM, &to_uri_column.s          },
251         { "to_tag_column",         STR_PARAM, &to_tag_column.s          },
252         { "h_id_column",           STR_PARAM, &h_id_column.s            },
253         { "h_entry_column",        STR_PARAM, &h_entry_column.s         },
254         { "state_column",          STR_PARAM, &state_column.s           },
255         { "start_time_column",     STR_PARAM, &start_time_column.s      },
256         { "timeout_column",        STR_PARAM, &timeout_column.s         },
257         { "to_cseq_column",        STR_PARAM, &to_cseq_column.s         },
258         { "from_cseq_column",      STR_PARAM, &from_cseq_column.s       },
259         { "to_route_column",       STR_PARAM, &to_route_column.s        },
260         { "from_route_column",     STR_PARAM, &from_route_column.s      },
261         { "to_contact_column",     STR_PARAM, &to_contact_column.s      },
262         { "from_contact_column",   STR_PARAM, &from_contact_column.s    },
263         { "to_sock_column",        STR_PARAM, &to_sock_column.s         },
264         { "from_sock_column",      STR_PARAM, &from_sock_column.s       },
265         { "sflags_column",         STR_PARAM, &sflags_column.s          },
266         { "toroute_name_column",   STR_PARAM, &toroute_name_column.s    },
267
268         { "vars_table_name",       STR_PARAM, &dialog_vars_table_name   },
269         { "vars_h_id_column",      STR_PARAM, &vars_h_id_column.s       },
270         { "vars_h_entry_column",   STR_PARAM, &vars_h_entry_column.s    },
271         { "vars_key_column",       STR_PARAM, &vars_key_column.s        },
272         { "vars_value_column",     STR_PARAM, &vars_value_column.s      },
273
274         { "db_update_period",      INT_PARAM, &db_update_period         },
275         { "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
276         { "profiles_with_value",   STR_PARAM, &profiles_wv_s            },
277         { "profiles_no_value",     STR_PARAM, &profiles_nv_s            },
278         { "bridge_controller",     STR_PARAM, &dlg_bridge_controller.s  },
279         { "bridge_contact",        PARAM_STR, &dlg_bridge_contact       },
280         { "ruri_pvar",             STR_PARAM, &ruri_pvar_param.s        },
281         { "initial_cbs_inscript",  INT_PARAM, &initial_cbs_inscript     },
282         { "send_bye",              INT_PARAM, &dlg_send_bye             },
283         { "wait_ack",              INT_PARAM, &dlg_wait_ack             },
284         { "xavp_cfg",              STR_PARAM, &dlg_xavp_cfg.s           },
285         { "ka_timer",              INT_PARAM, &dlg_ka_timer             },
286         { "ka_interval",           INT_PARAM, &dlg_ka_interval          },
287         { "timeout_noreset",       INT_PARAM, &dlg_timeout_noreset      },
288         { 0,0,0 }
289 };
290
291
292 static stat_export_t mod_stats[] = {
293         {"active_dialogs" ,     STAT_NO_RESET,  &active_dlgs       },
294         {"early_dialogs",       STAT_NO_RESET,  &early_dlgs        },
295         {"processed_dialogs" ,  0,              &processed_dlgs    },
296         {"expired_dialogs" ,    0,              &expired_dlgs      },
297         {"failed_dialogs",      0,              &failed_dlgs       },
298         {0,0,0}
299 };
300
301 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param);
302
303 static mi_export_t mi_cmds[] = {
304         { "dlg_list",           mi_print_dlgs,       0,  0,  0},
305         { "dlg_list_ctx",       mi_print_dlgs_ctx,   0,  0,  0},
306         { "dlg_end_dlg",        mi_terminate_dlg,    0,  0,  0},
307         { "dlg_terminate_dlg",  mi_terminate_dlgs,   0,  0,  0},
308         { "profile_get_size",   mi_get_profile,      0,  0,  0},
309         { "profile_list_dlgs",  mi_profile_list,     0,  0,  0},
310         { "dlg_bridge",         mi_dlg_bridge,       0,  0,  0},
311         { 0, 0, 0, 0, 0}
312 };
313
314 static rpc_export_t rpc_methods[];
315
316 static pv_export_t mod_items[] = {
317         { {"DLG_count",  sizeof("DLG_count")-1}, PVT_OTHER,  pv_get_dlg_count,    0,
318                 0, 0, 0, 0 },
319         { {"DLG_lifetime",sizeof("DLG_lifetime")-1}, PVT_OTHER, pv_get_dlg_lifetime, 0,
320                 0, 0, 0, 0 },
321         { {"DLG_status",  sizeof("DLG_status")-1}, PVT_OTHER, pv_get_dlg_status, 0,
322                 0, 0, 0, 0 },
323         { {"dlg_ctx",  sizeof("dlg_ctx")-1}, PVT_OTHER, pv_get_dlg_ctx,
324                 pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
325         { {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
326                 0, pv_parse_dlg_name, 0, 0, 0 },
327         { {"dlg_var", sizeof("dlg_var")-1}, PVT_OTHER, pv_get_dlg_variable,
328                 pv_set_dlg_variable,    pv_parse_dialog_var_name, 0, 0, 0},
329         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
330 };
331
332 struct module_exports exports= {
333         "dialog",        /* module's name */
334         DEFAULT_DLFLAGS, /* dlopen flags */
335         cmds,            /* exported functions */
336         mod_params,      /* param exports */
337         mod_stats,       /* exported statistics */
338         mi_cmds,         /* exported MI functions */
339         mod_items,       /* exported pseudo-variables */
340         0,               /* extra processes */
341         mod_init,        /* module initialization function */
342         0,               /* reply processing function */
343         mod_destroy,
344         child_init       /* per-child init function */
345 };
346
347
348 static int fixup_profile(void** param, int param_no)
349 {
350         struct dlg_profile_table *profile;
351         pv_elem_t *model=NULL;
352         str s;
353
354         s.s = (char*)(*param);
355         s.len = strlen(s.s);
356         if(s.len==0) {
357                 LM_ERR("param %d is empty string!\n", param_no);
358                 return E_CFG;
359         }
360
361         if (param_no==1) {
362                 profile = search_dlg_profile( &s );
363                 if (profile==NULL) {
364                         LM_CRIT("profile <%s> not definited\n",s.s);
365                         return E_CFG;
366                 }
367                 pkg_free(*param);
368                 *param = (void*)profile;
369                 return 0;
370         } else if (param_no==2) {
371                 if(pv_parse_format(&s ,&model) || model==NULL) {
372                         LM_ERR("wrong format [%s] for value param!\n", s.s);
373                         return E_CFG;
374                 }
375                 *param = (void*)model;
376         }
377         return 0;
378 }
379
380
381 static int fixup_get_profile2(void** param, int param_no)
382 {
383         pv_spec_t *sp;
384         int ret;
385
386         if (param_no==1) {
387                 return fixup_profile(param, 1);
388         } else if (param_no==2) {
389                 ret = fixup_pvar_null(param, 1);
390                 if (ret<0) return ret;
391                 sp = (pv_spec_t*)(*param);
392                 if (sp->type!=PVT_AVP && sp->type!=PVT_SCRIPTVAR) {
393                         LM_ERR("return must be an AVP or SCRIPT VAR!\n");
394                         return E_SCRIPT;
395                 }
396         }
397         return 0;
398 }
399
400
401 static int fixup_get_profile3(void** param, int param_no)
402 {
403         if (param_no==1) {
404                 return fixup_profile(param, 1);
405         } else if (param_no==2) {
406                 return fixup_profile(param, 2);
407         } else if (param_no==3) {
408                 return fixup_get_profile2( param, 2);
409         }
410         return 0;
411 }
412
413
414
415 int load_dlg( struct dlg_binds *dlgb )
416 {
417         dlgb->register_dlgcb = register_dlgcb;
418         dlgb->terminate_dlg = dlg_bye_all;
419         dlgb->set_dlg_var = set_dlg_variable;
420         dlgb->get_dlg_var = get_dlg_variable;
421         dlgb->get_dlg = dlg_get_msg_dialog;
422         dlgb->release_dlg = dlg_release;
423         return 1;
424 }
425
426
427 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
428                 pv_value_t *res)
429 {
430         int n;
431         int l;
432         char *ch;
433
434         if(msg==NULL || res==NULL)
435                 return -1;
436
437         n = active_dlgs ? get_stat_val(active_dlgs) : 0;
438         l = 0;
439         ch = int2str( n, &l);
440
441         res->rs.s = ch;
442         res->rs.len = l;
443
444         res->ri = n;
445         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
446
447         return 0;
448 }
449
450
451 static int mod_init(void)
452 {
453         unsigned int n;
454
455         if(dlg_ka_interval!=0 && dlg_ka_interval<30) {
456                 LM_ERR("ka interval too low (%d), has to be at least 30\n",
457                                 dlg_ka_interval);
458                 return -1;
459         }
460
461         dlg_event_rt[DLG_EVENTRT_START] = route_lookup(&event_rt, "dialog:start");
462         dlg_event_rt[DLG_EVENTRT_END] = route_lookup(&event_rt, "dialog:end");
463         dlg_event_rt[DLG_EVENTRT_FAILED] = route_lookup(&event_rt, "dialog:failed");
464
465 #ifdef STATISTICS
466         /* register statistics */
467         if (register_module_stats( exports.name, mod_stats)!=0 ) {
468                 LM_ERR("failed to register %s statistics\n", exports.name);
469                 return -1;
470         }
471 #endif
472
473         if(register_mi_mod(exports.name, mi_cmds)!=0)
474         {
475                 LM_ERR("failed to register MI commands\n");
476                 return -1;
477         }
478
479         if (rpc_register_array(rpc_methods)!=0) {
480                 LM_ERR("failed to register RPC commands\n");
481                 return -1;
482         }
483
484         if(faked_msg_init()<0)
485                 return -1;
486
487         if(dlg_bridge_init_hdrs()<0)
488                 return -1;
489
490         if (timeout_spec.s)
491                 timeout_spec.len = strlen(timeout_spec.s);
492
493         dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
494         db_url.len = strlen(db_url.s);
495         call_id_column.len = strlen(call_id_column.s);
496         from_uri_column.len = strlen(from_uri_column.s);
497         from_tag_column.len = strlen(from_tag_column.s);
498         to_uri_column.len = strlen(to_uri_column.s);
499         to_tag_column.len = strlen(to_tag_column.s);
500         h_id_column.len = strlen(h_id_column.s);
501         h_entry_column.len = strlen(h_entry_column.s);
502         state_column.len = strlen(state_column.s);
503         start_time_column.len = strlen(start_time_column.s);
504         timeout_column.len = strlen(timeout_column.s);
505         to_cseq_column.len = strlen(to_cseq_column.s);
506         from_cseq_column.len = strlen(from_cseq_column.s);
507         to_route_column.len = strlen(to_route_column.s);
508         from_route_column.len = strlen(from_route_column.s);
509         to_contact_column.len = strlen(to_contact_column.s);
510         from_contact_column.len = strlen(from_contact_column.s);
511         to_sock_column.len = strlen(to_sock_column.s);
512         from_sock_column.len = strlen(from_sock_column.s);
513         sflags_column.len = strlen(sflags_column.s);
514         toroute_name_column.len = strlen(toroute_name_column.s);
515         dialog_table_name.len = strlen(dialog_table_name.s);
516
517         dialog_vars_table_name.len = strlen(dialog_vars_table_name.s);
518         vars_h_id_column.len = strlen(vars_h_id_column.s);
519         vars_h_entry_column.len = strlen(vars_h_entry_column.s);
520         vars_key_column.len = strlen(vars_key_column.s);
521         vars_value_column.len = strlen(vars_value_column.s);
522
523         if(dlg_xavp_cfg.s!=NULL)
524                 dlg_xavp_cfg.len = strlen(dlg_xavp_cfg.s);
525
526         /* param checkings */
527         if (dlg_flag==-1) {
528                 LM_ERR("no dlg flag set!!\n");
529                 return -1;
530         } else if (dlg_flag>MAX_FLAG) {
531                 LM_ERR("invalid dlg flag %d!!\n",dlg_flag);
532                 return -1;
533         }
534
535         if (rr_param==0 || rr_param[0]==0) {
536                 LM_ERR("empty rr_param!!\n");
537                 return -1;
538         } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
539                 LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
540                 return -1;
541         }
542
543         if (timeout_spec.s) {
544                 if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 
545                                 && (timeout_avp.type!=PVT_AVP)){
546                         LM_ERR("malformed or non AVP timeout "
547                                 "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
548                         return -1;
549                 }
550         }
551
552         if (default_timeout<=0) {
553                 LM_ERR("0 default_timeout not accepted!!\n");
554                 return -1;
555         }
556
557         if (ruri_pvar_param.s==NULL || *ruri_pvar_param.s=='\0') {
558                 LM_ERR("invalid r-uri PV string\n");
559                 return -1;
560         }
561         ruri_pvar_param.len = strlen(ruri_pvar_param.s);
562         if(pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
563                                 || ruri_param_model==NULL) {
564                 LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
565                 return -1;
566         }
567
568         if (initial_cbs_inscript != 0 && initial_cbs_inscript != 1) {
569                 LM_ERR("invalid parameter for running initial callbacks in-script"
570                                 " (must be either 0 or 1)\n");
571                 return -1;
572         }
573
574         /* update the len of the extra headers */
575         if (dlg_extra_hdrs.s)
576                 dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
577
578         if (seq_match_mode!=SEQ_MATCH_NO_ID &&
579         seq_match_mode!=SEQ_MATCH_FALLBACK &&
580         seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
581                 LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
582                 return -1;
583         }
584
585         if (detect_spirals != 0 && detect_spirals != 1) {
586                 LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
587                 return -1;
588         }
589
590         if (dlg_timeout_noreset != 0 && dlg_timeout_noreset != 1) {
591                 LM_ERR("invalid value %d for timeout_noreset param!!\n",
592                                 dlg_timeout_noreset);
593                 return -1;
594         }
595
596         /* if statistics are disabled, prevent their registration to core */
597         if (dlg_enable_stats==0)
598                 exports.stats = 0;
599
600         /* create profile hashes */
601         if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
602                 LM_ERR("failed to add profiles without value\n");
603                 return -1;
604         }
605         if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
606                 LM_ERR("failed to add profiles with value\n");
607                 return -1;
608         }
609
610         /* load the TM API */
611         if (load_tm_api(&d_tmb)!=0) {
612                 LM_ERR("can't load TM API\n");
613                 return -1;
614         }
615
616         /* load RR API also */
617         if (load_rr_api(&d_rrb)!=0) {
618                 LM_ERR("can't load RR API\n");
619                 return -1;
620         }
621
622         /* register callbacks*/
623         /* listen for all incoming requests  */
624         if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
625                 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
626                 return -1;
627         }
628
629         /* listen for all routed requests  */
630         if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
631                 LM_ERR("cannot register RR callback\n");
632                 return -1;
633         }
634
635         if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
636                 LM_ERR("cannot register script callback");
637                 return -1;
638         }
639         if (register_script_cb(dlg_cfg_cb,
640                                 PRE_SCRIPT_CB|REQUEST_CB,0)<0)
641         {
642                 LM_ERR("cannot register pre-script ctx callback\n");
643                 return -1;
644         }
645         if (register_script_cb(dlg_cfg_cb,
646                                 POST_SCRIPT_CB|REQUEST_CB,0)<0)
647         {
648                 LM_ERR("cannot register post-script ctx callback\n");
649                 return -1;
650         }
651
652         if (register_script_cb( spiral_detect_reset, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
653                 LM_ERR("cannot register req pre-script spiral detection reset callback\n");
654                 return -1;
655         }
656
657         if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
658                 LM_ERR("failed to register timer \n");
659                 return -1;
660         }
661
662         /* init handlers */
663         init_dlg_handlers( rr_param, dlg_flag,
664                 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
665
666         /* init timer */
667         if (init_dlg_timer(dlg_ontimeout)!=0) {
668                 LM_ERR("cannot init timer list\n");
669                 return -1;
670         }
671
672         /* sanitize dlg_hash_zie */
673         if (dlg_hash_size < 1){
674                 LM_WARN("hash_size is smaller "
675                                 "then 1  -> rounding from %d to 1\n",
676                                 dlg_hash_size);
677                 dlg_hash_size = 1;
678         }
679         /* initialized the hash table */
680         for( n=0 ; n<(8*sizeof(n)) ; n++) {
681                 if (dlg_hash_size==(1<<n))
682                         break;
683                 if (n && dlg_hash_size<(1<<n)) {
684                         LM_WARN("hash_size is not a power "
685                                 "of 2 as it should be -> rounding from %d to %d\n",
686                                 dlg_hash_size, 1<<(n-1));
687                         dlg_hash_size = 1<<(n-1);
688                 }
689         }
690
691         if ( init_dlg_table(dlg_hash_size)<0 ) {
692                 LM_ERR("failed to create hash table\n");
693                 return -1;
694         }
695
696         /* if a database should be used to store the dialogs' information */
697         dlg_db_mode = dlg_db_mode_param;
698         if (dlg_db_mode==DB_MODE_NONE) {
699                 db_url.s = 0; db_url.len = 0;
700         } else {
701                 if (dlg_db_mode!=DB_MODE_REALTIME &&
702                 dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
703                         LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
704                         return -1;
705                 }
706                 if ( !db_url.s || db_url.len==0 ) {
707                         LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
708                         return -1;
709                 }
710                 if (init_dlg_db(&db_url, dlg_hash_size, db_update_period,db_fetch_rows)!=0) {
711                         LM_ERR("failed to initialize the DB support\n");
712                         return -1;
713                 }
714                 run_load_callbacks();
715         }
716
717         destroy_dlg_callbacks( DLGCB_LOADED );
718
719         /* timer process to send keep alive requests */
720         if(dlg_ka_timer>0 && dlg_ka_interval>0)
721                 register_sync_timers(1);
722
723         /* timer process to clean old unconfirmed dialogs */
724         register_sync_timers(1);
725
726         return 0;
727 }
728
729
730 static int child_init(int rank)
731 {
732         dlg_db_mode = dlg_db_mode_param;
733
734         if(rank==PROC_MAIN) {
735                 if(dlg_ka_timer>0 && dlg_ka_interval>0) {
736                         if(fork_sync_timer(PROC_TIMER, "Dialog KA Timer", 1 /*socks flag*/,
737                                         dlg_ka_timer_exec, NULL, dlg_ka_timer /*sec*/)<0) {
738                                 LM_ERR("failed to start ka timer routine as process\n");
739                                 return -1; /* error */
740                         }
741                 }
742
743                 if(fork_sync_timer(PROC_TIMER, "Dialog Clean Timer", 1 /*socks flag*/,
744                                         dlg_clean_timer_exec, NULL, dlg_clean_timer /*sec*/)<0) {
745                         LM_ERR("failed to start clean timer routine as process\n");
746                         return -1; /* error */
747                 }
748         }
749
750         if (rank==1) {
751                 if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
752                 if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
753         }
754
755         if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
756         (rank>0 || rank==PROC_TIMER)) ||
757         (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
758                 if ( dlg_connect_db(&db_url) ) {
759                         LM_ERR("failed to connect to database (rank=%d)\n",rank);
760                         return -1;
761                 }
762         }
763
764         /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
765          * for the rest of the processes will be the same as DB_MODE_NONE */
766         if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
767                 dlg_db_mode = DB_MODE_NONE;
768         /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
769         if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
770                         rank==PROC_MAIN)
771                 dlg_db_mode = DB_MODE_NONE;
772
773         return 0;
774 }
775
776
777 static void mod_destroy(void)
778 {
779         if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
780                 dialog_update_db(0, 0);
781                 destroy_dlg_db();
782         }
783         dlg_bridge_destroy_hdrs();
784         /* no DB interaction from now on */
785         dlg_db_mode = DB_MODE_NONE;
786         destroy_dlg_table();
787         destroy_dlg_timer();
788         destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
789         destroy_dlg_handlers();
790         destroy_dlg_profiles();
791 }
792
793
794
795 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
796 {
797         pv_elem_t *pve;
798         str val_s;
799
800         pve = (pv_elem_t *)value;
801
802         if (((struct dlg_profile_table*)profile)->has_value) {
803                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
804                 val_s.len == 0 || val_s.s == NULL) {
805                         LM_WARN("cannot get string for value\n");
806                         return -1;
807                 }
808                 if ( set_dlg_profile( msg, &val_s,
809                 (struct dlg_profile_table*)profile) < 0 ) {
810                         LM_ERR("failed to set profile");
811                         return -1;
812                 }
813         } else {
814                 if ( set_dlg_profile( msg, NULL,
815                 (struct dlg_profile_table*)profile) < 0 ) {
816                         LM_ERR("failed to set profile");
817                         return -1;
818                 }
819         }
820         return 1;
821 }
822
823
824
825 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
826 {
827         pv_elem_t *pve;
828         str val_s;
829
830         pve = (pv_elem_t *)value;
831
832         if (((struct dlg_profile_table*)profile)->has_value) {
833                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
834                 val_s.len == 0 || val_s.s == NULL) {
835                         LM_WARN("cannot get string for value\n");
836                         return -1;
837                 }
838                 if ( unset_dlg_profile( msg, &val_s,
839                 (struct dlg_profile_table*)profile) < 0 ) {
840                         LM_ERR("failed to unset profile");
841                         return -1;
842                 }
843         } else {
844                 if ( unset_dlg_profile( msg, NULL,
845                 (struct dlg_profile_table*)profile) < 0 ) {
846                         LM_ERR("failed to unset profile");
847                         return -1;
848                 }
849         }
850         return 1;
851 }
852
853
854
855 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
856 {
857         pv_elem_t *pve;
858         str val_s;
859
860         pve = (pv_elem_t *)value;
861
862         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
863                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
864                 val_s.len == 0 || val_s.s == NULL) {
865                         LM_WARN("cannot get string for value\n");
866                         return -1;
867                 }
868                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
869                         &val_s);
870         } else {
871                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
872                         NULL);
873         }
874 }
875
876
877 /**
878  * get dynamic name profile size
879  */
880 static int w_get_profile_size3(struct sip_msg *msg, char *profile,
881                 char *value, char *result)
882 {
883         pv_elem_t *pve;
884         str val_s;
885         pv_spec_t *sp_dest;
886         unsigned int size;
887         pv_value_t val;
888
889         if(result!=NULL)
890         {
891                 pve = (pv_elem_t *)value;
892                 sp_dest = (pv_spec_t *)result;
893         } else {
894                 pve = NULL;
895                 sp_dest = (pv_spec_t *)value;
896         }
897         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
898                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
899                 val_s.len == 0 || val_s.s == NULL) {
900                         LM_WARN("cannot get string for value\n");
901                         return -1;
902                 }
903                 size = get_profile_size( (struct dlg_profile_table*)profile, &val_s );
904         } else {
905                 size = get_profile_size( (struct dlg_profile_table*)profile, NULL );
906         }
907
908         memset(&val, 0, sizeof(pv_value_t));
909         val.flags = PV_VAL_INT|PV_TYPE_INT;
910         val.ri = (int)size;
911
912         if(sp_dest->setf(msg, &sp_dest->pvp, (int)EQ_T, &val)<0)
913         {
914                 LM_ERR("setting profile PV failed\n");
915                 return -1;
916         }
917
918         return 1;
919 }
920
921
922 /**
923  * get static name profile size
924  */
925 static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result)
926 {
927         return w_get_profile_size3(msg, profile, result, NULL);
928 }
929
930
931 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
932 {
933         dlg_ctx_t *dctx;
934         dlg_cell_t *d;
935         int val;
936
937         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
938         {
939                 LM_ERR("no flag value\n");
940                 return -1;
941         }
942         if(val<0 || val>31)
943                 return -1;
944         if ( (dctx=dlg_get_dlg_ctx())==NULL )
945                 return -1;
946
947         dctx->flags |= 1<<val;
948         d = dlg_get_by_iuid(&dctx->iuid);
949         if(d!=NULL) {
950                 d->sflags |= 1<<val;
951                 dlg_release(d);
952         }
953         return 1;
954 }
955
956
957 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
958 {
959         dlg_ctx_t *dctx;
960         dlg_cell_t *d;
961         int val;
962
963         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
964         {
965                 LM_ERR("no flag value\n");
966                 return -1;
967         }
968         if(val<0 || val>31)
969                 return -1;
970
971         if ( (dctx=dlg_get_dlg_ctx())==NULL )
972                 return -1;
973
974         dctx->flags &= ~(1<<val);
975         d = dlg_get_by_iuid(&dctx->iuid);
976         if(d!=NULL) {
977                 d->sflags &= ~(1<<val);
978                 dlg_release(d);
979         }
980         return 1;
981 }
982
983
984 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
985 {
986         dlg_ctx_t *dctx;
987         dlg_cell_t *d;
988         int val;
989         int ret;
990
991         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
992         {
993                 LM_ERR("no flag value\n");
994                 return -1;
995         }
996         if(val<0 || val>31)
997                 return -1;
998
999         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1000                 return -1;
1001
1002         d = dlg_get_by_iuid(&dctx->iuid);
1003         if(d!=NULL) {
1004                 ret = (d->sflags&(1<<val))?1:-1;
1005                 dlg_release(d);
1006                 return ret;
1007         }
1008         return (dctx->flags&(1<<val))?1:-1;
1009 }
1010
1011 /**
1012  *
1013  */
1014 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
1015 {
1016         return dlg_manage(msg);
1017 }
1018
1019 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
1020 {
1021         dlg_cell_t *dlg = NULL;
1022         int n;
1023
1024         dlg = dlg_get_ctx_dialog();
1025         if(dlg==NULL)
1026                 return -1;
1027         
1028         n = (int)(long)side;
1029         if(n==1)
1030         {
1031                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
1032                         goto error;
1033                 goto done;
1034         } else if(n==2) {
1035                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
1036                         goto error;
1037                 goto done;
1038         } else {
1039                 if(dlg_bye_all(dlg, NULL)!=0)
1040                         goto error;
1041                 goto done;
1042         }
1043
1044 done:
1045         dlg_release(dlg);
1046         return 1;
1047
1048 error:
1049         dlg_release(dlg);
1050         return -1;
1051 }
1052
1053 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
1054 {
1055         dlg_cell_t *dlg;
1056         int n;
1057         str st = {0,0};
1058
1059         dlg = dlg_get_ctx_dialog();
1060         if(dlg==NULL)
1061                 return -1;
1062         
1063         n = (int)(long)side;
1064
1065         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
1066         {
1067                 LM_ERR("unable to get To\n");
1068                 goto error;
1069         }
1070         if(st.s==NULL || st.len == 0)
1071         {
1072                 LM_ERR("invalid To parameter\n");
1073                 goto error;
1074         }
1075         if(n==1)
1076         {
1077                 if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
1078                         goto error;
1079         } else {
1080                 if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
1081                         goto error;
1082         }
1083
1084         dlg_release(dlg);
1085         return 1;
1086
1087 error:
1088         dlg_release(dlg);
1089         return -1;
1090 }
1091
1092 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
1093 {
1094         str sf = {0,0};
1095         str st = {0,0};
1096         str so = {0,0};
1097
1098         if(from==0 || to==0 || op==0)
1099         {
1100                 LM_ERR("invalid parameters\n");
1101                 return -1;
1102         }
1103
1104         if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
1105         {
1106                 LM_ERR("unable to get From\n");
1107                 return -1;
1108         }
1109         if(sf.s==NULL || sf.len == 0)
1110         {
1111                 LM_ERR("invalid From parameter\n");
1112                 return -1;
1113         }
1114         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
1115         {
1116                 LM_ERR("unable to get To\n");
1117                 return -1;
1118         }
1119         if(st.s==NULL || st.len == 0)
1120         {
1121                 LM_ERR("invalid To parameter\n");
1122                 return -1;
1123         }
1124         if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
1125         {
1126                 LM_ERR("unable to get OP\n");
1127                 return -1;
1128         }
1129
1130         if(dlg_bridge(&sf, &st, &so, NULL)!=0)
1131                 return -1;
1132         return 1;
1133 }
1134
1135 /**
1136  *
1137  */
1138 static int w_dlg_set_timeout(struct sip_msg *msg, char *pto, char *phe, char *phi)
1139 {
1140         int to = 0;
1141         unsigned int he = 0;
1142         unsigned int hi = 0;
1143         dlg_cell_t *dlg = NULL;
1144
1145         if(fixup_get_ivalue(msg, (gparam_p)pto, &to)!=0)
1146         {
1147                 LM_ERR("no timeout value\n");
1148                 return -1;
1149         }
1150         if(phe!=NULL)
1151         {
1152                 if(fixup_get_ivalue(msg, (gparam_p)phe, (int*)&he)!=0)
1153                 {
1154                         LM_ERR("no hash entry value value\n");
1155                         return -1;
1156                 }
1157                 if(fixup_get_ivalue(msg, (gparam_p)phi, (int*)&hi)!=0)
1158                 {
1159                         LM_ERR("no hash id value value\n");
1160                         return -1;
1161                 }
1162                 dlg = dlg_lookup(he, hi);
1163         } else {
1164                 dlg = dlg_get_msg_dialog(msg);
1165         }
1166
1167         if(dlg==NULL)
1168         {
1169                 LM_DBG("no dialog found\n");
1170                 return -1;
1171         }
1172
1173         if(update_dlg_timeout(dlg, to) != 0) 
1174                 return -1;
1175
1176         return 1;
1177 }
1178
1179 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2)
1180 {
1181         dlg_ctx_t *dctx;
1182         dlg_cell_t *d;
1183         str val;
1184
1185         if(fixup_get_svalue(msg, (gparam_t*)prop, &val)!=0)
1186         {
1187                 LM_ERR("no property value\n");
1188                 return -1;
1189         }
1190         if(val.len<=0)
1191         {
1192                 LM_ERR("empty property value\n");
1193                 return -1;
1194         }
1195         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1196                 return -1;
1197
1198         if(val.len==6 && strncmp(val.s, "ka-src", 6)==0) {
1199                 dctx->iflags |= DLG_IFLAG_KA_SRC;
1200                 d = dlg_get_by_iuid(&dctx->iuid);
1201                 if(d!=NULL) {
1202                         d->iflags |= DLG_IFLAG_KA_SRC;
1203                         dlg_release(d);
1204                 }
1205         } else if(val.len==6 && strncmp(val.s, "ka-dst", 6)==0) {
1206                 dctx->iflags |= DLG_IFLAG_KA_DST;
1207                 d = dlg_get_by_iuid(&dctx->iuid);
1208                 if(d!=NULL) {
1209                         d->iflags |= DLG_IFLAG_KA_DST;
1210                         dlg_release(d);
1211                 }
1212         } else if(val.len==15 && strncmp(val.s, "timeout-noreset", 15)==0) {
1213                 dctx->iflags |= DLG_IFLAG_TIMER_NORESET;
1214                 d = dlg_get_by_iuid(&dctx->iuid);
1215                 if(d!=NULL) {
1216                         d->iflags |= DLG_IFLAG_TIMER_NORESET;
1217                         dlg_release(d);
1218                 }
1219         } else {
1220                 LM_ERR("unknown property value [%.*s]\n", val.len, val.s);
1221                 return -1;
1222         }
1223
1224         return 1;
1225 }
1226
1227 static int w_dlg_set_timeout_by_profile3(struct sip_msg *msg, char *profile,
1228                                         char *value, char *timeout_str) 
1229 {
1230         pv_elem_t *pve = NULL;
1231         str val_s;
1232
1233         pve = (pv_elem_t *) value;
1234
1235         if(pve != NULL && ((struct dlg_profile_table *) profile)->has_value) {
1236                 if(pv_printf_s(msg,pve, &val_s) != 0 || 
1237                    !val_s.s || val_s.len == 0) {
1238                         LM_WARN("cannot get string for value\n");
1239                         return -1;
1240                 }
1241         }
1242
1243         if(dlg_set_timeout_by_profile((struct dlg_profile_table *) profile,
1244                                    &val_s, atoi(timeout_str)) != 0)
1245                 return -1;
1246
1247         return 1;
1248 }
1249
1250 static int w_dlg_set_timeout_by_profile2(struct sip_msg *msg, 
1251                                          char *profile, char *timeout_str)
1252 {
1253         return w_dlg_set_timeout_by_profile3(msg, profile, NULL, timeout_str);
1254 }
1255
1256 void dlg_ka_timer_exec(unsigned int ticks, void* param)
1257 {
1258         dlg_ka_run(ticks);
1259 }
1260
1261 void dlg_clean_timer_exec(unsigned int ticks, void* param)
1262 {
1263         dlg_clean_run(ticks);
1264 }
1265
1266 static int fixup_dlg_bye(void** param, int param_no)
1267 {
1268         char *val;
1269         int n = 0;
1270
1271         if (param_no==1) {
1272                 val = (char*)*param;
1273                 if (strcasecmp(val,"all")==0) {
1274                         n = 0;
1275                 } else if (strcasecmp(val,"caller")==0) {
1276                         n = 1;
1277                 } else if (strcasecmp(val,"callee")==0) {
1278                         n = 2;
1279                 } else {
1280                         LM_ERR("invalid param \"%s\"\n", val);
1281                         return E_CFG;
1282                 }
1283                 pkg_free(*param);
1284                 *param=(void*)(long)n;
1285         } else {
1286                 LM_ERR("called with parameter != 1\n");
1287                 return E_BUG;
1288         }
1289         return 0;
1290 }
1291
1292 static int fixup_dlg_refer(void** param, int param_no)
1293 {
1294         char *val;
1295         int n = 0;
1296
1297         if (param_no==1) {
1298                 val = (char*)*param;
1299                 if (strcasecmp(val,"caller")==0) {
1300                         n = 1;
1301                 } else if (strcasecmp(val,"callee")==0) {
1302                         n = 2;
1303                 } else {
1304                         LM_ERR("invalid param \"%s\"\n", val);
1305                         return E_CFG;
1306                 }
1307                 pkg_free(*param);
1308                 *param=(void*)(long)n;
1309         } else if (param_no==2) {
1310                 return fixup_spve_null(param, 1);
1311         } else {
1312                 LM_ERR("called with parameter idx %d\n", param_no);
1313                 return E_BUG;
1314         }
1315         return 0;
1316 }
1317
1318 static int fixup_dlg_bridge(void** param, int param_no)
1319 {
1320         if (param_no>=1 && param_no<=3) {
1321                 return fixup_spve_null(param, 1);
1322         } else {
1323                 LM_ERR("called with parameter idx %d\n", param_no);
1324                 return E_BUG;
1325         }
1326         return 0;
1327 }
1328
1329 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
1330 {
1331         dlg_cell_t *dlg = NULL;
1332         str sc = {0,0};
1333         str sf = {0,0};
1334         str st = {0,0};
1335         unsigned int dir = 0;
1336
1337         if(ci==0 || ft==0 || tt==0)
1338         {
1339                 LM_ERR("invalid parameters\n");
1340                 return -1;
1341         }
1342
1343         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
1344         {
1345                 LM_ERR("unable to get Call-ID\n");
1346                 return -1;
1347         }
1348         if(sc.s==NULL || sc.len == 0)
1349         {
1350                 LM_ERR("invalid Call-ID parameter\n");
1351                 return -1;
1352         }
1353         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
1354         {
1355                 LM_ERR("unable to get From tag\n");
1356                 return -1;
1357         }
1358         if(sf.s==NULL || sf.len == 0)
1359         {
1360                 LM_ERR("invalid From tag parameter\n");
1361                 return -1;
1362         }
1363         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
1364         {
1365                 LM_ERR("unable to get To Tag\n");
1366                 return -1;
1367         }
1368         if(st.s==NULL || st.len == 0)
1369         {
1370                 LM_ERR("invalid To tag parameter\n");
1371                 return -1;
1372         }
1373
1374         dlg = get_dlg(&sc, &sf, &st, &dir);
1375         if(dlg==NULL)
1376                 return -1;
1377     /* set shorcut to dialog internal unique id */
1378         _dlg_ctx.iuid.h_entry = dlg->h_entry;
1379         _dlg_ctx.iuid.h_id = dlg->h_id;
1380         _dlg_ctx.dir = dir;
1381         dlg_release(dlg);
1382         return 1;
1383 }
1384
1385 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
1386 {
1387         str from = {0,0};
1388         str to = {0,0};
1389         str op = {0,0};
1390         str bd = {0,0};
1391         struct mi_node* node;
1392
1393         node = cmd_tree->node.kids;
1394         if(node == NULL)
1395                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1396         from = node->value;
1397         if(from.len<=0 || from.s==NULL)
1398         {
1399                 LM_ERR("bad From value\n");
1400                 return init_mi_tree( 500, "Bad From value", 14);
1401         }
1402
1403         node = node->next;
1404         if(node == NULL)
1405                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1406         to = node->value;
1407         if(to.len<=0 || to.s == NULL)
1408         {
1409                 return init_mi_tree(500, "Bad To value", 12);
1410         }
1411
1412         node= node->next;
1413         if(node != NULL)
1414         {
1415                 op = node->value;
1416                 if(op.len<=0 || op.s==NULL)
1417                 {
1418                         return init_mi_tree(500, "Bad OP value", 12);
1419                 }
1420                 if(op.len==1 && *op.s=='.')
1421                 {
1422                         op.s = NULL;
1423                         op.len = 0;
1424                 }
1425                 node= node->next;
1426                 if(node != NULL)
1427                 {
1428                         bd = node->value;
1429                         if(bd.len<=0 || bd.s==NULL)
1430                         {
1431                                 return init_mi_tree(500, "Bad SDP value", 13);
1432                         }
1433                 }
1434         }
1435
1436         if(dlg_bridge(&from, &to, &op, &bd)!=0)
1437                 return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
1438
1439         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
1440 }
1441
1442 /**************************** RPC functions ******************************/
1443 /*!
1444  * \brief Helper method that outputs a dialog via the RPC interface
1445  * \see rpc_print_dlg
1446  * \param rpc RPC node that should be filled
1447  * \param c RPC void pointer
1448  * \param dlg printed dialog
1449  * \param with_context if 1 then the dialog context will be also printed
1450  * \return 0 on success, -1 on failure
1451  */
1452 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, dlg_cell_t *dlg,
1453                 int with_context)
1454 {
1455         rpc_cb_ctx_t rpc_cb;
1456         time_t _start_ts, _stop_ts;
1457         struct tm *_start_t, *_stop_t;
1458         char _start_date_buf[RPC_DATE_BUF_LEN]="UNSPECIFIED";
1459         char _stop_date_buf[RPC_DATE_BUF_LEN]="UNSPECIFIED";
1460
1461         _start_ts = (time_t)dlg->start_ts;
1462         if (_start_ts) {
1463                 _start_t = localtime(&_start_ts);
1464                 strftime(_start_date_buf, RPC_DATE_BUF_LEN - 1,
1465                         "%Y-%m-%d %H:%M:%S", _start_t);
1466                 if (dlg->tl.timeout) {
1467                         _stop_ts = time(0) + dlg->tl.timeout - get_ticks();
1468                         _stop_t = localtime(&_stop_ts);
1469                         strftime(_stop_date_buf, RPC_DATE_BUF_LEN - 1,
1470                                 "%Y-%m-%d %H:%M:%S", _stop_t);
1471                 }
1472         }
1473
1474         rpc->printf(c, "hash:%u:%u state:%u ref_count:%u "
1475                 "timestart:%u timeout:%u lifetime:%u datestart:%s datestop:%s",
1476                 dlg->h_entry, dlg->h_id, dlg->state, dlg->ref, _start_ts, dlg->tl.timeout, dlg->lifetime,
1477                 _start_date_buf, _stop_date_buf);
1478         rpc->printf(c, "\tcallid:%.*s from_tag:%.*s to_tag:%.*s",
1479                 dlg->callid.len, dlg->callid.s,
1480                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
1481                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
1482         rpc->printf(c, "\tfrom_uri:%.*s to_uri:%.*s",
1483                 dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s);
1484         rpc->printf(c, "\tcaller_contact:%.*s caller_cseq:%.*s",
1485                 dlg->contact[DLG_CALLER_LEG].len, dlg->contact[DLG_CALLER_LEG].s,
1486                 dlg->cseq[DLG_CALLER_LEG].len, dlg->cseq[DLG_CALLER_LEG].s);
1487         rpc->printf(c, "\tcaller_route_set: %.*s",
1488                 dlg->route_set[DLG_CALLER_LEG].len, dlg->route_set[DLG_CALLER_LEG].s);
1489         rpc->printf(c, "\tcallee_contact:%.*s callee_cseq:%.*s",
1490                 dlg->contact[DLG_CALLEE_LEG].len, dlg->contact[DLG_CALLEE_LEG].s,
1491                 dlg->cseq[DLG_CALLEE_LEG].len, dlg->cseq[DLG_CALLEE_LEG].s);
1492         rpc->printf(c, "\tcallee_route_set: %.*s",
1493                 dlg->route_set[DLG_CALLEE_LEG].len, dlg->route_set[DLG_CALLEE_LEG].s);
1494         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
1495                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:%.*s",
1496                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
1497                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s);
1498         } else {
1499                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:",
1500                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s);
1501         }
1502         if (with_context) {
1503                 rpc_cb.rpc = rpc;
1504                 rpc_cb.c = c;
1505                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
1506         }
1507 }
1508
1509 /*!
1510  * \brief Helper function that outputs all dialogs via the RPC interface
1511  * \see rpc_print_dlgs
1512  * \param rpc RPC node that should be filled
1513  * \param c RPC void pointer
1514  * \param with_context if 1 then the dialog context will be also printed
1515  */
1516 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
1517 {
1518         dlg_cell_t *dlg;
1519         unsigned int i;
1520
1521         for( i=0 ; i<d_table->size ; i++ ) {
1522                 dlg_lock( d_table, &(d_table->entries[i]) );
1523
1524                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
1525                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1526                 }
1527                 dlg_unlock( d_table, &(d_table->entries[i]) );
1528         }
1529 }
1530
1531 /*!
1532  * \brief Helper function that outputs a dialog via the RPC interface
1533  * \see rpc_print_dlgs
1534  * \param rpc RPC node that should be filled
1535  * \param c RPC void pointer
1536  * \param with_context if 1 then the dialog context will be also printed
1537  */
1538 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
1539         str callid, from_tag;
1540         dlg_entry_t *d_entry;
1541         dlg_cell_t *dlg;
1542         unsigned int h_entry;
1543
1544         if (rpc->scan(c, ".S.S", &callid, &from_tag) < 2) return;
1545
1546         h_entry = core_hash( &callid, 0, d_table->size);
1547         d_entry = &(d_table->entries[h_entry]);
1548         dlg_lock( d_table, d_entry);
1549         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
1550                 if (match_downstream_dialog( dlg, &callid, &from_tag)==1) {
1551                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1552                 }
1553         }
1554         dlg_unlock( d_table, d_entry);
1555 }
1556
1557 /*!
1558  * \brief Helper function that outputs the size of a given profile via the RPC interface
1559  * \see rpc_profile_get_size
1560  * \see rpc_profile_w_value_get_size
1561  * \param rpc RPC node that should be filled
1562  * \param c RPC void pointer
1563  * \param profile_name the given profile
1564  * \param value the given profile value
1565  */
1566 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name,
1567                 str *value) {
1568         unsigned int size;
1569         dlg_profile_table_t *profile;
1570
1571         profile = search_dlg_profile( profile_name );
1572         if (!profile) {
1573                 rpc->printf(c, "Non existing profile:%.*s",
1574                         profile_name->len, profile_name->s);
1575                 return;
1576         }
1577         size = get_profile_size(profile, value);
1578         if (value) {
1579                 rpc->printf(c, "Profile:%.*s => profile:%.*s value:%.*s count:%u",
1580                         profile_name->len, profile_name->s,
1581                         profile->name.len, profile->name.s,
1582                         value->len, value->s, size);
1583                 return;
1584         } else {
1585                 rpc->printf(c, "Profile:%.*s => profile:%.*s value: count:%u",
1586                         profile_name->len, profile_name->s,
1587                         profile->name.len, profile->name.s, size);
1588                 return;
1589         }
1590         return;
1591 }
1592
1593 /*!
1594  * \brief Helper function that outputs the dialogs belonging to a given profile via the RPC interface
1595  * \see rpc_profile_print_dlgs
1596  * \see rpc_profile_w_value_print_dlgs
1597  * \param rpc RPC node that should be filled
1598  * \param c RPC void pointer
1599  * \param profile_name the given profile
1600  * \param value the given profile value
1601  * \param with_context if 1 then the dialog context will be also printed
1602  */
1603 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name,
1604                 str *value) {
1605         dlg_profile_table_t *profile;
1606         dlg_profile_hash_t *ph;
1607         unsigned int i;
1608
1609         profile = search_dlg_profile( profile_name );
1610         if (!profile) {
1611                 rpc->printf(c, "Non existing profile:%.*s",
1612                         profile_name->len, profile_name->s);
1613                 return;
1614         }
1615
1616         /* go through the hash and print the dialogs */
1617         if (profile->has_value==0 || value==NULL) {
1618                 /* no value */
1619                 lock_get( &profile->lock );
1620                 for ( i=0 ; i< profile->size ; i++ ) {
1621                         ph = profile->entries[i].first;
1622                         if(ph) {
1623                                 do {
1624                                         /* print dialog */
1625                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1626                                         /* next */
1627                                         ph=ph->next;
1628                                 }while(ph!=profile->entries[i].first);
1629                         }
1630                         lock_release(&profile->lock);
1631                 }
1632         } else {
1633                 /* check for value also */
1634                 lock_get( &profile->lock );
1635                 for ( i=0 ; i< profile->size ; i++ ) {
1636                         ph = profile->entries[i].first;
1637                         if(ph) {
1638                                 do {
1639                                         if ( value->len==ph->value.len &&
1640                                                 memcmp(value->s,ph->value.s,value->len)==0 ) {
1641                                                 /* print dialog */
1642                                                 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1643                                         }
1644                                         /* next */
1645                                         ph=ph->next;
1646                                 }while(ph!=profile->entries[i].first);
1647                         }
1648                         lock_release(&profile->lock);
1649                 }
1650         }
1651 }
1652
1653 /*
1654  * Wrapper around is_known_dlg().
1655  */
1656
1657 static int w_is_known_dlg(sip_msg_t *msg) {
1658         return  is_known_dlg(msg);
1659 }
1660
1661 static const char *rpc_print_dlgs_doc[2] = {
1662         "Print all dialogs", 0
1663 };
1664 static const char *rpc_print_dlgs_ctx_doc[2] = {
1665         "Print all dialogs with associated context", 0
1666 };
1667 static const char *rpc_print_dlg_doc[2] = {
1668         "Print dialog based on callid and fromtag", 0
1669 };
1670 static const char *rpc_print_dlg_ctx_doc[2] = {
1671         "Print dialog with associated context based on callid and fromtag", 0
1672 };
1673 static const char *rpc_end_dlg_entry_id_doc[2] = {
1674         "End a given dialog based on [h_entry] [h_id]", 0
1675 };
1676 static const char *rpc_profile_get_size_doc[2] = {
1677         "Returns the number of dialogs belonging to a profile", 0
1678 };
1679 static const char *rpc_profile_print_dlgs_doc[2] = {
1680         "Lists all the dialogs belonging to a profile", 0
1681 };
1682 static const char *rpc_dlg_bridge_doc[2] = {
1683         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:\
1684  to, from, [outbound SIP proxy]", 0
1685 };
1686
1687
1688 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
1689         internal_rpc_print_dlgs(rpc, c, 0);
1690 }
1691 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
1692         internal_rpc_print_dlgs(rpc, c, 1);
1693 }
1694 static void rpc_print_dlg(rpc_t *rpc, void *c) {
1695         internal_rpc_print_single_dlg(rpc, c, 0);
1696 }
1697 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
1698         internal_rpc_print_single_dlg(rpc, c, 1);
1699 }
1700 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
1701         unsigned int h_entry, h_id;
1702         dlg_cell_t * dlg = NULL;
1703         str rpc_extra_hdrs = {NULL,0};
1704         int n;
1705
1706         n = rpc->scan(c, "dd", &h_entry, &h_id);
1707         if (n < 2) {
1708                 LM_ERR("unable to read the parameters (%d)\n", n);
1709                 rpc->fault(c, 500, "Invalid parameters");
1710                 return;
1711         }
1712         if(rpc->scan(c, "*S", &rpc_extra_hdrs)<1)
1713         {
1714                 rpc_extra_hdrs.s = NULL;
1715                 rpc_extra_hdrs.len = 0;
1716         }
1717
1718         dlg = dlg_lookup(h_entry, h_id);
1719         if(dlg==NULL) {
1720                 rpc->fault(c, 404, "Dialog not found");
1721                 return;
1722         }
1723
1724         dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
1725         dlg_release(dlg);
1726 }
1727 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
1728         str profile_name = {NULL,0};
1729         str value = {NULL,0};
1730
1731         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1732         if (rpc->scan(c, "*.S", &value) > 0) {
1733                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
1734         } else {
1735                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
1736         }
1737         return;
1738 }
1739 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
1740         str profile_name = {NULL,0};
1741         str value = {NULL,0};
1742
1743         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1744         if (rpc->scan(c, "*.S", &value) > 0) {
1745                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
1746         } else {
1747                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
1748         }
1749         return;
1750 }
1751 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
1752         str from = {NULL,0};
1753         str to = {NULL,0};
1754         str op = {NULL,0};
1755         str bd = {NULL,0};
1756         int n;
1757
1758         n = rpc->scan(c, "SS", &from, &to);
1759         if (n< 2) {
1760                 LM_ERR("unable to read the parameters (%d)\n", n);
1761                 rpc->fault(c, 500, "Invalid parameters");
1762                 return;
1763         }
1764         if(rpc->scan(c, "*S", &op)<1) {
1765                 op.s = NULL;
1766                 op.len = 0;
1767         } else {
1768                 if(op.len==1 && *op.s=='.') {
1769                         op.s = NULL;
1770                         op.len = 0;
1771                 }
1772                 if(rpc->scan(c, "*S", &bd)<1) {
1773                         bd.s = NULL;
1774                         bd.len = 0;
1775                 }
1776         }
1777
1778         dlg_bridge(&from, &to, &op, &bd);
1779 }
1780
1781 static rpc_export_t rpc_methods[] = {
1782         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, 0},
1783         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, 0},
1784         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
1785         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
1786         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
1787         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
1788         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, 0},
1789         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
1790         {0, 0, 0, 0}
1791 };