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