dlg_req_within.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlg_req_within.c 5529 2009-01-28 21:51:20Z miconda $
00003  *
00004  * Copyright (C) 2007 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  * 2007-07-10  initial version (ancuta)
00025  * 2008-04-04  added direction reporting in dlg callbacks (bogdan)
00026 */
00027 
00028 #include <stdlib.h>
00029 #include <string.h>
00030 
00031 #include "../../dprint.h"
00032 #include "../../ut.h"
00033 #include "../../db/db.h"
00034 #include "../../dprint.h"
00035 #include "../../config.h"
00036 #include "../../socket_info.h"
00037 #include "../tm/dlg.h"
00038 #include "../tm/tm_load.h"
00039 #include "../../mi/tree.h"
00040 #include "dlg_timer.h"
00041 #include "dlg_hash.h"
00042 #include "dlg_req_within.h"
00043 #include "dlg_db_handler.h"
00044 
00045 
00046 #define MAX_FWD_HDR        "Max-Forwards: " MAX_FWD CRLF
00047 #define MAX_FWD_HDR_LEN    (sizeof(MAX_FWD_HDR) - 1)
00048 
00049 extern str dlg_extra_hdrs;
00050 
00051 
00052 
00053 int free_tm_dlg(dlg_t *td)
00054 {
00055    if(td)
00056    {
00057       if(td->route_set)
00058          free_rr(&td->route_set);
00059       pkg_free(td);
00060    }
00061    return 0;
00062 }
00063 
00064 
00065 
00066 dlg_t * build_dlg_t(struct dlg_cell * cell, int dir){
00067 
00068    dlg_t* td = NULL;
00069    str cseq;
00070    unsigned int loc_seq;
00071 
00072    td = (dlg_t*)pkg_malloc(sizeof(dlg_t));
00073    if(!td){
00074    
00075       LM_ERR("out of pkg memory\n");
00076       return NULL;
00077    }
00078    memset(td, 0, sizeof(dlg_t));
00079 
00080    /*local sequence number*/
00081    cseq = (dir == DLG_CALLER_LEG) ? cell->cseq[DLG_CALLEE_LEG]:
00082                               cell->cseq[DLG_CALLER_LEG];
00083    if(str2int(&cseq, &loc_seq) != 0){
00084       LM_ERR("invalid cseq\n");
00085       goto error;
00086    }
00087    /*we don not increase here the cseq as this will be done by TM*/
00088    td->loc_seq.value = loc_seq;
00089    td->loc_seq.is_set = 1;
00090 
00091    /*route set*/
00092    if( cell->route_set[dir].s && cell->route_set[dir].len){
00093       
00094       if( parse_rr_body(cell->route_set[dir].s, cell->route_set[dir].len, 
00095                   &td->route_set) !=0){
00096          LM_ERR("failed to parse route set\n");
00097          goto error;
00098       }
00099    } 
00100 
00101    /*remote target--- Request URI*/
00102    if(cell->contact[dir].s==0 || cell->contact[dir].len==0){
00103 
00104       LM_ERR("no contact available\n");
00105       goto error;
00106    }
00107    td->rem_target = cell->contact[dir];
00108 
00109    td->rem_uri =   (dir == DLG_CALLER_LEG)?  cell->from_uri: cell->to_uri;
00110    td->loc_uri =  (dir == DLG_CALLER_LEG)?   cell->to_uri: cell->from_uri;
00111    td->id.call_id = cell->callid;
00112    td->id.rem_tag = cell->tag[dir];
00113    td->id.loc_tag = (dir == DLG_CALLER_LEG) ?   cell->tag[DLG_CALLEE_LEG]:
00114                                     cell->tag[DLG_CALLER_LEG];
00115    
00116    td->state= DLG_CONFIRMED;
00117    td->send_sock = cell->bind_addr[dir];
00118 
00119    return td;
00120 
00121 error:
00122    free_tm_dlg(td);
00123    return NULL;
00124 }
00125 
00126 
00127 
00128 /*callback function to handle responses to the BYE request */
00129 void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps){
00130 
00131    struct dlg_cell* dlg;
00132    int event, old_state, new_state, unref, ret;
00133 
00134    if(ps->param == NULL || *ps->param == NULL){
00135       LM_ERR("invalid parameter\n");
00136       return;
00137    }
00138 
00139    if(ps->code < 200){
00140       LM_DBG("receiving a provisional reply\n");
00141       return;
00142    }
00143 
00144    LM_DBG("receiving a final reply %d\n",ps->code);
00145 
00146    dlg = (struct dlg_cell *)(*(ps->param));
00147    event = DLG_EVENT_REQBYE;
00148    next_state_dlg(dlg, event, &old_state, &new_state, &unref);
00149 
00150 
00151    if(new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED){
00152 
00153       LM_DBG("removing dialog with h_entry %u and h_id %u\n", 
00154          dlg->h_entry, dlg->h_id);
00155 
00156       /* remove from timer */
00157       ret = remove_dialog_timer(&dlg->tl);
00158       if (ret < 0) {
00159          LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
00160             "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00161             dlg, dlg->h_entry, dlg->h_id,
00162             dlg->callid.len, dlg->callid.s,
00163             dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00164             dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00165       } else if (ret > 0) {
00166          LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
00167             "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00168             dlg, dlg->h_entry, dlg->h_id,
00169             dlg->callid.len, dlg->callid.s,
00170             dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00171             dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00172       } else {
00173          unref++;
00174       }
00175       /* dialog terminated (BYE) */
00176       run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, DLG_DIR_NONE, 0);
00177 
00178       LM_DBG("first final reply\n");
00179       /* derefering the dialog */
00180       unref_dlg(dlg, unref+1);
00181 
00182       if_update_stat( dlg_enable_stats, active_dlgs, -1);
00183    }
00184 
00185    if(new_state == DLG_STATE_DELETED && old_state == DLG_STATE_DELETED ) {
00186       /* trash the dialog from DB and memory */
00187       LM_DBG("second final reply\n");
00188       /* delete the dialog from DB */
00189       if (dlg_db_mode)
00190          remove_dialog_from_db(dlg);
00191       /* force delete from mem */
00192       unref_dlg(dlg, 1);
00193    }
00194 
00195 }
00196 
00197 
00198 
00199 static inline int build_extra_hdr(struct dlg_cell * cell, str *extra_hdrs,
00200       str *str_hdr)
00201 {
00202    char *p;
00203 
00204    str_hdr->len = MAX_FWD_HDR_LEN + dlg_extra_hdrs.len;
00205    if(extra_hdrs && extra_hdrs->len>0)
00206       str_hdr->len += extra_hdrs->len;
00207 
00208    str_hdr->s = (char*)pkg_malloc( str_hdr->len * sizeof(char) );
00209    if(!str_hdr->s){
00210       LM_ERR("out of pkg memory\n");
00211       goto error;
00212    }
00213 
00214    memcpy(str_hdr->s , MAX_FWD_HDR, MAX_FWD_HDR_LEN );
00215    p = str_hdr->s + MAX_FWD_HDR_LEN;
00216    if (dlg_extra_hdrs.len) {
00217       memcpy( p, dlg_extra_hdrs.s, dlg_extra_hdrs.len);
00218       p += dlg_extra_hdrs.len;
00219    }
00220    if (extra_hdrs && extra_hdrs->len>0)
00221       memcpy( p, extra_hdrs->s, extra_hdrs->len);
00222 
00223    return 0;
00224 
00225 error: 
00226    return -1;
00227 }
00228 
00229 
00230 
00231 /* cell- pointer to a struct dlg_cell
00232  * dir- direction: the request will be sent to:
00233  *       DLG_CALLER_LEG (0): caller
00234  *       DLG_CALLEE_LEG (1): callee
00235  */
00236 static inline int send_bye(struct dlg_cell * cell, int dir, str *hdrs)
00237 {
00238    /*verify direction*/
00239    dlg_t* dialog_info;
00240    str met = {"BYE", 3};
00241    int result;
00242 
00243    if ((dialog_info = build_dlg_t(cell, dir)) == 0){
00244       LM_ERR("failed to create dlg_t\n");
00245       goto err;
00246    }
00247 
00248    LM_DBG("sending BYE to %s\n", (dir==DLG_CALLER_LEG)?"caller":"callee");
00249 
00250    ref_dlg(cell, 1);
00251 
00252    result = d_tmb.t_request_within
00253       (&met,         /* method*/
00254       hdrs,         /* extra headers*/
00255       NULL,          /* body*/
00256       dialog_info,   /* dialog structure*/
00257       bye_reply_cb,  /* callback function*/
00258       (void*)cell);  /* callback parameter*/
00259 
00260    if(result < 0){
00261       LM_ERR("failed to send the BYE request\n");
00262       goto err1;
00263    }
00264 
00265    free_tm_dlg(dialog_info);
00266 
00267    LM_DBG("BYE sent to %s\n", (dir==0)?"caller":"callee");
00268    return 0;
00269 
00270 err1:
00271    unref_dlg(cell, 1);
00272 err:
00273    if(dialog_info)
00274       free_tm_dlg(dialog_info);
00275    return -1;
00276 }
00277 
00278 
00279 
00280 /*parameters from MI: h_entry, h_id of the requested dialog*/
00281 struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param ){
00282 
00283    struct mi_node* node;
00284    unsigned int h_entry, h_id;
00285    struct dlg_cell * dlg = NULL;
00286    str mi_extra_hdrs = {NULL,0};
00287    int status, msg_len;
00288    char *msg;
00289 
00290 
00291    if( d_table ==NULL)
00292       goto end;
00293 
00294    node = cmd_tree->node.kids;
00295    h_entry = h_id = 0;
00296 
00297    if (node==NULL || node->next==NULL)
00298       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00299 
00300    if (!node->value.s|| !node->value.len|| strno2int(&node->value,&h_entry)<0)
00301       goto error;
00302 
00303    node = node->next;
00304    if ( !node->value.s || !node->value.len || strno2int(&node->value,&h_id)<0)
00305       goto error;
00306 
00307    if (node->next) {
00308       node = node->next;
00309       if (node->value.len && node->value.s)
00310          mi_extra_hdrs = node->value;
00311    }
00312 
00313    LM_DBG("h_entry %u h_id %u\n", h_entry, h_id);
00314 
00315    dlg = lookup_dlg(h_entry, h_id);
00316 
00317    // lookup_dlg has incremented the reference count
00318 
00319    if(dlg){
00320       if(dlg_bye_all(dlg,(mi_extra_hdrs.len>0)?&mi_extra_hdrs:NULL)<0) {
00321          status = 500;
00322          msg = MI_DLG_OPERATION_ERR;
00323          msg_len = MI_DLG_OPERATION_ERR_LEN;
00324       } else {
00325          status = 200;
00326          msg = MI_OK_S;
00327          msg_len = MI_OK_LEN;
00328       }
00329 
00330       unref_dlg(dlg, 1);
00331 
00332       return init_mi_tree(status, msg, msg_len);
00333    }
00334 
00335 end:
00336    return init_mi_tree(404, MI_DIALOG_NOT_FOUND, MI_DIALOG_NOT_FOUND_LEN);
00337    
00338 error:
00339    return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00340 
00341 }
00342 
00343 int dlg_bye(struct dlg_cell *dlg, str *hdrs, int side)
00344 {
00345    str all_hdrs = { 0, 0 };
00346    int ret;
00347 
00348    if(side==DLG_CALLER_LEG)
00349    {
00350       if(dlg->dflags&DLG_FLAG_CALLERBYE)
00351          return -1;
00352       dlg->dflags |= DLG_FLAG_CALLERBYE;
00353    } else {
00354       if(dlg->dflags&DLG_FLAG_CALLEEBYE)
00355          return -1;
00356       dlg->dflags |= DLG_FLAG_CALLEEBYE;
00357    }
00358    if ((build_extra_hdr(dlg, hdrs, &all_hdrs)) != 0)
00359    {
00360       LM_ERR("failed to build dlg headers\n");
00361       return -1;
00362    }
00363    ret = send_bye(dlg, side, &all_hdrs);
00364    pkg_free(all_hdrs.s);
00365    return ret;
00366 }
00367 
00368 int dlg_bye_all(struct dlg_cell *dlg, str *hdrs)
00369 {
00370    str all_hdrs = { 0, 0 };
00371    int ret;
00372 
00373    if ((build_extra_hdr(dlg, hdrs, &all_hdrs)) != 0)
00374    {
00375       LM_ERR("failed to build dlg headers\n");
00376       return -1;
00377    }
00378 
00379    ret = send_bye(dlg, DLG_CALLER_LEG, &all_hdrs);
00380    ret |= send_bye(dlg, DLG_CALLEE_LEG, &all_hdrs);
00381    
00382    pkg_free(all_hdrs.s);
00383    return ret;
00384 
00385 }
00386 

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