[Home]

Summary:ASTERISK-24889: Possible bug: PJSIP: stateless behavior when transport=tcp
Reporter:Anatoli (anatoli)Labels:
Date Opened:2015-03-17 02:09:42Date Closed:2015-03-17 05:41:14
Priority:MajorRegression?
Status:Closed/CompleteComponents:pjproject/pjsip
Versions:13.2.0 Frequency of
Occurrence
Constant
Related
Issues:
duplicatesASTERISK-22658 PJSIP: If a transport is set on an endpoint, Asterisk will not reuse established connections for that endpoint
Environment:OS: Ubuntu 14.04, with all updates Kernel: 3.13.0-44-generic pjsip: 2.3 from http://www.pjsip.org/release/2.3/pjproject-2.3.tar.bz2 (./configure --prefix=/usr --enable-shared --enable-epoll; make; sudo make install) Asterisk: 13.2.0 from http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13.2.0.tar.gz (./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var; make; sudo make install) Attachments:
Description:When an endpoint registers via TCP, PJSIP processes everything as corresponds: the communication is via TCP, REGISTER/ACK pass OK, the endpoint can even establish calls. But, when another endpoint calls to the first one, PJSIP sends INVITE message in a new TCP session to the already opened port.

So if the registration was performed from TCP 55880 to 5060 and everything except INVITE flows in the same TCP session, INVITE is sent via a new TCP session from a random port on asterisk server (e.g. 32926) to the already opened 55880 port. With tcpdump I see a new SYN packet (and the already established TCP session was not closed/reset yet):

