diff --git a/core/SipCtrlInterface.cpp b/core/SipCtrlInterface.cpp index e2f79ef6..984501eb 100644 --- a/core/SipCtrlInterface.cpp +++ b/core/SipCtrlInterface.cpp @@ -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& routes, string& route_field) { - if(!routes.empty()){ + if(routes.empty()) + return; - list::const_reverse_iterator it = routes.rbegin(); + list::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::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& routes, string& route_field) diff --git a/core/sip/parse_route.cpp b/core/sip/parse_route.cpp index 25ebb6d8..2fc9c1dd 100644 --- a/core/sip/parse_route.cpp +++ b/core/sip/parse_route.cpp @@ -5,9 +5,13 @@ #include using std::auto_ptr; +route_elmt::~route_elmt() { + if(addr) delete addr; +} + sip_route::~sip_route() { - for(list::iterator it = elmts.begin(); + for(list::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(;cp) 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 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::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 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); } diff --git a/core/sip/parse_route.h b/core/sip/parse_route.h index 03fe18c2..4543e551 100644 --- a/core/sip/parse_route.h +++ b/core/sip/parse_route.h @@ -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 elmts; + list 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); diff --git a/core/sip/trans_layer.cpp b/core/sip/trans_layer.cpp index 50be796e..341230ad 100644 --- a/core/sip/trans_layer.cpp +++ b/core/sip/trans_layer.cpp @@ -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(;cp; + 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::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::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.