dlg_transfer.c

Go to the documentation of this file.
00001 /**
00002  * $Id$
00003  *
00004  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
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 
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include "../../dprint.h"
00027 #include "../../ut.h"
00028 #include "../../trim.h"
00029 #include "../../mem/mem.h"
00030 #include "../../mem/shm_mem.h"
00031 #include "../../parser/parse_from.h"
00032 #include "../../parser/msg_parser.h"
00033 
00034 #include "../tm/tm_load.h"
00035 
00036 #include "dlg_req_within.h"
00037 #include "dlg_transfer.h"
00038 
00039 #define DLG_HOLD_SDP "v=0\r\no=kamailio-bridge 0 0 IN IP4 0.0.0.0\r\ns=kamailio\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 9 RTP/AVP 8 0\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\n"
00040 #define DLG_HOLD_SDP_LEN   (sizeof(DLG_HOLD_SDP)-1)
00041 
00042 #define DLG_HOLD_CT_HDR "Contact: <sip:kamailio.org:5060>\r\nContent-Type: application/sdp\r\n"
00043 #define DLG_HOLD_CT_HDR_LEN   (sizeof(DLG_HOLD_CT_HDR)-1)
00044 
00045 extern str dlg_bridge_controller;
00046 
00047 void dlg_transfer_ctx_free(dlg_transfer_ctx_t *dtc)
00048 {
00049    struct dlg_cell *dlg;
00050 
00051    if(dtc==NULL)
00052       return;
00053    if(dtc->from.s!=NULL)
00054       shm_free(dtc->from.s);
00055    if(dtc->to.s!=NULL)
00056       shm_free(dtc->to.s);
00057 
00058    dlg = dtc->dlg;
00059    if(dlg!=NULL)
00060    {
00061       if (dlg->tag[DLG_CALLER_LEG].s)
00062          shm_free(dlg->tag[DLG_CALLER_LEG].s);
00063 
00064       if (dlg->tag[DLG_CALLEE_LEG].s)
00065          shm_free(dlg->tag[DLG_CALLEE_LEG].s);
00066 
00067       if (dlg->cseq[DLG_CALLER_LEG].s)
00068          shm_free(dlg->cseq[DLG_CALLER_LEG].s);
00069 
00070       if (dlg->cseq[DLG_CALLEE_LEG].s)
00071          shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
00072 
00073       shm_free(dlg);
00074    }
00075 
00076    shm_free(dtc);
00077 }
00078 
00079 void dlg_refer_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
00080 {
00081    dlg_transfer_ctx_t *dtc = NULL;
00082    dlg_t* dialog_info = NULL;
00083    str met = {"BYE", 3};
00084    int result;
00085    struct dlg_cell *dlg;
00086 
00087    if(ps->param==NULL || *ps->param==0)
00088    {
00089       LM_DBG("message id not received\n");
00090       return;
00091    }
00092    dtc = *((dlg_transfer_ctx_t**)ps->param);
00093    if(dtc==NULL)
00094       return;
00095    LM_DBG("REFER completed with status %d\n", ps->code);
00096 
00097    /* we send the BYE anyhow */
00098    dlg = dtc->dlg;
00099    if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){
00100       LM_ERR("failed to create dlg_t\n");
00101       goto error;
00102    }
00103 
00104    result = d_tmb.t_request_within
00105       (&met,         /* method */
00106       0,             /* extra headers */
00107       NULL,          /* body */
00108       dialog_info,   /* dialog structure */
00109       0,             /* callback function */
00110       0);            /* callback parameter */
00111 
00112    if(result < 0) {
00113       LM_ERR("failed to send the REFER request\n");
00114       /* todo: clean-up dtc */
00115       goto error;
00116    }
00117 
00118    free_tm_dlg(dialog_info);
00119    dlg_transfer_ctx_free(dtc);
00120 
00121    LM_DBG("BYE sent\n");
00122    return;
00123 
00124 error:
00125    dlg_transfer_ctx_free(dtc);
00126    if(dialog_info)
00127       free_tm_dlg(dialog_info);
00128    return;
00129 
00130 }
00131 
00132 static int dlg_refer_callee(dlg_transfer_ctx_t *dtc)
00133 {
00134    /*verify direction*/
00135    dlg_t* dialog_info = NULL;
00136    str met = {"REFER", 5};
00137    int result;
00138    str hdrs;
00139    struct dlg_cell *dlg;
00140 
00141    dlg = dtc->dlg;
00142 
00143    if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){
00144       LM_ERR("failed to create dlg_t\n");
00145       goto error;
00146    }
00147 
00148    hdrs.len = 23 + 2*CRLF_LEN + dlg_bridge_controller.len
00149       + dtc->to.len;
00150    LM_DBG("sending REFER [%d] <%.*s>\n", hdrs.len, dtc->to.len, dtc->to.s);
00151    hdrs.s = (char*)pkg_malloc(hdrs.len*sizeof(char));
00152    if(hdrs.s == NULL)
00153       goto error;
00154    memcpy(hdrs.s, "Referred-By: ", 13);
00155    memcpy(hdrs.s+13, dlg_bridge_controller.s, dlg_bridge_controller.len);
00156    memcpy(hdrs.s+13+dlg_bridge_controller.len, CRLF, CRLF_LEN);
00157    memcpy(hdrs.s+13+dlg_bridge_controller.len+CRLF_LEN, "Refer-To: ", 10);
00158    memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN, dtc->to.s,
00159          dtc->to.len);
00160    memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len,
00161          CRLF, CRLF_LEN);
00162 
00163    result = d_tmb.t_request_within
00164       (&met,         /* method */
00165       &hdrs,         /* extra headers */
00166       NULL,          /* body */
00167       dialog_info,   /* dialog structure */
00168       dlg_refer_tm_callback,  /* callback function */
00169       (void*)dtc);            /* callback parameter */
00170 
00171    pkg_free(hdrs.s);
00172    if(result < 0) {
00173       LM_ERR("failed to send the REFER request\n");
00174       /* todo: clean-up dtc */
00175       goto error;
00176    }
00177 
00178    free_tm_dlg(dialog_info);
00179 
00180    LM_DBG("REFER sent\n");
00181    return 0;
00182 
00183 error:
00184    if(dialog_info)
00185       free_tm_dlg(dialog_info);
00186    return -1;
00187 }
00188 
00189 
00190 void dlg_bridge_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
00191 {
00192    struct sip_msg *msg = NULL;
00193    dlg_transfer_ctx_t *dtc = NULL;
00194    struct dlg_cell *dlg = NULL;
00195    str s;
00196    str cseq;
00197    str empty = {"", 0};
00198 
00199    if(ps->param==NULL || *ps->param==0)
00200    {
00201       LM_DBG("message id not received\n");
00202       return;
00203    }
00204    dtc = *((dlg_transfer_ctx_t**)ps->param);
00205    if(dtc==NULL)
00206       return;
00207    LM_DBG("completed with status %d\n", ps->code);
00208    if(ps->code>=300)
00209       goto error;
00210 
00211    /* 2xx - build dialog/send refer */
00212    msg = ps->rpl;
00213    if((msg->cseq==NULL || parse_headers(msg,HDR_CSEQ_F,0)<0)
00214          || msg->cseq==NULL || msg->cseq->parsed==NULL)
00215    {
00216          LM_ERR("bad sip message or missing CSeq hdr :-/\n");
00217          goto error;
00218    }
00219    cseq = (get_cseq(msg))->number;
00220 
00221    if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
00222    {
00223       LM_ERR("bad request or missing TO hdr\n");
00224       goto error;
00225    }
00226    if(parse_from_header(msg))
00227    {
00228       LM_ERR("bad request or missing FROM hdr\n");
00229       goto error;
00230    }
00231    if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
00232          || msg->callid==NULL){
00233       LM_ERR("bad request or missing CALLID hdr\n");
00234       goto error;
00235    }
00236    s = msg->callid->body;
00237    trim(&s);
00238 
00239    /* some sanity checks */
00240    if (s.len==0 || get_from(msg)->tag_value.len==0) {
00241       LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
00242          s.len, get_from(msg)->tag_value.len);
00243       goto error;
00244    }
00245 
00246    dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
00247       &(get_to(msg)->uri) /*to uri*/,
00248       &(get_from(msg)->tag_value)/*from_tag*/ );
00249    if (dlg==0) {
00250       LM_ERR("failed to create new dialog\n");
00251       goto error;
00252    }
00253    dtc->dlg = dlg;
00254    if (dlg_set_leg_info(dlg, &(get_from(msg)->tag_value),
00255             &empty, &dlg_bridge_controller, &cseq, DLG_CALLER_LEG)!=0) {
00256       LM_ERR("dlg_set_leg_info failed\n");
00257       goto error;
00258    }
00259 
00260    if (populate_leg_info(dlg, msg, t, DLG_CALLEE_LEG,
00261          &(get_to(msg)->tag_value)) !=0)
00262    {
00263       LM_ERR("could not add further info to the dialog\n");
00264       shm_free(dlg);
00265       goto error;
00266    }
00267 
00268    if(dlg_refer_callee(dtc)!=0)
00269       goto error;
00270    return;
00271 
00272 error:
00273    dlg_transfer_ctx_free(dtc);
00274    return;
00275 }
00276 
00277 
00278 int dlg_bridge(str *from, str *to, str *op)
00279 {
00280    dlg_transfer_ctx_t *dtc;
00281    int ret;
00282    str s_method = {"INVITE", 6};
00283    str s_body;
00284    str s_hdrs;
00285 
00286    dtc = (dlg_transfer_ctx_t*)shm_malloc(sizeof(dlg_transfer_ctx_t));
00287    if(dtc==NULL)
00288    {
00289       LM_ERR("no shm\n");
00290       return -1;
00291    }
00292    memset(dtc, 0, sizeof(dlg_transfer_ctx_t));
00293    dtc->from.s = (char*)shm_malloc((from->len+1)*sizeof(char));
00294    if(dtc->from.s==NULL)
00295    {
00296       LM_ERR("no shm\n");
00297       shm_free(dtc);
00298       return -1;
00299    }
00300    dtc->to.s = (char*)shm_malloc((to->len+1)*sizeof(char));
00301    if(dtc->to.s==NULL)
00302    {
00303       LM_ERR("no shm\n");
00304       shm_free(dtc->from.s);
00305       shm_free(dtc);
00306       return -1;
00307    }
00308    memcpy(dtc->from.s, from->s, from->len);
00309    dtc->from.len = from->len;
00310    dtc->from.s[dtc->from.len] = '\0';
00311    memcpy(dtc->to.s, to->s, to->len);
00312    dtc->to.len = to->len;
00313    dtc->to.s[dtc->to.len] = '\0';
00314 
00315    LM_DBG("bridge <%.*s> to <%.*s>\n", dtc->from.len, dtc->from.s,
00316          dtc->to.len, dtc->to.s);
00317    s_body.s   = DLG_HOLD_SDP;
00318    s_body.len = DLG_HOLD_SDP_LEN;
00319    s_hdrs.s   = DLG_HOLD_CT_HDR;
00320    s_hdrs.len = DLG_HOLD_CT_HDR_LEN;
00321 
00322    ret = d_tmb.t_request(&s_method,  /* Type of the message */
00323       &dtc->from,                   /* Request-URI (To) */
00324       &dtc->from,                   /* To */
00325       &dlg_bridge_controller,       /* From */
00326       &s_hdrs, /* Optional headers including CRLF */
00327       &s_body, /* Message body */
00328       (op!=NULL && op->len>0)?op:NULL, /* outbound uri */
00329       dlg_bridge_tm_callback, /* Callback function */
00330       (void*)(long)dtc        /* Callback parameter */
00331       );
00332 
00333    if(ret<0)
00334    {
00335       dlg_transfer_ctx_free(dtc);
00336       return -1;
00337    }
00338    return 0;
00339 }
00340 
00341 int dlg_transfer(struct dlg_cell *dlg, str *to, int side)
00342 {
00343    dlg_transfer_ctx_t *dtc = NULL;
00344    struct dlg_cell *ndlg = NULL;
00345    str from;
00346    str empty = {"", 0};
00347 
00348    dtc = (dlg_transfer_ctx_t*)shm_malloc(sizeof(dlg_transfer_ctx_t));
00349    if(dtc==NULL)
00350    {
00351       LM_ERR("no shm\n");
00352       return -1;
00353    }
00354    if(side==DLG_CALLEE_LEG)
00355    {
00356       from = dlg->from_uri;
00357    } else {
00358       from = dlg->to_uri;
00359    }
00360    memset(dtc, 0, sizeof(dlg_transfer_ctx_t));
00361    dtc->from.s = (char*)shm_malloc((from.len+1)*sizeof(char));
00362    if(dtc->from.s==NULL)
00363    {
00364       LM_ERR("no shm\n");
00365       shm_free(dtc);
00366       return -1;
00367    }
00368    dtc->to.s = (char*)shm_malloc((to->len+1)*sizeof(char));
00369    if(dtc->to.s==NULL)
00370    {
00371       LM_ERR("no shm\n");
00372       shm_free(dtc->from.s);
00373       shm_free(dtc);
00374       return -1;
00375    }
00376    memcpy(dtc->from.s, from.s, from.len);
00377    dtc->from.len = from.len;
00378    dtc->from.s[dtc->from.len] = '\0';
00379    memcpy(dtc->to.s, to->s, to->len);
00380    dtc->to.len = to->len;
00381    dtc->to.s[dtc->to.len] = '\0';
00382    
00383    if(side==DLG_CALLER_LEG)
00384       ndlg = build_new_dlg(&dlg->callid /*callid*/,
00385             &dlg->to_uri /*from uri*/, &dlg->from_uri /*to uri*/,
00386             &dlg->tag[side]/*from_tag*/ );
00387    else
00388       ndlg = build_new_dlg(&dlg->callid /*callid*/,
00389             &dlg->from_uri /*from uri*/, &dlg->to_uri /*to uri*/,
00390             &dlg->tag[side]/*from_tag*/ );
00391    if (ndlg==0) {
00392       LM_ERR("failed to create new dialog\n");
00393       goto error;
00394    }
00395    dtc->dlg = ndlg;
00396    if (dlg_set_leg_info(ndlg, &dlg->tag[side], &empty,
00397          &dlg->contact[side], &dlg->cseq[side], DLG_CALLER_LEG)!=0)
00398    {
00399       LM_ERR("dlg_set_leg_info failed for caller\n");
00400       goto error;
00401    }
00402    if(side==DLG_CALLEE_LEG)
00403       side = DLG_CALLER_LEG;
00404    else
00405       side = DLG_CALLEE_LEG;
00406    if (dlg_set_leg_info(ndlg, &dlg->tag[side], &dlg->route_set[side],
00407          &dlg->contact[side], &dlg->cseq[side], DLG_CALLEE_LEG)!=0)
00408    {
00409       LM_ERR("dlg_set_leg_info failed for caller\n");
00410       goto error;
00411    }
00412 
00413    if(dlg_refer_callee(dtc)!=0)
00414       goto error;
00415    return 0;
00416 
00417 error:
00418    dlg_transfer_ctx_free(dtc);
00419    return -1;
00420 }
00421 

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