Sip.js: Missing Route header on ACK after reInvite.

Created on 17 Jan 2018  ·  7Comments  ·  Source: onsip/SIP.js

We are trying to update our SIP.js library from 0.7.5 to 0.9.1 .

We have a problem when we making Reinvite to add Video in call. The problem is that our Kamailio server doesn't sends Record-Route header in reINVITE call. According to SIP RFC this Kamailio behaviour is normal.

https://tools.ietf.org/html/rfc3261#section-12.1.2

The route set MUST be set to the list of URIs in the Record-Route header field from the response, taken in reverse order and preserving all URI parameters. If no Record-Route header field is present in the response, the route set MUST be set to the empty set. This route set, even if empty, overrides any pre-existing route set for future requests in this dialog. The remote target MUST be set to the URI from the Contact header field of the response

https://tools.ietf.org/html/rfc3261#section-12.2

Requests within a dialog MAY contain Record-Route and Contact header fields. However, these requests do not cause the dialog's route set to be modified, although they may modify the remote target URI.

As I can see in sip.js version 0.7.5 the Route header were always taken from request(this.request) but in sip.js version 0.9.1 it takes from last response(this.response) which in our case doesn't have Record-route header.

Here is the difference between versions:
0.7.5) https://www.dropbox.com/s/jo055zsn9286q17/Screenshot%202018-01-17%2013.40.41.png?dl=0
0.9.1) https://www.dropbox.com/s/u41kh91h3kzvt27/Screenshot%202018-01-17%2013.42.13.png?dl=0

So what i did is changed a bit your 0.9.1 code. If response has Record-Route header(s) we will add them to ACK, is not we will try to take it from request we had before. If we will had no Route we will just leave it empty.

https://www.dropbox.com/s/1rrhyfnxe9sa88a/Screenshot%202018-01-17%2013.50.11.png?dl=0

I just want to know why you changed behaviour. Is there is my or yours mistake ?

bug

Most helpful comment

Hey Denis, I looked into this and spoke with James about it.

This is a bug, but it appears the original behavior was also not correct in that it allowed the route set to be updated within a dialog.

The UAS behavior when responding to a dialog forming request, described in https://tools.ietf.org/html/rfc3261#section-12.1.1 , should be to copy the record route headers, reverse them and save them in a dialog scoped variable as the route set.

When responding to requests within a dialog the UAS behavior, as described in https://tools.ietf.org/html/rfc3261#section-12.2, should be to reuse the existing route set scoped within the dialog.

The current behavior of depending on the presence of record route headers on requests within a dialog to re-create the route set is not correct.

We will fix this in the next release, but in the meantime you can work around by calling record_route() for all requests, initial and sequential, so that record-route headers will be in sequential requests as https://tools.ietf.org/html/rfc3261#section-12.2 says is optional.

All 7 comments

The section you are looking for is actually section 14:

https://tools.ietf.org/html/rfc3261#section-14

Please check your code's functionality against that section, as section 12 does not apply in this case. Generally speaking, reINVITE support was not stable enough in 0.7.x to even be considered supported, but the support was fleshed out to spec in 0.8.x.

I thoroughly checked the section 14, and it says nothing about usage/modifying "routing set"

But coming back to section 12 - "route set" - has to be formed while initial INVITE processing, and reused without modification while in-dialog messages processing.
Citing of appropriate parts of RFC is given above.

For now the question is why "route set" is modified in-dialog (sip.js version 0.9.1 it takes from last response this.response) - as this is non RFC conformant.

Hey Denis, I looked into this and spoke with James about it.

This is a bug, but it appears the original behavior was also not correct in that it allowed the route set to be updated within a dialog.

The UAS behavior when responding to a dialog forming request, described in https://tools.ietf.org/html/rfc3261#section-12.1.1 , should be to copy the record route headers, reverse them and save them in a dialog scoped variable as the route set.

When responding to requests within a dialog the UAS behavior, as described in https://tools.ietf.org/html/rfc3261#section-12.2, should be to reuse the existing route set scoped within the dialog.

The current behavior of depending on the presence of record route headers on requests within a dialog to re-create the route set is not correct.

We will fix this in the next release, but in the meantime you can work around by calling record_route() for all requests, initial and sequential, so that record-route headers will be in sequential requests as https://tools.ietf.org/html/rfc3261#section-12.2 says is optional.

I am having the same issue, why is this issue closed while the issue is not actually fixed?
I managed to get the headers by finding the dialog and copying them from there.

diff --git a/src/SIPMessage.ts b/src/SIPMessage.ts
index a95e8ee..3226160 100644
--- a/src/SIPMessage.ts
+++ b/src/SIPMessage.ts
@@ -755,6 +755,9 @@ export class IncomingResponse extends IncomingMessage implements IncomingRespons
     if (!contact || !contact.uri) {
       throw new Error("Failed to parse contact header.");
     }
+
+    const dialog = this.ua.dialogs[this.callId + this.fromTag + this.toTag];
+
     const ruri = contact.uri;
     const request = new OutgoingRequest(
       C.ACK,
@@ -767,7 +770,7 @@ export class IncomingResponse extends IncomingMessage implements IncomingRespons
         fromTag: this.fromTag,
         toUri: this.to.uri,
         toTag: this.toTag,
-        routeSet: this.getHeaders("record-route").reverse()
+        routeSet: (dialog ? dialog.routeSet : this.getHeaders("record-route").reverse())
       },
       options ? options.extraHeaders : undefined,
       options ? options.body : undefined

0 points for the style I think, but I think the solution will be similar to this.

It looks like the original reporter closed the issue. I have reopened it and we are actively looking at this code.

Thank you @egreenmachine. This also affects hold/unhold (re-invites).

The case we had was the BYE packet not having the right routes after a hold re-invite.

Was this page helpful?
0 / 5 - 0 ratings