Pull to refresh

Asterisk: обработка регистрационных событий на сервере на примере взаимодействия с VoIP-сервисом «Мультифон»

Reading time5 min
Views21K
Здравствуй, Хабрахабр! В этой статье я хочу поведать о том, как можно решить вопрос автоматического переключения режима приёма звонков в «Мультифоне» (gsm-to-gsm/gsm-to-sip) при регистрации смартфона на сервере Asterisk. Ниже будет рассказано, для чего мне это понадобилось, какие варианты решения рассматривались, и как в итоге было реализовано. Приведённый ниже пример был использован на базе домашнего сервера под управлением Debian Lenny вместе с Asterisk 1.6, но с большой вероятностью будет работать и на других распространённых Linux-платформах.

Вкратце о предыстории вопроса


Являясь абонентом Мегафона, с недавнего времени стал пользоваться их VoIP-сервисом. Одной из особенностей сервиса является то, что кроме совершения исходящих, можно принимать входящие на мобильный номер звонки через SIP-клиент. Этой возможностью мне и захотелось воспользоваться, настроив подключение своего смартфона к домашнему серверу Asterisk через SIP. На самой процедуре регистрации, подключении к услуге и настройке SIP-аккаунта, я останавливаться не буду — про это уже достаточно написано. Хотелось сделать следующее: при подключении смартфона к серверу, все входящие сотовые звонки начинают поступать через SIP; при отключении от сервера должен восстанавливаться обычный режим приёма звонков телефоном (gsm-to-gsm). Решение должно быть максимально автоматизированным и требовать от меня не более одного движения — нажатия на кнопку подключения к серверу на рабочем столе смартфона.

Что необходимо для выполнения задачи


Для реализации задуманного необходимо выполнение как минимум двух условий:
1. «Мультифон» должен предоставлять возможность переключения режима приёма сотовых звонков: приём на сотовый, приём в sip-клиент. Такая возможность у сервиса есть, и реализована она через отправку определённого https-запроса на сервер (подробнее о формате запроса можно прочитать перейдя по ссылке, указанной в конце статьи). Запрос можно выполнить из консоли (например при помощи curl или wget), что делает возможным его использование в скриптах.
2. Сервер должен «знать», что на Asterisk'e зарегистрировался определённый peer (смартфон), и при подключении/отключении выполнить https-запрос. Подробнее рассмотрим это вопрос ниже.

В поисках решения


Необходимо определить момент, когда смартфон зарегистрируется на сервере. Изучив реакцию Asterisk'a на подключение клиента и доступные средства информирования о произошедшем событии, определил для себя 2 основных варианта решения: узнать о событии через AMI (Asterisk manager API) или обрабатывать через внешний скрипт список подключенных клиентов, которые Asterisk выводит по команде «sip show peers». Мне был ближе второй вариант, поэтому я решил остановиться на нём. (Кстати, сейчас подумал о том, что есть еще третий способ — парсить вывод файла /var/log/asterisk/full на предмет наличия строк «Registered SIP 'peername'» и «Unregistered SIP 'peername'». Возможно, так было бы даже проще, но я пошел по другому пути. Если вы знаете более простые варианты, расскажите, я их с удовольствием выслушаю).

Посмотрим, что пишет сервер:

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]

В колонке «Host» у отключенных клиентов видим надпись (Unspecified), а у зарегистрированных — IP-адрес. Этих данных достаточно для того, чтобы определить состояние регистрации у клиента. Таким образом задача свелась к тому, чтобы написать скрипт, который будет опрашивать на сервере состояние необходимого sip-аккаунта (смартфон — mywifipeer), и если состояние его регистрации изменилось, отправлять https-запрос. Для контроля внесённых изменений, информацию о произошедшем событии будем дублировать в jabber. Далее скрипт помещается в cron и выполняется ежеминутно.

Поскольку скрипт будет работать по запросу, а не как демон, для определения того, что статус подключения изменился, необходимо иметь информацию о том, каким он был в момент предыдущего запуска. Если этого не сделать, наш скрипт будет DOS'ить мегафоновский сервер, отправляя ему запрос на установку GSM-режима каждый раз во время проверки, что плохо. Поэтому при первом вызове скрипт поместит информацию о текущем статусе ($peer_state_now) во внешний файл ($peer_state_last_file), а все последующие — будет читать информацию из этого файла ($peer_state_last) и сверяться с текущим статусом.

Для отправки http-запроса использовался curl, для уведомления в жаббер — sendxmpp ($xmpp_bin и $xmpp_jid). Перед использованием скрипта необходимо задать логин-пароль, соответствующий регистрационной записи Мультифон-SIP ($multifon_login и $multifon_password).

Скрипт asterisk_peer_check



#!/bin/bash                                                                                                                     
#
# press F1 for help
if [ -z "$1" ]; then
    echo "Usage: $0 <peer_name>"
    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
#

Осталось добавить запуск скрипта в /etc/crontab

#
* *     * * *   root    /etc/cron/asterisk_peer_check mywifipeer
#

Готово! Теперь можно проверить работоспособность всей системы. Подключаемся телефоном к серверу и через минуту получаем в jabber подтверждающее сообщение. Делаем тестовый звонок на телефон и убеждаемся в том, что все работает так, как и было задумано.

Ссылки:


Мультифон: формат http-запроса, ответы сервера и обработка кодов
Tags:
Hubs:
+16
Comments14

Articles