The aim of this document is to provide information about how to monitor the status of SIP servers with which your machine interacts with and how to make handling decisions based on their status using lib_srv_qualifier.js (https://github.com/yatevoip/yate-common/blob/master/scripts/lib_srv_qualifier.js) from yate-common (https://github.com/yatevoip/yate-common).
Enabling functionality
For this, in your Yate machine, you need to have enabled a script that loads and configures lib_srv_qualifier.js from SVN/yate-common. The script should look like this:
conf_name = “my_sip_qual”;
module_name = “my_sip_qual”;
Server.type = “SIP”;
#require “lib_srv_qualifier.js”
qualifier_init(true);
/* vi: set ts=8 sw=4 sts=4 noet: */
where:
- conf_name specifies the file to use for configuration.
- module_name specifies the name of the module and it is used in debug messages and in filtering Yate messages.
- Server.type specifies what kind of monitoring you want. Options are SIP and HTTP. For this case, SIP is the needed option.
In YateUCN, there is such a script that monitors SIP servers that is loaded by default. That script is ucn_sip_qual.
How it works
In order to determine the availability status of a SIP server, the script generates at the configured interval of time a SIP OPTIONS request for a server from its list of monitored servers. The request is generated by using ‘xsip.generate’ message. The server for which the request is generates is picked using round-robin, so every number_of_servers * check_interval seconds, that server is checked. The server is considered to be available if the response to SIP OPTIONS is in the 2xx range.
Upon receiving the response to the SIP options request, if there is a transition from one state to another (e.g up → down / down → up) the script will generate a notification message that looks like this:
Sniffed ‘xsip.qualify’ time=1604320653.400904
thread=0x6e2a3d0 ‘Engine Worker’
data=(nil)
retval='(null)’
param[‘server’] = ‘192.168.168.139’
param[‘name’] = ‘sip_139’
param[‘available’] = ‘false’
where:
- server is the SIP URI/address
- name is the name of the configuration section for this server
- available denotes the status of the server: true for up, false otherwise.
This message can then be caught by other modules in Yate that are interested in the state of SIP servers.
Configuration
Once the script in loaded, it will read as configuration the file with the name set from conf_name.
This configuration file specifies what servers should be monitored.
The configuration file for SIP monitoring should look like this:
[general]
check_interval=60
trans_count=3
[server gw139]
;enable=no
uri= 192.168.168.139
conn_id=core
trans_count=2
[server 192.168.168.241]
;enable=no
line=sip241
[server 999@192.168.168.11]
conn_id=core
The general section configures:
- check_interval: interval in seconds at which the script picks the server to check
- trans_count: number of SIP re-transmissions for SIP OPTIONS
Every sections that starts with server configures a server to be monitored. The configuration parameters for each section are:
- enable: boolean that enables or disables the checking of this servers
- uri: the SIP URI to use in the SIP OPTIONS message. If not provided, URI will be taken to be the name of the configuration sections without the ‘server ‘ prefix
- conn_id: the SIP listener to use for sending the SIP OPTIONS message towards the SIP server. Parameters line or conn_id must be present in a valid configuration
- line: the SIP account to use for sending the SIP OPTIONS message towards the SIP server. This is usually configured via accfile.conf. Parameters line or conn_id must be present in a valid configuration
- trans_count: this is the same parameter from the general configuration section and it is used to override the value from there.
Changes of parameters are applied on reload.
Using SIP monitoring for routing
The xsip.qualify messages sent by the SIP qualifier script can be used for making routing decisions for SIP calls based on the availability of the server. The script below provides an example on how to route a SIP call in round-robin fashion to available servers.
Engine.debugName(“sip_qual_routing”);
Message.trackName(“sip_qual_routing”);
// list of servers used to route a call, all considered to be down initially
sip_servers = {
“192.168.168.139” : false,
“192.168.168.241” : false,
“192.168.168.1” : false,
};
avail_srv = []; // list of servers that are available
idx = 0;
function onXsipQualify(msg)
{
if(sip_servers[msg.server] == undefined)
return;
sip_servers[msg.server] = msg.available;
// rebuild the list of available servers
avail_srv = [];
for (var s in sip_servers) {
if (sip_servers[s])
avail_srv.push(s);
}
Engine.debug(Engine.DebugInfo,”Available SIP servers:”,avail_srv.join());
return false; // let others to handle the message too
}
function onRoute(msg)
{
if (msg.called.startsWith(“123”)) {
if (!avail_srv.length) // no available servers
return false;
msg.retValue(“sip/sip:” + msg.called + “@” + avail_srv[idx++ % avail_srv.length]);
return true;
}
return false;
}
Message.install(onXsipQualify,”xsip.qualify”,50);
Message.install(onRoute,”call.route”,50);
This is a piece of log showing the xsip.qualify messages being caught by the script and routing of a call:
Sniffed ‘xsip.qualify’ time=1604327107.569913
thread=0x6e2a3b0 ‘Engine Worker’
data=(nil)
retval='(null)’
param[‘server’] = ‘192.168.168.1’
param[‘name’] = ‘192.168.168.1’
param[‘available’] = ‘true’
2020-11-02_14:25:07.578010 <sip_qual_routing:INFO> Available SIP servers: 192.168.168.241,192.168.168.1
Returned false ‘xsip.qualify’ delay=0.011641
thread=0x6e2a3b0 ‘Engine Worker’
data=(nil)
retval='(null)’
param[‘server’] = ‘192.168.168.1’
param[‘name’] = ‘192.168.168.1’
param[‘available’] = ‘true’
param[‘handlers’] = ‘sip_qual_routing:50’
Sniffed ‘call.route’ time=1604327187.849314
thread=0x7f60a00017c0 ‘RManager Connection’
data=(nil)
retval='(null)’
param[‘module’] = ‘tone’
param[‘cdrtrack’] = ‘false’
param[‘called’] = ‘123’
param[‘caller’] = ‘tone/dial’
Returned true ‘call.route’ delay=0.002136
thread=0x7f60a00017c0 ‘RManager Connection’
data=(nil)
retval=’sip/sip:123@192.168.168.241′
param[‘module’] = ‘tone’
param[‘cdrtrack’] = ‘false’
param[‘called’] = ‘123’
param[‘caller’] = ‘tone/dial’
param[‘handlers’] = ‘javascript:15,regexroute:40,cdrbuild:50,sip_qual_routing:50’
Using SIP qualifier with regexp
In order to use SIP qualifier with regexp, we need:
- Store/detect SIP server availability/status
To store the last detected SIP server status we need to add a regexroute routing rule to equipment:
It can be added from YateMMI in My Network -> Routing -> Equipment Type: select from dropdown -> Add
name : sip_qual
[extra]
xsip_qualify=120
[xsip_qualify]
; Store last detected SIP server status in variable srv_IP_address, to be used later in [default] routing section
.*=;$srv_${server}=${available}

2. Round-robin SIP servers that are up using regexp route rule
This can be also done from YateMMI -> Equipment -> pick equipment ->Edit -> Routing -> Add
name : round_robin
[default]
; Build a list of active servers, delete any previous value of variable_srv
; we will use YateUCN name and [default] routing section as examples
.*=;srv=
; example: YateUCN1
$(srv_192.168.168.139)=;srv=${srv},192.168.168.139
; example: YateUCN2
$(srv_192.168.168.241)=;srv=${srv},192.168.168.241
; Round-robin SIP servers that are up on YateUCN1 or YateUCN2 from YateUCN3
${srv}.=sip/sip:${called}${npdi}${rn}@$(index,$tkidx${srv})$()user=phone;srv;npdi;rn
; if no servers are available, throw an error and stop call routing
${srv}^$-;error=service-unavailable;reason=All gateways down
