dlg_handlers.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlg_handlers.c 6001 2010-04-22 11:35:47Z ibc_sf $
00003  *
00004  * Copyright (C) 2006 Voice System SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * --------
00024  * 2006-04-14  initial version (bogdan)
00025  * 2006-11-28  Added support for tracking the number of early dialogs, and the
00026  *             number of failed dialogs. This involved updates to dlg_onreply()
00027  *             (Jeffrey Magder - SOMA Networks)
00028  * 2007-03-06  syncronized state machine added for dialog state. New tranzition
00029  *             design based on events; removed num_1xx and num_2xx (bogdan)
00030  * 2007-04-30  added dialog matching without DID (dialog ID), but based only
00031  *             on RFC3261 elements - based on an original patch submitted
00032  *             by Michel Bensoussan <michel@extricom.com> (bogdan)
00033  * 2007-05-17  new feature: saving dialog info into a database if
00034  *             realtime update is set(ancuta)
00035  * 2007-07-06  support for saving additional dialog info : cseq, contact,
00036  *             route_set and socket_info for both caller and callee (ancuta)
00037  * 2007-07-10  Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper
00038  *             hash table lookup and isn't dependant on the is_direction
00039  *             function (which requires an RR param like dlg_match_mode 0
00040  *             anyways.. ;) ; based on a patch from
00041  *             Tavis Paquette <tavis@galaxytelecom.net>
00042  *             and Peter Baer <pbaer@galaxytelecom.net>  (bogdan)
00043  * 2008-04-04  added direction reporting in dlg callbacks (bogdan)
00044  */
00045 
00046 
00047 #include <string.h>
00048 #include <time.h>
00049 
00050 #include "../../trim.h"
00051 #include "../../pvar.h"
00052 #include "../../timer.h"
00053 #include "../../statistics.h"
00054 #include "../../action.h"
00055 #include "../../script_cb.h"
00056 #include "../../faked_msg.h"
00057 #include "../../parser/parse_from.h"
00058 #include "../../parser/parse_cseq.h"
00059 #include "../../parser/contact/parse_contact.h"
00060 #include "../../parser/parse_from.h"
00061 #include "../../parser/parse_rr.h"
00062 #include "../tm/tm_load.h"
00063 #include "../rr/api.h"
00064 #include "dlg_hash.h"
00065 #include "dlg_timer.h"
00066 #include "dlg_cb.h"
00067 #include "dlg_handlers.h"
00068 #include "dlg_req_within.h"
00069 #include "dlg_db_handler.h"
00070 #include "dlg_profile.h"
00071 #include "dlg_var.h"
00072 
00073 static str       rr_param;
00074 static int       dlg_flag;
00075 static pv_spec_t *timeout_avp;
00076 static int       default_timeout;
00077 static int       seq_match_mode;
00078 static int       shutdown_done = 0;
00079 
00080 extern struct rr_binds d_rrb;
00081 
00082 /* statistic variables */
00083 extern stat_var *early_dlgs;
00084 extern stat_var *processed_dlgs;
00085 extern stat_var *expired_dlgs;
00086 extern stat_var *failed_dlgs;
00087 
00088 
00089 static unsigned int CURR_DLG_LIFETIME = 0;
00090 static unsigned int CURR_DLG_STATUS = 0;
00091 static unsigned int CURR_DLG_ID  = 0xffffffff;
00092 
00093 #define RR_DLG_PARAM_SIZE  (2*2*sizeof(int)+3+MAX_DLG_RR_PARAM_NAME)
00094 #define DLG_SEPARATOR      '.'
00095 
00096 
00097 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
00098       pv_spec_t *timeout_avp_p ,int default_timeout_p,
00099       int seq_match_mode_p)
00100 {
00101    rr_param.s = rr_param_p;
00102    rr_param.len = strlen(rr_param.s);
00103 
00104    dlg_flag = 1<<dlg_flag_p;
00105 
00106    timeout_avp = timeout_avp_p;
00107    default_timeout = default_timeout_p;
00108    seq_match_mode = seq_match_mode_p;
00109 }
00110 
00111 
00112 void destroy_dlg_handlers(void)
00113 {
00114    shutdown_done = 1;
00115 }
00116 
00117 
00118 static inline int add_dlg_rr_param(struct sip_msg *req, unsigned int entry,
00119                                        unsigned int id)
00120 {
00121    static char buf[RR_DLG_PARAM_SIZE];
00122    str s;
00123    int n;
00124    char *p;
00125 
00126    s.s = p = buf;
00127 
00128    *(p++) = ';';
00129    memcpy(p, rr_param.s, rr_param.len);
00130    p += rr_param.len;
00131    *(p++) = '=';
00132 
00133    n = RR_DLG_PARAM_SIZE - (p-buf);
00134    if (int2reverse_hex( &p, &n, entry)==-1)
00135       return -1;
00136 
00137    *(p++) = DLG_SEPARATOR;
00138 
00139    n = RR_DLG_PARAM_SIZE - (p-buf);
00140    if (int2reverse_hex( &p, &n, id)==-1)
00141       return -1;
00142 
00143    s.len = p-buf;
00144 
00145    if (d_rrb.add_rr_param( req, &s)<0) {
00146       LM_ERR("failed to add rr param\n");
00147       return -1;
00148    }
00149 
00150    return 0;
00151 }
00152 
00153 
00154 /*usage: dlg: the dialog to add cseq, contact & record_route
00155  *        msg: sip message
00156  *        flag: 0-for a request(INVITE),
00157  *             1- for a reply(200 ok)
00158  *
00159  * for a request: get record route in normal order
00160  * for a reply  : get in reverse order, skipping the ones from the request and
00161  *             the proxies' own
00162  */
00163 int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
00164    struct cell* t, unsigned int leg, str *tag)
00165 {
00166    unsigned int skip_recs;
00167    str cseq;
00168    str contact;
00169    str rr_set;
00170 
00171    dlg->bind_addr[leg] = msg->rcv.bind_address;
00172 
00173    /* extract the cseq number as string */
00174    if (leg==DLG_CALLER_LEG) {
00175       if((!msg->cseq && (parse_headers(msg,HDR_CSEQ_F,0)<0 || !msg->cseq))
00176          || !msg->cseq->parsed){
00177          LM_ERR("bad sip message or missing CSeq hdr :-/\n");
00178          goto error0;
00179       }
00180       cseq = (get_cseq(msg))->number;
00181    } else {
00182       /* use the same as in request */
00183       cseq = dlg->cseq[DLG_CALLER_LEG];
00184    }
00185 
00186    /* extract the contact address */
00187    if (!msg->contact&&(parse_headers(msg,HDR_CONTACT_F,0)<0||!msg->contact)){
00188       LM_ERR("bad sip message or missing Contact hdr\n");
00189       goto error0;
00190    }
00191    if ( parse_contact(msg->contact)<0 ||
00192    ((contact_body_t *)msg->contact->parsed)->contacts==NULL ||
00193    ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) {
00194       LM_ERR("bad Contact HDR\n");
00195       goto error0;
00196    }
00197    contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri;
00198 
00199    /* extract the RR parts */
00200    if(!msg->record_route && (parse_headers(msg,HDR_EOH_F,0)<0)  ){
00201       LM_ERR("failed to parse record route header\n");
00202       goto error0;
00203    }
00204 
00205    if (leg==DLG_CALLER_LEG) {
00206       skip_recs = 0;
00207    } else {
00208       /* was the 200 OK received or local generated */
00209       skip_recs = dlg->from_rr_nb +
00210          ((t->relayed_reply_branch>=0)?
00211             (t->uac[t->relayed_reply_branch].added_rr):0);
00212    }
00213 
00214    if(msg->record_route){
00215       if( print_rr_body(msg->record_route, &rr_set, leg,
00216                      &skip_recs) != 0 ){
00217          LM_ERR("failed to print route records \n");
00218          goto error0;
00219       }
00220    } else {
00221       rr_set.s = 0;
00222       rr_set.len = 0;
00223    }
00224 
00225    if(leg==DLG_CALLER_LEG)
00226       dlg->from_rr_nb = skip_recs;
00227 
00228    LM_DBG("route_set %.*s, contact %.*s, cseq %.*s and bind_addr %.*s\n",
00229       rr_set.len, rr_set.s, contact.len, contact.s,
00230       cseq.len, cseq.s,
00231       msg->rcv.bind_address->sock_str.len,
00232       msg->rcv.bind_address->sock_str.s);
00233 
00234    if (dlg_set_leg_info( dlg, tag, &rr_set, &contact, &cseq, leg)!=0) {
00235       LM_ERR("dlg_set_leg_info failed\n");
00236       if (rr_set.s) pkg_free(rr_set.s);
00237       goto error0;
00238    }
00239 
00240    if (rr_set.s) pkg_free(rr_set.s);
00241 
00242    return 0;
00243 error0:
00244    return -1;
00245 }
00246 
00247 
00248 static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
00249 {
00250    struct sip_msg *rpl;
00251    struct dlg_cell *dlg;
00252    int new_state;
00253    int old_state;
00254    int unref;
00255    int event;
00256    str tag;
00257 
00258    dlg = (struct dlg_cell *)(*param->param);
00259    if (shutdown_done || dlg==0)
00260       return;
00261 
00262    rpl = param->rpl;
00263 
00264    if (type==TMCB_RESPONSE_FWDED) {
00265       /* The state does not change, but the msg is mutable in this callback*/
00266       run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
00267       return;
00268    }
00269 
00270    if (type==TMCB_TRANS_DELETED)
00271       event = DLG_EVENT_TDEL;
00272    else if (param->code<200)
00273       event = DLG_EVENT_RPL1xx;
00274    else if (param->code<300)
00275       event = DLG_EVENT_RPL2xx;
00276    else
00277       event = DLG_EVENT_RPL3xx;
00278 
00279    next_state_dlg( dlg, event, &old_state, &new_state, &unref);
00280 
00281    if (new_state==DLG_STATE_EARLY) {
00282       run_dlg_callbacks(DLGCB_EARLY, dlg, rpl, DLG_DIR_UPSTREAM, 0);
00283       if (old_state!=DLG_STATE_EARLY)
00284          if_update_stat(dlg_enable_stats, early_dlgs, 1);
00285       return;
00286    }
00287 
00288    if (new_state==DLG_STATE_CONFIRMED_NA &&
00289    old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) {
00290       LM_DBG("dialog %p confirmed\n",dlg);
00291 
00292       /* get to tag*/
00293       if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0) || !rpl->to) ) {
00294          LM_ERR("bad reply or missing TO hdr :-/\n");
00295          tag.s = 0;
00296          tag.len = 0;
00297       } else {
00298          tag = get_to(rpl)->tag_value;
00299          if (tag.s==0 || tag.len==0) {
00300             LM_ERR("missing TAG param in TO hdr :-/\n");
00301             tag.s = 0;
00302             tag.len = 0;
00303          }
00304       }
00305 
00306       /* save callee's tag, cseq, contact and record route*/
00307       if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) {
00308          LM_ERR("could not add further info to the dialog\n");
00309       }
00310 
00311       /* set start time */
00312       dlg->start_ts = (unsigned int)(time(0));
00313 
00314       /* save the settings to the database,
00315        * if realtime saving mode configured- save dialog now
00316        * else: the next time the timer will fire the update*/
00317       dlg->dflags |= DLG_FLAG_NEW;
00318       if ( dlg_db_mode==DB_MODE_REALTIME )
00319          update_dialog_dbinfo(dlg);
00320 
00321       if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) {
00322          LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] "
00323             "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00324             dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state,
00325             dlg->callid.len, dlg->callid.s,
00326             dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00327             dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00328       } else {
00329          ref_dlg(dlg,1);
00330       }
00331 
00332       /* dialog confirmed */
00333       run_dlg_callbacks( DLGCB_CONFIRMED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
00334 
00335       if (old_state==DLG_STATE_EARLY)
00336          if_update_stat(dlg_enable_stats, early_dlgs, -1);
00337 
00338       if (unref) unref_dlg(dlg,unref);
00339       if_update_stat(dlg_enable_stats, active_dlgs, 1);
00340       return;
00341    }
00342 
00343    if ( old_state!=DLG_STATE_DELETED && new_state==DLG_STATE_DELETED ) {
00344       LM_DBG("dialog %p failed (negative reply)\n", dlg);
00345       /* dialog setup not completed (3456XX) */
00346       run_dlg_callbacks( DLGCB_FAILED, dlg, rpl, DLG_DIR_UPSTREAM, 0);
00347       /* do unref */
00348       if (unref)
00349          unref_dlg(dlg,unref);
00350       if (old_state==DLG_STATE_EARLY)
00351          if_update_stat(dlg_enable_stats, early_dlgs, -1);
00352       return;
00353    }
00354 
00355    if (unref) unref_dlg(dlg,unref);
00356 
00357    return;
00358 }
00359 
00360 
00361 static void dlg_seq_up_onreply(struct cell* t, int type,
00362                                        struct tmcb_params *param)
00363 {
00364    struct dlg_cell *dlg;
00365 
00366    dlg = (struct dlg_cell *)(*param->param);
00367    if (shutdown_done || dlg==0)
00368       return;
00369 
00370    if (type==TMCB_RESPONSE_FWDED) {
00371       run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
00372          DLG_DIR_UPSTREAM, 0);
00373       return;
00374    }
00375 
00376    return;
00377 }
00378 
00379 
00380 
00381 static void dlg_seq_down_onreply(struct cell* t, int type,
00382                                        struct tmcb_params *param)
00383 {
00384    struct dlg_cell *dlg;
00385 
00386    dlg = (struct dlg_cell *)(*param->param);
00387    if (shutdown_done || dlg==0)
00388       return;
00389 
00390    if (type==TMCB_RESPONSE_FWDED) {
00391       run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
00392          DLG_DIR_DOWNSTREAM, 0);
00393       return;
00394    }
00395 
00396    return;
00397 }
00398 
00399 
00400 inline static int get_dlg_timeout(struct sip_msg *req)
00401 {
00402    pv_value_t pv_val;
00403 
00404    if( timeout_avp && pv_get_spec_value( req, timeout_avp, &pv_val)==0
00405    && pv_val.flags&PV_VAL_INT && pv_val.ri>0 ) {
00406       return pv_val.ri;
00407    }
00408    LM_DBG("invalid AVP value, use default timeout");
00409    return default_timeout;
00410 }
00411 
00412 
00413 
00414 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
00415 {
00416    struct sip_msg *msg;
00417    msg = param->req;
00418    if((msg->flags&dlg_flag)!=dlg_flag)
00419       return;
00420    if (current_dlg_pointer!=NULL)
00421       return;
00422    dlg_new_dialog(msg, t);
00423 }
00424 
00425 void unref_new_dialog(void *dialog)
00426 {
00427    struct tmcb_params p;
00428 
00429    p.param = (void*)&dialog;
00430    dlg_onreply(0, TMCB_TRANS_DELETED, &p);
00431 }
00432 
00433 
00434 int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
00435 {
00436    struct dlg_cell *dlg;
00437    str s;
00438 
00439    if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
00440    {
00441       LM_ERR("bad request or missing TO hdr\n");
00442       return -1;
00443    }
00444    s = get_to(msg)->tag_value;
00445    if(s.s!=0 && s.len!=0)
00446       return -1;
00447 
00448    if(msg->first_line.u.request.method_value==METHOD_CANCEL)
00449       return -1;
00450 
00451    if(parse_from_header(msg))
00452    {
00453       LM_ERR("bad request or missing FROM hdr\n");
00454       return -1;
00455    }
00456    if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
00457          || msg->callid==NULL){
00458       LM_ERR("bad request or missing CALLID hdr\n");
00459       return -1;
00460    }
00461    s = msg->callid->body;
00462    trim(&s);
00463 
00464    /* some sanity checks */
00465    if (s.len==0 || get_from(msg)->tag_value.len==0) {
00466       LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
00467          s.len, get_from(msg)->tag_value.len);
00468       return -1;
00469    }
00470 
00471    dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
00472       &(get_to(msg)->uri) /*to uri*/,
00473       &(get_from(msg)->tag_value)/*from_tag*/ );
00474    if (dlg==0) {
00475       LM_ERR("failed to create new dialog\n");
00476       return -1;
00477    }
00478 
00479    /* save caller's tag, cseq, contact and record route*/
00480    if (populate_leg_info(dlg, msg, t, DLG_CALLER_LEG,
00481          &(get_from(msg)->tag_value)) !=0)
00482    {
00483       LM_ERR("could not add further info to the dialog\n");
00484       shm_free(dlg);
00485       return -1;
00486    }
00487 
00488    current_dlg_pointer = dlg;
00489    _dlg_ctx.dlg = dlg;
00490 
00491    link_dlg(dlg, 2/* extra ref for the callback and current dlg hook */);
00492 
00493    /* first INVITE seen (dialog created, unconfirmed) */
00494    if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
00495          add_dlg_rr_param( msg, dlg->h_entry, dlg->h_id)<0 ) {
00496       LM_ERR("failed to add RR param\n");
00497       goto error;
00498    }
00499 
00500    if ( d_tmb.register_tmcb( msg, t,
00501             TMCB_RESPONSE_PRE_OUT|TMCB_RESPONSE_FWDED,
00502             dlg_onreply, (void*)dlg, unref_new_dialog)<0 ) {
00503       LM_ERR("failed to register TMCB\n");
00504       goto error;
00505    }
00506 
00507    dlg->lifetime = get_dlg_timeout(msg);
00508    dlg->toroute = _dlg_ctx.to_route;
00509    dlg->sflags |= _dlg_ctx.flags;
00510 
00511    if (_dlg_ctx.to_bye!=0)
00512       dlg->dflags |= DLG_FLAG_TOBYE;
00513 
00514    if (t)
00515       t->dialog_ctx = (void*) dlg;
00516 
00517    run_create_callbacks( dlg, msg);
00518 
00519    if_update_stat( dlg_enable_stats, processed_dlgs, 1);
00520 
00521    return 0;
00522 error:
00523    unref_dlg(dlg,1);
00524    profile_cleanup(msg, NULL);
00525    update_stat(failed_dlgs, 1);
00526    return -1;
00527 }
00528 
00529 
00530 static inline int parse_dlg_rr_param(char *p, char *end,
00531                                        int *h_entry, int *h_id)
00532 {
00533    char *s;
00534 
00535    for ( s=p ; p<end && *p!=DLG_SEPARATOR ; p++ );
00536    if (*p!=DLG_SEPARATOR) {
00537       LM_ERR("malformed rr param '%.*s'\n", (int)(long)(end-s), s);
00538       return -1;
00539    }
00540 
00541    if ( (*h_entry=reverse_hex2int( s, p-s))<0 ) {
00542       LM_ERR("invalid hash entry '%.*s'\n", (int)(long)(p-s), s);
00543       return -1;
00544    }
00545 
00546    if ( (*h_id=reverse_hex2int( p+1, end-(p+1)))<0 ) {
00547       LM_ERR("invalid hash id '%.*s'\n", (int)(long)(end-(p+1)), p+1 );
00548       return -1;
00549    }
00550 
00551    return 0;
00552 }
00553 
00554 
00555 static inline int pre_match_parse( struct sip_msg *req, str *callid,
00556                                           str *ftag, str *ttag)
00557 {
00558    if (parse_headers(req,HDR_CALLID_F|HDR_TO_F,0)<0 || !req->callid ||
00559    !req->to ) {
00560       LM_ERR("bad request or missing CALLID/TO hdr :-/\n");
00561       return -1;
00562    }
00563 
00564    if (get_to(req)->tag_value.len==0) {
00565       /* out of dialog request with preloaded Route headers; ignore. */
00566       return -1;
00567    }
00568 
00569    if (parse_from_header(req)<0 || get_from(req)->tag_value.len==0) {
00570       LM_ERR("failed to get From header\n");
00571       return -1;
00572    }
00573 
00574    /* callid */
00575    *callid = req->callid->body;
00576    trim(callid);
00577    /* to tag */
00578    *ttag = get_to(req)->tag_value;
00579    /* from tag */
00580    *ftag = get_from(req)->tag_value;
00581    return 0;
00582 }
00583 
00584 
00585 static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
00586                                              unsigned int dir)
00587 {
00588    if ( (!req->cseq && parse_headers(req,HDR_CSEQ_F,0)<0) || !req->cseq ||
00589    !req->cseq->parsed) {
00590       LM_ERR("bad sip message or missing CSeq hdr :-/\n");
00591       return -1;
00592    }
00593 
00594    if ( dir==DLG_DIR_UPSTREAM) {
00595       return dlg_update_cseq(dlg, DLG_CALLEE_LEG,&((get_cseq(req))->number));
00596    } else if ( dir==DLG_DIR_DOWNSTREAM) {
00597       return dlg_update_cseq(dlg, DLG_CALLER_LEG,&((get_cseq(req))->number));
00598    } else {
00599       LM_CRIT("dir is not set!\n");
00600       return -1;
00601    }
00602 }
00603 
00604 
00605 static void
00606 unreference_dialog(void *dialog)
00607 {
00608    // if the dialog table is gone, it means the system is shutting down.
00609    if (!d_table)
00610       return;
00611    unref_dlg((struct dlg_cell*)dialog, 1);
00612 }
00613 
00614 
00615 void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
00616 {
00617    struct dlg_cell *dlg;
00618    str val;
00619    str callid;
00620    str ftag;
00621    str ttag;
00622    int h_entry;
00623    int h_id;
00624    int new_state;
00625    int old_state;
00626    int unref;
00627    int event;
00628    int timeout;
00629    unsigned int dir;
00630    int ret = 0;
00631 
00632    if (current_dlg_pointer!=NULL)
00633       return;
00634 
00635    /* skip initial requests - they may end up here because of the
00636     * preloaded route */
00637    if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) {
00638       LM_ERR("bad request or missing TO hdr :-/\n");
00639       return;
00640    }
00641    if ( get_to(req)->tag_value.len==0 )
00642       return;
00643 
00644    dlg = 0;
00645    dir = DLG_DIR_NONE;
00646 
00647    if ( seq_match_mode!=SEQ_MATCH_NO_ID ) {
00648       if( d_rrb.get_route_param( req, &rr_param, &val)!=0) {
00649          LM_DBG("Route param '%.*s' not found\n", rr_param.len,rr_param.s);
00650          if (seq_match_mode==SEQ_MATCH_STRICT_ID )
00651             return;
00652       } else {
00653          LM_DBG("route param is '%.*s' (len=%d)\n",val.len,val.s,val.len);
00654 
00655          if ( parse_dlg_rr_param( val.s, val.s+val.len, &h_entry, &h_id)<0 )
00656             return;
00657 
00658          dlg = lookup_dlg( h_entry, h_id);
00659          if (dlg==0) {
00660             LM_WARN("unable to find dialog for %.*s "
00661                "with route param '%.*s' [%u:%u]\n",
00662                req->first_line.u.request.method.len,
00663                req->first_line.u.request.method.s,
00664                val.len,val.s, h_entry, h_id);
00665             if (seq_match_mode==SEQ_MATCH_STRICT_ID )
00666                return;
00667          } else {
00668             // lookup_dlg has incremented the ref count by 1
00669             if (pre_match_parse( req, &callid, &ftag, &ttag)<0) {
00670                unref_dlg(dlg, 1);
00671                return;
00672             }
00673             if (match_dialog( dlg, &callid, &ftag, &ttag, &dir )==0) {
00674                LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, "
00675                      "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n",
00676                      req->first_line.u.request.method.len,
00677                      req->first_line.u.request.method.s,
00678                      callid.len, callid.s, callid.len,
00679                      ftag.len, ftag.s, ftag.len,
00680                      ttag.len, ttag.s, ttag.len, dir);
00681                LM_WARN("dialog identification elements are callid='%.*s'/%d, "
00682                      "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n",
00683                      dlg->callid.len, dlg->callid.s, dlg->callid.len,
00684                      dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00685                      dlg->tag[DLG_CALLER_LEG].len,
00686                      dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s,
00687                      dlg->tag[DLG_CALLEE_LEG].len);
00688                unref_dlg(dlg, 1);
00689 
00690                // Reset variables in order to do a lookup based on SIP-Elements.
00691                dlg = 0;
00692                dir = DLG_DIR_NONE;
00693 
00694                if (seq_match_mode==SEQ_MATCH_STRICT_ID )
00695                   return;
00696             }
00697          }
00698       }
00699    }
00700 
00701    if (dlg==0) {
00702       if (pre_match_parse( req, &callid, &ftag, &ttag)<0)
00703          return;
00704       /* TODO - try to use the RR dir detection to speed up here the
00705        * search -bogdan */
00706       dlg = get_dlg(&callid, &ftag, &ttag, &dir);
00707       if (!dlg){
00708          LM_DBG("Callid '%.*s' not found\n",
00709             req->callid->body.len, req->callid->body.s);
00710          return;
00711       }
00712    }
00713 
00714    /* run state machine */
00715    switch ( req->first_line.u.request.method_value ) {
00716       case METHOD_PRACK:
00717          event = DLG_EVENT_REQPRACK; break;
00718       case METHOD_ACK:
00719          event = DLG_EVENT_REQACK; break;
00720       case METHOD_BYE:
00721          event = DLG_EVENT_REQBYE; break;
00722       default:
00723          event = DLG_EVENT_REQ;
00724    }
00725 
00726    next_state_dlg( dlg, event, &old_state, &new_state, &unref);
00727 
00728    CURR_DLG_ID = req->id;
00729    CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
00730    CURR_DLG_STATUS = new_state;
00731 
00732    /* set current dialog - it will keep a ref! */
00733    set_current_dialog( req, dlg);
00734    _dlg_ctx.dlg = dlg;
00735 
00736    /* run actions for the transition */
00737    if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED &&
00738    old_state!=DLG_STATE_DELETED) {
00739       LM_DBG("BYE successfully processed\n");
00740       /* remove from timer */
00741       ret = remove_dialog_timer(&dlg->tl);
00742       if (ret < 0) {
00743          LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
00744             "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00745             dlg, dlg->h_entry, dlg->h_id,
00746             dlg->callid.len, dlg->callid.s,
00747             dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00748             dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00749       } else if (ret > 0) {
00750          LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
00751             "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00752             dlg, dlg->h_entry, dlg->h_id,
00753             dlg->callid.len, dlg->callid.s,
00754             dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00755             dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00756       } else {
00757          unref++;
00758       }
00759       /* dialog terminated (BYE) */
00760       run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, dir, 0);
00761 
00762       /* delete the dialog from DB */
00763       if (dlg_db_mode)
00764          remove_dialog_from_db(dlg);
00765 
00766       /* destroy dialog */
00767       unref_dlg(dlg, unref);
00768 
00769       if_update_stat( dlg_enable_stats, active_dlgs, -1);
00770       return;
00771    }
00772 
00773    if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK)
00774    && new_state==DLG_STATE_CONFIRMED) {
00775       LM_DBG("sequential request successfully processed\n");
00776       timeout = get_dlg_timeout(req);
00777       /* update timer during sequential request? */
00778       if (timeout!=default_timeout) {
00779          dlg->lifetime = timeout;
00780          if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1)
00781             LM_ERR("failed to update dialog lifetime\n");
00782       }
00783       if (update_cseqs(dlg, req, dir)!=0) {
00784          LM_ERR("cseqs update failed\n");
00785       } else {
00786          dlg->dflags |= DLG_FLAG_CHANGED;
00787          if ( dlg_db_mode==DB_MODE_REALTIME )
00788             update_dialog_dbinfo(dlg);
00789       }
00790 
00791       /* within dialog request */
00792       run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0);
00793 
00794       if ( (event!=DLG_EVENT_REQACK) &&
00795       (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) {
00796          /* ref the dialog as registered into the transaction callback.
00797           * unref will be done when the callback will be destroyed */
00798          ref_dlg( dlg , 1);
00799          /* register callback for the replies of this request */
00800          if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
00801          (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply:dlg_seq_up_onreply,
00802          (void*)dlg, unreference_dialog)<0 ) {
00803             LM_ERR("failed to register TMCB (2)\n");
00804                unref_dlg( dlg , 1);
00805          }
00806       }
00807    }
00808 
00809    if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){
00810       dlg->dflags |= DLG_FLAG_CHANGED;
00811       if(dlg_db_mode == DB_MODE_REALTIME)
00812          update_dialog_dbinfo(dlg);
00813    }
00814 
00815    return;
00816 }
00817 
00818 
00819 
00820 #define get_dlg_tl_payload(_tl_)  ((struct dlg_cell*)((char *)(_tl_)- \
00821       (unsigned long)(&((struct dlg_cell*)0)->tl)))
00822 
00823 void dlg_ontimeout( struct dlg_tl *tl)
00824 {
00825    struct dlg_cell *dlg;
00826    int new_state;
00827    int old_state;
00828    int unref;
00829    struct sip_msg *fmsg;
00830 
00831    dlg = get_dlg_tl_payload(tl);
00832 
00833    if(dlg->toroute>0 && dlg->toroute<RT_NO)
00834    {
00835       dlg_set_ctx_dialog(dlg);
00836       fmsg = faked_msg_next();
00837       if (exec_pre_req_cb(fmsg)>0)
00838       {
00839          LM_DBG("executing route %d on timeout\n", dlg->toroute);
00840          set_route_type(REQUEST_ROUTE);
00841          run_top_route(rlist[dlg->toroute], fmsg);
00842          exec_post_req_cb(fmsg);
00843       }
00844    }
00845 
00846    if ((dlg->dflags&DLG_FLAG_TOBYE)
00847          && (dlg->state==DLG_STATE_CONFIRMED_NA
00848             || dlg->state==DLG_STATE_CONFIRMED))
00849    {
00850       dlg_bye_all(dlg, NULL);
00851       unref_dlg(dlg, 1);
00852       if_update_stat(dlg_enable_stats, expired_dlgs, 1);
00853       return;
00854    }
00855 
00856    next_state_dlg( dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref);
00857 
00858    if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
00859       LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
00860          dlg->callid.len, dlg->callid.s,
00861          dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00862          dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00863 
00864       /* dialog timeout */
00865       run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0);
00866 
00867       /* delete the dialog from DB */
00868       if (dlg_db_mode)
00869          remove_dialog_from_db(dlg);
00870 
00871       unref_dlg(dlg, unref+1);
00872 
00873       if_update_stat( dlg_enable_stats, expired_dlgs, 1);
00874       if_update_stat( dlg_enable_stats, active_dlgs, -1);
00875    } else {
00876       unref_dlg(dlg, 1);
00877    }
00878 
00879    return;
00880 }
00881 
00882 
00883 /* item/pseudo-variables functions */
00884 int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param,
00885       pv_value_t *res)
00886 {
00887    int l = 0;
00888    char *ch = NULL;
00889 
00890    if(msg==NULL || res==NULL)
00891       return -1;
00892 
00893    if (CURR_DLG_ID!=msg->id)
00894       return pv_get_null( msg, param, res);
00895 
00896    res->ri = CURR_DLG_LIFETIME;
00897    ch = int2str( (unsigned long)res->ri, &l);
00898 
00899    res->rs.s = ch;
00900    res->rs.len = l;
00901 
00902    res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
00903 
00904    return 0;
00905 }
00906 
00907 
00908 int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param,
00909       pv_value_t *res)
00910 {
00911    int l = 0;
00912    char *ch = NULL;
00913 
00914    if(msg==NULL || res==NULL)
00915       return -1;
00916 
00917    if (CURR_DLG_ID!=msg->id)
00918       return pv_get_null( msg, param, res);
00919 
00920    res->ri = CURR_DLG_STATUS;
00921    ch = int2str( (unsigned long)res->ri, &l);
00922 
00923    res->rs.s = ch;
00924    res->rs.len = l;
00925 
00926    res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
00927 
00928    return 0;
00929 }
00930 

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6