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