mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1015 lines
20 KiB
1015 lines
20 KiB
/**
|
|
* Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* This file 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
|
|
*
|
|
*
|
|
* This file 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*!
|
|
* \file
|
|
* \brief SIP-router topoh ::
|
|
* \ingroup topoh
|
|
* Module: \ref topoh
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "../../dprint.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../data_lump.h"
|
|
#include "../../forward.h"
|
|
#include "../../trim.h"
|
|
#include "../../dset.h"
|
|
#include "../../msg_translator.h"
|
|
#include "../../parser/parse_rr.h"
|
|
#include "../../parser/parse_uri.h"
|
|
#include "../../parser/parse_param.h"
|
|
#include "../../parser/parse_from.h"
|
|
#include "../../parser/parse_to.h"
|
|
#include "../../parser/parse_via.h"
|
|
#include "../../parser/contact/parse_contact.h"
|
|
#include "../../parser/parse_refer_to.h"
|
|
#include "tps_msg.h"
|
|
#include "tps_storage.h"
|
|
|
|
extern int _tps_param_mask_callid;
|
|
|
|
str _sr_hname_xbranch = str_init("P-SR-XBranch");
|
|
str _sr_hname_xuuid = str_init("P-SR-XUID");
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_skip_rw(char *s, int len)
|
|
{
|
|
while(len>0)
|
|
{
|
|
if(s[len-1]==' ' || s[len-1]=='\t' || s[len-1]=='\n' || s[len-1]=='\r'
|
|
|| s[len-1]==',')
|
|
len--;
|
|
else return len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
struct via_param *tps_get_via_param(struct via_body *via, str *name)
|
|
{
|
|
struct via_param *p;
|
|
for(p=via->param_lst; p; p=p->next)
|
|
{
|
|
if(p->name.len==name->len
|
|
&& strncasecmp(p->name.s, name->s, name->len)==0)
|
|
return p;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_get_param_value(str *in, str *name, str *value)
|
|
{
|
|
param_t* params = NULL;
|
|
param_t* p = NULL;
|
|
param_hooks_t phooks;
|
|
if (parse_params(in, CLASS_ANY, &phooks, ¶ms)<0)
|
|
return -1;
|
|
for (p = params; p; p=p->next)
|
|
{
|
|
if (p->name.len==name->len
|
|
&& strncasecmp(p->name.s, name->s, name->len)==0)
|
|
{
|
|
*value = p->body;
|
|
free_params(params);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if(params) free_params(params);
|
|
return 1;
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_remove_headers(sip_msg_t *msg, uint32_t hdr)
|
|
{
|
|
struct hdr_field *hf;
|
|
struct lump* l;
|
|
|
|
parse_headers(msg, HDR_EOH_F, 0);
|
|
for (hf=msg->headers; hf; hf=hf->next) {
|
|
if (hdr!=hf->type)
|
|
continue;
|
|
l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
|
|
if (l==0) {
|
|
LM_ERR("failed to remove the header\n");
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_add_headers(sip_msg_t *msg, str *hname, str *hbody, int hpos)
|
|
{
|
|
struct lump* anchor;
|
|
str hs;
|
|
|
|
if(hname==NULL || hname->len<=0 || hbody==NULL || hbody->len<=0)
|
|
return 0;
|
|
|
|
parse_headers(msg, HDR_EOH_F, 0);
|
|
if(hpos == 0) { /* append */
|
|
/* after last header */
|
|
anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
|
|
} else { /* insert */
|
|
/* before first header */
|
|
anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0, 0);
|
|
}
|
|
|
|
if(anchor == 0) {
|
|
LM_ERR("can't get anchor\n");
|
|
return -1;
|
|
}
|
|
|
|
hs.len = hname->len + 2 + hbody->len;
|
|
hs.s = (char*)pkg_malloc(hs.len + 3);
|
|
if (hs.s==NULL) {
|
|
LM_ERR("no pkg memory left (%.*s - %d)\n",
|
|
hname->len, hname->s, hs.len);
|
|
return -1;
|
|
}
|
|
memcpy(hs.s, hname->s, hname->len);
|
|
hs.s[hname->len] = ':';
|
|
hs.s[hname->len+1] = ' ';
|
|
memcpy(hs.s + hname->len + 2, hbody->s, hbody->len);
|
|
|
|
/* add end of header if not present */
|
|
if(hs.s[hname->len + 2 + hbody->len - 1]!='\n') {
|
|
hs.s[hname->len + 2 + hbody->len] = '\r';
|
|
hs.s[hname->len + 2 + hbody->len+1] = '\n';
|
|
hs.len += 2;
|
|
}
|
|
|
|
if (insert_new_lump_before(anchor, hs.s, hs.len, 0) == 0) {
|
|
LM_ERR("can't insert lump\n");
|
|
pkg_free(hs.s);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_get_uri_param_value(str *uri, str *name, str *value)
|
|
{
|
|
struct sip_uri puri;
|
|
|
|
memset(value, 0, sizeof(str));
|
|
if(parse_uri(uri->s, uri->len, &puri)<0)
|
|
return -1;
|
|
return tps_get_param_value(&puri.params, name, value);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_get_uri_type(str *uri, int *mode, str *value)
|
|
{
|
|
struct sip_uri puri;
|
|
int ret;
|
|
str r2 = {"r2", 2};
|
|
|
|
memset(value, 0, sizeof(str));
|
|
*mode = 0;
|
|
if(parse_uri(uri->s, uri->len, &puri)<0)
|
|
return -1;
|
|
|
|
LM_DBG("PARAMS [%.*s]\n", puri.params.len, puri.params.s);
|
|
|
|
if(check_self(&puri.host, puri.port_no, 0)==1)
|
|
{
|
|
/* myself -- matched on all protos */
|
|
ret = tps_get_param_value(&puri.params, &r2, value);
|
|
if(ret<0)
|
|
return -1;
|
|
if(ret==1) /* not found */
|
|
return 0; /* skip */
|
|
LM_DBG("VALUE [%.*s]\n",
|
|
value->len, value->s);
|
|
if(value->len==2 && strncasecmp(value->s, "on", 2)==0)
|
|
*mode = 1;
|
|
memset(value, 0, sizeof(str));
|
|
return 0; /* skip */
|
|
}
|
|
/* not myself & not mask ip */
|
|
return 1; /* encode */
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
char* tps_msg_update(sip_msg_t *msg, unsigned int *olen)
|
|
{
|
|
struct dest_info dst;
|
|
|
|
init_dest_info(&dst);
|
|
dst.proto = PROTO_UDP;
|
|
return build_req_buf_from_sip_req(msg,
|
|
olen, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_skip_msg(sip_msg_t *msg)
|
|
{
|
|
if (msg->cseq==NULL || get_cseq(msg)==NULL) {
|
|
LM_WARN("Invalid/Unparsed CSeq in message. Skipping.");
|
|
return 1;
|
|
}
|
|
|
|
if((get_cseq(msg)->method_id)&(METHOD_REGISTER|METHOD_PUBLISH))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_dlg_message_update(sip_msg_t *msg, tps_data_t *ptsd)
|
|
{
|
|
if(parse_sip_msg_uri(msg)<0) {
|
|
LM_ERR("failed to parse r-uri\n");
|
|
return -1;
|
|
}
|
|
if(msg->parsed_uri.user.len<10) {
|
|
LM_DBG("not an expected user format\n");
|
|
return 1;
|
|
}
|
|
if(memcmp(msg->parsed_uri.user.s, "atpsh-", 6)==0) {
|
|
ptsd->a_uuid = msg->parsed_uri.user;
|
|
return 0;
|
|
}
|
|
if(memcmp(msg->parsed_uri.user.s, "btpsh-", 6)==0) {
|
|
ptsd->a_uuid = msg->parsed_uri.user;
|
|
ptsd->b_uuid = msg->parsed_uri.user;
|
|
return 0;
|
|
}
|
|
LM_DBG("not an expected user prefix\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_pack_message(sip_msg_t *msg, tps_data_t *ptsd)
|
|
{
|
|
hdr_field_t *hdr;
|
|
via_body_t *via;
|
|
rr_t *rr;
|
|
int i;
|
|
int vlen;
|
|
int r2;
|
|
int isreq;
|
|
|
|
if(ptsd->cp==NULL) {
|
|
ptsd->cp = ptsd->cbuf;
|
|
}
|
|
|
|
i = 0;
|
|
for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr)) {
|
|
for(via=(struct via_body*)hdr->parsed; via; via=via->next) {
|
|
i++;
|
|
vlen = tps_skip_rw(via->name.s, via->bsize);
|
|
if(ptsd->cp + vlen + 2 >= ptsd->cbuf + TPS_DATA_SIZE) {
|
|
LM_ERR("no more spage to pack via headers\n");
|
|
return -1;
|
|
}
|
|
if(i>1) {
|
|
*ptsd->cp = ',';
|
|
ptsd->cp++;
|
|
if(i>2) {
|
|
ptsd->x_via2.len++;
|
|
}
|
|
}
|
|
memcpy(ptsd->cp, via->name.s, vlen);
|
|
if(i==1) {
|
|
ptsd->x_via1.s = ptsd->cp;
|
|
ptsd->x_via1.len = vlen;
|
|
if(via->branch!=NULL) {
|
|
ptsd->x_vbranch1.s = ptsd->x_via1.s + (via->branch->value.s - via->name.s);
|
|
ptsd->x_vbranch1.len = via->branch->value.len;
|
|
}
|
|
} else {
|
|
if(i==2) {
|
|
ptsd->x_via2.s = ptsd->cp;
|
|
}
|
|
ptsd->x_via2.len += vlen;
|
|
}
|
|
ptsd->cp += vlen;
|
|
}
|
|
}
|
|
LM_DBG("compacted headers - x_via1: [%.*s](%d) - x_via2: [%.*s](%d)"
|
|
" - x_vbranch1: [%.*s](%d)\n",
|
|
ptsd->x_via1.len, ZSW(ptsd->x_via1.s), ptsd->x_via1.len,
|
|
ptsd->x_via2.len, ZSW(ptsd->x_via2.s), ptsd->x_via2.len,
|
|
ptsd->x_vbranch1.len, ZSW(ptsd->x_vbranch1.s), ptsd->x_vbranch1.len);
|
|
|
|
ptsd->a_rr.len = 0;
|
|
ptsd->s_rr.len = 0;
|
|
i = 0;
|
|
r2 = 0;
|
|
isreq = (msg->first_line.type==SIP_REQUEST)?1:0;
|
|
for(hdr=msg->record_route; hdr; hdr=next_sibling_hdr(hdr)) {
|
|
if (parse_rr(hdr) < 0) {
|
|
LM_ERR("failed to parse RR\n");
|
|
return -1;
|
|
}
|
|
|
|
for(rr =(rr_t*)hdr->parsed; rr; rr=rr->next) {
|
|
i++;
|
|
if(ptsd->cp + rr->nameaddr.uri.len + 4 >= ptsd->cbuf + TPS_DATA_SIZE) {
|
|
LM_ERR("no more spage to pack rr headers\n");
|
|
return -1;
|
|
}
|
|
if(isreq==1) {
|
|
/* sip request - get a+s-side record route */
|
|
if(i>1) {
|
|
if(i==2 &&r2==0) {
|
|
ptsd->s_rr.len = ptsd->a_rr.len;
|
|
}
|
|
if(i==3 &&r2==1) {
|
|
ptsd->s_rr.len = ptsd->a_rr.len;
|
|
}
|
|
*ptsd->cp = ',';
|
|
ptsd->cp++;
|
|
ptsd->a_rr.len++;
|
|
}
|
|
*ptsd->cp = '<';
|
|
if(i==1) {
|
|
ptsd->a_rr.s = ptsd->cp;
|
|
ptsd->s_rr.s = ptsd->cp;
|
|
}
|
|
if(i==2 && r2==0) {
|
|
ptsd->a_rr.s = ptsd->cp;
|
|
ptsd->a_rr.len = 0;
|
|
}
|
|
if(i==3 && r2==1) {
|
|
ptsd->a_rr.s = ptsd->cp;
|
|
ptsd->a_rr.len = 0;
|
|
}
|
|
|
|
ptsd->cp++;
|
|
ptsd->a_rr.len++;
|
|
|
|
memcpy(ptsd->cp, rr->nameaddr.uri.s, rr->nameaddr.uri.len);
|
|
if(i==1) {
|
|
ptsd->bs_contact.s = ptsd->cp;
|
|
ptsd->bs_contact.len = rr->nameaddr.uri.len;
|
|
if(_strnstr(ptsd->bs_contact.s, ";r2=on",
|
|
ptsd->bs_contact.len)==0) {
|
|
LM_DBG("single record routing by proxy\n");
|
|
ptsd->as_contact.s = ptsd->cp;
|
|
ptsd->as_contact.len = rr->nameaddr.uri.len;
|
|
} else {
|
|
r2 = 1;
|
|
}
|
|
} else {
|
|
if(i==2 && ptsd->as_contact.len==0) {
|
|
LM_DBG("double record routing by proxy\n");
|
|
ptsd->as_contact.s = ptsd->cp;
|
|
ptsd->as_contact.len = rr->nameaddr.uri.len;
|
|
}
|
|
}
|
|
ptsd->a_rr.len += rr->nameaddr.uri.len;
|
|
ptsd->cp += rr->nameaddr.uri.len;
|
|
*ptsd->cp = '>';
|
|
ptsd->cp++;
|
|
ptsd->a_rr.len++;
|
|
} else {
|
|
/* sip response - get b-side record route */
|
|
*ptsd->cp = '<';
|
|
ptsd->b_rr.s = ptsd->cp;
|
|
ptsd->cp++;
|
|
ptsd->b_rr.len++;
|
|
memcpy(ptsd->cp, rr->nameaddr.uri.s, rr->nameaddr.uri.len);
|
|
ptsd->cp += rr->nameaddr.uri.len;
|
|
ptsd->b_rr.len += rr->nameaddr.uri.len;
|
|
*ptsd->cp = '>';
|
|
ptsd->cp++;
|
|
ptsd->b_rr.len++;
|
|
}
|
|
}
|
|
}
|
|
if(isreq==1) {
|
|
if(i==1) {
|
|
ptsd->s_rr.len = ptsd->a_rr.len;
|
|
ptsd->a_rr.len = 0;
|
|
}
|
|
if(i==2 && r2==1) {
|
|
ptsd->s_rr.len = ptsd->a_rr.len;
|
|
ptsd->a_rr.len = 0;
|
|
}
|
|
}
|
|
LM_DBG("compacted headers - a_rr: [%.*s](%d) - b_rr: [%.*s](%d)"
|
|
" - s_rr: [%.*s](%d)\n",
|
|
ptsd->a_rr.len, ZSW(ptsd->a_rr.s), ptsd->a_rr.len,
|
|
ptsd->b_rr.len, ZSW(ptsd->b_rr.s), ptsd->b_rr.len,
|
|
ptsd->s_rr.len, ZSW(ptsd->s_rr.s), ptsd->s_rr.len);
|
|
LM_DBG("compacted headers - as_contact: [%.*s](%d) - bs_contact: [%.*s](%d)\n",
|
|
ptsd->as_contact.len, ZSW(ptsd->as_contact.s), ptsd->as_contact.len,
|
|
ptsd->bs_contact.len, ZSW(ptsd->bs_contact.s), ptsd->bs_contact.len);
|
|
ptsd->x_rr = ptsd->a_rr;
|
|
ptsd->s_method_id = get_cseq(msg)->method_id;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_reinsert_via(sip_msg_t *msg, tps_data_t *ptsd, str *hbody)
|
|
{
|
|
str hname = str_init("Via");
|
|
|
|
if(tps_add_headers(msg, &hname, hbody, 1)<0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_reinsert_contact(sip_msg_t *msg, tps_data_t *ptsd, str *hbody)
|
|
{
|
|
str hname = str_init("Contact");
|
|
|
|
if(tps_add_headers(msg, &hname, hbody, 0)<0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_remove_name_headers(sip_msg_t *msg, str *hname)
|
|
{
|
|
hdr_field_t *hf;
|
|
struct lump* l;
|
|
for (hf=msg->headers; hf; hf=hf->next)
|
|
{
|
|
if (hf->name.len==hname->len
|
|
&& strncasecmp(hf->name.s, hname->s,
|
|
hname->len)==0)
|
|
{
|
|
l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
|
|
if (l==0) {
|
|
LM_ERR("unable to delete header [%.*s]\n",
|
|
hname->len, hname->s);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_reappend_via(sip_msg_t *msg, tps_data_t *ptsd, str *hbody)
|
|
{
|
|
str hname = str_init("Via");
|
|
|
|
if(tps_add_headers(msg, &hname, hbody, 0)<0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_append_xbranch(sip_msg_t *msg, str *hbody)
|
|
{
|
|
if(tps_add_headers(msg, &_sr_hname_xbranch, hbody, 0)<0) {
|
|
LM_ERR("failed to add xbranch header [%.*s]/%d\n",
|
|
hbody->len, hbody->s, hbody->len);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_remove_xbranch(sip_msg_t *msg)
|
|
{
|
|
return tps_remove_name_headers(msg, &_sr_hname_xbranch);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_get_xbranch(sip_msg_t *msg, str *hbody)
|
|
{
|
|
hdr_field_t *hf;
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
return -1;
|
|
}
|
|
|
|
for (hf=msg->headers; hf; hf=hf->next)
|
|
{
|
|
if(_sr_hname_xbranch.len==hf->name.len
|
|
&& strncasecmp(_sr_hname_xbranch.s, hf->name.s,
|
|
hf->name.len)==0) {
|
|
break;
|
|
}
|
|
}
|
|
if(hf!=NULL) {
|
|
*hbody = hf->body;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_append_xuuid(sip_msg_t *msg, str *hbody)
|
|
{
|
|
if(tps_add_headers(msg, &_sr_hname_xuuid, hbody, 0)<0) {
|
|
LM_ERR("failed to add xuuid header [%.*s]/%d\n",
|
|
hbody->len, hbody->s, hbody->len);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_remove_xuuid(sip_msg_t *msg)
|
|
{
|
|
return tps_remove_name_headers(msg, &_sr_hname_xuuid);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_get_xuuid(sip_msg_t *msg, str *hbody)
|
|
{
|
|
hdr_field_t *hf;
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
return -1;
|
|
}
|
|
|
|
for (hf=msg->headers; hf; hf=hf->next)
|
|
{
|
|
if(_sr_hname_xuuid.len==hf->name.len
|
|
&& strncasecmp(_sr_hname_xuuid.s, hf->name.s,
|
|
hf->name.len)==0) {
|
|
break;
|
|
}
|
|
}
|
|
if(hf!=NULL) {
|
|
*hbody = hf->body;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_reappend_rr(sip_msg_t *msg, tps_data_t *ptsd, str *hbody)
|
|
{
|
|
str hname = str_init("Record-Route");
|
|
|
|
if(tps_add_headers(msg, &hname, hbody, 0)<0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_reappend_route(sip_msg_t *msg, tps_data_t *ptsd, str *hbody, int rev)
|
|
{
|
|
str hname = str_init("Route");
|
|
int i;
|
|
int c;
|
|
str sb;
|
|
|
|
if(hbody==NULL || hbody->s==NULL || hbody->len<=0 || hbody->s[0]=='\0')
|
|
return 0;
|
|
|
|
if(rev==1) {
|
|
c = 0;
|
|
sb.len = 1;
|
|
for(i=hbody->len-2; i>=0; i--) {
|
|
if(hbody->s[i]==',') {
|
|
c = 1;
|
|
if(sb.len>0) {
|
|
sb.s = hbody->s + i + 1;
|
|
if(sb.s[sb.len-1]==',') sb.len--;
|
|
if(tps_add_headers(msg, &hname, &sb, 0)<0) {
|
|
return -1;
|
|
}
|
|
}
|
|
sb.len = 0;
|
|
}
|
|
sb.len++;
|
|
}
|
|
if(c==1) {
|
|
if(sb.len>0) {
|
|
sb.s = hbody->s;
|
|
if(sb.s[sb.len-1]==',') sb.len--;
|
|
if(tps_add_headers(msg, &hname, &sb, 0)<0) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
sb = *hbody;
|
|
if(sb.len>0 && sb.s[sb.len-1]==',') sb.len--;
|
|
trim_zeros_lr(&sb);
|
|
trim(&sb);
|
|
if(sb.len>0 && sb.s[sb.len-1]==',') sb.len--;
|
|
if(tps_add_headers(msg, &hname, &sb, 0)<0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_request_received(sip_msg_t *msg, int dialog)
|
|
{
|
|
tps_data_t mtsd;
|
|
tps_data_t stsd;
|
|
str lkey;
|
|
str ftag;
|
|
str nuri;
|
|
uint32_t direction = TPS_DIR_DOWNSTREAM;
|
|
int ret;
|
|
|
|
LM_DBG("handling incoming request\n");
|
|
|
|
if(dialog==0) {
|
|
/* nothing to do for initial request */
|
|
return 0;
|
|
}
|
|
|
|
memset(&mtsd, 0, sizeof(tps_data_t));
|
|
memset(&stsd, 0, sizeof(tps_data_t));
|
|
|
|
if(tps_pack_message(msg, &mtsd)<0) {
|
|
LM_ERR("failed to extract and pack the headers\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = tps_dlg_message_update(msg, &mtsd);
|
|
if(ret<0) {
|
|
LM_ERR("failed to update on dlg message\n");
|
|
return -1;
|
|
}
|
|
|
|
lkey = msg->callid->body;
|
|
|
|
tps_storage_lock_get(&lkey);
|
|
|
|
if(tps_storage_load_dialog(msg, &mtsd, &stsd)<0) {
|
|
goto error;
|
|
}
|
|
|
|
/* detect direction - get from-tag */
|
|
if(parse_from_header(msg)<0 || msg->from==NULL) {
|
|
LM_ERR("failed getting 'from' header!\n");
|
|
goto error;
|
|
}
|
|
ftag = get_from(msg)->tag_value;
|
|
|
|
if(stsd.a_tag.len!=ftag.len) {
|
|
direction = TPS_DIR_UPSTREAM;
|
|
} else {
|
|
if(memcmp(stsd.a_tag.s, ftag.s, ftag.len)==0) {
|
|
direction = TPS_DIR_DOWNSTREAM;
|
|
} else {
|
|
direction = TPS_DIR_UPSTREAM;
|
|
}
|
|
}
|
|
mtsd.direction = direction;
|
|
|
|
tps_storage_lock_release(&lkey);
|
|
|
|
if(direction == TPS_DIR_UPSTREAM) {
|
|
nuri = stsd.a_contact;
|
|
} else {
|
|
nuri = stsd.b_contact;
|
|
}
|
|
if(nuri.len>0) {
|
|
if(rewrite_uri(msg, &nuri)<0) {
|
|
LM_ERR("failed to update r-uri\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(tps_reappend_route(msg, &stsd, &stsd.s_rr,
|
|
(direction==TPS_DIR_UPSTREAM)?0:1)<0) {
|
|
LM_ERR("failed to reappend s-route\n");
|
|
return -1;
|
|
}
|
|
if(direction == TPS_DIR_UPSTREAM) {
|
|
if(tps_reappend_route(msg, &stsd, &stsd.a_rr, 0)<0) {
|
|
LM_ERR("failed to reappend a-route\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
if(tps_reappend_route(msg, &stsd, &stsd.b_rr, 0)<0) {
|
|
LM_ERR("failed to reappend b-route\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if(dialog!=0) {
|
|
tps_append_xuuid(msg, &stsd.a_uuid);
|
|
}
|
|
return 0;
|
|
|
|
error:
|
|
tps_storage_lock_release(&lkey);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_response_received(sip_msg_t *msg)
|
|
{
|
|
tps_data_t mtsd;
|
|
tps_data_t stsd;
|
|
tps_data_t btsd;
|
|
str lkey;
|
|
str ftag;
|
|
uint32_t direction;
|
|
|
|
LM_DBG("handling incoming response\n");
|
|
|
|
if(msg->first_line.u.reply.statuscode==100) {
|
|
/* nothing to do - it should be absorbed */
|
|
return 0;
|
|
}
|
|
|
|
memset(&mtsd, 0, sizeof(tps_data_t));
|
|
memset(&stsd, 0, sizeof(tps_data_t));
|
|
memset(&btsd, 0, sizeof(tps_data_t));
|
|
|
|
lkey = msg->callid->body;
|
|
|
|
if(tps_pack_message(msg, &mtsd)<0) {
|
|
LM_ERR("failed to extract and pack the headers\n");
|
|
return -1;
|
|
}
|
|
tps_storage_lock_get(&lkey);
|
|
if(tps_storage_load_branch(msg, &mtsd, &btsd)<0) {
|
|
goto error;
|
|
}
|
|
LM_DBG("loaded dialog a_uuid [%.*s]\n",
|
|
btsd.a_uuid.len, ZSW(btsd.a_uuid.s));
|
|
if(tps_storage_load_dialog(msg, &btsd, &stsd)<0) {
|
|
goto error;
|
|
}
|
|
|
|
/* detect direction - get from-tag */
|
|
if(parse_from_header(msg)<0 || msg->from==NULL) {
|
|
LM_ERR("failed getting 'from' header!\n");
|
|
goto error;
|
|
}
|
|
ftag = get_from(msg)->tag_value;
|
|
|
|
if(stsd.a_tag.len!=ftag.len) {
|
|
direction = TPS_DIR_UPSTREAM;
|
|
} else {
|
|
if(memcmp(stsd.a_tag.s, ftag.s, ftag.len)==0) {
|
|
direction = TPS_DIR_DOWNSTREAM;
|
|
} else {
|
|
direction = TPS_DIR_UPSTREAM;
|
|
}
|
|
}
|
|
mtsd.direction = direction;
|
|
if(tps_storage_update_branch(msg, &mtsd, &btsd)<0) {
|
|
goto error;
|
|
}
|
|
if(tps_storage_update_dialog(msg, &mtsd, &stsd)<0) {
|
|
goto error;
|
|
}
|
|
tps_storage_lock_release(&lkey);
|
|
|
|
tps_reappend_via(msg, &btsd, &btsd.x_via);
|
|
tps_reappend_rr(msg, &btsd, &btsd.s_rr);
|
|
tps_reappend_rr(msg, &btsd, &btsd.x_rr);
|
|
tps_append_xbranch(msg, &mtsd.x_vbranch1);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
tps_storage_lock_release(&lkey);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_request_sent(sip_msg_t *msg, int dialog, int local)
|
|
{
|
|
tps_data_t mtsd;
|
|
tps_data_t btsd;
|
|
tps_data_t stsd;
|
|
tps_data_t *ptsd;
|
|
str lkey;
|
|
str xuuid;
|
|
int direction = TPS_DIR_DOWNSTREAM;
|
|
|
|
LM_DBG("handling outgoing request\n");
|
|
|
|
memset(&mtsd, 0, sizeof(tps_data_t));
|
|
memset(&btsd, 0, sizeof(tps_data_t));
|
|
memset(&stsd, 0, sizeof(tps_data_t));
|
|
ptsd = &mtsd;
|
|
|
|
if(tps_pack_message(msg, &mtsd)<0) {
|
|
LM_ERR("failed to extract and pack the headers\n");
|
|
return -1;
|
|
}
|
|
|
|
if(dialog!=0) {
|
|
if(tps_get_xuuid(msg, &xuuid)<0) {
|
|
LM_DBG("no x-uuid header - nothing to do\n");
|
|
return 0;
|
|
}
|
|
mtsd.a_uuid = xuuid;
|
|
tps_remove_xuuid(msg);
|
|
}
|
|
|
|
lkey = msg->callid->body;
|
|
|
|
tps_storage_lock_get(&lkey);
|
|
|
|
if(tps_storage_load_branch(msg, &mtsd, &btsd)!=0) {
|
|
if(tps_storage_record(msg, ptsd, dialog)<0) {
|
|
goto error;
|
|
}
|
|
} else {
|
|
ptsd = &btsd;
|
|
}
|
|
|
|
if(dialog!=0) {
|
|
if(tps_storage_load_dialog(msg, &mtsd, &stsd)==0) {
|
|
ptsd = &stsd;
|
|
}
|
|
}
|
|
|
|
/* local generated requests */
|
|
if(local) {
|
|
/* ACK and CANCEL go downstream */
|
|
if(get_cseq(msg)->method_id==METHOD_ACK
|
|
|| get_cseq(msg)->method_id==METHOD_CANCEL
|
|
|| local==2) {
|
|
// ts_mask_callid(&msg);
|
|
goto done;
|
|
} else {
|
|
/* should be for upstream */
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
tps_remove_headers(msg, HDR_RECORDROUTE_T);
|
|
tps_remove_headers(msg, HDR_CONTACT_T);
|
|
tps_remove_headers(msg, HDR_VIA_T);
|
|
|
|
tps_reinsert_via(msg, &mtsd, &mtsd.x_via1);
|
|
if(direction==TPS_DIR_UPSTREAM) {
|
|
tps_reinsert_contact(msg, ptsd, &ptsd->as_contact);
|
|
} else {
|
|
tps_reinsert_contact(msg, ptsd, &ptsd->bs_contact);
|
|
}
|
|
|
|
if(dialog!=0) {
|
|
tps_storage_end_dialog(msg, &mtsd, ptsd);
|
|
}
|
|
|
|
done:
|
|
tps_storage_lock_release(&lkey);
|
|
return 0;
|
|
|
|
error:
|
|
tps_storage_lock_release(&lkey);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int tps_response_sent(sip_msg_t *msg)
|
|
{
|
|
tps_data_t mtsd;
|
|
tps_data_t stsd;
|
|
tps_data_t btsd;
|
|
str lkey;
|
|
int direction = TPS_DIR_UPSTREAM;
|
|
str xvbranch = {0, 0};
|
|
|
|
LM_DBG("handling outgoing response\n");
|
|
|
|
memset(&mtsd, 0, sizeof(tps_data_t));
|
|
memset(&stsd, 0, sizeof(tps_data_t));
|
|
memset(&btsd, 0, sizeof(tps_data_t));
|
|
|
|
if(tps_get_xbranch(msg, &xvbranch)<0) {
|
|
LM_DBG("no x-branch header - nothing to do\n");
|
|
return 0;
|
|
}
|
|
|
|
if(tps_pack_message(msg, &mtsd)<0) {
|
|
LM_ERR("failed to extract and pack the headers\n");
|
|
return -1;
|
|
}
|
|
mtsd.x_vbranch1 = xvbranch;
|
|
tps_remove_xbranch(msg);
|
|
|
|
if(get_cseq(msg)->method_id==METHOD_MESSAGE) {
|
|
tps_remove_headers(msg, HDR_RECORDROUTE_T);
|
|
tps_remove_headers(msg, HDR_CONTACT_T);
|
|
return 0;
|
|
}
|
|
|
|
lkey = msg->callid->body;
|
|
|
|
tps_storage_lock_get(&lkey);
|
|
if(tps_storage_load_branch(msg, &mtsd, &btsd)<0) {
|
|
goto error;
|
|
}
|
|
LM_DBG("loaded dialog a_uuid [%.*s]\n",
|
|
btsd.a_uuid.len, ZSW(btsd.a_uuid.s));
|
|
if(tps_storage_load_dialog(msg, &btsd, &stsd)<0) {
|
|
goto error;
|
|
}
|
|
tps_storage_lock_release(&lkey);
|
|
|
|
tps_remove_headers(msg, HDR_RECORDROUTE_T);
|
|
tps_remove_headers(msg, HDR_CONTACT_T);
|
|
|
|
if(direction==TPS_DIR_UPSTREAM) {
|
|
tps_reinsert_contact(msg, &stsd, &stsd.as_contact);
|
|
} else {
|
|
tps_reinsert_contact(msg, &stsd, &stsd.bs_contact);
|
|
}
|
|
|
|
tps_reappend_rr(msg, &btsd, &btsd.x_rr);
|
|
return 0;
|
|
|
|
error:
|
|
tps_storage_lock_release(&lkey);
|
|
return -1;
|
|
}
|