dlg_handlers.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Voice System SRL
00003  *
00004  * This file is part of Kamailio, a free SIP server.
00005  *
00006  * Kamailio is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version
00010  *
00011  * Kamailio is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  * History:
00021  * --------
00022  * 2006-04-14  initial version (bogdan)
00023  * 2006-11-28  Added support for tracking the number of early dialogs, and the
00024  *             number of failed dialogs. This involved updates to dlg_onreply()
00025  *             (Jeffrey Magder - SOMA Networks)
00026  * 2007-03-06  syncronized state machine added for dialog state. New tranzition
00027  *             design based on events; removed num_1xx and num_2xx (bogdan)
00028  * 2007-04-30  added dialog matching without DID (dialog ID), but based only
00029  *             on RFC3261 elements - based on an original patch submitted
00030  *             by Michel Bensoussan <michel@extricom.com> (bogdan)
00031  * 2007-05-17  new feature: saving dialog info into a database if
00032  *             realtime update is set(ancuta)
00033  * 2007-07-06  support for saving additional dialog info : cseq, contact,
00034  *             route_set and socket_info for both caller and callee (ancuta)
00035  * 2007-07-10  Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper
00036  *             hash table lookup and isn't dependant on the is_direction
00037  *             function (which requires an RR param like dlg_match_mode 0
00038  *             anyways.. ;) ; based on a patch from
00039  *             Tavis Paquette <tavis@galaxytelecom.net>
00040  *             and Peter Baer <pbaer@galaxytelecom.net>  (bogdan)
00041  * 2008-04-04  added direction reporting in dlg callbacks (bogdan)
00042  */
00043 
00044 
00052 #include <string.h>
00053 #include <time.h>
00054 
00055 #include "../../trim.h"
00056 #include "../../pvar.h"
00057 #include "../../timer.h"
00058 #include "../../lib/kcore/statistics.h"
00059 #include "../../action.h"
00060 #include "../../script_cb.h"
00061 #include "../../lib/kcore/faked_msg.h"
00062 #include "../../parser/parse_from.h"
00063 #include "../../parser/parse_cseq.h"
00064 #include "../../parser/contact/parse_contact.h"
00065 #include "../../parser/parse_from.h"
00066 #include "../../parser/parse_rr.h"
00067 #include "../../modules/tm/tm_load.h"
00068 #include "../rr/api.h"
00069 #include "dlg_hash.h"
00070 #include "dlg_timer.h"
00071 #include "dlg_cb.h"
00072 #include "dlg_handlers.h"
00073 #include "dlg_req_within.h"
00074 #include "dlg_db_handler.h"
00075 #include "dlg_profile.h"
00076 #include "dlg_var.h"
00077 
00078 static str       rr_param;              
00079 static int       dlg_flag;              
00080 static pv_spec_t *timeout_avp;          
00081 static int       default_timeout;       
00082 static int       seq_match_mode;        
00083 static int       shutdown_done = 0;     
00084 extern int       detect_spirals;
00085 extern int       initial_cbs_inscript;
00086 extern int       dlg_send_bye;
00087 extern int       dlg_event_rt[DLG_EVENTRT_MAX];
00088 extern int       dlg_wait_ack;
00089 int              spiral_detected = -1;
00090 
00091 extern struct rr_binds d_rrb;           
00093 /* statistic variables */
00094 extern stat_var *early_dlgs;            
00095 extern stat_var *processed_dlgs;        
00096 extern stat_var *expired_dlgs;          
00097 extern stat_var *failed_dlgs;           
00099 extern pv_elem_t *ruri_param_model;     
00101 static unsigned int CURR_DLG_LIFETIME = 0;      
00102 static unsigned int CURR_DLG_STATUS = 0;        
00103 static unsigned int CURR_DLG_ID  = 0xffffffff;  
00107 #define RR_DLG_PARAM_SIZE  (2*2*sizeof(int)+3+MAX_DLG_RR_PARAM_NAME)
00108 
00109 #define DLG_SEPARATOR      '.'
00110 
00111 int dlg_set_tm_callbacks(tm_cell_t *t, sip_msg_t *req, dlg_cell_t *dlg,
00112                 int mode);
00113 int dlg_set_tm_waitack(tm_cell_t *t, dlg_cell_t *dlg);
00114 
00123 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
00124                 pv_spec_t *timeout_avp_p ,int default_timeout_p,
00125                 int seq_match_mode_p)
00126 {
00127         rr_param.s = rr_param_p;
00128         rr_param.len = strlen(rr_param.s);
00129 
00130         dlg_flag = 1<<dlg_flag_p;
00131 
00132         timeout_avp = timeout_avp_p;
00133         default_timeout = default_timeout_p;
00134         seq_match_mode = seq_match_mode_p;
00135 }
00136 
00137 
00141 void destroy_dlg_handlers(void)
00142 {
00143         shutdown_done = 1;
00144 }
00145 
00146 
00154 static inline int add_dlg_rr_param(struct sip_msg *req, unsigned int entry,
00155                 unsigned int id)
00156 {
00157         static char buf[RR_DLG_PARAM_SIZE];
00158         str s;
00159         int n;
00160         char *p;
00161 
00162         s.s = p = buf;
00163 
00164         *(p++) = ';';
00165         memcpy(p, rr_param.s, rr_param.len);
00166         p += rr_param.len;
00167         *(p++) = '=';
00168 
00169         n = RR_DLG_PARAM_SIZE - (p-buf);
00170         if (int2reverse_hex( &p, &n, entry)==-1)
00171                 return -1;
00172 
00173         *(p++) = DLG_SEPARATOR;
00174 
00175         n = RR_DLG_PARAM_SIZE - (p-buf);
00176         if (int2reverse_hex( &p, &n, id)==-1)
00177                 return -1;
00178 
00179         s.len = p-buf;
00180 
00181         if (d_rrb.add_rr_param( req, &s)<0) {
00182                 LM_ERR("failed to add rr param\n");
00183                 return -1;
00184         }
00185 
00186         return 0;
00187 }
00188 
00189 
00203 int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
00204         struct cell* t, unsigned int leg, str *tag)
00205 {
00206         unsigned int skip_recs;
00207         str cseq;
00208         str contact;
00209         str rr_set;
00210 
00211         dlg->bind_addr[leg] = msg->rcv.bind_address;
00212 
00213         /* extract the cseq number as string */
00214         if (leg==DLG_CALLER_LEG) {
00215                 if((!msg->cseq && (parse_headers(msg,HDR_CSEQ_F,0)<0 || !msg->cseq))
00216                         || !msg->cseq->parsed){
00217                         LM_ERR("bad sip message or missing CSeq hdr :-/\n");
00218                         goto error0;
00219                 }
00220                 cseq = (get_cseq(msg))->number;
00221         } else {
00222                 /* use the same as in request */
00223                 cseq = dlg->cseq[DLG_CALLER_LEG];
00224         }
00225 
00226         /* extract the contact address */
00227         if (!msg->contact&&(parse_headers(msg,HDR_CONTACT_F,0)<0||!msg->contact)){
00228                 LM_ERR("bad sip message or missing Contact hdr\n");
00229                 goto error0;
00230         }
00231         if ( parse_contact(msg->contact)<0 ||
00232         ((contact_body_t *)msg->contact->parsed)->contacts==NULL ||
00233         ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) {
00234                 LM_ERR("bad Contact HDR\n");
00235                 goto error0;
00236         }
00237         contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri;
00238 
00239         /* extract the RR parts */
00240         if(!msg->record_route && (parse_headers(msg,HDR_EOH_F,0)<0)  ){
00241                 LM_ERR("failed to parse record route header\n");
00242                 goto error0;
00243         }
00244 
00245         if (leg==DLG_CALLER_LEG) {
00246                 skip_recs = 0;
00247         } else {
00248                 /* was the 200 OK received or local generated */
00249                 skip_recs = dlg->from_rr_nb +
00250                         ((t->relayed_reply_branch>=0)?
00251                                 ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_R2)?2:
00252                                  ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_RR)?1:0))
00253                                 :0);
00254         }
00255 
00256         if(msg->record_route){
00257                 if( print_rr_body(msg->record_route, &rr_set, leg,
00258                                                         &skip_recs) != 0 ){
00259                         LM_ERR("failed to print route records \n");
00260                         goto error0;
00261                 }
00262         } else {
00263                 rr_set.s = 0;
00264                 rr_set.len = 0;
00265         }
00266 
00267         if(leg==DLG_CALLER_LEG)
00268                 dlg->from_rr_nb = skip_recs;
00269 
00270         LM_DBG("route_set %.*s, contact %.*s, cseq %.*s and bind_addr %.*s\n",
00271                 rr_set.len, rr_set.s, contact.len, contact.s,
00272                 cseq.len, cseq.s,
00273                 msg->rcv.bind_address->sock_str.len,
00274                 msg->rcv.bind_address->sock_str.s);
00275 
00276         if (dlg_set_leg_info( dlg, tag, &rr_set, &contact, &cseq, leg)!=0) {
00277                 LM_ERR("dlg_set_leg_info failed\n");
00278                 if (rr_set.s) pkg_free(rr_set.s);
00279                 goto error0;
00280         }
00281 
00282         if (rr_set.s) pkg_free(rr_set.s);
00283 
00284         return 0;
00285 error0:
00286         return -1;
00287 }
00288 
00292 dlg_iuid_t *dlg_get_iuid_shm_clone(dlg_cell_t *dlg)
00293 {
00294         dlg_iuid_t *iuid = NULL;
00295 
00296         if(dlg==NULL)
00297                 return NULL;
00298 
00299         iuid = (dlg_iuid_t*)shm_malloc(sizeof(dlg_iuid_t));
00300         if(iuid==NULL)
00301         {
00302                 LM_ERR("failed to clone dialog iuid\n");
00303                 return NULL;
00304         }
00305 
00306         memset(iuid, 0, sizeof(dlg_iuid_t));
00307         iuid->h_entry = dlg->h_entry;
00308         iuid->h_id = dlg->h_id;
00309 
00310         return iuid;
00311 }
00312 
00313 
00317 void dlg_iuid_sfree(void *iuid)
00318 {
00319     if(iuid) {
00320                 LM_DBG("freeing dlg iuid [%u:%u] (%p)\n",
00321                                 ((dlg_iuid_t*)iuid)->h_entry,
00322                                 ((dlg_iuid_t*)iuid)->h_id, iuid);
00323                 shm_free(iuid);
00324         }
00325 }
00326 
00327 
00334 static void dlg_terminated_confirmed(tm_cell_t *t, int type,
00335                                      struct tmcb_params* params)
00336 {
00337     dlg_cell_t *dlg = NULL;
00338         dlg_iuid_t *iuid = NULL;
00339 
00340     if(!params || !params->req || !params->param)
00341     {
00342         LM_ERR("invalid parameters!\n");
00343         return;
00344     }
00345 
00346         iuid = (dlg_iuid_t*)*params->param;
00347         if(iuid==NULL)
00348                 return;
00349 
00350     dlg = dlg_get_by_iuid(iuid);
00351 
00352     if(dlg==NULL)
00353     {
00354         LM_ERR("failed to get dialog from params!\n");
00355         return;
00356     }
00357     /* dialog termination confirmed (BYE reply) */
00358     run_dlg_callbacks(DLGCB_TERMINATED_CONFIRMED,
00359                       dlg,
00360                       params->req,
00361                       params->rpl,
00362                       DLG_DIR_UPSTREAM,
00363                       0);
00364         dlg_release(dlg);
00365 }
00366 
00373 static void dlg_terminated(sip_msg_t *req, dlg_cell_t *dlg, unsigned int dir)
00374 {
00375         dlg_iuid_t *iuid = NULL;
00376 
00377     if(!req) {
00378         LM_ERR("request is empty!");
00379         return;
00380     }
00381 
00382     if(!dlg) {
00383         LM_ERR("dialog is empty!");
00384         return;
00385     }
00386 
00387     /* dialog terminated (BYE) */
00388     run_dlg_callbacks(DLGCB_TERMINATED, dlg, req, NULL, dir, 0);
00389 
00390         iuid = dlg_get_iuid_shm_clone(dlg);
00391         if(iuid==NULL)
00392                 return;
00393 
00394     /* register callback for the coresponding reply */
00395     if (d_tmb.register_tmcb(req,
00396                             0,
00397                             TMCB_RESPONSE_OUT,
00398                             dlg_terminated_confirmed,
00399                             (void*)iuid,
00400                             dlg_iuid_sfree) <= 0 ) {
00401         LM_ERR("cannot register response callback for BYE request\n");
00402         return;
00403     }
00404 }
00405 
00412 static void dlg_ontdestroy(struct cell* t, int type, struct tmcb_params *param)
00413 {
00414         dlg_cell_t *dlg = NULL;
00415         dlg_iuid_t *iuid = NULL;
00416 
00417         iuid = (dlg_iuid_t*)(*param->param);
00418         dlg = dlg_get_by_iuid(iuid);
00419         if(dlg==0)
00420                 return;
00421         /* 1 for callback and 1 for dlg lookup */
00422         dlg_unref(dlg, 2);
00423 }
00424 
00437 static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
00438 {
00439     dlg_cell_t *dlg = NULL;
00440         dlg_iuid_t *iuid = NULL;
00441     int new_state, old_state, unref, event;
00442     str tag;
00443     sip_msg_t *req = param->req;
00444         sip_msg_t *rpl = param->rpl;
00445 
00446         if (shutdown_done)
00447                 return;
00448         iuid = (dlg_iuid_t*)(*param->param);
00449         dlg = dlg_get_by_iuid(iuid);
00450         if(dlg==0)
00451                 return;
00452 
00453         unref = 0;
00454         if (type==TMCB_RESPONSE_FWDED) {
00455                 /* The state does not change, but the msg is mutable in this callback*/
00456                 run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
00457                 goto done;
00458         }
00459 
00460         if (type==TMCB_DESTROY)
00461                 event = DLG_EVENT_TDEL;
00462         else if (param->code<200)
00463                 event = DLG_EVENT_RPL1xx;
00464         else if (param->code<300)
00465                 event = DLG_EVENT_RPL2xx;
00466         else
00467                 event = DLG_EVENT_RPL3xx;
00468 
00469         next_state_dlg( dlg, event, &old_state, &new_state, &unref);
00470         dlg_run_event_route(dlg, (rpl==FAKED_REPLY)?NULL:rpl, old_state, new_state);
00471 
00472         if (new_state==DLG_STATE_EARLY) {
00473                 run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
00474                 if (old_state!=DLG_STATE_EARLY)
00475                         if_update_stat(dlg_enable_stats, early_dlgs, 1);
00476                 goto done;
00477         }
00478 
00479         if (new_state==DLG_STATE_CONFIRMED_NA &&
00480         old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) {
00481                 LM_DBG("dialog %p confirmed (ACK pending)\n",dlg);
00482 
00483                  if (rpl != FAKED_REPLY) {
00484                         /* get to tag*/
00485                         if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0)
00486                                                 || !rpl->to) ) {
00487                                 LM_ERR("bad reply or missing TO hdr :-/\n");
00488                                 tag.s = 0;
00489                                 tag.len = 0;
00490                         } else {
00491                                 tag = get_to(rpl)->tag_value;
00492                                 if (tag.s==0 || tag.len==0) {
00493                                         LM_ERR("missing TAG param in TO hdr :-/\n");
00494                                         tag.s = 0;
00495                                         tag.len = 0;
00496                                 }
00497                         }
00498 
00499                         /* save callee's tag, cseq, contact and record route*/
00500                         if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) {
00501                                 LM_ERR("could not add further info to the dialog\n");
00502                         }
00503                  } else {
00504                          LM_ERR("Faked reply!\n");
00505                  }
00506 
00507                 /* set start time */
00508                 dlg->start_ts = (unsigned int)(time(0));
00509 
00510                 /* save the settings to the database,
00511                  * if realtime saving mode configured- save dialog now
00512                  * else: the next time the timer will fire the update*/
00513                 dlg->dflags |= DLG_FLAG_NEW;
00514                 if ( dlg_db_mode==DB_MODE_REALTIME )
00515                         update_dialog_dbinfo(dlg);
00516 
00517                 if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) {
00518                         LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] "
00519                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00520                                 dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state,
00521                                 dlg->callid.len, dlg->callid.s,
00522                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00523                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00524                 } else {
00525                         /* dialog pointer inserted in timer list */
00526                         dlg_ref(dlg, 1);
00527                 }
00528 
00529                 /* dialog confirmed (ACK pending) */
00530                 run_dlg_callbacks( DLGCB_CONFIRMED_NA, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
00531 
00532                 if (old_state==DLG_STATE_EARLY)
00533                         if_update_stat(dlg_enable_stats, early_dlgs, -1);
00534 
00535                 if (unref) dlg_unref(dlg, unref);
00536                 if_update_stat(dlg_enable_stats, active_dlgs, 1);
00537                 goto done;
00538         }
00539 
00540         if ( new_state==DLG_STATE_DELETED
00541                                 && (old_state==DLG_STATE_UNCONFIRMED
00542                                         || old_state==DLG_STATE_EARLY) ) {
00543                 LM_DBG("dialog %p failed (negative reply)\n", dlg);
00544                 /* dialog setup not completed (3456XX) */
00545                 run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
00546                 /* do unref */
00547                 if (unref)
00548                         dlg_unref(dlg, unref);
00549                 if (old_state==DLG_STATE_EARLY)
00550                         if_update_stat(dlg_enable_stats, early_dlgs, -1);
00551 
00552                 if_update_stat(dlg_enable_stats, failed_dlgs, 1);
00553 
00554                 if(dlg_wait_ack==1)
00555                         dlg_set_tm_waitack(t, dlg);
00556                 goto done;
00557         }
00558 
00559         if (unref) dlg_unref(dlg, unref);
00560 
00561 done:
00562         /* unref due to dlg_get_by_iuid() */
00563         dlg_release(dlg);
00564         return;
00565 }
00566 
00567 
00577 static void dlg_seq_onreply_helper(struct cell* t, int type,
00578                 struct tmcb_params *param, const int direction)
00579 {
00580         dlg_cell_t *dlg = NULL;
00581         dlg_iuid_t *iuid = NULL;
00582 
00583         if (shutdown_done)
00584                 return;
00585         iuid = (dlg_iuid_t*)(*param->param);
00586         dlg = dlg_get_by_iuid(iuid);
00587         if (dlg==0)
00588                 return;
00589 
00590         if (type==TMCB_RESPONSE_FWDED)
00591         {
00592                 run_dlg_callbacks( DLGCB_RESPONSE_WITHIN,
00593                                    dlg,
00594                                    param->req,
00595                                    param->rpl,
00596                                    direction,
00597                                    0);
00598         }
00599         dlg_release(dlg);
00600 
00601         return;
00602 }
00603 
00604 
00612 static void dlg_seq_up_onreply(struct cell* t, int type, struct tmcb_params *param)
00613 {
00614         return dlg_seq_onreply_helper(t, type, param, DLG_DIR_UPSTREAM);
00615 }
00616 
00617 
00625 static void dlg_seq_down_onreply(struct cell* t, int type, struct tmcb_params *param)
00626 {
00627         return dlg_seq_onreply_helper(t, type, param, DLG_DIR_DOWNSTREAM);
00628 }
00629 
00630 
00636 inline static int get_dlg_timeout(struct sip_msg *req)
00637 {
00638         pv_value_t pv_val;
00639 
00640         if( timeout_avp ) {
00641                 if ( pv_get_spec_value( req, timeout_avp, &pv_val)==0 &&
00642                                 pv_val.flags&PV_VAL_INT && pv_val.ri>0 ) {
00643                         return pv_val.ri;
00644                 }
00645                 LM_DBG("invalid AVP value, using default timeout\n");
00646         }
00647         return default_timeout;
00648 }
00649 
00650 
00660 static inline int pre_match_parse( struct sip_msg *req, str *callid,
00661                 str *ftag, str *ttag, int with_ttag)
00662 {
00663         if (parse_headers(req,HDR_CALLID_F|HDR_TO_F,0)<0 || !req->callid ||
00664                         !req->to ) {
00665                 LM_ERR("bad request or missing CALLID/TO hdr :-/\n");
00666                 return -1;
00667         }
00668 
00669         if (get_to(req)->tag_value.len==0) {
00670                 if (with_ttag == 1) {
00671                         /* out of dialog request with preloaded Route headers; ignore. */
00672                         return -1;
00673                 } else {
00674                         ttag->s = NULL;
00675                         ttag->len = 0;
00676                 }
00677         } else {
00678                 *ttag = get_to(req)->tag_value;
00679         }
00680 
00681         if (parse_from_header(req)<0 || get_from(req)->tag_value.len==0) {
00682                 LM_ERR("failed to get From header\n");
00683                 return -1;
00684         }
00685 
00686         /* callid */
00687         *callid = req->callid->body;
00688         trim(callid);
00689         /* from tag */
00690         *ftag = get_from(req)->tag_value;
00691         return 0;
00692 }
00693 
00694 
00702 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
00703 {
00704         sip_msg_t *req = param->req;
00705         dlg_cell_t *dlg = NULL;
00706 
00707         if(req->first_line.u.request.method_value != METHOD_INVITE)
00708                 return;
00709 
00710         dlg = dlg_get_ctx_dialog();
00711 
00712         if (dlg!=NULL) {
00713                 if (!initial_cbs_inscript) {
00714                         if (spiral_detected == 1)
00715                                 run_dlg_callbacks( DLGCB_SPIRALED, dlg,
00716                                                 req, NULL, DLG_DIR_DOWNSTREAM, 0);
00717                         else if (spiral_detected == 0)
00718                                 run_create_callbacks(dlg, req);
00719                 }
00720         }
00721         if (dlg==NULL) {
00722                 if((req->flags&dlg_flag)!=dlg_flag)
00723                         return;
00724                 dlg_new_dialog(req, t, 1);
00725                 dlg = dlg_get_ctx_dialog();
00726         }
00727         if (dlg!=NULL) {
00728                 dlg_set_tm_callbacks(t, req, dlg, spiral_detected);
00729                 dlg_release(dlg);
00730         }
00731 }
00732 
00733 
00739 #if 0
00740 static void unref_new_dialog(void *iuid)
00741 {
00742         struct tmcb_params p;
00743 
00744         memset(&p, 0, sizeof(struct tmcb_params));
00745         p.param = (void*)&iuid;
00746         dlg_onreply(0, TMCB_DESTROY, &p);
00747 }
00748 #endif
00749 
00750 
00765 int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
00766 {
00767         dlg_cell_t *dlg;
00768         str s;
00769         str callid;
00770     str ftag;
00771     str ttag;
00772     str req_uri;
00773     unsigned int dir;
00774 
00775         dlg = dlg_get_ctx_dialog();
00776     if(dlg != NULL) {
00777                 dlg_release(dlg);
00778         return -1;
00779         }
00780 
00781         if(req->first_line.u.request.method_value != METHOD_INVITE)
00782                 return -1;
00783 
00784     if(pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
00785         LM_WARN("pre-matching failed\n");
00786         return -1;
00787     }
00788 
00789     if(ttag.s!=0 && ttag.len!=0)
00790         return -1;
00791 
00792     if(pv_printf_s(req, ruri_param_model, &req_uri)<0) {
00793         LM_ERR("error - cannot print the r-uri format\n");
00794         return -1;
00795     }
00796     trim(&req_uri);
00797 
00798     if (detect_spirals)
00799     {
00800         if (spiral_detected == 1)
00801             return 0;
00802 
00803         dir = DLG_DIR_NONE;
00804 
00805         dlg = get_dlg(&callid, &ftag, &ttag, &dir);
00806         if (dlg)
00807         {
00808             LM_DBG("Callid '%.*s' found, must be a spiraled request\n",
00809                 callid.len, callid.s);
00810             spiral_detected = 1;
00811 
00812             if (run_initial_cbs)
00813                 run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL,
00814                                                 DLG_DIR_DOWNSTREAM, 0);
00815             /* get_dlg() has incremented the ref count by 1
00816                          * - it's ok, dlg will be unref at the end of function */
00817             goto finish;
00818         }
00819     }
00820     spiral_detected = 0;
00821 
00822     dlg = build_new_dlg (&callid /*callid*/,
00823                          &(get_from(req)->uri) /*from uri*/,
00824                          &(get_to(req)->uri) /*to uri*/,
00825                          &ftag/*from_tag*/,
00826                          &req_uri /*r-uri*/ );
00827 
00828         if (dlg==0)
00829         {
00830                 LM_ERR("failed to create new dialog\n");
00831                 return -1;
00832         }
00833 
00834         /* save caller's tag, cseq, contact and record route*/
00835         if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
00836                         &(get_from(req)->tag_value)) !=0)
00837         {
00838                 LM_ERR("could not add further info to the dialog\n");
00839                 shm_free(dlg);
00840                 return -1;
00841         }
00842 
00843         /* Populate initial varlist: */
00844         dlg->vars = get_local_varlist_pointer(req, 1);
00845 
00846         link_dlg(dlg, 0);
00847 
00848         dlg->lifetime = get_dlg_timeout(req);
00849         s.s   = _dlg_ctx.to_route_name;
00850         s.len = strlen(s.s);
00851         dlg_set_toroute(dlg, &s);
00852         dlg->sflags |= _dlg_ctx.flags;
00853         dlg->iflags |= _dlg_ctx.iflags;
00854 
00855         if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0)
00856                 dlg->iflags |= DLG_IFLAG_TIMEOUTBYE;
00857 
00858     if (run_initial_cbs)  run_create_callbacks( dlg, req);
00859 
00860         /* first INVITE seen (dialog created, unconfirmed) */
00861         if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
00862                         add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) {
00863                 LM_ERR("failed to add RR param\n");
00864                 goto error;
00865         }
00866 
00867         /* new dlg - reference it once more for current dialog iuid shortcut */
00868     dlg_ref(dlg, 1);
00869 
00870     if_update_stat( dlg_enable_stats, processed_dlgs, 1);
00871 
00872 finish:
00873     _dlg_ctx.iuid.h_entry = dlg->h_entry;
00874     _dlg_ctx.iuid.h_id = dlg->h_id;
00875     set_current_dialog(req, dlg);
00876         dlg_release(dlg);
00877 
00878         return 0;
00879 
00880 error:
00881         if (!spiral_detected)
00882                 dlg_unref(dlg, 1);               // undo ref regarding linking
00883         return -1;
00884 }
00885 
00886 
00895 int dlg_set_tm_callbacks(tm_cell_t *t, sip_msg_t *req, dlg_cell_t *dlg,
00896                 int smode)
00897 {
00898         dlg_iuid_t *iuid = NULL;
00899         if(t==NULL)
00900                 return -1;
00901 
00902         if(smode==0) {
00903                 iuid = dlg_get_iuid_shm_clone(dlg);
00904                 if(iuid==NULL)
00905                 {
00906                         LM_ERR("failed to create dialog unique id clone\n");
00907                         goto error;
00908                 }
00909                 if ( d_tmb.register_tmcb( req, t,
00910                                 TMCB_RESPONSE_READY|TMCB_RESPONSE_FWDED,
00911                                 dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) {
00912                         LM_ERR("failed to register TMCB\n");
00913                         goto error;
00914                 }
00915         }
00916 
00917         dlg->dflags |= DLG_FLAG_TM;
00918 
00919         return 0;
00920 error:
00921         dlg_iuid_sfree(iuid);
00922         return -1;
00923 }
00924 
00931 int dlg_set_tm_waitack(tm_cell_t *t, dlg_cell_t *dlg)
00932 {
00933         dlg_iuid_t *iuid = NULL;
00934         if(t==NULL)
00935                 return -1;
00936 
00937         LM_DBG("registering TMCB to wait for negative ACK\n");
00938         iuid = dlg_get_iuid_shm_clone(dlg);
00939         if(iuid==NULL)
00940         {
00941                 LM_ERR("failed to create dialog unique id clone\n");
00942                 goto error;
00943         }
00944         dlg_ref(dlg, 1);
00945         if ( d_tmb.register_tmcb( NULL, t,
00946                         TMCB_DESTROY,
00947                         dlg_ontdestroy, (void*)iuid, dlg_iuid_sfree)<0 ) {
00948                 LM_ERR("failed to register TMCB to wait for negative ACK\n");
00949                 dlg_unref(dlg, 1);
00950                 goto error;
00951         }
00952 
00953         return 0;
00954 error:
00955         dlg_iuid_sfree(iuid);
00956         return -1;
00957 }
00958 
00967 static inline int parse_dlg_rr_param(char *p, char *end, int *h_entry, int *h_id)
00968 {
00969         char *s;
00970 
00971         for ( s=p ; p<end && *p!=DLG_SEPARATOR ; p++ );
00972         if (*p!=DLG_SEPARATOR) {
00973                 LM_ERR("malformed rr param '%.*s'\n", (int)(long)(end-s), s);
00974                 return -1;
00975         }
00976 
00977         if ( reverse_hex2int( s, p-s, (unsigned int*)h_entry)<0 ) {
00978                 LM_ERR("invalid hash entry '%.*s'\n", (int)(long)(p-s), s);
00979                 return -1;
00980         }
00981 
00982         if ( reverse_hex2int( p+1, end-(p+1), (unsigned int*)h_id)<0 ) {
00983                 LM_ERR("invalid hash id '%.*s'\n", (int)(long)(end-(p+1)), p+1 );
00984                 return -1;
00985         }
00986 
00987         return 0;
00988 }
00989 
00990 
00998 static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
00999                 unsigned int dir)
01000 {
01001         if ( (!req->cseq && parse_headers(req,HDR_CSEQ_F,0)<0) || !req->cseq ||
01002         !req->cseq->parsed) {
01003                 LM_ERR("bad sip message or missing CSeq hdr :-/\n");
01004                 return -1;
01005         }
01006 
01007         if ( dir==DLG_DIR_UPSTREAM) {
01008                 return dlg_update_cseq(dlg, DLG_CALLEE_LEG,&((get_cseq(req))->number));
01009         } else if ( dir==DLG_DIR_DOWNSTREAM) {
01010                 return dlg_update_cseq(dlg, DLG_CALLER_LEG,&((get_cseq(req))->number));
01011         } else {
01012                 LM_CRIT("dir is not set!\n");
01013                 return -1;
01014         }
01015 }
01016 
01023 static void unref_dlg_from_cb(struct cell* t, int type, struct tmcb_params *param)
01024 {
01025         dlg_cell_t *dlg = NULL;
01026         dlg_iuid_t *iuid = NULL;
01027 
01028         iuid = (dlg_iuid_t*)(*param->param);
01029         if (iuid==NULL)
01030                 return;
01031 
01032         dlg = dlg_get_by_iuid(iuid);
01033         if(dlg==NULL)
01034                 return;
01035         /* unref by 2: 1 set when adding in tm cb, 1 sent by dlg_get_by_iuid() */
01036         dlg_unref(dlg, 2);
01037 }
01038 
01039 
01040 dlg_cell_t *dlg_get_msg_dialog(sip_msg_t *msg)
01041 {
01042         dlg_cell_t *dlg = NULL;
01043         str callid;
01044         str ftag;
01045         str ttag;
01046         unsigned int dir;
01047 
01048         /* Retrieve the current dialog */
01049         dlg = dlg_get_ctx_dialog();
01050         if(dlg!=NULL)
01051                 return dlg;
01052         
01053         if (pre_match_parse(msg, &callid, &ftag, &ttag, 0)<0)
01054                 return NULL;
01055         dir = DLG_DIR_NONE;
01056         dlg = get_dlg(&callid, &ftag, &ttag, &dir);
01057         if (dlg==NULL){
01058                 LM_DBG("dlg with callid '%.*s' not found\n",
01059                                 msg->callid->body.len, msg->callid->body.s);
01060                 return NULL;
01061         }
01062         return dlg;
01063 }
01064 
01076 void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
01077 {
01078         dlg_cell_t *dlg;
01079         dlg_iuid_t *iuid;
01080         str val, callid, ftag, ttag;
01081         int h_entry, h_id, new_state, old_state, unref, event, timeout;
01082         unsigned int dir;
01083         int ret = 0;
01084 
01085         dlg = dlg_get_ctx_dialog();
01086         if (dlg!=NULL) {
01087                 dlg_release(dlg);
01088                 return;
01089         }
01090 
01091         /* skip initial requests - they may end up here because of the
01092          * preloaded route */
01093         if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) {
01094                 LM_ERR("bad request or missing TO hdr :-/\n");
01095                 return;
01096         }
01097         if ( get_to(req)->tag_value.len==0 )
01098                 return;
01099 
01100         dlg = 0;
01101         dir = DLG_DIR_NONE;
01102 
01103         if ( seq_match_mode!=SEQ_MATCH_NO_ID ) {
01104                 if( d_rrb.get_route_param( req, &rr_param, &val)!=0) {
01105                         LM_DBG("Route param '%.*s' not found\n", rr_param.len,rr_param.s);
01106                         if (seq_match_mode==SEQ_MATCH_STRICT_ID )
01107                                 return;
01108                 } else {
01109                         LM_DBG("route param is '%.*s' (len=%d)\n",val.len,val.s,val.len);
01110 
01111                         if ( parse_dlg_rr_param( val.s, val.s+val.len, &h_entry, &h_id)<0 )
01112                                 return;
01113 
01114                         dlg = dlg_lookup(h_entry, h_id);
01115                         if (dlg==0) {
01116                                 LM_WARN("unable to find dialog for %.*s "
01117                                         "with route param '%.*s' [%u:%u]\n",
01118                                         req->first_line.u.request.method.len,
01119                                         req->first_line.u.request.method.s,
01120                                         val.len,val.s, h_entry, h_id);
01121                                 if (seq_match_mode==SEQ_MATCH_STRICT_ID )
01122                                         return;
01123                         } else {
01124                                 if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) {
01125                                         // lookup_dlg has incremented the ref count by 1
01126                                         dlg_release(dlg);
01127                                         return;
01128                                 }
01129                                 if (match_dialog( dlg, &callid, &ftag, &ttag, &dir )==0) {
01130                                         LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, "
01131                                                         "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n",
01132                                                         req->first_line.u.request.method.len,
01133                                                         req->first_line.u.request.method.s,
01134                                                         callid.len, callid.s, callid.len,
01135                                                         ftag.len, ftag.s, ftag.len,
01136                                                         ttag.len, ttag.s, ttag.len, dir);
01137                                         LM_WARN("dialog identification elements are callid='%.*s'/%d, "
01138                                                         "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n",
01139                                                         dlg->callid.len, dlg->callid.s, dlg->callid.len,
01140                                                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
01141                                                         dlg->tag[DLG_CALLER_LEG].len,
01142                                                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s,
01143                                                         dlg->tag[DLG_CALLEE_LEG].len);
01144                                         // lookup_dlg has incremented the ref count by 1
01145                                         dlg_release(dlg);
01146 
01147                                         // Reset variables in order to do a lookup based on SIP-Elements.
01148                                         dlg = 0;
01149                                         dir = DLG_DIR_NONE;
01150 
01151                                         if (seq_match_mode==SEQ_MATCH_STRICT_ID )
01152                                                 return;
01153                                 }
01154                         }
01155                 }
01156         }
01157 
01158         if (dlg==0) {
01159                 if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0)
01160                         return;
01161                 /* TODO - try to use the RR dir detection to speed up here the
01162                  * search -bogdan */
01163                 dlg = get_dlg(&callid, &ftag, &ttag, &dir);
01164                 if (dlg==0){
01165                         LM_DBG("Callid '%.*s' not found\n",
01166                                 req->callid->body.len, req->callid->body.s);
01167                         return;
01168                 }
01169         }
01170 
01171     /* set current dialog - re-use ref increment from dlg_get() above */
01172     set_current_dialog( req, dlg);
01173     _dlg_ctx.iuid.h_entry = dlg->h_entry;
01174     _dlg_ctx.iuid.h_id = dlg->h_id;
01175 
01176         /* run state machine */
01177         switch ( req->first_line.u.request.method_value ) {
01178                 case METHOD_PRACK:
01179                         event = DLG_EVENT_REQPRACK; break;
01180                 case METHOD_ACK:
01181                         event = DLG_EVENT_REQACK; break;
01182                 case METHOD_BYE:
01183                         event = DLG_EVENT_REQBYE; break;
01184                 default:
01185                         event = DLG_EVENT_REQ;
01186         }
01187 
01188         next_state_dlg( dlg, event, &old_state, &new_state, &unref);
01189         dlg_run_event_route(dlg, req, old_state, new_state);
01190 
01191         CURR_DLG_ID = req->id;
01192         CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
01193         CURR_DLG_STATUS = new_state;
01194 
01195         /* delay deletion of dialog until transaction has died off in order
01196          * to absorb in-air messages */
01197         if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
01198                 iuid = dlg_get_iuid_shm_clone(dlg);
01199                 if(iuid!=NULL) {
01200                         if ( d_tmb.register_tmcb(req, NULL, TMCB_DESTROY,
01201                                         unref_dlg_from_cb, (void*)iuid, dlg_iuid_sfree)<0 ) {
01202                                 LM_ERR("failed to register deletion delay function\n");
01203                                 shm_free(iuid);
01204                         } else {
01205                                 dlg_ref(dlg, 1);
01206                         }
01207                 }
01208         }
01209 
01210         if (new_state==DLG_STATE_CONFIRMED && old_state!=DLG_STATE_CONFIRMED)
01211                 dlg_ka_add(dlg);
01212 
01213         /* run actions for the transition */
01214         if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED &&
01215         old_state!=DLG_STATE_DELETED) {
01216                 LM_DBG("BYE successfully processed\n");
01217                 /* remove from timer */
01218                 ret = remove_dialog_timer(&dlg->tl);
01219                 if (ret < 0) {
01220                         LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
01221                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",
01222                                 dlg, dlg->h_entry, dlg->h_id,
01223                                 dlg->callid.len, dlg->callid.s,
01224                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
01225                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
01226                 } else if (ret > 0) {
01227                         LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
01228                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",
01229                                 dlg, dlg->h_entry, dlg->h_id,
01230                                 dlg->callid.len, dlg->callid.s,
01231                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
01232                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
01233                 } else {
01234                         /* one extra unref due to removal from timer list */
01235                         unref++;
01236                 }
01237                 /* dialog terminated (BYE) */
01238         dlg_terminated( req, dlg, dir);
01239 
01240                 dlg_unref(dlg, unref);
01241 
01242                 if_update_stat( dlg_enable_stats, active_dlgs, -1);
01243                 goto done;
01244         }
01245 
01246         if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK)
01247         && new_state==DLG_STATE_CONFIRMED) {
01248 
01249                 timeout = get_dlg_timeout(req);
01250                 if (timeout!=default_timeout) {
01251                         dlg->lifetime = timeout;
01252                 }
01253                 if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) {
01254                         LM_ERR("failed to update dialog lifetime\n");
01255                 }
01256                 if (update_cseqs(dlg, req, dir)!=0) {
01257                         LM_ERR("cseqs update failed\n");
01258                 } else {
01259                         dlg->dflags |= DLG_FLAG_CHANGED;
01260                         if ( dlg_db_mode==DB_MODE_REALTIME )
01261                                 update_dialog_dbinfo(dlg);
01262                 }
01263 
01264                 if (old_state==DLG_STATE_CONFIRMED_NA) {
01265                         LM_DBG("confirming ACK successfully processed\n");
01266 
01267                         /* confirming ACK request */
01268                         run_dlg_callbacks( DLGCB_CONFIRMED, dlg, req, NULL, dir, 0);
01269                 } else {
01270                         LM_DBG("sequential request successfully processed\n");
01271 
01272                         /* within dialog request */
01273                         run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0);
01274 
01275                         if ( (event!=DLG_EVENT_REQACK) &&
01276                                         (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) {
01277                                 iuid = dlg_get_iuid_shm_clone(dlg);
01278                                 if(iuid!=NULL)
01279                                 {
01280                                         /* register callback for the replies of this request */
01281                                         if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
01282                                                         (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply:
01283                                                                                                                 dlg_seq_up_onreply,
01284                                                         (void*)iuid, dlg_iuid_sfree)<0 ) {
01285                                                 LM_ERR("failed to register TMCB (2)\n");
01286                                                 shm_free(iuid);
01287                                         }
01288                                 }
01289                         }
01290                 }
01291         }
01292 
01293         if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){
01294                 dlg->dflags |= DLG_FLAG_CHANGED;
01295                 if(dlg_db_mode == DB_MODE_REALTIME)
01296                         update_dialog_dbinfo(dlg);
01297         }
01298 
01299 done:
01300         dlg_release(dlg);
01301         return;
01302 }
01303 
01304 
01309 void dlg_ontimeout(struct dlg_tl *tl)
01310 {
01311         dlg_cell_t *dlg;
01312         int new_state, old_state, unref;
01313         sip_msg_t *fmsg;
01314 
01315         /* get the dialog tl payload */
01316         dlg = ((struct dlg_cell*)((char *)(tl) -
01317                         (unsigned long)(&((struct dlg_cell*)0)->tl)));
01318 
01319         if(dlg->state==DLG_STATE_CONFIRMED_NA
01320                                 || dlg->state==DLG_STATE_CONFIRMED)
01321         {
01322                 if(dlg->toroute>0 && dlg->toroute<main_rt.entries
01323                         && main_rt.rlist[dlg->toroute]!=NULL)
01324                 {
01325                         fmsg = faked_msg_next();
01326                         if (exec_pre_script_cb(fmsg, REQUEST_CB_TYPE)>0)
01327                         {
01328                                 dlg_ref(dlg, 1);
01329                                 dlg_set_ctx_iuid(dlg);
01330                                 LM_DBG("executing route %d on timeout\n", dlg->toroute);
01331                                 set_route_type(REQUEST_ROUTE);
01332                                 run_top_route(main_rt.rlist[dlg->toroute], fmsg, 0);
01333                                 dlg_reset_ctx_iuid();
01334                                 exec_post_script_cb(fmsg, REQUEST_CB_TYPE);
01335                                 dlg_unref(dlg, 1);
01336                         }
01337                 }
01338 
01339                 if(dlg->iflags&DLG_IFLAG_TIMEOUTBYE)
01340                 {
01341                         dlg_bye_all(dlg, NULL);
01342                         /* run event route for end of dlg */
01343                         dlg_run_event_route(dlg, NULL, dlg->state, DLG_STATE_DELETED);
01344                         dlg_unref(dlg, 1);
01345                         if_update_stat(dlg_enable_stats, expired_dlgs, 1);
01346                         return;
01347                 }
01348         }
01349 
01350         next_state_dlg( dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref);
01351         dlg_run_event_route(dlg, NULL, old_state, new_state);
01352 
01353         if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
01354                 LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
01355                         dlg->callid.len, dlg->callid.s,
01356                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
01357                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
01358 
01359                 /* dialog timeout */
01360                 run_dlg_callbacks( DLGCB_EXPIRED, dlg, NULL, NULL, DLG_DIR_NONE, 0);
01361 
01362                 dlg_unref(dlg, unref+1);
01363 
01364                 if_update_stat( dlg_enable_stats, expired_dlgs, 1);
01365                 if_update_stat( dlg_enable_stats, active_dlgs, -1);
01366         } else {
01367                 dlg_unref(dlg, 1);
01368         }
01369 
01370         return;
01371 }
01372 
01373 
01381 int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
01382 {
01383         int l = 0;
01384         char *ch = NULL;
01385 
01386         if(msg==NULL || res==NULL)
01387                 return -1;
01388 
01389         if (CURR_DLG_ID!=msg->id)
01390                 return pv_get_null( msg, param, res);
01391 
01392         res->ri = CURR_DLG_LIFETIME;
01393         ch = int2str( (unsigned long)res->ri, &l);
01394 
01395         res->rs.s = ch;
01396         res->rs.len = l;
01397 
01398         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
01399 
01400         return 0;
01401 }
01402 
01403 
01411 int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
01412 {
01413         int l = 0;
01414         char *ch = NULL;
01415 
01416         if(msg==NULL || res==NULL)
01417                 return -1;
01418 
01419         if (CURR_DLG_ID!=msg->id)
01420                 return pv_get_null( msg, param, res);
01421 
01422         res->ri = CURR_DLG_STATUS;
01423         ch = int2str( (unsigned long)res->ri, &l);
01424 
01425         res->rs.s = ch;
01426         res->rs.len = l;
01427 
01428         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
01429 
01430         return 0;
01431 }
01432 
01437 void dlg_run_event_route(dlg_cell_t *dlg, sip_msg_t *msg, int ostate, int nstate)
01438 {
01439         sip_msg_t *fmsg;
01440         int rt;
01441 
01442         if(dlg==NULL)
01443                 return;
01444         if(ostate==nstate)
01445                 return;
01446 
01447         rt = -1;
01448         if(nstate==DLG_STATE_CONFIRMED_NA) {
01449                 rt = dlg_event_rt[DLG_EVENTRT_START];
01450         } else if(nstate==DLG_STATE_DELETED) {
01451                 if(ostate==DLG_STATE_CONFIRMED || ostate==DLG_STATE_CONFIRMED_NA)
01452                         rt = dlg_event_rt[DLG_EVENTRT_END];
01453                 else if(ostate==DLG_STATE_UNCONFIRMED || ostate==DLG_STATE_EARLY)
01454                         rt = dlg_event_rt[DLG_EVENTRT_FAILED];
01455         }
01456 
01457         if(rt==-1 || event_rt.rlist[rt]==NULL)
01458                 return;
01459 
01460         if(msg==NULL)
01461                 fmsg = faked_msg_next();
01462         else
01463                 fmsg = msg;
01464 
01465         if (exec_pre_script_cb(fmsg, REQUEST_CB_TYPE)>0)
01466         {
01467                 dlg_ref(dlg, 1);
01468                 dlg_set_ctx_iuid(dlg);
01469                 LM_DBG("executing event_route %d on state %d\n", rt, nstate);
01470                 set_route_type(REQUEST_ROUTE);
01471                 run_top_route(event_rt.rlist[rt], fmsg, 0);
01472                 dlg_reset_ctx_iuid();
01473                 exec_post_script_cb(fmsg, REQUEST_CB_TYPE);
01474                 dlg_unref(dlg, 1);
01475         }
01476 }
01477 
01478 int dlg_manage(sip_msg_t *msg)
01479 {
01480         str tag;
01481         int backup_mode;
01482         dlg_cell_t *dlg = NULL;
01483         tm_cell_t *t = NULL;
01484 
01485         if( (msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL )
01486         {
01487                 LM_ERR("bad TO header\n");
01488                 return -1;
01489         }
01490         tag = get_to(msg)->tag_value;
01491         if(tag.s!=0 && tag.len!=0)
01492         {
01493                 backup_mode = seq_match_mode;
01494                 seq_match_mode = SEQ_MATCH_NO_ID;
01495                 dlg_onroute(msg, NULL, NULL);
01496                 seq_match_mode = backup_mode;
01497         } else {
01498                 t = d_tmb.t_gett();
01499                 if(t==T_UNDEFINED)
01500                         t = NULL;
01501                 if(dlg_new_dialog(msg, t, initial_cbs_inscript)!=0)
01502                         return -1;
01503                 dlg = dlg_get_ctx_dialog();
01504                 if(dlg==NULL)
01505                         return -1;
01506                 if(t!=NULL)
01507                         dlg_set_tm_callbacks(t, msg, dlg, spiral_detected);
01508                 dlg_release(dlg);
01509         }
01510         return 1;
01511 }