Menu

#56 Response Record Route header not set

jiplet
open
Becky Mc
Jiplet (19)
8
2014-05-09
2009-04-22
Becky Mc
No

I have been implementing a UAC and UAS using the NIST Jain Sip stack and the SipPhone,SipCall etc classes from SipUnit. My testing is using the Jiplet ref as the sip proxy.

The UAC and the UAS have only the TCP transport listener.

I create an INVITE in the UAC which is sent to the UAS via the proxy. I get the correct responses back i.e. TRYING,RINGING and then the Answer.

The UAC then tries to create an ACK message by making a call to SIPDialog.createAck and the following error occurs:

2009-04-22 11:47:17,459 [Thread-6] com.sit.sip.DoSipCall - Error message Exception: java.lang.RuntimeException: Unexpected internal error FIXME!! Cannot create ACK - no ListeningPoint for transport towards next hop found:UDP on stack testAgent1
Unexpected internal error FIXME!! Cannot create ACK - no ListeningPoint for transport towards next hop found:UDP
javax.sip.SipException: Cannot create ACK - no ListeningPoint for transport towards next hop found:UDP
at gov.nist.javax.sip.stack.SIPDialog.createAck(SIPDialog.java:1997)
at com.sit.sip.SipCall.sendInviteOkAck(SipCall.java:1859)
at com.sit.sip.DoSipCall.run(DoSipCall.java:71)

Looking at SIPDialog.createAck the following piece of code decides on the transport:

if (this.routeList != null && !this.routeList.isEmpty()) {
Route r = (Route) this.routeList.getFirst();
uri4transport = ((SipURI) r.getAddress().getURI());
} else { // should be !=null, checked above
uri4transport = ((SipURI) this.remoteTarget.getURI());
}

String transport = uri4transport.getTransportParam();
if (transport == null) {
// JvB fix: also support TLS
transport = uri4transport.isSecure() ? ListeningPoint.TLS : ListeningPoint.UDP;
}
ListeningPointImpl lp = (ListeningPointImpl) sipProvider.getListeningPoint(transport);
if (lp == null) {
sipStack.getLogWriter().logError("remoteTargetURI " + this.remoteTarget.getURI());
sipStack.getLogWriter().logError("uri4transport = " + uri4transport);
sipStack.getLogWriter().logError("No LP found for transport=" + transport);
throw new SipException(
"Cannot create ACK - no ListeningPoint for transport towards next hop found:"
+ transport);
}

The responses from the proxy to the UAC for the INVITE request are listed below and what we can see is that the Record-Route Header is present but the transport parameter is not set. Since the createAck looks at this first it defaults to UDP, for which there is no listener set up, hence the failure.

SIPUNIT TRACE: 1240364836474 SipSession:waitResponse
SIPUNIT TRACE: 1240364836474 SipSession:waitResponse waiting for event
SIPUNIT TRACE: 1240364837349 SipStackLocal:processResponse:testAgent1 SIP/2.0 200 Answer - Hello world
Call-ID: e192917b74dcb18069346f8a36c748b1@192.168.0.93
CSeq: 1 INVITE
From: <sip:amit@sitsydws025.sit.com.au>;tag=323395978
To: <sip:becky@sitsydws025.sit.com.au>;tag=2012341050
Via: SIP/2.0/TCP 192.168.0.93:3000;branch=z9hG4bK55e9a17cc5f7c4ff3e3e0c02d8431cf0;rport=3000
Record-Route: <sip:192.168.0.89:5060;lr>
Contact: <sip:becky@sitsydws025.sit.com.au:4000;transport=tcp>
Expires: 0
Content-Length: 0

The response coming into the proxy from the UAS is shown below and shows the shows the Record-Route header has the transport parameter set but has not been propagted:

SIP/2.0 200 Answer - Hello world
Call-ID: e192917b74dcb18069346f8a36c748b1@192.168.0.93
CSeq: 1 INVITE
From: <sip:amit@sitsydws025.sit.com.au>;tag=323395978
To: <sip:becky@sitsydws025.sit.com.au>;tag=2012341050
Via: SIP/2.0/TCP 192.168.0.89:5060;branch=z9hG4bKdf5f5c599287a8fc1d18a2d65375660
2;rport=5060,SIP/2.0/TCP 192.168.0.93:3000;branch=z9hG4bK55e9a17cc5f7c4ff3e3e0c0
2d8431cf0;rport=3000
Record-Route: <sip:192.168.0.89-5060@192.168.0.89:5060;transport=tcp;lr>
Contact: <sip:becky@sitsydws025.sit.com.au:4000;transport=tcp>
Expires: 0
Content-Length: 0

My fix to this problem is to modify ResponseForwarding.java class as such, I have added the four lines under the comment "check for transport" :

while (rrHeaders.hasNext())
{
// look for the 1st one to replace, replace it & get out
RecordRouteHeader rr = (RecordRouteHeader) rrHeaders.next();
jiplet.info("ResponseForwarding:forwardResponse RecordRoute = " + rr.toString());
URI uri = rr.getAddress().getURI();
if (uri instanceof SipURI)
{
SipURI sipURI = (SipURI) uri;
// is this a record route header we added?
if (jiplet.hasAddress(sipURI.getHost(), sipURI
.getPort()))
{
// does this one need replacing?
String user = sipURI.getUser();
if (user != null)
{
StringTokenizer tok = new StringTokenizer(user,
"-");
if (tok.countTokens() == 2)
{
SipURI sourceURI = jiplet
.getAddressFactory().createSipURI(
null, tok.nextToken());

sourceURI.setPort(Integer.valueOf(
tok.nextToken()).intValue());
sourceURI.setLrParam();

//check for transport
String protocol = sipURI.getTransportParam();
if (null != protocol){
jiplet.info("ResponseForwarding:forwardResponse transport = " + protocol);
sourceURI.setTransportParam(protocol);
}

// rewrite it back into the RR header
rr.getAddress().setURI(sourceURI);
rrHeaders.set(rr);
break;
}
}
}
}
}

Discussion

MongoDB Logo MongoDB