123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- /**
- * $Id$
- *
- * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
- *
- * This file is part of kamailio, a free SIP server.
- *
- * kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "../../dprint.h"
- #include "../../ut.h"
- #include "../../trim.h"
- #include "../../mem/mem.h"
- #include "../../mem/shm_mem.h"
- #include "../../parser/parse_from.h"
- #include "../../parser/msg_parser.h"
- #include "../../modules/tm/tm_load.h"
- #include "dlg_req_within.h"
- #include "dlg_handlers.h"
- #include "dlg_transfer.h"
- #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"
- #define DLG_HOLD_SDP_LEN (sizeof(DLG_HOLD_SDP)-1)
- /*
- #define DLG_HOLD_CT_HDR "Contact: <sip:kamailio.org:5060>\r\nContent-Type: application/sdp\r\n"
- #define DLG_HOLD_CT_HDR_LEN (sizeof(DLG_HOLD_CT_HDR)-1)
- */
- extern str dlg_bridge_controller;
- extern str dlg_bridge_contact;
- static char *dlg_bridge_hdrs_buf = NULL;
- static str dlg_bridge_inv_hdrs = {0};
- static str dlg_bridge_ref_hdrs = {0};
- int dlg_bridge_init_hdrs(void)
- {
- if(dlg_bridge_hdrs_buf!=NULL)
- return 0;
- dlg_bridge_hdrs_buf = (char*)pkg_malloc((dlg_bridge_contact.len + 46)
- * sizeof(char));
- if(dlg_bridge_hdrs_buf==NULL) {
- LM_ERR("no more pkg memory\n");
- return -1;
- }
- strncpy(dlg_bridge_hdrs_buf,
- "Contact: <", 10);
- strncpy(dlg_bridge_hdrs_buf + 10,
- dlg_bridge_contact.s, dlg_bridge_contact.len);
- strncpy(dlg_bridge_hdrs_buf + 10 + dlg_bridge_contact.len,
- ">\r\nContent-Type: application/sdp\r\n", 34);
- dlg_bridge_hdrs_buf[dlg_bridge_contact.len+44] = '\0';
- dlg_bridge_inv_hdrs.s = dlg_bridge_hdrs_buf;
- dlg_bridge_inv_hdrs.len = dlg_bridge_contact.len + 44;
- dlg_bridge_ref_hdrs.s = dlg_bridge_hdrs_buf;
- dlg_bridge_ref_hdrs.len = dlg_bridge_contact.len + 13;
- return 0;
- }
- void dlg_bridge_destroy_hdrs(void)
- {
- if(dlg_bridge_hdrs_buf!=NULL)
- pkg_free(dlg_bridge_hdrs_buf);
- }
- void dlg_transfer_ctx_free(dlg_transfer_ctx_t *dtc)
- {
- struct dlg_cell *dlg;
- if(dtc==NULL)
- return;
- if(dtc->from.s!=NULL)
- shm_free(dtc->from.s);
- if(dtc->to.s!=NULL)
- shm_free(dtc->to.s);
- dlg = dtc->dlg;
- if(dlg!=NULL)
- {
- if (dlg->tag[DLG_CALLER_LEG].s)
- shm_free(dlg->tag[DLG_CALLER_LEG].s);
- if (dlg->tag[DLG_CALLEE_LEG].s)
- shm_free(dlg->tag[DLG_CALLEE_LEG].s);
- if (dlg->cseq[DLG_CALLER_LEG].s)
- shm_free(dlg->cseq[DLG_CALLER_LEG].s);
- if (dlg->cseq[DLG_CALLEE_LEG].s)
- shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
- shm_free(dlg);
- }
- shm_free(dtc);
- }
- void dlg_refer_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
- {
- dlg_transfer_ctx_t *dtc = NULL;
- dlg_t* dialog_info = NULL;
- str met = {"BYE", 3};
- int result;
- struct dlg_cell *dlg;
- uac_req_t uac_r;
- if(ps->param==NULL || *ps->param==0)
- {
- LM_DBG("message id not received\n");
- return;
- }
- dtc = *((dlg_transfer_ctx_t**)ps->param);
- if(dtc==NULL)
- return;
- LM_DBG("REFER completed with status %d\n", ps->code);
- /* we send the BYE anyhow */
- dlg = dtc->dlg;
- if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){
- LM_ERR("failed to create dlg_t\n");
- goto error;
- }
- memset(&uac_r, '\0', sizeof(uac_req_t));
- set_uac_req(&uac_r, &met, NULL, NULL, dialog_info, 0, NULL, NULL);
- result = d_tmb.t_request_within(&uac_r);
- if(result < 0) {
- LM_ERR("failed to send the REFER request\n");
- /* todo: clean-up dtc */
- goto error;
- }
- free_tm_dlg(dialog_info);
- dlg_transfer_ctx_free(dtc);
- LM_DBG("BYE sent\n");
- return;
- error:
- dlg_transfer_ctx_free(dtc);
- if(dialog_info)
- free_tm_dlg(dialog_info);
- return;
- }
- static int dlg_refer_callee(dlg_transfer_ctx_t *dtc)
- {
- /*verify direction*/
- dlg_t* dialog_info = NULL;
- str met = {"REFER", 5};
- int result;
- str hdrs;
- struct dlg_cell *dlg;
- uac_req_t uac_r;
- dlg = dtc->dlg;
- if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){
- LM_ERR("failed to create dlg_t\n");
- goto error;
- }
- hdrs.len = 23 + 2*CRLF_LEN + dlg_bridge_controller.len
- + dtc->to.len + dlg_bridge_ref_hdrs.len;
- LM_DBG("sending REFER [%d] <%.*s>\n", hdrs.len, dtc->to.len, dtc->to.s);
- hdrs.s = (char*)pkg_malloc(hdrs.len*sizeof(char));
- if(hdrs.s == NULL)
- goto error;
- memcpy(hdrs.s, "Referred-By: ", 13);
- memcpy(hdrs.s+13, dlg_bridge_controller.s, dlg_bridge_controller.len);
- memcpy(hdrs.s+13+dlg_bridge_controller.len, CRLF, CRLF_LEN);
- memcpy(hdrs.s+13+dlg_bridge_controller.len+CRLF_LEN, "Refer-To: ", 10);
- memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN, dtc->to.s,
- dtc->to.len);
- memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len,
- CRLF, CRLF_LEN);
- memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len+CRLF_LEN,
- dlg_bridge_controller.s, dlg_bridge_controller.len);
- memset(&uac_r, '\0', sizeof(uac_req_t));
- set_uac_req(&uac_r, &met, &hdrs, NULL, dialog_info, TMCB_LOCAL_COMPLETED,
- dlg_refer_tm_callback, (void*)dtc);
- result = d_tmb.t_request_within(&uac_r);
- pkg_free(hdrs.s);
- if(result < 0) {
- LM_ERR("failed to send the REFER request\n");
- /* todo: clean-up dtc */
- goto error;
- }
- free_tm_dlg(dialog_info);
- LM_DBG("REFER sent\n");
- return 0;
- error:
- if(dialog_info)
- free_tm_dlg(dialog_info);
- return -1;
- }
- void dlg_bridge_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
- {
- struct sip_msg *msg = NULL;
- dlg_transfer_ctx_t *dtc = NULL;
- struct dlg_cell *dlg = NULL;
- str s;
- str cseq;
- str empty = {"", 0};
- if(ps->param==NULL || *ps->param==0)
- {
- LM_DBG("message id not received\n");
- return;
- }
- dtc = *((dlg_transfer_ctx_t**)ps->param);
- if(dtc==NULL)
- return;
- LM_DBG("completed with status %d\n", ps->code);
- if(ps->code>=300)
- goto error;
- /* 2xx - build dialog/send refer */
- msg = ps->rpl;
- if((msg->cseq==NULL || parse_headers(msg,HDR_CSEQ_F,0)<0)
- || msg->cseq==NULL || msg->cseq->parsed==NULL)
- {
- LM_ERR("bad sip message or missing CSeq hdr :-/\n");
- goto error;
- }
- cseq = (get_cseq(msg))->number;
- if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
- {
- LM_ERR("bad request or missing TO hdr\n");
- goto error;
- }
- if(parse_from_header(msg))
- {
- LM_ERR("bad request or missing FROM hdr\n");
- goto error;
- }
- if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
- || msg->callid==NULL){
- LM_ERR("bad request or missing CALLID hdr\n");
- goto error;
- }
- s = msg->callid->body;
- trim(&s);
- /* some sanity checks */
- if (s.len==0 || get_from(msg)->tag_value.len==0) {
- LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
- s.len, get_from(msg)->tag_value.len);
- goto error;
- }
- dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
- &(get_to(msg)->uri) /*to uri*/,
- &(get_from(msg)->tag_value)/*from_tag*/,
- &(get_to(msg)->uri) /*use to as r-uri*/ );
- if (dlg==0) {
- LM_ERR("failed to create new dialog\n");
- goto error;
- }
- dtc->dlg = dlg;
- if (dlg_set_leg_info(dlg, &(get_from(msg)->tag_value),
- &empty, &dlg_bridge_controller, &cseq, DLG_CALLER_LEG)!=0) {
- LM_ERR("dlg_set_leg_info failed\n");
- goto error;
- }
- if (populate_leg_info(dlg, msg, t, DLG_CALLEE_LEG,
- &(get_to(msg)->tag_value)) !=0)
- {
- LM_ERR("could not add further info to the dialog\n");
- shm_free(dlg);
- goto error;
- }
- if(dlg_refer_callee(dtc)!=0)
- goto error;
- return;
- error:
- dlg_transfer_ctx_free(dtc);
- return;
- }
- int dlg_bridge(str *from, str *to, str *op)
- {
- dlg_transfer_ctx_t *dtc;
- int ret;
- str s_method = {"INVITE", 6};
- str s_body;
- uac_req_t uac_r;
- dtc = (dlg_transfer_ctx_t*)shm_malloc(sizeof(dlg_transfer_ctx_t));
- if(dtc==NULL)
- {
- LM_ERR("no shm\n");
- return -1;
- }
- memset(dtc, 0, sizeof(dlg_transfer_ctx_t));
- dtc->from.s = (char*)shm_malloc((from->len+1)*sizeof(char));
- if(dtc->from.s==NULL)
- {
- LM_ERR("no shm\n");
- shm_free(dtc);
- return -1;
- }
- dtc->to.s = (char*)shm_malloc((to->len+1)*sizeof(char));
- if(dtc->to.s==NULL)
- {
- LM_ERR("no shm\n");
- shm_free(dtc->from.s);
- shm_free(dtc);
- return -1;
- }
- memcpy(dtc->from.s, from->s, from->len);
- dtc->from.len = from->len;
- dtc->from.s[dtc->from.len] = '\0';
- memcpy(dtc->to.s, to->s, to->len);
- dtc->to.len = to->len;
- dtc->to.s[dtc->to.len] = '\0';
- LM_DBG("bridge <%.*s> to <%.*s>\n", dtc->from.len, dtc->from.s,
- dtc->to.len, dtc->to.s);
- s_body.s = DLG_HOLD_SDP;
- s_body.len = DLG_HOLD_SDP_LEN;
- memset(&uac_r, '\0', sizeof(uac_req_t));
- uac_r.method = &s_method;
- uac_r.headers = &dlg_bridge_inv_hdrs;
- uac_r.body = &s_body;
- uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
- uac_r.cb = dlg_bridge_tm_callback;
- uac_r.cbp = (void*)(long)dtc;
- ret = d_tmb.t_request(&uac_r, /* UAC Req */
- &dtc->from, /* Request-URI (To) */
- &dtc->from, /* To */
- &dlg_bridge_controller, /* From */
- (op != NULL && op->len>0)?op:NULL /* Outbound-URI */
- );
- if(ret<0)
- {
- dlg_transfer_ctx_free(dtc);
- return -1;
- }
- return 0;
- }
- int dlg_transfer(struct dlg_cell *dlg, str *to, int side)
- {
- dlg_transfer_ctx_t *dtc = NULL;
- struct dlg_cell *ndlg = NULL;
- str from;
- str empty = {"", 0};
- dtc = (dlg_transfer_ctx_t*)shm_malloc(sizeof(dlg_transfer_ctx_t));
- if(dtc==NULL)
- {
- LM_ERR("no shm\n");
- return -1;
- }
- if(side==DLG_CALLEE_LEG)
- {
- from = dlg->from_uri;
- } else {
- from = dlg->to_uri;
- }
- memset(dtc, 0, sizeof(dlg_transfer_ctx_t));
- dtc->from.s = (char*)shm_malloc((from.len+1)*sizeof(char));
- if(dtc->from.s==NULL)
- {
- LM_ERR("no shm\n");
- shm_free(dtc);
- return -1;
- }
- dtc->to.s = (char*)shm_malloc((to->len+1)*sizeof(char));
- if(dtc->to.s==NULL)
- {
- LM_ERR("no shm\n");
- shm_free(dtc->from.s);
- shm_free(dtc);
- return -1;
- }
- memcpy(dtc->from.s, from.s, from.len);
- dtc->from.len = from.len;
- dtc->from.s[dtc->from.len] = '\0';
- memcpy(dtc->to.s, to->s, to->len);
- dtc->to.len = to->len;
- dtc->to.s[dtc->to.len] = '\0';
-
- if(side==DLG_CALLER_LEG)
- ndlg = build_new_dlg(&dlg->callid /*callid*/,
- &dlg->to_uri /*from uri*/, &dlg->from_uri /*to uri*/,
- &dlg->tag[side]/*from_tag*/, &dlg->req_uri /*req uri */ );
- else
- ndlg = build_new_dlg(&dlg->callid /*callid*/,
- &dlg->from_uri /*from uri*/, &dlg->to_uri /*to uri*/,
- &dlg->tag[side]/*from_tag*/, &dlg->req_uri /*req uri */ );
- if (ndlg==0) {
- LM_ERR("failed to create new dialog\n");
- goto error;
- }
- dtc->dlg = ndlg;
- if (dlg_set_leg_info(ndlg, &dlg->tag[side], &empty,
- &dlg->contact[side], &dlg->cseq[side], DLG_CALLER_LEG)!=0)
- {
- LM_ERR("dlg_set_leg_info failed for caller\n");
- goto error;
- }
- if(side==DLG_CALLEE_LEG)
- side = DLG_CALLER_LEG;
- else
- side = DLG_CALLEE_LEG;
- if (dlg_set_leg_info(ndlg, &dlg->tag[side], &dlg->route_set[side],
- &dlg->contact[side], &dlg->cseq[side], DLG_CALLEE_LEG)!=0)
- {
- LM_ERR("dlg_set_leg_info failed for caller\n");
- goto error;
- }
- if(dlg_refer_callee(dtc)!=0)
- goto error;
- return 0;
- error:
- dlg_transfer_ctx_free(dtc);
- return -1;
- }
|