{noformat}
From: 10.101.10.1 (asterisk IP)
To: 10.101.100.100 (endpoint IP)
Source port: 32926
Destination port: 55880
Protocol: TCP
TCP Data: [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=9227246 TSecr=0 WS=128
{noformat}

Naturally, the endpoint responds with a RST,ACK.


The CLI shows the following:

{noformat}
ERROR[19352]: pjsip:0 <?>:    tcpc0x7fcdb404 TCP connect() error: Connection refused [code=120111]
WARNING[19352]: pjsip:0 <?>:  tsx0x7fcdb402e Failed to send Request msg INVITE/cseq=31054 (tdta0x7fcdb4034260)! err=120111 (Connection refused)
{noformat}


Investigating the code, I've found that to send the INVITE message PJSIP calls pjsip_endpt_send_request_stateless, which, as the name indicates, behaves statelessly, though using TCP.


Call trace:

{noformat}
sip_dialog.c@1164 pjsip_dlg_send_request(INVITE) => @1214 call to pjsip_tsx_create_uac
sip_transaction.c@1266 pjsip_tsx_create_uac  => call to pjsip_tsx_create_uac2
sip_transaction.c@1273 pjsip_tsx_create_uac2  => @1367 tsx_on_state_null  callback assignment
sip_transaction.c@2311 tsx_on_state_null => @2351 call to tsx_send_msg
sip_transaction.c@2006 tsx_send_msg => @2120 call to pjsip_endpt_send_request_stateless
{noformat}

Asterisk 13.2.0, PJSIP 2.3, everything compiled from sources.

Config: same as in the examples except for one endpoint the transport=<tcp_transport> option is specified.

Client: a number of softphones, tested with latest Linphone on iPhone, SessionChat (freeware from AppStore), Jitsi on Windows.


Please let me know if additional information is required.

Regards,
Anatoli
Comments:By: Olle Johansson (oej) 2015-03-17 05:12:08.950-0500

Theory lesson:

The endpoint should register a listen port and not use that port when opening a session to Asterisk. Connection reuse happens if the endpoint signals support of the outbound extension to SIP - in that case Asterisk is allowed to reuse the existing TCP connection for the outbound request (the INVITE).

--- End theory lesson ---
Implementations may wary - some servers reuse connections as long as their open. They should NOT do this for TLS without outbound though.

Can you add the contact used at registration to this bug report? It's interesting to see how the client suggest that the server should connect to it.



By: Joshua C. Colp (jcolp) 2015-03-17 05:41:06.192-0500

This is a duplicate of ASTERISK-22658. If a "transport" is specified PJSIP will currently never reuse TCP connections. As well in order to have the existing connection reused the "rewrite_contact" option needs to be set to yes so the target address is the source.

By: Anatoli (anatoli) 2015-03-21 18:16:21.871-0500

Olle,

It looks like there are 2 problems involved in this issue. First one is what Joshua described, that res_pjsip won't reuse TCP connections if for the endpoint in question there is a {{transport=<transport_name>}} option specified in pjsip.conf.

But there is also another problem (as you suspected): the Contact header filed that the softphones send is (in my opinion) incorrectly formatted.

From SIP RFP: _"While the Via header field tells other elements where to send the response, the Contact header field tells other elements where to send future requests."_

And this is what Jitsi on Windows 7 sends:

{code}REGISTER sip:server_ip;transport=tcp SIP/2.0
Call-ID: dd753e83b597b5ca2a2e4f162775375e@0:0:0:0:0:0:0:0
CSeq: 1 REGISTER
From: "Name1" <sip:555@server_ip>;tag=1dde9f02
To: "Name1" <sip:555@server_ip>
Via: SIP/2.0/TCP host_ip:3409;branch=z9hG4bK-313537-071be23f01c7c2ee583675273d44e27d
Max-Forwards: 70
User-Agent: Jitsi2.6.5390Windows 7
Expires: 600
Contact: "Name1" <sip:555@host_ip:3409;transport=tcp;registering_acc=10_101_10_1>;expires=600
Content-Length: 0{code}

Here Via says _"send the responses to host_ip:3409"_ and Contact says _"send new requests (INVITE, BYE), establishing a new TCP session, to.. the same host_ip:3409"_. If I understand it correctly, {{Contact}} should say {{host_ip:5060}} or omit the port entirely for the default value to be applied. Nevertheless Jitsi listens on all 3 standard SIP ports: tcp/5060, tcp/5061 & udp/5060 on 0.0.0.0 (they are specified in the global SIP configuration section) BUT the 3409 (random) port appears in netstat as ESTABLISHED, _not_ LISTENING and it doesn't accept new incoming connections.

So, Jitsi expects incoming connections on 5060, but specifies the incoming port as 3409 in {{Contact}} field.


Same behavior is observed in Linphone and SessionChat/SessionTalk both on iPhone:

{code}REGISTER sip:server_ip SIP/2.0
Via: SIP/2.0/TCP host2_ip:59911;alias;branch=z9hG4bK.3kRQgBAbb;rport
From: <sip:777@server_ip>;tag=4Yzj~FqLz
To: sip:777@server_ip
CSeq: 20 REGISTER
Call-ID: 47V~RpZbNs
Max-Forwards: 70
Supported: outbound
Contact: <sip:777@host2_ip:59911;transport=tcp>;+sip.instance="<urn:uuid:1e603d84-0b11-42a7-83cb-7c34f71e0089>"
Expires: 600
User-Agent: LinphoneIphone/2.2.4.1-27-ge8ab36a (belle-sip/1.3.3)
Content-Length: 0{code}


{code}REGISTER sip:server_ip SIP/2.0
Via: SIP/2.0/TCP host2_ip:35210;branch=z9hG4bK-524287-1---0a74526f8a4d825c;rport;alias
Max-Forwards: 70
Contact: <sip:777@host2_ip:35210;rinstance=2a2202a7c0b108dd;transport=tcp>
To: "Name1"<sip:777@server_ip>
From: "Name1"<sip:777@server_ip>;tag=02dd3253
Call-ID: QFlg48EH71b0n3hklDy1IQ..
CSeq: 1 REGISTER
Expires: 600
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, SUBSCRIBE
Supported: replaces, norefersub
User-Agent: SessionTalk Version 5.11
Content-Length: 0{code}

A similar discussion is held in the pjsip dev mailing list: http://comments.gmane.org/gmane.comp.voip.pjsip/19202.