Skip to content

ysipchan MESSAGE picks wrong connection #19

@DigitalBrains1

Description

@DigitalBrains1

When you have multiple listeners and/or TCP listeners, ysipchan needs to pick a connection to use to send out SIP messages. For voice call setup, it uses the oconnection_id parameter for that, but for SIP MESSAGEs, it seems to pick connection_id, which is the incoming connection, not the outgoing one.

Modifying the msg.execute YATE message to set connection_id to the correct connection as well as setting ip_transport to the correct value for the outgoing connection, makes the SIP MESSAGE go out to the correct target.

It would seem that voice call setup, for example the call.execute YATE message, picks the outgoing connection from oconnection_id but that SIP MESSAGE messaging picks the outgoing connection from connection_id instead, and that the latter is wrong.

I believe the fix would be to make msg.execute in ysipchan work the same way as call.execute in this respect, and pick oconnection_id (and ignore the value set for ip_transport, which refers to the incoming connection).

Workaround

(I happen to use sqlite as the database, so that is the dialect used here)

Store the user's transport_ip value on register (as well as oconnection_id, which was already there to support multiple listeners in the first place):

register.conf:

[user.register]
query=UPDATE users SET oconnection_id='${oconnection_id}',oconnection_transport='${ip_transport}',location='${data}',expires=datetime('now', '${expires} seconds') WHERE username='${username}'

[call.route]
query=SELECT location,oconnection_id,oconnection_transport,(CASE WHEN location IS NULL THEN 'offline' ELSE NULL END) AS error FROM users WHERE username='${called}'
result=location

and then patch msg.execute to overwrite connection_id and ip_transport with the values for the outgoing connection:

regexroute.conf:

[extra]
msg.execute=90

[msg.execute]
.*=return;connection_id=${oconnection_id};ip_transport=${oconnection_transport}

Details

All the details

When using multiple listeners:

ysipchan.conf:

[general]
ipv6_support=yes
type=udp
ipv6=yes
udp_force_bind=no
useragent=YATE
generate=enable

[listener udp4]
type=udp
ipv6=no
udp_force_bind=no

[listener tcp6]
type=tcp
ipv6=yes

[listener tcp4]
type=tcp
ipv6=no

ysipchan needs to have a way to select which connection it is going to send an outgoing SIP message on. I have this configured as follows:

register.conf:

[user.register]
query=UPDATE users SET oconnection_id='${oconnection_id}',location='${data}',expires=datetime('now', '${expires} seconds') WHERE username='${username}'

[call.route]
query=SELECT location,oconnection_id,(CASE WHEN location IS NULL THEN 'offline' ELSE NULL END) AS error FROM users WHERE username='${called}'
result=location

I store oconnection_id on user.register and retrieve it on call.route. When a call is routed to a user connected on the tcp6 listener while originating from the udp4 listener, we see something like this (partly redacted for privacy):

2025-07-07_11:21:34.626092 Returned true 'call.execute' delay=0.001462
  param['address'] = '10.222.7.<calling user address>:5060'
  param['ip_host'] = '10.222.7.<calling user address>'
  param['ip_port'] = '5060'
  param['ip_transport'] = 'UDP'
  param['address'] = '10.222.7.<calling user address>:5060'
  param['connection_id'] = 'udp4'
  param['connection_reliable'] = 'false'
  param['oconnection_id'] = 'tcp:[2a10:3781:1696:<YATE address>]:5060-[2a10:3781:1696:<called user address>]:46726'
  param['callto'] = 'sip/sip:101@[2a10:3781:1696:<called user address>]:46726;transport=Tcp;line=jru96hpi'

2025-07-07_11:21:34.628858 <sip:INFO> 'tcp:[2a10:3781:1696:<YATE address>]:5060-[2a10:3781:1696:<called user address>]:46726' sending 881 bytes 'INVITE sip:101@[2a10:3781:1696:<called user address>]:46726;transport=Tcp;line=jru96hpi' 0x7fd544020580 [0x7fd55c001020]

(Somehow, this YATE message has the address parameter twice; I only notice this as I'm editing the parameter list here. Weird!)

However, if we enable SIP MESSAGEs:
ysipchan.conf:

[message]
enable=yes

then we can't send a message to that TCP user; it picks the incoming connection (here udp4) for the outgoing message, which of course fails:

2025-07-07_12:01:08.944308 Returned true 'msg.execute' delay=0.003161
  param['connection_id'] = 'udp4'
  param['connection_reliable'] = 'false'
  param['ip_host'] = '10.0.2.<sender address>'
  param['ip_port'] = '58745'
  param['ip_transport'] = 'UDP'
  param['address'] = '10.0.2.<sender address>:58745'
  param['oconnection_id'] = 'tcp:[2a10:3781:1696:<YATE address>]:5060-[2a10:3781:1696:<recipient address>]:46726'
  param['callto'] = 'sip/sip:101@[2a10:3781:1696:<recipient address>]:46726;transport=Tcp;line=jru96hpi'

2025-07-07_12:01:08.946437 <sip:INFO> 'udp:0.0.0.0:5060' sending 683 bytes 'MESSAGE sip:101@[2a10:3781:1696:<recipient address>]:46726;transport=Tcp;line=jru96hpi' 0x7fd544077b70 to [2a10:3781:1696:<recipient address>]:46726 [0x56099b5bf7e0]

2025-07-07_12:01:08.946506 <sip:WARN> Transport(udp4) Socket send error: Address family not supported by protocol (97) [0x56099b5bf7e0]

2025-07-07_12:01:08.946516 <sipengine:INFO> SIPTransaction send failed state=Trying: clearing [0x7fd544066400]

With the workaround above, overwriting connection_id and ip_transport (other fields don't matter), we get the correct result:

2025-07-07_12:08:47.015993 Returned true 'msg.execute' delay=0.001831
  param['connection_id'] = 'tcp:[2a10:3781:1696:<YATE address>]:5060-[2a10:3781:1696:<recipient address>]:40503'
  param['connection_reliable'] = 'false'
  param['ip_host'] = '10.0.2.<sender address>'
  param['ip_port'] = '56361'
  param['ip_transport'] = 'TCP'
  param['address'] = '10.0.2.<sender address>:56361'
  param['oconnection_id'] = 'tcp:[2a10:3781:1696:<YATE address>]:5060-[2a10:3781:1696:<recipient address>]:40503'
  param['oconnection_transport'] = 'TCP'
  param['callto'] = 'sip/sip:101@[2a10:3781:1696:<recipient address>]:40503;transport=Tcp;line=jru96hpi'

2025-07-07_12:08:47.023039 <sip:INFO> 'tcp:[2a10:3781:1696:<YATE address>]:5060-[2a10:3781:1696:<recipient address>]:40503' sending 687 bytes 'MESSAGE sip:101@[2a10:3781:1696:<recipient address>]:40503;transport=Tcp;line=jru96hpi' 0x7f8958076030 [0x7f8978001020]

Since only connection_id and ip_transport seem to matter, the other fields still refer to the sender, which makes for a bit of an odd read of those parameters together.

(I use the word message in three different senses; unfortunate, but it's difficult to avoid. Sometimes I mean just any command flow occuring over SIP, sometimes I mean the SIP MESSAGE method, and sometimes I mean the things happening in the message passing system inside YATE. I think it's clear when I mean what.)

Environment

CPU: x86-64
OS: Debian bookworm/stable
YATE: Compiled from master, slightly behind at 25a425e

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions