Asterisk: processing registration events on a server using the example of interaction with the Multifon VoIP service
Hello, Habrahabr! In this article I want to talk about how you can solve the issue of automatically switching the mode of receiving calls in the Multiphone (gsm-to-gsm / gsm-to-sip) when registering a smartphone on the Asterisk server. Below we will explain why I needed it, what solution options were considered, and how it was eventually implemented. The following example was used on the basis of a home server running Debian Lenny along with Asterisk 1.6, but it will most likely work on other common Linux platforms.
Being a subscriber of Megafon, recently began to use their VoIP service. One of the features of the service is that in addition to making outgoing calls, you can receive incoming calls to a mobile number through a SIP client. I wanted to take this opportunity by setting up the connection of my smartphone to the Asterisk home server via SIP. I will not dwell on the registration procedure itself, connecting to the service and setting up the SIP account - this has already been written about enough. I wanted to do the following: when you connect your smartphone to the server, all incoming cellular calls begin to come through SIP; when disconnected from the server, the normal mode of receiving calls by the phone (gsm-to-gsm) should be restored.
To achieve this, it is necessary to fulfill at least two conditions:
1. “Multifon” should provide the ability to switch the mode of receiving cellular calls: receive to mobile, receive to a sip client. The service has such an opportunity, and it is implemented by sending a specific https request to the server (more about the request format can be found by clicking on the link indicated at the end of the article). The request can be executed from the console (for example, using curl or wget), which makes it possible to use it in scripts.
2. The server should “know” that a certain peer (smartphone) has registered on Asterisk, and when connecting / disconnecting, perform an https request. We will consider this question in more detail below.
It is necessary to determine the moment when the smartphone will register on the server. Having studied Asterisk’s reaction to the client’s connection and the available means of informing about the event, I determined for myself 2 main solutions: to find out about the event through the AMI (Asterisk manager API) or to process through the external script a list of connected clients that Asterisk displays with the command “sip show peers. " The second option was closer to me, so I decided to stay on it. ( By the way, now I thought that there is still a third way - to parse the output of the file / var / log / asterisk / full for the presence of the lines “Registered SIP 'peername'” and “Unregistered SIP 'peername'.” Perhaps this would be even simpler, but I went the other way. If you know simpler options, tell me, I will listen to them with pleasure ).
Let's see what the server writes:
In the column “Host” for disconnected clients we see the inscription (Unspecified), and for registered ones - IP-address. This data is enough to determine the registration status of the client. Thus, the task boiled down to writing a script that would query the server for the status of the necessary sip account (smartphone - mywifipeer), and if its registration status had changed, send an https request. To control the changes made, information about the event will be duplicated in jabber. Next, the script is placed in cron and executed every minute.
Since the script will work on demand, and not as a daemon, to determine that the connection status has changed, you must have information about how it was at the time of the previous launch. If this is not done, our script will DOS the megaphone server, sending him a request to set the GSM mode every time during the check, which is bad. Therefore, the first time the script calls, it will put information about the current status ($ peer_state_now) into an external file ($ peer_state_last_file), and all subsequent ones will read information from this file ($ peer_state_last) and check against the current status.
Curl was used to send the http request, sendxmpp ($ xmpp_bin and $ xmpp_jid) was used to notify the gabber. Before using the script, you must specify the login password corresponding to the Multifon-SIP registration record ($ multifon_login and $ multifon_password).
It remains to add the launch of the script in / etc / crontab
Done! Now you can check the health of the entire system. We connect the phone to the server and in a minute we get a confirmation message in jabber. We make a test call to the phone and make sure that everything works as it was intended.
Multifon: http-request format, server responses and code processing
Briefly on the background of the issue
Being a subscriber of Megafon, recently began to use their VoIP service. One of the features of the service is that in addition to making outgoing calls, you can receive incoming calls to a mobile number through a SIP client. I wanted to take this opportunity by setting up the connection of my smartphone to the Asterisk home server via SIP. I will not dwell on the registration procedure itself, connecting to the service and setting up the SIP account - this has already been written about enough. I wanted to do the following: when you connect your smartphone to the server, all incoming cellular calls begin to come through SIP; when disconnected from the server, the normal mode of receiving calls by the phone (gsm-to-gsm) should be restored.
What is needed to complete the task
To achieve this, it is necessary to fulfill at least two conditions:
1. “Multifon” should provide the ability to switch the mode of receiving cellular calls: receive to mobile, receive to a sip client. The service has such an opportunity, and it is implemented by sending a specific https request to the server (more about the request format can be found by clicking on the link indicated at the end of the article). The request can be executed from the console (for example, using curl or wget), which makes it possible to use it in scripts.
2. The server should “know” that a certain peer (smartphone) has registered on Asterisk, and when connecting / disconnecting, perform an https request. We will consider this question in more detail below.
In search of a solution
It is necessary to determine the moment when the smartphone will register on the server. Having studied Asterisk’s reaction to the client’s connection and the available means of informing about the event, I determined for myself 2 main solutions: to find out about the event through the AMI (Asterisk manager API) or to process through the external script a list of connected clients that Asterisk displays with the command “sip show peers. " The second option was closer to me, so I decided to stay on it. ( By the way, now I thought that there is still a third way - to parse the output of the file / var / log / asterisk / full for the presence of the lines “Registered SIP 'peername'” and “Unregistered SIP 'peername'.” Perhaps this would be even simpler, but I went the other way. If you know simpler options, tell me, I will listen to them with pleasure ).
Let's see what the server writes:
asterisk*CLI> sip show peers
Name/username Host Dyn Nat ACL Port Status
peer1/peer1 192.168.XXX.XXX D 5060 Unmonitored
peer2/peer2 (Unspecified) D 5060 Unmonitored
peer3/peer3 192.168.XXX.XXX D 5060 Unmonitored
multifon/7922XXXXXXX 193.201.229.35 5060 OK (34 ms)
sipnet/sipnet 212.53.40.40 5060 Unmonitored
mywifipeer/mywifipeer (Unspecified) D 0 Unmonitored
6 sip peers [Monitored: 1 online, 0 offline Unmonitored: 4 online, 1 offline]
In the column “Host” for disconnected clients we see the inscription (Unspecified), and for registered ones - IP-address. This data is enough to determine the registration status of the client. Thus, the task boiled down to writing a script that would query the server for the status of the necessary sip account (smartphone - mywifipeer), and if its registration status had changed, send an https request. To control the changes made, information about the event will be duplicated in jabber. Next, the script is placed in cron and executed every minute.
Since the script will work on demand, and not as a daemon, to determine that the connection status has changed, you must have information about how it was at the time of the previous launch. If this is not done, our script will DOS the megaphone server, sending him a request to set the GSM mode every time during the check, which is bad. Therefore, the first time the script calls, it will put information about the current status ($ peer_state_now) into an external file ($ peer_state_last_file), and all subsequent ones will read information from this file ($ peer_state_last) and check against the current status.
Curl was used to send the http request, sendxmpp ($ xmpp_bin and $ xmpp_jid) was used to notify the gabber. Before using the script, you must specify the login password corresponding to the Multifon-SIP registration record ($ multifon_login and $ multifon_password).
Asterisk_peer_check script
#!/bin/bash
#
# press F1 for help
if [ -z "$1" ]; then
echo "Usage: $0 "
exit 1
fi
# determining the future...
peer=$1
path="/var/spool/asterisk/tmp"
peer_state_last_file="$path/peer_state_$peer"
# Multifon account
multifon_login="7922XXXXXXX@multifon.ru"
multifon_password="mypassword"
# Jabber account for report
xmpp_jid="change_me@jabberserver.ru"
xmpp_bin="sendxmpp"
#getting actual peer state from asterisk
peer_state_now=`asterisk -rx "sip show peers" | grep -i $peer | awk '{print $2}'`;
#getting previous peer state from file
if [ -f "$peer_state_last_file" ];
then
peer_state_last=`cat $peer_state_last_file`
else
#first run
peer_state_last=$peer_state_now
fi
#comparing actual peer status with previous
if [ "$peer_state_now" != "$peer_state_last" ]
then
#peer status changed
if [ "$peer_state_now" = "(Unspecified)" ]
then
#GSM-2-GSM
multifon_routing="0"
else
#GSM-2-SIP
multifon_routing="1"
fi
#changing multifon status
multifon_url="https://sm.megafon.ru/sm/client/routing/set?login=$multifon_login&password=$multifon_password&routing=$multifon_routing"
curl --silent $multifon_url >/dev/null
#jabber announce, if sendxmpp installed
which $xmpp_bin >/dev/null || [ $? -eq 0 ] && echo "[`hostname`] Asterisk: Megafon incoming calls set to $multifon_routing" | $xmpp_bin -i $xmpp_jid
fi
#writing actual peer state in file
echo $peer_state_now > $peer_state_last_file
#
It remains to add the launch of the script in / etc / crontab
#
* * * * * root /etc/cron/asterisk_peer_check mywifipeer
#
Done! Now you can check the health of the entire system. We connect the phone to the server and in a minute we get a confirmation message in jabber. We make a test call to the phone and make sure that everything works as it was intended.
References:
Multifon: http-request format, server responses and code processing