b/f: multiple routes within a [Record-]Route HF.

sayer/1.4-spce2.6
Raphael Coeffic 16 years ago
parent 62b60a44ab
commit 71c24a546d

@ -39,6 +39,7 @@
#include "sip/parse_cseq.h"
#include "sip/parse_extensions.h"
#include "sip/parse_100rel.h"
#include "sip/parse_route.h"
#include "sip/trans_table.h"
#include "sip/sip_trans.h"
#include "sip/wheeltimer.h"
@ -695,18 +696,42 @@ void SipCtrlInterface::handle_reply_timeout(AmSipTimeoutEvent::EvType evt,
void SipCtrlInterface::prepare_routes_uac(const list<sip_header*>& routes, string& route_field)
{
if(!routes.empty()){
if(routes.empty())
return;
list<sip_header*>::const_reverse_iterator it = routes.rbegin();
list<sip_header*>::const_reverse_iterator it_rh = routes.rbegin();
if(parse_route(*it_rh) < 0){
DBG("Could not parse route header [%.*s]\n",
(*it_rh)->value.len,(*it_rh)->value.s);
return;
}
sip_route* route = (sip_route*)(*it_rh)->p;
route_field = c2stlstr((*it)->value);
++it;
list<route_elmt*>::const_reverse_iterator it_re = route->elmts.rbegin();
route_field = c2stlstr((*it_re)->route);
while(true) {
if(++it_re == route->elmts.rend()){
if(++it_rh == routes.rend()){
DBG("route_field = [%s]\n",route_field.c_str());
return;
}
for(; it != routes.rend(); ++it) {
route_field += ", " + c2stlstr((*it)->value);
if(parse_route(*it_rh) < 0){
DBG("Could not parse route header [%.*s]\n",
(*it_rh)->value.len,(*it_rh)->value.s);
return;
}
route = (sip_route*)(*it_rh)->p;
if(route->elmts.empty())
return;
it_re = route->elmts.rbegin();
}
route_field += ", " + c2stlstr((*it_re)->route);
}
}
void SipCtrlInterface::prepare_routes_uas(const list<sip_header*>& routes, string& route_field)

@ -5,9 +5,13 @@
#include <memory>
using std::auto_ptr;
route_elmt::~route_elmt() {
if(addr) delete addr;
}
sip_route::~sip_route()
{
for(list<sip_nameaddr*>::iterator it = elmts.begin();
for(list<route_elmt*>::iterator it = elmts.begin();
it != elmts.end(); ++it)
delete *it;
}
@ -33,18 +37,171 @@ bool is_loose_route(const sip_uri* fr_uri)
return is_lr;
}
static int skip_2_next_route(const char*& c,
const char*& eor,
const char* end)
{
assert(c && end && (c<=end));
// detect beginning of next route
enum {
RR_BEGIN=0,
RR_QUOTED,
RR_SWS,
RR_SEP_SWS, // space(s) after ','
RR_NXT_ROUTE
};
int st = RR_BEGIN;
eor = NULL;
for(;c<end;c++){
switch(st){
case RR_BEGIN:
switch(*c){
case SP:
case HTAB:
case CR:
case LF:
st = RR_SWS;
eor = c;
break;
case COMMA:
st = RR_SEP_SWS;
eor = c;
break;
case DQUOTE:
st = RR_QUOTED;
break;
}
break;
case RR_QUOTED:
switch(*c){
case BACKSLASH:
if(++c == end) goto error;
break;
case DQUOTE:
st = RR_BEGIN;
break;
}
break;
case RR_SWS:
switch(*c){
case SP:
case HTAB:
case CR:
case LF:
break;
case COMMA:
st = RR_SEP_SWS;
break;
default:
st = RR_BEGIN;
eor = NULL;
break;
}
break;
case RR_SEP_SWS:
switch(*c){
case SP:
case HTAB:
case CR:
case LF:
break;
default:
st = RR_NXT_ROUTE;
goto nxt_route;
}
break;
}
}
nxt_route:
error:
switch(st){
case RR_QUOTED:
DBG("Malformed route header\n");
return -1;
case RR_SEP_SWS: // not fine, but acceptable
case RR_BEGIN: // end of route header
eor = c;
return 0;
case RR_NXT_ROUTE:
return 1; // next route available
}
// should never be reached
// makes GCC happy
return 0;
}
int parse_route(sip_header* rh)
{
if(rh->p) return 0;
sip_route* route = new sip_route();
rh->p = route;
const char* c = rh->value.s;
const char* end = rh->value.s + rh->value.len;
const char* eor = NULL;
while(c < end) {
const char* route_begin = c;
int err = skip_2_next_route(c,eor,end);
if(err < 0){
ERROR("While parsing route header\n");
return -1;
}
if(eor) {
route_elmt* re = new route_elmt();
re->route.s = route_begin;
re->route.len = eor - route_begin;
route->elmts.push_back(re);
}
if(err == 0)
break;
}
return 0;
}
int parse_first_route_uri(sip_header* fr)
{
if(fr->p) return 0;
if(parse_route(fr) < 0) {
DBG("Could not parse route hf [%.*s]\n",
fr->value.len,fr->value.s);
return -1;
}
auto_ptr<sip_nameaddr> na(new sip_nameaddr());
const char* c = fr->value.s;
sip_route* route = (sip_route*)fr->p;
assert(route);
if(parse_nameaddr(na.get(), &c, fr->value.len)<0) {
DBG("Parsing name-addr failed\n");
if(route->elmts.empty()) {
DBG("No first route\n");
return -1;
}
list<route_elmt*>::iterator route_it = route->elmts.begin();
if((*route_it)->addr)
return 0;
cstring route_str((*route_it)->route);
const char* c = route_str.s;
auto_ptr<sip_nameaddr> na(new sip_nameaddr());
if(parse_nameaddr(na.get(), &c, route_str.len)<0) {
DBG("Parsing name-addr failed\n");
return -1;
}
if(parse_uri(&na->uri,na->addr.s,na->addr.len) < 0) {
@ -52,8 +209,7 @@ int parse_first_route_uri(sip_header* fr)
return -1;
}
fr->p = new sip_route();
((sip_route*)(fr->p))->elmts.push_back(na.release());
(*route_it)->addr = na.release();
return 0;
}
@ -63,12 +219,18 @@ sip_uri* get_first_route_uri(sip_header* fr)
int err=0;
assert(fr);
if(!fr->p) err = parse_first_route_uri(fr);
if(err || ((sip_route*)(fr->p))->elmts.empty())
err = parse_first_route_uri(fr);
if(err < 0)
return NULL;
sip_nameaddr* na = ((sip_route*)(fr->p))->elmts.front();
assert(na);
sip_route* route = (sip_route*)(fr->p);
if(!route || route->elmts.empty()){
DBG("No first route\n");
return NULL;
}
route_elmt* re = route->elmts.front();
sip_nameaddr* na = re->addr;
return &(na->uri);
}

@ -34,9 +34,21 @@
struct sip_nameaddr;
struct sip_uri;
struct route_elmt
{
sip_nameaddr* addr;
cstring route;
route_elmt()
: addr(NULL), route()
{}
~route_elmt();
};
struct sip_route: public sip_parsed_hdr
{
list<sip_nameaddr*> elmts;
list<route_elmt*> elmts;
sip_route()
: sip_parsed_hdr(),
@ -46,6 +58,8 @@ struct sip_route: public sip_parsed_hdr
~sip_route();
};
int parse_route(sip_header* rh);
int parse_first_route_uri(sip_header* fr);
sip_uri* get_first_route_uri(sip_header* fr);

@ -586,91 +586,34 @@ static void prepare_strict_routing(sip_msg* msg, string& ext_uri_buffer)
// no need for further processing
if(!route_uri || is_loose_route(route_uri))
return;
// place a cursor at the end of the 1st name-addr
cstring fr_na_addr = ((sip_route*)(fr->p))->elmts.front()->addr;
const char* c = fr_na_addr.s + fr_na_addr.len;
const char* end = fr->value.s + fr->value.len;
assert(c<=end);
// detect beginning of next route
enum {
RR_PARAMS=0,
RR_QUOTED,
RR_SEP_SWS, // space(s) after ','
RR_NXT_ROUTE
};
int st = RR_PARAMS;
for(;c<end;c++){
switch(st){
case RR_PARAMS:
switch(*c){
case SP:
case HTAB:
case CR:
case LF:
break;
case COMMA:
st = RR_SEP_SWS;
break;
case DQUOTE:
st = RR_QUOTED;
break;
}
break;
case RR_QUOTED:
switch(*c){
case BACKSLASH:
c++;
break;
case DQUOTE:
st = RR_PARAMS;
break;
}
break;
case RR_SEP_SWS:
switch(*c){
case SP:
case HTAB:
case CR:
case LF:
break;
default:
st = RR_NXT_ROUTE;
goto nxt_route;
}
break;
}
}
nxt_route:
switch(st){
case RR_QUOTED:
case RR_SEP_SWS:
DBG("Malformed first route header\n");
case RR_PARAMS:
sip_route* route = (sip_route*)fr->p;
sip_nameaddr* fr_na = route->elmts.front()->addr;
cstring fr_na_addr = fr_na->addr;
if(route->elmts.size() == 1){
// remove current route header from message
msg->route.pop_front();
DBG("route_hdrs.length() = %i\n",(int)msg->route.size());
{
list<sip_header*>::iterator h_it =
std::find(msg->hdrs.begin(),msg->hdrs.end(),fr);
msg->route.pop_front();
if(h_it != msg->hdrs.end())
msg->hdrs.erase(h_it);
}
DBG("delete (fr=0x%p)\n",fr);
delete fr;
break;
case RR_NXT_ROUTE:
// remove current route from this header
fr->value.s = c;
fr->value.len = end-c;
break;
list<sip_header*>::iterator h_it =
std::find(msg->hdrs.begin(),msg->hdrs.end(),fr);
if(h_it != msg->hdrs.end())
msg->hdrs.erase(h_it);
delete fr;
}
else if(route->elmts.size() > 1) {
// remove first element from the list
delete route->elmts.front();
route->elmts.pop_front();
// fetch the next route element
route_elmt* nxt_re = route->elmts.front();
// adjust route header
fr->value.len = (fr->value.s + fr->value.len) - nxt_re->route.s;
fr->value.s = nxt_re->route.s;
}
// copy r_uri at the end of the route set.

Loading…
Cancel
Save