Saturday, 5 March 2011

Record-route and route fun in SIPp

We've found a problem with SIPp's handling of Record-route and route headers. Specifically, it inserts the correct Routes for "client scripts" requests, but gets them wrong in "server scripts" requests. (Note that here I am using "server" and "client" as SIPp does...)

This is what I did:

I started with the two default scenarios from SIPP ("sipp -sd uac > uac.xml" and "sipp -sd uas > uas.xml"). Using two terminals, I ran these back-to-back ("sipp -sf uas.xml -m 1" then "sipp -sf uac.xml -m 1 localhost:5061"). [The "-m 1" makes sure both sipp scripts do a single call. If I don't put one on the server script, I forget to restart it when I edit the script, and wonder why my changes take no effect....]

Assuming this works OK, we can go on to add some Record-Route headers. I'm going to use the pair from RFC3261 § 16.12.1.1 Basic SIP Trapezoid to avoid any confusion.

Modify uac.xml at the following points:
  1) Add the lines "Record-Route: <sip:p2.domain.com;lr>" and "Record-Route: <sip:p1.example.com;lr>"
to the INVITE
  2) Add 'rrs="true"' to the 'recv response="200"' command.
  3) Add a '[routes]' line to both the ACK and the BYE

Modify uas.xml at the following points:
  1) Add 'rrs="true"' to the 'recv request="INVITE"' command
  2) Add a '[last_Record-route]' line to both the 180 and 200

Now if you re-run the test you should see:
 In the INVITE:
Record-Route: <sip:p2.domain.com;lr>
  Record-Route: <sip:p1.example.com;lr>

 In the 180 and the 200:
   Record-Route: <sip:p2.domain.com;lr>, <sip:p1.example.com;lr>

 In the ACK and the BYE
   Route:  <sip:p1.example.com;lr>,<sip:p2.domain.com;lr>

So, SIPp has choosen to put both the Record-route and Route headers on the same line, but that's absolutlely fine. What is important is the order, and this is correct. So far, so good.

OK, so lets try this in the opposite direction. Copy uac.xml and uas.xml to uac1.xml and uas1.xml. Cut the BYE and the 200 out of the UAS and paste them into the UAC; cut the PAUSE, the BYE and 200 out of the UAC and paste them UAS. Remove the 'optional="true"' parameter from the ACK in the UAS (ACKs are not optional....).

Re-run using these new scripts. All the Record-route and Route headers are the same. This is a shame as the Route header in the BYE should be "Route:  <sip:p2.domain.com;lr>,<sip:p1.example.com;lr>".

There are some other signalling errors in the traces as well, but I'm going to ignore these right now.
For now, here is my finely crafted fix. (AKA boadge).

In the UAS script (uas1.xml that is) make the following changes.
  1) Add an action to the recv INVITE command to extract and store the content of the two Record-Route headers.
<action>
  <ereg regexp=".*" search_in="hdr" header="Record-Route:" occurence="1" assign_to="1"/>
  <ereg regexp=".*" search_in="hdr" header="Record-Route:" occurence="2" assign_to="2"/>
</action>
  2) Replace the '[routes]' line in the BYE with two lines to insert them back
Route: [$1]
  Route: [$2]
      
Re-run it (there is no need to change the uac1.xml script), and you should find that you have Route: headers in the right order!

This bodge has one draw-backs. You have to handle each Record-route individually, if you have more headers, you need to add more lines. However, it does cope with the Record-Route headers being on the same line. However, you could use it to get strict routing right (if you feel the urge).

More on SIPp when I get some spare time, or maybe I'll patch the code..(Don't hold your breath folks).