Increase failed_dlgs when a non-2xx final response has been
[sip-router] / modules_k / dialog / dlg_handlers.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2006 Voice System SRL
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * History:
23  * --------
24  * 2006-04-14  initial version (bogdan)
25  * 2006-11-28  Added support for tracking the number of early dialogs, and the
26  *             number of failed dialogs. This involved updates to dlg_onreply()
27  *             (Jeffrey Magder - SOMA Networks)
28  * 2007-03-06  syncronized state machine added for dialog state. New tranzition
29  *             design based on events; removed num_1xx and num_2xx (bogdan)
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-17  new feature: saving dialog info into a database if
34  *             realtime update is set(ancuta)
35  * 2007-07-06  support for saving additional dialog info : cseq, contact,
36  *             route_set and socket_info for both caller and callee (ancuta)
37  * 2007-07-10  Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper
38  *             hash table lookup and isn't dependant on the is_direction
39  *             function (which requires an RR param like dlg_match_mode 0
40  *             anyways.. ;) ; based on a patch from
41  *             Tavis Paquette <tavis@galaxytelecom.net>
42  *             and Peter Baer <pbaer@galaxytelecom.net>  (bogdan)
43  * 2008-04-04  added direction reporting in dlg callbacks (bogdan)
44  */
45
46
47 /*!
48  * \file
49  * \brief Functions related to dialog handling
50  * \ingroup dialog
51  * Module: \ref dialog
52  */
53
54 #include <string.h>
55 #include <time.h>
56
57 #include "../../trim.h"
58 #include "../../pvar.h"
59 #include "../../timer.h"
60 #include "../../lib/kcore/statistics.h"
61 #include "../../action.h"
62 #include "../../script_cb.h"
63 #include "../../lib/kcore/faked_msg.h"
64 #include "../../lib/kcore/parser_helpers.h"
65 #include "../../parser/parse_from.h"
66 #include "../../parser/parse_cseq.h"
67 #include "../../parser/contact/parse_contact.h"
68 #include "../../parser/parse_from.h"
69 #include "../../parser/parse_rr.h"
70 #include "../../modules/tm/tm_load.h"
71 #include "../rr/api.h"
72 #include "dlg_hash.h"
73 #include "dlg_timer.h"
74 #include "dlg_cb.h"
75 #include "dlg_handlers.h"
76 #include "dlg_req_within.h"
77 #include "dlg_db_handler.h"
78 #include "dlg_profile.h"
79 #include "dlg_var.h"
80
81 static str       rr_param;              /*!< record-route parameter for matching */
82 static int       dlg_flag;              /*!< flag for dialog tracking */
83 static pv_spec_t *timeout_avp;          /*!< AVP for timeout setting */
84 static int       default_timeout;       /*!< default dialog timeout */
85 static int       seq_match_mode;        /*!< dlg_match mode */ 
86 static int       shutdown_done = 0;     /*!< 1 when destroy_dlg_handlers was called */
87
88 extern struct rr_binds d_rrb;           /*!< binding to record-routing module */
89
90 /* statistic variables */
91 extern stat_var *early_dlgs;            /*!< number of early dialogs */
92 extern stat_var *processed_dlgs;        /*!< number of processed dialogs */
93 extern stat_var *expired_dlgs;          /*!< number of expired dialogs */
94 extern stat_var *failed_dlgs;           /*!< number of failed dialogs */
95
96 extern pv_elem_t *ruri_param_model;     /*!< pv-string to get r-uri */
97
98 static unsigned int CURR_DLG_LIFETIME = 0;      /*!< current dialog lifetime */
99 static unsigned int CURR_DLG_STATUS = 0;        /*!< current dialog state */
100 static unsigned int CURR_DLG_ID  = 0xffffffff;  /*!< current dialog id */
101
102
103 /*! size of the dialog record-route parameter */
104 #define RR_DLG_PARAM_SIZE  (2*2*sizeof(int)+3+MAX_DLG_RR_PARAM_NAME)
105 /*! separator inside the record-route paramter */
106 #define DLG_SEPARATOR      '.'
107
108
109 /*!
110  * \brief Initialize the dialog handlers
111  * \param rr_param_p added record-route parameter
112  * \param dlg_flag_p dialog flag
113  * \param timeout_avp_p AVP for timeout setting
114  * \param default_timeout_p default timeout
115  * \param seq_match_mode_p matching mode
116  */
117 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
118                 pv_spec_t *timeout_avp_p ,int default_timeout_p,
119                 int seq_match_mode_p)
120 {
121         rr_param.s = rr_param_p;
122         rr_param.len = strlen(rr_param.s);
123
124         dlg_flag = 1<<dlg_flag_p;
125
126         timeout_avp = timeout_avp_p;
127         default_timeout = default_timeout_p;
128         seq_match_mode = seq_match_mode_p;
129 }
130
131
132 /*!
133  * \brief Shutdown operation of the module
134  */
135 void destroy_dlg_handlers(void)
136 {
137         shutdown_done = 1;
138 }
139
140
141 /*!
142  * \brief Add record-route parameter for dialog tracking
143  * \param req SIP request
144  * \param entry dialog hash entry
145  * \param id dialog hash id
146  * \return 0 on success, -1 on failure
147  */
148 static inline int add_dlg_rr_param(struct sip_msg *req, unsigned int entry,
149                 unsigned int id)
150 {
151         static char buf[RR_DLG_PARAM_SIZE];
152         str s;
153         int n;
154         char *p;
155
156         s.s = p = buf;
157
158         *(p++) = ';';
159         memcpy(p, rr_param.s, rr_param.len);
160         p += rr_param.len;
161         *(p++) = '=';
162
163         n = RR_DLG_PARAM_SIZE - (p-buf);
164         if (int2reverse_hex( &p, &n, entry)==-1)
165                 return -1;
166
167         *(p++) = DLG_SEPARATOR;
168
169         n = RR_DLG_PARAM_SIZE - (p-buf);
170         if (int2reverse_hex( &p, &n, id)==-1)
171                 return -1;
172
173         s.len = p-buf;
174
175         if (d_rrb.add_rr_param( req, &s)<0) {
176                 LM_ERR("failed to add rr param\n");
177                 return -1;
178         }
179
180         return 0;
181 }
182
183
184 /*!
185  * \brief Parse SIP message and populate leg informations
186  *
187  * Parse SIP message and populate leg informations. 
188  * \param dlg the dialog to add cseq, contact & record_route
189  * \param msg sip message
190  * \param flag  0-for a request(INVITE), 1- for a reply(200 ok)
191  * \return 0 on success, -1 on failure
192  * \note for a request: get record route in normal order, for a reply get
193  * in reverse order, skipping the ones from the request and the proxies' own
194  */
195 int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
196         struct cell* t, unsigned int leg, str *tag)
197 {
198         unsigned int skip_recs;
199         str cseq;
200         str contact;
201         str rr_set;
202
203         dlg->bind_addr[leg] = msg->rcv.bind_address;
204
205         /* extract the cseq number as string */
206         if (leg==DLG_CALLER_LEG) {
207                 if((!msg->cseq && (parse_headers(msg,HDR_CSEQ_F,0)<0 || !msg->cseq))
208                         || !msg->cseq->parsed){
209                         LM_ERR("bad sip message or missing CSeq hdr :-/\n");
210                         goto error0;
211                 }
212                 cseq = (get_cseq(msg))->number;
213         } else {
214                 /* use the same as in request */
215                 cseq = dlg->cseq[DLG_CALLER_LEG];
216         }
217
218         /* extract the contact address */
219         if (!msg->contact&&(parse_headers(msg,HDR_CONTACT_F,0)<0||!msg->contact)){
220                 LM_ERR("bad sip message or missing Contact hdr\n");
221                 goto error0;
222         }
223         if ( parse_contact(msg->contact)<0 ||
224         ((contact_body_t *)msg->contact->parsed)->contacts==NULL ||
225         ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) {
226                 LM_ERR("bad Contact HDR\n");
227                 goto error0;
228         }
229         contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri;
230
231         /* extract the RR parts */
232         if(!msg->record_route && (parse_headers(msg,HDR_EOH_F,0)<0)  ){
233                 LM_ERR("failed to parse record route header\n");
234                 goto error0;
235         }
236
237         if (leg==DLG_CALLER_LEG) {
238                 skip_recs = 0;
239         } else {
240                 /* was the 200 OK received or local generated */
241                 skip_recs = dlg->from_rr_nb +
242                         ((t->relayed_reply_branch>=0)?
243                                 ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_R2)?2:
244                                  ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_RR)?1:0))
245                                 :0);
246         }
247
248         if(msg->record_route){
249                 if( print_rr_body(msg->record_route, &rr_set, leg,
250                                                         &skip_recs) != 0 ){
251                         LM_ERR("failed to print route records \n");
252                         goto error0;
253                 }
254         } else {
255                 rr_set.s = 0;
256                 rr_set.len = 0;
257         }
258
259         if(leg==DLG_CALLER_LEG)
260                 dlg->from_rr_nb = skip_recs;
261
262         LM_DBG("route_set %.*s, contact %.*s, cseq %.*s and bind_addr %.*s\n",
263                 rr_set.len, rr_set.s, contact.len, contact.s,
264                 cseq.len, cseq.s,
265                 msg->rcv.bind_address->sock_str.len,
266                 msg->rcv.bind_address->sock_str.s);
267
268         if (dlg_set_leg_info( dlg, tag, &rr_set, &contact, &cseq, leg)!=0) {
269                 LM_ERR("dlg_set_leg_info failed\n");
270                 if (rr_set.s) pkg_free(rr_set.s);
271                 goto error0;
272         }
273
274         if (rr_set.s) pkg_free(rr_set.s);
275
276         return 0;
277 error0:
278         return -1;
279 }
280
281
282 /*!
283  * \brief Function that is registered as TM callback and called on replies
284  *
285  * Function that is registered as TM callback and called on replies. It
286  * parses the reply and set the appropriate event. This is then used to
287  * update the dialog state, run eventual dialog callbacks and save or
288  * update the necessary informations about the dialog.
289  * \see next_state_dlg
290  * \param t transaction, unused
291  * \param type type of the entered callback
292  * \param param saved dialog structure in the callback
293  */
294 static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
295 {
296         struct sip_msg *rpl;
297         struct dlg_cell *dlg;
298         int new_state, old_state, unref, event;
299         str tag;
300
301         dlg = (struct dlg_cell *)(*param->param);
302         if (shutdown_done || dlg==0)
303                 return;
304
305         rpl = param->rpl;
306
307         if (type==TMCB_RESPONSE_FWDED) {
308                 /* The state does not change, but the msg is mutable in this callback*/
309                 run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
310                 return;
311         }
312
313         if (type==TMCB_DESTROY)
314                 event = DLG_EVENT_TDEL;
315         else if (param->code<200)
316                 event = DLG_EVENT_RPL1xx;
317         else if (param->code<300)
318                 event = DLG_EVENT_RPL2xx;
319         else
320                 event = DLG_EVENT_RPL3xx;
321
322         next_state_dlg( dlg, event, &old_state, &new_state, &unref);
323
324         if (new_state==DLG_STATE_EARLY) {
325                 run_dlg_callbacks(DLGCB_EARLY, dlg, rpl, DLG_DIR_UPSTREAM, 0);
326                 if (old_state!=DLG_STATE_EARLY)
327                         if_update_stat(dlg_enable_stats, early_dlgs, 1);
328                 return;
329         }
330
331         if (new_state==DLG_STATE_CONFIRMED_NA &&
332         old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) {
333                 LM_DBG("dialog %p confirmed\n",dlg);
334
335                  if (rpl != FAKED_REPLY) {
336                         /* get to tag*/
337                         if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0)
338                                                 || !rpl->to) ) {
339                                 LM_ERR("bad reply or missing TO hdr :-/\n");
340                                 tag.s = 0;
341                                 tag.len = 0;
342                         } else {
343                                 tag = get_to(rpl)->tag_value;
344                                 if (tag.s==0 || tag.len==0) {
345                                         LM_ERR("missing TAG param in TO hdr :-/\n");
346                                         tag.s = 0;
347                                         tag.len = 0;
348                                 }
349                         }
350
351                         /* save callee's tag, cseq, contact and record route*/
352                         if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) {
353                                 LM_ERR("could not add further info to the dialog\n");
354                         }
355                  } else {
356                          LM_ERR("Faked reply!\n");
357                  }
358
359                 /* set start time */
360                 dlg->start_ts = (unsigned int)(time(0));
361
362                 /* save the settings to the database,
363                  * if realtime saving mode configured- save dialog now
364                  * else: the next time the timer will fire the update*/
365                 dlg->dflags |= DLG_FLAG_NEW;
366                 if ( dlg_db_mode==DB_MODE_REALTIME )
367                         update_dialog_dbinfo(dlg);
368
369                 if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) {
370                         LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] "
371                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",
372                                 dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state,
373                                 dlg->callid.len, dlg->callid.s,
374                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
375                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
376                 } else {
377                         ref_dlg(dlg,1);
378                 }
379
380                 /* dialog confirmed */
381                 run_dlg_callbacks( DLGCB_CONFIRMED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
382
383                 if (old_state==DLG_STATE_EARLY)
384                         if_update_stat(dlg_enable_stats, early_dlgs, -1);
385
386                 if (unref) unref_dlg(dlg,unref);
387                 if_update_stat(dlg_enable_stats, active_dlgs, 1);
388                 return;
389         }
390
391         if ( old_state!=DLG_STATE_DELETED && new_state==DLG_STATE_DELETED ) {
392                 LM_DBG("dialog %p failed (negative reply)\n", dlg);
393                 /* dialog setup not completed (3456XX) */
394                 run_dlg_callbacks( DLGCB_FAILED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
395                 /* do unref */
396                 if (unref)
397                         unref_dlg(dlg,unref);
398                 if (old_state==DLG_STATE_EARLY)
399                         if_update_stat(dlg_enable_stats, early_dlgs, -1);
400
401                 if_update_stat(dlg_enable_stats, failed_dlgs, 1);
402
403                 return;
404         }
405
406         if (unref) unref_dlg(dlg,unref);
407
408         return;
409 }
410
411
412 /*!
413  * \brief Helper function that run dialog callbacks on forwarded requests
414  * \see dlg_seq_up_onreply
415  * \see dlg_seq_down_onreply
416  * \param t transaction, unused
417  * \param type type of the callback, should be TMCB_RESPONSE_FWDED
418  * \param param saved dialog structure inside the callback
419  * \param direction direction of the request
420  */
421 static void dlg_seq_onreply_helper(struct cell* t, int type,
422                 struct tmcb_params *param, const int direction)
423 {
424         struct dlg_cell *dlg;
425
426         dlg = (struct dlg_cell *)(*param->param);
427         if (shutdown_done || dlg==0)
428                 return;
429
430         if (type==TMCB_RESPONSE_FWDED) {
431                 run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
432                         direction, 0);
433                 return;
434         }
435
436         return;
437 }
438
439
440 /*!
441  * \brief Run dialog callbacks on forwarded requests in upstream direction
442  * \see dlg_seq_onreply_helper
443  * \param t transaction, unused
444  * \param type type of the callback, should be TMCB_RESPONSE_FWDED
445  * \param param saved dialog structure inside the callback
446  */
447 static void dlg_seq_up_onreply(struct cell* t, int type, struct tmcb_params *param)
448 {
449         return dlg_seq_onreply_helper(t, type, param, DLG_DIR_UPSTREAM);
450 }
451
452
453 /*!
454  * \brief Run dialog callbacks on forwarded requests in downstream direction
455  * \see dlg_seq_onreply_helper
456  * \param t transaction, unused
457  * \param type type of the callback, should be TMCB_RESPONSE_FWDED
458  * \param param saved dialog structure inside the callback
459  */
460 static void dlg_seq_down_onreply(struct cell* t, int type, struct tmcb_params *param)
461 {
462         return dlg_seq_onreply_helper(t, type, param, DLG_DIR_DOWNSTREAM);
463 }
464
465
466 /*!
467  * \brief Return the timeout for a dialog
468  * \param req SIP message
469  * \return value from timeout AVP if present or default timeout
470  */
471 inline static int get_dlg_timeout(struct sip_msg *req)
472 {
473         pv_value_t pv_val;
474
475         if( timeout_avp ) {
476                 if ( pv_get_spec_value( req, timeout_avp, &pv_val)==0 &&
477                                 pv_val.flags&PV_VAL_INT && pv_val.ri>0 ) {
478                         return pv_val.ri;
479                 }
480                 LM_DBG("invalid AVP value, using default timeout\n");
481         }
482         return default_timeout;
483 }
484
485
486 /*!
487  * \brief Function that is registered as TM callback and called on requests
488  * \see dlg_new_dialog
489  * \param t transaction, used to created the dialog
490  * \param type type of the entered callback
491  * \param param saved dialog structure in the callback
492  */
493 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
494 {
495         struct sip_msg *msg;
496         msg = param->req;
497         if((msg->flags&dlg_flag)!=dlg_flag)
498                 return;
499         if (current_dlg_pointer!=NULL)
500                 return;
501         dlg_new_dialog(msg, t);
502 }
503
504
505 /*!
506  * \brief Unreference a new dialog, helper function for dlg_onreq
507  * \see dlg_onreq
508  * \param dialog unreferenced dialog
509  */
510 static void unref_new_dialog(void *dialog)
511 {
512         struct tmcb_params p;
513
514         memset(&p, 0, sizeof(struct tmcb_params));
515         p.param = (void*)&dialog;
516         dlg_onreply(0, TMCB_DESTROY, &p);
517 }
518
519
520 /*!
521  * \brief Dummy callback just to keep the compiler happy
522  * \param t unused
523  * \param type unused
524  * \param param unused
525  */
526 void dlg_tmcb_dummy(struct cell* t, int type, struct tmcb_params *param)
527 {
528         return;
529 }
530
531
532 /*!
533  * \brief Create a new dialog from a sip message
534  *
535  * Create a new dialog from a SIP message, register a callback
536  * to keep track of the dialog with help of the tm module.
537  * This function is either called from the request callback, or
538  * from the dlg_manage function in the configuration script.
539  * \see dlg_onreq
540  * \see w_dlg_manage
541  * \param msg SIP message
542  * \param t transaction
543  * \return 0 on success, -1 on failure
544  */ 
545 int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
546 {
547         struct dlg_cell *dlg;
548         str s;
549         str req_uri;
550
551         if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
552         {
553                 LM_ERR("bad request or missing TO hdr\n");
554                 return -1;
555         }
556         s = get_to(msg)->tag_value;
557         if(s.s!=0 && s.len!=0)
558                 return -1;
559
560         if(msg->first_line.u.request.method_value==METHOD_CANCEL)
561                 return -1;
562
563         if(parse_from_header(msg))
564         {
565                 LM_ERR("bad request or missing FROM hdr\n");
566                 return -1;
567         }
568         if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
569                         || msg->callid==NULL){
570                 LM_ERR("bad request or missing CALLID hdr\n");
571                 return -1;
572         }
573         s = msg->callid->body;
574         trim(&s);
575
576         if (pv_printf_s(msg, ruri_param_model, &req_uri)<0) {
577                 LM_ERR("error - cannot print the r-uri format\n");
578                 return -1;
579         }
580         trim(&req_uri);
581
582         /* some sanity checks */
583         if (s.len==0 || get_from(msg)->tag_value.len==0) {
584                 LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
585                         s.len, get_from(msg)->tag_value.len);
586                 return -1;
587         }
588
589         dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
590                 &(get_to(msg)->uri) /*to uri*/,
591                 &(get_from(msg)->tag_value)/*from_tag*/, &req_uri /*r-uri*/ );
592         if (dlg==0) {
593                 LM_ERR("failed to create new dialog\n");
594                 return -1;
595         }
596
597         /* save caller's tag, cseq, contact and record route*/
598         if (populate_leg_info(dlg, msg, t, DLG_CALLER_LEG,
599                         &(get_from(msg)->tag_value)) !=0)
600         {
601                 LM_ERR("could not add further info to the dialog\n");
602                 shm_free(dlg);
603                 return -1;
604         }
605
606         set_current_dialog(msg, dlg);
607         _dlg_ctx.dlg = dlg;
608
609         link_dlg(dlg, 2/* extra ref for the callback and current dlg hook */);
610
611         /* first INVITE seen (dialog created, unconfirmed) */
612         if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
613                         add_dlg_rr_param( msg, dlg->h_entry, dlg->h_id)<0 ) {
614                 LM_ERR("failed to add RR param\n");
615                 goto error;
616         }
617
618         if ( d_tmb.register_tmcb( msg, t,
619                                 TMCB_RESPONSE_READY|TMCB_RESPONSE_FWDED,
620                                 dlg_onreply, (void*)dlg, unref_new_dialog)<0 ) {
621                 LM_ERR("failed to register TMCB\n");
622                 goto error;
623         }
624
625         dlg->lifetime = get_dlg_timeout(msg);
626         dlg->toroute = _dlg_ctx.to_route;
627         dlg->sflags |= _dlg_ctx.flags;
628
629         if (_dlg_ctx.to_bye!=0)
630                 dlg->dflags |= DLG_FLAG_TOBYE;
631
632         if (t) {
633                 if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
634                                         dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
635                         LM_ERR("failed cache in T the shortcut to dlg\n");
636                         goto error;
637                 }
638         }
639 #if 0
640                 t->dialog_ctx = (void*) dlg;
641 #endif
642
643         run_create_callbacks( dlg, msg);
644
645         if_update_stat( dlg_enable_stats, processed_dlgs, 1);
646
647         return 0;
648 error:
649         unref_dlg(dlg,1);
650         profile_cleanup(msg, 0, NULL);
651         return -1;
652 }
653
654
655 /*!
656  * \brief Parse the record-route parameter, to get dialog information back
657  * \param p start of parameter string
658  * \param end end of parameter string
659  * \param h_entry found dialog hash entry
660  * \param h_id found dialog hash id
661  * \return 0 on success, -1 on failure
662  */
663 static inline int parse_dlg_rr_param(char *p, char *end, int *h_entry, int *h_id)
664 {
665         char *s;
666
667         for ( s=p ; p<end && *p!=DLG_SEPARATOR ; p++ );
668         if (*p!=DLG_SEPARATOR) {
669                 LM_ERR("malformed rr param '%.*s'\n", (int)(long)(end-s), s);
670                 return -1;
671         }
672
673         if ( reverse_hex2int( s, p-s, (unsigned int*)h_entry)<0 ) {
674                 LM_ERR("invalid hash entry '%.*s'\n", (int)(long)(p-s), s);
675                 return -1;
676         }
677
678         if ( reverse_hex2int( p+1, end-(p+1), (unsigned int*)h_id)<0 ) {
679                 LM_ERR("invalid hash id '%.*s'\n", (int)(long)(end-(p+1)), p+1 );
680                 return -1;
681         }
682
683         return 0;
684 }
685
686
687 /*!
688  * \brief Helper function to get the necessary content from SIP message
689  * \param req SIP request
690  * \param callid found callid
691  * \param ftag found from tag
692  * \param ttag found to tag
693  * \return 0 on succes, -1 on failure
694  */
695 static inline int pre_match_parse( struct sip_msg *req, str *callid,
696                 str *ftag, str *ttag)
697 {
698         if (parse_headers(req,HDR_CALLID_F|HDR_TO_F,0)<0 || !req->callid ||
699         !req->to ) {
700                 LM_ERR("bad request or missing CALLID/TO hdr :-/\n");
701                 return -1;
702         }
703
704         if (get_to(req)->tag_value.len==0) {
705                 /* out of dialog request with preloaded Route headers; ignore. */
706                 return -1;
707         }
708
709         if (parse_from_header(req)<0 || get_from(req)->tag_value.len==0) {
710                 LM_ERR("failed to get From header\n");
711                 return -1;
712         }
713
714         /* callid */
715         *callid = req->callid->body;
716         trim(callid);
717         /* to tag */
718         *ttag = get_to(req)->tag_value;
719         /* from tag */
720         *ftag = get_from(req)->tag_value;
721         return 0;
722 }
723
724
725 /*!
726  * \brief Update the saved CSEQ information in dialog from SIP message
727  * \param dlg updated dialog
728  * \param req SIP request
729  * \param dir direction of request, must DLG_DIR_UPSTREAM or DLG_DIR_DOWNSTREAM
730  * \return 0 on success, -1 on failure
731  */
732 static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
733                 unsigned int dir)
734 {
735         if ( (!req->cseq && parse_headers(req,HDR_CSEQ_F,0)<0) || !req->cseq ||
736         !req->cseq->parsed) {
737                 LM_ERR("bad sip message or missing CSeq hdr :-/\n");
738                 return -1;
739         }
740
741         if ( dir==DLG_DIR_UPSTREAM) {
742                 return dlg_update_cseq(dlg, DLG_CALLEE_LEG,&((get_cseq(req))->number));
743         } else if ( dir==DLG_DIR_DOWNSTREAM) {
744                 return dlg_update_cseq(dlg, DLG_CALLER_LEG,&((get_cseq(req))->number));
745         } else {
746                 LM_CRIT("dir is not set!\n");
747                 return -1;
748         }
749 }
750
751
752 /*!
753  * \brief Unreference a dialog, small wrapper to care for shutdown
754  * \see unref_dlg 
755  * \param dialog unreferenced dialog
756  */
757 static void unreference_dialog(void *dialog)
758 {
759         // if the dialog table is gone, it means the system is shutting down.
760         if (!d_table)
761                 return;
762         unref_dlg((struct dlg_cell*)dialog, 1);
763 }
764
765
766 /*!
767  * \brief Function that is registered as RR callback for dialog tracking
768  * 
769  * Function that is registered as RR callback for dialog tracking. It
770  * sets the appropriate events after the SIP method and run the state
771  * machine to update the dialog state. It updates then the saved
772  * dialogs and also the statistics.
773  * \param req SIP request
774  * \param route_params record-route parameter
775  * \param param unused
776  */
777 void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
778 {
779         struct dlg_cell *dlg;
780         str val, callid, ftag, ttag;
781         int h_entry, h_id, new_state, old_state, unref, event, timeout;
782         unsigned int dir;
783         int ret = 0;
784
785         if (current_dlg_pointer!=NULL)
786                 return;
787
788         /* skip initial requests - they may end up here because of the
789          * preloaded route */
790         if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) {
791                 LM_ERR("bad request or missing TO hdr :-/\n");
792                 return;
793         }
794         if ( get_to(req)->tag_value.len==0 )
795                 return;
796
797         dlg = 0;
798         dir = DLG_DIR_NONE;
799
800         if ( seq_match_mode!=SEQ_MATCH_NO_ID ) {
801                 if( d_rrb.get_route_param( req, &rr_param, &val)!=0) {
802                         LM_DBG("Route param '%.*s' not found\n", rr_param.len,rr_param.s);
803                         if (seq_match_mode==SEQ_MATCH_STRICT_ID )
804                                 return;
805                 } else {
806                         LM_DBG("route param is '%.*s' (len=%d)\n",val.len,val.s,val.len);
807
808                         if ( parse_dlg_rr_param( val.s, val.s+val.len, &h_entry, &h_id)<0 )
809                                 return;
810
811                         dlg = lookup_dlg( h_entry, h_id);
812                         if (dlg==0) {
813                                 LM_WARN("unable to find dialog for %.*s "
814                                         "with route param '%.*s' [%u:%u]\n",
815                                         req->first_line.u.request.method.len,
816                                         req->first_line.u.request.method.s,
817                                         val.len,val.s, h_entry, h_id);
818                                 if (seq_match_mode==SEQ_MATCH_STRICT_ID )
819                                         return;
820                         } else {
821                                 // lookup_dlg has incremented the ref count by 1
822                                 if (pre_match_parse( req, &callid, &ftag, &ttag)<0) {
823                                         unref_dlg(dlg, 1);
824                                         return;
825                                 }
826                                 if (match_dialog( dlg, &callid, &ftag, &ttag, &dir )==0) {
827                                         LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, "
828                                                         "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n",
829                                                         req->first_line.u.request.method.len,
830                                                         req->first_line.u.request.method.s,
831                                                         callid.len, callid.s, callid.len,
832                                                         ftag.len, ftag.s, ftag.len,
833                                                         ttag.len, ttag.s, ttag.len, dir);
834                                         LM_WARN("dialog identification elements are callid='%.*s'/%d, "
835                                                         "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n",
836                                                         dlg->callid.len, dlg->callid.s, dlg->callid.len,
837                                                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
838                                                         dlg->tag[DLG_CALLER_LEG].len,
839                                                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s,
840                                                         dlg->tag[DLG_CALLEE_LEG].len);
841                                         unref_dlg(dlg, 1);
842
843                                         // Reset variables in order to do a lookup based on SIP-Elements.
844                                         dlg = 0;
845                                         dir = DLG_DIR_NONE;
846
847                                         if (seq_match_mode==SEQ_MATCH_STRICT_ID )
848                                                 return;
849                                 }
850                         }
851                 }
852         }
853
854         if (dlg==0) {
855                 if (pre_match_parse( req, &callid, &ftag, &ttag)<0)
856                         return;
857                 /* TODO - try to use the RR dir detection to speed up here the
858                  * search -bogdan */
859                 dlg = get_dlg(&callid, &ftag, &ttag, &dir);
860                 if (!dlg){
861                         LM_DBG("Callid '%.*s' not found\n",
862                                 req->callid->body.len, req->callid->body.s);
863                         return;
864                 }
865         }
866
867         /* run state machine */
868         switch ( req->first_line.u.request.method_value ) {
869                 case METHOD_PRACK:
870                         event = DLG_EVENT_REQPRACK; break;
871                 case METHOD_ACK:
872                         event = DLG_EVENT_REQACK; break;
873                 case METHOD_BYE:
874                         event = DLG_EVENT_REQBYE; break;
875                 default:
876                         event = DLG_EVENT_REQ;
877         }
878
879         next_state_dlg( dlg, event, &old_state, &new_state, &unref);
880
881         CURR_DLG_ID = req->id;
882         CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
883         CURR_DLG_STATUS = new_state;
884
885         /* set current dialog - it will keep a ref! */
886         set_current_dialog( req, dlg);
887         _dlg_ctx.dlg = dlg;
888
889         /* run actions for the transition */
890         if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED &&
891         old_state!=DLG_STATE_DELETED) {
892                 LM_DBG("BYE successfully processed\n");
893                 /* remove from timer */
894                 ret = remove_dialog_timer(&dlg->tl);
895                 if (ret < 0) {
896                         LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
897                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",
898                                 dlg, dlg->h_entry, dlg->h_id,
899                                 dlg->callid.len, dlg->callid.s,
900                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
901                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
902                 } else if (ret > 0) {
903                         LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
904                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",
905                                 dlg, dlg->h_entry, dlg->h_id,
906                                 dlg->callid.len, dlg->callid.s,
907                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
908                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
909                 } else {
910                         unref++;
911                 }
912                 /* dialog terminated (BYE) */
913                 run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, dir, 0);
914
915                 /* delete the dialog from DB */
916                 if (dlg_db_mode)
917                         remove_dialog_from_db(dlg);
918
919                 /* destroy dialog */
920                 unref_dlg(dlg, unref);
921
922                 if_update_stat( dlg_enable_stats, active_dlgs, -1);
923                 return;
924         }
925
926         if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK)
927         && new_state==DLG_STATE_CONFIRMED) {
928                 LM_DBG("sequential request successfully processed\n");
929                 timeout = get_dlg_timeout(req);
930                 if (timeout!=default_timeout) {
931                         dlg->lifetime = timeout;
932                 }
933                 if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) {
934                         LM_ERR("failed to update dialog lifetime\n");
935                 }
936                 if (update_cseqs(dlg, req, dir)!=0) {
937                         LM_ERR("cseqs update failed\n");
938                 } else {
939                         dlg->dflags |= DLG_FLAG_CHANGED;
940                         if ( dlg_db_mode==DB_MODE_REALTIME )
941                                 update_dialog_dbinfo(dlg);
942                 }
943
944                 /* within dialog request */
945                 run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0);
946
947                 if ( (event!=DLG_EVENT_REQACK) &&
948                 (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) {
949                         /* ref the dialog as registered into the transaction callback.
950                          * unref will be done when the callback will be destroyed */
951                         ref_dlg( dlg , 1);
952                         /* register callback for the replies of this request */
953                         if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
954                         (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply:dlg_seq_up_onreply,
955                         (void*)dlg, unreference_dialog)<0 ) {
956                                 LM_ERR("failed to register TMCB (2)\n");
957                                         unref_dlg( dlg , 1);
958                         }
959                 }
960         }
961
962         if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){
963                 dlg->dflags |= DLG_FLAG_CHANGED;
964                 if(dlg_db_mode == DB_MODE_REALTIME)
965                         update_dialog_dbinfo(dlg);
966         }
967
968         return;
969 }
970
971
972 /*!
973  * \brief Timer function that removes expired dialogs, run timeout route
974  * \param tl dialog timer list
975  */
976 void dlg_ontimeout( struct dlg_tl *tl)
977 {
978         struct dlg_cell *dlg;
979         int new_state, old_state, unref;
980         struct sip_msg *fmsg;
981
982         /* get the dialog tl payload */
983         dlg = ((struct dlg_cell*)((char *)(tl) -
984                 (unsigned long)(&((struct dlg_cell*)0)->tl)));
985
986         if(dlg->toroute>0 && dlg->toroute<main_rt.entries
987                         && main_rt.rlist[dlg->toroute]!=NULL)
988         {
989                 fmsg = faked_msg_next();
990                 if (exec_pre_script_cb(fmsg, REQUEST_CB_TYPE)>0)
991                 {
992                         dlg_set_ctx_dialog(dlg);
993                         LM_DBG("executing route %d on timeout\n", dlg->toroute);
994                         set_route_type(REQUEST_ROUTE);
995                         run_top_route(main_rt.rlist[dlg->toroute], fmsg, 0);
996                         dlg_set_ctx_dialog(0);
997                         exec_post_script_cb(fmsg, REQUEST_CB_TYPE);
998                 }
999         }
1000
1001         if ((dlg->dflags&DLG_FLAG_TOBYE)
1002                         && (dlg->state==DLG_STATE_CONFIRMED_NA
1003                                 || dlg->state==DLG_STATE_CONFIRMED))
1004         {
1005                 dlg_bye_all(dlg, NULL);
1006                 unref_dlg(dlg, 1);
1007                 if_update_stat(dlg_enable_stats, expired_dlgs, 1);
1008                 return;
1009         }
1010
1011         next_state_dlg( dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref);
1012
1013         if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
1014                 LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
1015                         dlg->callid.len, dlg->callid.s,
1016                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
1017                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
1018
1019                 /* dialog timeout */
1020                 run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0);
1021
1022                 /* delete the dialog from DB */
1023                 if (dlg_db_mode)
1024                         remove_dialog_from_db(dlg);
1025
1026                 unref_dlg(dlg, unref+1);
1027
1028                 if_update_stat( dlg_enable_stats, expired_dlgs, 1);
1029                 if_update_stat( dlg_enable_stats, active_dlgs, -1);
1030         } else {
1031                 unref_dlg(dlg, 1);
1032         }
1033
1034         return;
1035 }
1036
1037
1038 /*!
1039  * \brief Function that returns the dialog lifetime as pseudo-variable
1040  * \param msg SIP message
1041  * \param param pseudo-variable parameter
1042  * \param res pseudo-variable result
1043  * \return 0 on success, -1 on failure
1044  */
1045 int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
1046 {
1047         int l = 0;
1048         char *ch = NULL;
1049
1050         if(msg==NULL || res==NULL)
1051                 return -1;
1052
1053         if (CURR_DLG_ID!=msg->id)
1054                 return pv_get_null( msg, param, res);
1055
1056         res->ri = CURR_DLG_LIFETIME;
1057         ch = int2str( (unsigned long)res->ri, &l);
1058
1059         res->rs.s = ch;
1060         res->rs.len = l;
1061
1062         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
1063
1064         return 0;
1065 }
1066
1067
1068 /*!
1069  * \brief Function that returns the dialog state as pseudo-variable
1070  * \param msg SIP message
1071  * \param param pseudo-variable parameter
1072  * \param res pseudo-variable result
1073  * \return 0 on success, -1 on failure
1074  */
1075 int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
1076 {
1077         int l = 0;
1078         char *ch = NULL;
1079
1080         if(msg==NULL || res==NULL)
1081                 return -1;
1082
1083         if (CURR_DLG_ID!=msg->id)
1084                 return pv_get_null( msg, param, res);
1085
1086         res->ri = CURR_DLG_STATUS;
1087         ch = int2str( (unsigned long)res->ri, &l);
1088
1089         res->rs.s = ch;
1090         res->rs.len = l;
1091
1092         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
1093
1094         return 0;
1095 }