Сравниваем конфигурации Freeswitch и Asterisk для одной задачи
Для чемпионата мира в России, который прошёл в 2018 году, нужно было решить задачу авторизации пользователей для услуги Wi-Fi при помощи звонка на телефонный номер как один из способов авторизации. Для решения использованы аналогичные конфигурации Freeswtich и Asterisk.
Смысл в том, что пользователь вводит номер телефона своего смартфона\планшета\компьютера через веб-форму авторизации в Wi-Fi сети, далее, пользователь выбирает каким способом он подтвердит, что это действительно его мобильный номер: при помощи отправки SMS-сообщения или звонком на номер телефона, где ему должна проиграться голосовая подсказка о успешности\неуспешности авторизации, в зависимости от языка интерфейса(русский, английский, французский, немецкий или испанский). Голосовая платформа Asterisk\Freeswith передаёт номер позвонившего серверу авторизации, сервер сверяет телефонный номер полученный через веб-форму с номером, который передала голосовая платформа, в ответ возвращается успешный или неуспешный код. Сообщение должно проигрываться в предответном состоянии до начала тарификации, чтобы абонент не платил деньги за звонок. Так как Asterisk и Freeswitch в этой схеме выполняют функции медиасерверов, будем называть далее их именно так.
Терминация из телефонных сетей на медасерверы работала через два транковых шлюза Eltex SMG1016M, голосовых платформ тоже две: первая Asterisk 15.3.0 установленный на ОС Linux Debian 9.4, вторая FreeSWITCH Version 1.6.20 установленная на ОС Linux Debian 8.10. В июне 2018 FreeSWITCH ещё не поддерживал ОС Linux Debian 9 для «продакшен» режима.
Asterisk и Freeswitch запущены на виртуальных машинах, основные пики нагрузки приходились, когда начинались футбольные матчи.
Главный минус схемы с такой авторизацией – иногда из телефонной сети общего пользования может приходить искажённый номер вызывающего абонента(А-номер), в таком случае пользователь не будет авторизован, хотя правильно указал свои данные. Данная ситуация была замечена у одного сотового оператора для парных номеров: федеральный номер плюс местный городской номер в которых равны последние 7 цифр номера.
Техническая реализация
Создан пул телефонных номеров равный количеству языков – 5, звонки на любой из 5 телефонных номеров по очереди попадает на шлюзы SMG1016: 192.168.25.8 и 192.168.25.9, на каждом из шлюзов созданы транковые направления терминации состоящие из двух транковых групп, по одной на медиасервер (Asterisk и Freeswitch), алгоритм работы направлений для терминации: последовательно вперёд.
Заметку по маршрутизации на шлюзах Элекс SMG можно найти по данной ссылке.
Оба шлюза подключены к городской АТС, где также создана группа терминации с алгоритмом работы по очереди. Такая схема даёт равномерное распределение нагрузки по шлюзам и медиасерверам.
Когда медиасервер получает вызов, он делает запрос по http на сервер авторизации куда в фомате JSON передаёт номер телефонный позвонившего и телефонный номер для авторизации куда позвонил пользователь:
1 | data={ 'user_phone' : user_phone, 'gw_phone' : gw_phone} |
В ответ сервер передаёт код ответа и результат в формате:
1 | resultCode=1&resultMessage=accepted |
Если,
- resultCode = 1 – проиграть подсказку об успешно авторизации
- Любой другой код – проиграть сообщение об ошибке
В статье я не буду касаться вопросов инсталляции Asterisk и Freeswtich, рассмотрю только необходимую конфигурации внешнего канала SIP и дайлплана, также скриптов которые делают запрос по http и возвращают результат.
Медиасервер Astersik
IP-адрес=192.168.25.32
Здесь из дайлплана при помощи AGI вызываем внешний скрипт, который сделает запрос на сервер и вернёт результат.
Настройка внешних каналов SIP для приёма трафика от шлюзов, файл /etc/asterisk/sip.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [FIFA-1] type=peer context=FIFA-IN host=192.168.25.8 ;Шлюз 1 SMG1016M insecure=port,invite disallow=all allow=ulaw nat=no canreinvite=no use_q850_reason = yes [FIFA-2] type=peer context=FIFA-IN host=192.168.25.9 ;Шлюз 2 SMG1016M insecure=port,invite disallow=all allow=ulaw nat=no canreinvite=no use_q850_reason = yes |
Здесь вызовы с любого из двух шлюзов отправляются в контекст FIFA-IN.
Дайплан Asterisk, файл /etc/asterisk/extensions.ael
Приведу только первые два номера, напомню, что всего языков подсказок 5 и номеров столько же, соответственно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | context FIFA-IN { 78120002915 => { AGI(get-res.py,${CALLERID(num)},${EXTEN:1}); Set(CDR(userfield)=${ANSWER}); NoOp(RES => ${RES}); switch (${RES}) { case 1: Progress(); Playback(/var/lib/asterisk/sounds/fifa/success_readyRUS1,noanswer); Busy(10); Hangup(16); default: Progress(); Playback(/var/lib/asterisk/sounds/fifa/Fail_RUS1,noanswer); //Playback(/var/lib/asterisk/sounds/ru/agent-alreadyon,noanswer); Busy(10); Hangup(16); }; }; 78120002916 => { //English AGI(get-res.py,${CALLERID(num)},${EXTEN:1}); Set(CDR(userfield)=${ANSWER}); NoOp(RES => ${RES}); switch (${RES}) { case 1: Progress(); Playback(/var/lib/asterisk/sounds/fifa/Success_readyEN1,noanswer); Busy(10); Hangup(16); default: Progress(); Playback(/var/lib/asterisk/sounds/fifa/Fail_EN1,noanswer); //Playback(/var/lib/asterisk/sounds/ru/agent-alreadyon,noanswer); Busy(10); Hangup(16); }; }; }; |
Любой вызов, пришедший со шлюзов 192.168.25.8 и 192.168.25.9 попадает в контекст FIFA-IN дайлплана Asterisk, здесь, в зависимости от одного из пяти набранных номеров, вызов попадает на нужный экстеншен, например, 78120002916, при помощи приложения AGI вызывается внешний скрипт из директории по умолчанию /var/lib/asterisk/agi-bin. Результат работы скрипта передаётся оператору выбора case, далее, приложение Progress() указывает Asterisk что не нужно посылать SIP 200OK, что равно соединению и началу тарификации, а проиграть голосовое сообщение в режиме предответа(early media) с помощью приложения Playback, затем послать сигнал занято — Busy(10) и повесить трубку Hangup. Аудиофайлы, которые нужно проиграть загружаются в /var/lib/asterisk/sounds/ru/.
Для контроля содержимого ответа в CDR Asterisk добавим содержимое переменой ANSWER при помощи приложения Set,
Set(CDR(userfield)=${ANSWER});
Далее, в примере CDR содержимое полученного значения переменной будет продемонстрировано.
Ниже два примера скрипта написанные на bash и Python3, скрипты передают номера и возвращают в дайлплан результат.
#cat /var/lib/asterisk/agi-bin/get-res.sh
1 2 3 4 5 6 7 8 | #!/bin/bash res=`curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "user_phone=$1&gw_phone=$2" http: //wfff-loginpage :8008 /ivr_auth | sed -n 's/^.*resultCode=\([^&]*\).*$/\1/p' | sed "s/%20/ /g" ` echo $res echo -e "SET VARIABLE RES $res" ; sleep 0 exit 0 |
Здесь я использовал консольную утилиту curl для http запроса на сервер авторизации. Кстати, последняя строчка exit 0, иначе в консоли Asterisk будут появляться ошибки результаты работы AGI-скрипта.
Ниже аналогичный скрипт на языке Python3, который я использовал в «боевой» конфигурации.
1 2 3 4 5 6 7 8 9 | #!/usr/bin/env python3 import requests from sys import argv user_phone,gw_phone = argv[ 1 :] answer = requests.post( 'http://wfff-loginpage:8008/ivr_auth' ,headers = { 'Content-Type' : 'application/x-www-form-urlencoded' },data = { 'user_phone' : user_phone, 'gw_phone' : gw_phone}) #res='resultCode=0&resultMessage=rejected' answer = str (answer.content) print ( "SET VARIABLE RES %s" % answer[ 13 ] + "\n" + "SET VARIABLE ANSWER %s" % answer) |
Здесь я использовал отличный модуль для http запросов requests. На этом настройка Asterisk закончена.
В CDR вызовы будут выглядеть так:
1 2 3 | "","+00000637658","sw_5_0","FIFA-IN",""""" <+00000637658>","SIP/FIFA-1-000034c0","","Busy","10","2018-07-15 18:54:34",,"2018-07-15 18:54:41",7,0,"BUSY","DOCUMENTATION","1531670074.27007","b'resultCode=0&amp;resultMessage=rejected'" "","79060003159","sw_4_1","FIFA-IN",""""" <79060003159>","SIP/FIFA-2-000034c1","","Busy","10","2018-07-15 18:55:22",,"2018-07-15 18:55:31",8,0,"BUSY","DOCUMENTATION","1531670122.27010","b'resultCode=1&amp;resultMessage=accepted'" |
По мониторингу Asterisk использую следующие основные параметры, ниже пример конфигурации для Zabbix файл /etc/zabbix/zabbix_agentd.conf в UserParameter:
1 2 3 4 5 6 7 | ### Option: UserParameter #Текущие вызовы UserParameter=asterisk.core.show.calls,/usr/bin/sudo /usr/sbin/asterisk -rx 'core show calls' | grep active| awk '{print $1}' #Текущие каналы SIP UserParameter=asterisk.sip.show.channels,/usr/bin/sudo /usr/sbin/asterisk -rx 'sip show channels' | grep "active SIP dialog" | awk '{print $1}' #Обработанные звонки, накопительный счётчик UserParameter=asterisk.sip.show.calls.processed,/usr/bin/sudo /usr/sbin/asterisk -rx 'core show calls' | grep processed | awk '{print $1}' |
Медиасервер Freeswitch
IP-адрес=192.168.25.32
У Freeswitch есть встроенный модуль curl.
Нам надо добавить модуль mod_curl поэтому, при компиляции снимаем комментарий с требуемых модулей в
/usr/src/freeswitch/modules.conf
1 2 | languages/mod_python applications/mod_curl |
Сохраняем. Запускаем конфигурацию сбоку и инсталляцию ещё раз:
1 2 3 | ./configure make make install |
Теперь в конфигурационных файлах Freeswtich /usr/local/freeswitch/conf/autoload_configs/modules.conf.xml, удаляем комментарии:
1 2 | < load module = "mod_curl" /> < load module = "mod_python" /> |
Проверим что модуль есть:
1 2 3 4 5 6 | #fs_cli $fs_cli freeswitch@FS1.6> module_exists mod_python true freeswitch@FS1.6> module_exists mod_curl true |
В файле можно /freeswitch/conf/autoload_configs/switch.conf.xml можно увеличить данные параметры:
1 2 3 4 5 | < param name = "max-sessions" value = "1000" /> <!--Most channels to create per second --> < param name = "sessions-per-second" value = "30" /> <!-- Default Global Log Level - value is one of debug,info,notice,warning,err,crit,alert --> < param name = "loglevel" value = "debug" /> |
Внешние каналы SIP, добавим новый профиль:
1 | #touch /freeswitch/conf/sip_profiles/fifa.xml |
Добавим в файл следующие строки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | < settings > < param name = "debug" value = "0" /> < param name = "sip-trace" value = "no" /> < param name = "sip-capture" value = "no" /> < param name = "rfc2833-pt" value = "101" /> < param name = "sip-port" value = "$${external_sip_port}" /> < param name = "dialplan" value = "XML" /> < param name = "context" value = "fifa" /> < param name = "dtmf-duration" value = "2000" /> < param name = "inbound-codec-prefs" value = "$${global_codec_prefs}" /> < param name = "outbound-codec-prefs" value = "$${outbound_codec_prefs}" /> < param name = "hold-music" value = "$${hold_music}" /> < param name = "rtp-timer-name" value = "soft" /> < param name = "local-network-acl" value = "localnet.auto" /> < param name = "manage-presence" value = "false" /> < param name = "rtp-ip" value = "192.168.25.32" /> < param name = "sip-ip" value = "192.168.25.32" /> </ settings > |
Значение $${external_sip_port} это глобальный параметр, его значение указано в /freeswitch/conf/vars.xml, и выглядит так: external_sip_port=5080.
Запустим наш новый профиль:
1 2 3 | freeswitch@wfff-media2> sofia profile fifa start Reload XML [Success] fifa started successfully |
В консоли Linux, проверим, что IP и порт прослушивает Freeswitch:
1 2 3 | root@wfff-media2:/freeswitch/conf/sip_profiles# netstat -anp | grep 5080 tcp 0 0 192.168.25.32:5080 0.0.0.0:* LISTEN 5499/freeswitch udp 0 0 192.168.25.32:5080 0.0.0.0:* 5499/freeswitch |
Теперь переходим к настройке дайлплана, файл /freeswitch/conf/dialplan/fifa.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | < include > < context name = "fifa" > < extension name = "FIFA_NUM_POOL" continue = "true" > < condition field = "destination_number" expression = "^(.*)$" > < action application = "curl" data = "http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=${caller_id_number}&amp;gw_phone=${destination_number:1}" inline = "true" /> <!--action application="set" data="answer=resultCode=0&amp;resultMessage=rejected"/--> <!--action application="set" data="respdata=${curl_response_data}"/--> < action application = "set" data = "result=${curl_response_data:11:1}" inline = "true" /> < action application = "log" data = "INFO result is ${result}" inline = "true" /> </ condition > < condition field = "destination_number" expression = "^78120002915$" break = "on-true" > <!-- Russian --> < action application = "log" data = "ANI NUMBER IS ${ani} " /> < action application = "log" data = "78120002915 WARNING RESULT IS ${result} " /> < action application = "pre_answer" /> < action application = "playback" data = "${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/success_readyRUS1.wav : /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)}" /> < action application = "sleep" data = "3000" /> < action application = "hangup" data = "USER_BUSY" /> </ condition > < condition field = "destination_number" expression = "^78120002916$" break = "on-true" > <!-- English --> < action application = "log" data = "RESULT IS ${result} " /> < action application = "pre_answer" /> < action application = "playback" data = "${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/Success_readyEN1.wav : /usr/local/freeswitch/sounds/fifa/Fail_EN1.wav" /> < action application = "hangup" data = "USER_BUSY" /> </ condition > </ context > </ include > |
Затем перезагружаем дайлплан:
1 2 3 4 5 | freeswitch@wfff-media2> reloadxml +OK [Success] 2019-02-22 13:32:23.277861 [INFO] mod_enum.c:879 ENUM Reloaded 2019-02-22 13:32:23.277861 [INFO] switch_time.c:1423 Timezone reloaded 1750 definitions |
Всё, на этом настройка закончена.
Что происходит в дайлплан?
В модуль SIP медиасервера Freeswitch (использует Sofia) приходит вызов, в соответствии с созданным sip профилем FIFA вызов направляется в контекст fifa для обработки.
Контекст fifa содержит единственный эктеншен с именем FIFA_NUM_POOL. В первое условие(condition) содержит правило
1 | <condition field="destination_number" expression="^(.*)$"> |
Поэтому туда попадает любой позвонивший пользователь. Начинается первая фаза ROUTING – формирования найденного по совпавшим в условиям списка действий(actions) TODO. Значение break в первом условии (condition) отсутствует, это равно break=”on-false”, то есть
не проверять следующее условие condition, если это условие ложно, но оно всегда в нашем случае истинно. Далее, проверяются остальные условия conditions которые содержат 5 номеров, соответствующих языку, на котором воспроизводятся голосовые подсказки, в примере я показываю только два номера 78120002915 и 78120002916. Когда условие по номеру позвонившего или destination_number совпадает с набранным пользователем номером, срабатывает директива break=»on-true», что значит прервать просмотр условий (condition)и запустить те условия, которые совпали. То есть первое и второе, одно из пяти. Причём условия как бы стекируются и связаны межу собой оператором И(AND).
Список на выполнение или TODO список действии(action) составлен, начинается фаза выполнения State EXECUTE.
Запускается первое приложение curl:
1 | <action application="curl" data="http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=${caller_id_number}&amp;gw_phone=${destination_number:1}"/> |
Мы отправляем сообщение POST в формате JSON номер звонящего и номер телефона на который позвонили, при этому удаляем первую цифру номера.
В ответ получаем ответ, наподобие
1 | resultCode=1&amp;resultMessage=accepted |
Приложение curl возвращает результа в стандартную переменную curl_response_data
Так как интересующее нас значение находится в 11 символе, извлечём её при помощи конструкции
1 | <action application="set" data="result=${curl_response_data:11:1}" inline="true"/> |
и присвоим переменной result.
Здесь запускается приложение curl, которое проверяет телефонный номер и возвращает результат в переменную ${result}. Далее, выполняются действия из второго найденного условия, во-первых
1 | <action application="pre_answer"/> |
означает что мы будем проигрывать сообщение в предответном состоянии, без начала тарификации.
Следующее действие:
1 | <action application="playback" data="${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/success_readyRUS1.wav : /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)}"/> |
Тут мы воспроизводим файл success_readyRUS1.wav, если значение переменной ${result}=1 или файл Fail_RUS1.wav в противном случае.
Сследующие действия:
1 2 | <action application="sleep" data="3000"/> <action application="hangup" data="USER_BUSY"/> |
Ждём 3000 миллисекунд и запускаем приложение «отбой» с кодом USER_BUSY или SIP 486.
Результат в CDR Freeswitch представлен ниже.
Если абонент авторизован:
1 | "70002783772","70002783772","78120002915","fifa","2018-07-17 13:40:58","","2018-07-17 13:41:05","7","0","ORIGINATOR_CANCEL","c6337123-7a94-4ba2-96ee-17d00d2e460b","","","PCMA","PCMA","resultCode=1&amp;resultMessage=accepted" |
Если абоненту отказано в авторизации:
1 | "70002254963","70002254963","78120002918","fifa","2018-07-17 17:13:23","","2018-07-17 17:13:34","11","0","USER_BUSY","854529fc-62c6-479a-8c10-4c639fa624d9","","","PCMA","PCMA","resultCode=0&amp;resultMessage=rejected" |
Как видно, в cdr отображается содержимое переменной ${curl_response_data}
Чтобы добавить её в CDR, нужно сделать следующее:
Открыть на редактирование файл /usr/local/freeswitch/conf/autoload_configs/cdr_csv.conf.xml, далее, смотрим какой используется темплейт для CDR:
1 | <param name=«default-template» value=«example»/> |
Затем, в
1 | <template name=«example»> |
добавляем в конце по образцу «${curl_response_data}»
Получится:
1 | <template name="example">"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}","${curl_response_data}"</template> |
Сохраняем.
Затем делаем перезагрузку модуля из fs_cli
1 | freeswitch@debian8> reload mod_cdr_csv |
Ниже лог примера выполнения дайлплана Freeswitch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | ====Вызов пришёл в модуль Sofia SIP==== 2019-02-22 17:38:40.497865 [NOTICE] switch_channel.c:1104 New Channel sofia/fifa/79500090900@192.168.25.9 [dac48249-f16f-4026-b176-d29d0719b8dc] 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_NEW (Cur 1 Tot 13675) 2019-02-22 17:38:40.497865 [DEBUG] sofia.c:9873 sofia/fifa/79500090900@192.168.25.9 receiving invite from 192.168.25.9:5060 version: 1.6.20 git 43a9feb 2018-05-07 18:56:11Z 64bit 2019-02-22 17:38:40.497865 [DEBUG] sofia.c:7084 Channel sofia/fifa/79500090900@192.168.25.9 entering state [received][100] 2019-02-22 17:38:40.497865 [DEBUG] sofia.c:7094 Remote SDP: v=0 o=- 1060 847210 IN IP4 192.168.25.9 s=SMG SIP session c=IN IP4 192.168.25.9 t=0 0 m=audio 25862 RTP/AVP 8 0 a=rtpmap:8 PCMA/8000 a=rtpmap:0 PCMU/8000 a=ptime:20 2019-02-22 17:38:40.497865 [DEBUG] sofia.c:7486 (sofia/fifa/79500090900@192.168.25.9) State Change CS_NEW -> CS_INIT 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:603 (sofia/fifa/79500090900@192.168.25.9) State NEW 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_INIT (Cur 1 Tot 13675) 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:627 (sofia/fifa/79500090900@192.168.25.9) State INIT 2019-02-22 17:38:40.497865 [DEBUG] mod_sofia.c:90 sofia/fifa/79500090900@192.168.25.9 SOFIA INIT 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:40 sofia/fifa/79500090900@192.168.25.9 Standard INIT 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:48 (sofia/fifa/79500090900@192.168.25.9) State Change CS_INIT -> CS_ROUTING 2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:627 (sofia/fifa/79500090900@192.168.25.9) State INIT going to sleep 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_ROUTING (Cur 1 Tot 13675) 2019-02-22 17:38:40.517818 [DEBUG] switch_channel.c:2249 (sofia/fifa/79500090900@192.168.25.9) Callstate Change DOWN -> RINGING 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:643 (sofia/fifa/79500090900@192.168.25.9) State ROUTING 2019-02-22 17:38:40.517818 [DEBUG] mod_sofia.c:143 sofia/fifa/79500090900@192.168.25.9 SOFIA ROUTING 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:236 sofia/fifa/79500090900@192.168.25.9 Standard ROUTING 2019-02-22 17:38:40.517818 [INFO] mod_dialplan_xml.c:637 Processing 79500090900 <79500090900>->78120002915 in context fifa === Вызов ушёл в контекст fifa ===== Dialplan: sofia/fifa/79500090900@192.168.25.9 parsing [fifa->FIFA_NUM_POOL] continue=false Dialplan: sofia/fifa/79500090900@192.168.25.9 Regex (PASS) [FIFA_NUM_POOL] destination_number(78120002915) =~ /^(.*)$/ break=on-false ===Условие сработало, добавить действия в этом условии в TODO список, фаза 1 === Dialplan: sofia/fifa/79500090900@192.168.25.9 Action curl(http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=${caller_id_number}&amp;gw_phone=${destination_number:1}) Dialplan: sofia/fifa/79500090900@192.168.25.9 Action set(result=${curl_response_data:11:1}) Dialplan: sofia/fifa/79500090900@192.168.25.9 Action log(INFO result is ${result}) Dialplan: sofia/fifa/79500090900@192.168.25.9 Regex (FAIL) [FIFA_NUM_POOL] ani(79500090900) =~ /^71110007780$/ break=on-true Dialplan: sofia/fifa/79500090900@192.168.25.9 Regex (PASS) [FIFA_NUM_POOL] destination_number(78120002915) =~ /^78120002915$/ break=on-true ===Условие destination_number(78120002915) сработало, добавить действия в этом условии в TODO список, другие условия проверяться не будут так как установлено break=on-true === Dialplan: sofia/fifa/79500090900@192.168.25.9 Action log(ANI NUMBER IS ${ani} ) Dialplan: sofia/fifa/79500090900@192.168.25.9 Action log(78120002915 WARNING RESULT IS ${result} ) Dialplan: sofia/fifa/79500090900@192.168.25.9 Action pre_answer() Dialplan: sofia/fifa/79500090900@192.168.25.9 Action playback(${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/success_readyRUS1.wav : /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)}) Dialplan: sofia/fifa/79500090900@192.168.25.9 Action sleep(3000) Dialplan: sofia/fifa/79500090900@192.168.25.9 Action hangup(USER_BUSY) 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:286 (sofia/fifa/79500090900@192.168.25.9) State Change CS_ROUTING -> CS_EXECUTE 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:643 (sofia/fifa/79500090900@192.168.25.9) State ROUTING going to sleep 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_EXECUTE (Cur 1 Tot 13675) 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:650 (sofia/fifa/79500090900@192.168.25.9) State EXECUTE 2019-02-22 17:38:40.517818 [DEBUG] mod_sofia.c:198 sofia/fifa/79500090900@192.168.25.9 SOFIA EXECUTE 2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:328 sofia/fifa/79500090900@192.168.25.9 Standard EXECUTE ====Начало запуска условии в состоянии EXECUTE, фаза 2. Выполняются действия из совпавших условий. EXECUTE sofia/fifa/79500090900@192.168.25.9 curl(http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=79500090900&amp;gw_phone=8120002915) 2019-02-22 17:38:40.517818 [DEBUG] mod_curl.c:182 method: post, url: http://wfff-loginpage:8008/ivr_auth, content-type: application/x-www-form-urlencoded 2019-02-22 17:38:40.517818 [DEBUG] mod_curl.c:211 Post data: user_phone=79500090900&amp;gw_phone=8120002915 EXECUTE sofia/fifa/79500090900@192.168.25.9 set(result=0) === От curl получен результат 0 === 2019-02-22 17:38:40.557875 [DEBUG] mod_dptools.c:1548 SET sofia/fifa/79500090900@192.168.25.9 [result]=[0] EXECUTE sofia/fifa/79500090900@192.168.25.9 log(INFO result is 0) 2019-02-22 17:38:40.557875 [INFO] mod_dptools.c:1742 result is 0 EXECUTE sofia/fifa/79500090900@192.168.25.9 log(ANI NUMBER IS 79500090900 ) 2019-02-22 17:38:40.557875 [DEBUG] mod_dptools.c:1742 NUMBER IS 79500090900 EXECUTE sofia/fifa/79500090900@192.168.25.9 log(78120002915 WARNING RESULT IS 0 ) EXECUTE sofia/fifa/79500090900@192.168.25.9 pre_answer() === Состояние предответа === 2019-02-22 17:38:40.557875 [INFO] mod_dptools.c:1355 Sending early media 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[opus:116:48000:20:0:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[G722:9:8000:20:64000:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMU:0:8000:20:64000:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMA:8:8000:20:64000:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4504 Audio Codec Compare [PCMA:8:8000:20:64000:1] ++++ is saved as a match 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[opus:116:48000:20:0:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[G722:9:8000:20:64000:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[PCMU:0:8000:20:64000:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4504 Audio Codec Compare [PCMU:0:8000:20:64000:1] ++++ is saved as a match 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[PCMA:8:8000:20:64000:1] 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:3061 Set Codec sofia/fifa/79500090900@192.168.25.9 PCMA/8000 20 ms 160 samples 64000 bits 1 channels 2019-02-22 17:38:40.557875 [DEBUG] switch_core_codec.c:111 sofia/fifa/79500090900@192.168.25.9 Original read codec set to PCMA:8 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4738 No 2833 in SDP. Liberal DTMF mode adding 101 as telephone-event. 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4767 sofia/fifa/79500090900@192.168.25.9 Set 2833 dtmf send payload to 101 recv payload to 101 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:6878 AUDIO RTP [sofia/fifa/79500090900@192.168.25.9] 192.168.25.32 port 16452 -> 192.168.25.9 port 25862 codec: 8 ms: 20 2019-02-22 17:38:40.557875 [DEBUG] switch_rtp.c:4137 Starting timer [soft] 160 bytes per 20ms 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:7180 sofia/fifa/79500090900@192.168.25.9 Set 2833 dtmf send payload to 101 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:7187 sofia/fifa/79500090900@192.168.25.9 Set 2833 dtmf receive payload to 101 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:7210 sofia/fifa/79500090900@192.168.25.9 Set rtp dtmf delay to 40 2019-02-22 17:38:40.557875 [NOTICE] sofia_media.c:92 Pre-Answer sofia/fifa/79500090900@192.168.25.9! 2019-02-22 17:38:40.557875 [DEBUG] switch_channel.c:3474 (sofia/fifa/79500090900@192.168.25.9) Callstate Change RINGING -> EARLY 2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:6861 Audio params are unchanged for sofia/fifa/79500090900@192.168.25.9. 2019-02-22 17:38:40.557875 [DEBUG] mod_sofia.c:2364 Ring SDP: v=0 o=FreeSWITCH 1550829868 1550829869 IN IP4 192.168.25.32 s=FreeSWITCH c=IN IP4 192.168.25.32 t=0 0 m=audio 16452 RTP/AVP 8 101 a=rtpmap:8 PCMA/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-16 a=ptime:20 a=sendrecv === Начало проигрывания звукового файла Fail_RUS1.wav === EXECUTE sofia/fifa/79500090900@192.168.25.9 playback(/usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav) 2019-02-22 17:38:40.557875 [DEBUG] sofia.c:7084 Channel sofia/fifa/79500090900@192.168.25.9 entering state [early][183] 2019-02-22 17:38:40.557875 [DEBUG] switch_ivr_play_say.c:1498 Codec Activated L16@8000hz 1 channels 20ms 2019-02-22 17:38:40.657867 [DEBUG] switch_rtp.c:7308 Correct audio ip/port confirmed. 2019-02-22 17:38:49.677867 [DEBUG] sofia.c:7084 Channel sofia/fifa/79500090900@192.168.25.9 entering state [terminated][487] 2019-02-22 17:38:49.677867 [NOTICE] sofia.c:8273 Hangup sofia/fifa/79500090900@192.168.25.9 [CS_EXECUTE] [ORIGINATOR_CANCEL] 2019-02-22 17:38:49.677867 [DEBUG] switch_ivr_play_say.c:1942 done playing file /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav 2019-02-22 17:38:49.677867 [DEBUG] switch_core_session.c:2815 sofia/fifa/79500090900@192.168.25.9 skip receive message [APPLICATION_EXEC_COMPLETE] (channel is hungup already) 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:650 (sofia/fifa/79500090900@192.168.25.9) State EXECUTE going to sleep 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_HANGUP (Cur 1 Tot 13675) 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:850 (sofia/fifa/79500090900@192.168.25.9) Callstate Change EARLY -> HANGUP 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:852 (sofia/fifa/79500090900@192.168.25.9) State HANGUP 2019-02-22 17:38:49.677867 [DEBUG] mod_sofia.c:438 Channel sofia/fifa/79500090900@192.168.25.9 hanging up, cause: ORIGINATOR_CANCEL 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:60 sofia/fifa/79500090900@192.168.25.9 Standard HANGUP, cause: ORIGINATOR_CANCEL 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:852 (sofia/fifa/79500090900@192.168.25.9) State HANGUP going to sleep 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:619 (sofia/fifa/79500090900@192.168.25.9) State Change CS_HANGUP -> CS_REPORTING 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_REPORTING (Cur 1 Tot 13675) 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:938 (sofia/fifa/79500090900@192.168.25.9) State REPORTING 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:174 sofia/fifa/79500090900@192.168.25.9 Standard REPORTING, cause: ORIGINATOR_CANCEL 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:938 (sofia/fifa/79500090900@192.168.25.9) State REPORTING going to sleep 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:610 (sofia/fifa/79500090900@192.168.25.9) State Change CS_REPORTING -> CS_DESTROY 2019-02-22 17:38:49.677867 [DEBUG] switch_core_session.c:1665 Session 13675 (sofia/fifa/79500090900@192.168.25.9) Locked, Waiting on external entities 2019-02-22 17:38:49.677867 [NOTICE] switch_core_session.c:1683 Session 13675 (sofia/fifa/79500090900@192.168.25.9) Ended 2019-02-22 17:38:49.677867 [NOTICE] switch_core_session.c:1687 Close Channel sofia/fifa/79500090900@192.168.25.9 [CS_DESTROY] 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:741 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_DESTROY (Cur 0 Tot 13675) 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:751 (sofia/fifa/79500090900@192.168.25.9) State DESTROY 2019-02-22 17:38:49.677867 [DEBUG] mod_sofia.c:343 sofia/fifa/79500090900@192.168.25.9 SOFIA DESTROY 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:181 sofia/fifa/79500090900@192.168.25.9 Standard DESTROY 2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:751 (sofia/fifa/79500090900@192.168.25.9) State DESTROY going to sleep |
По мониторингу Freeswitch использую следующие основные параметры, ниже пример конфигурации для Zabbix файл /etc/zabbix/zabbix_agentd.conf в UserParameter :
1 2 3 4 5 6 7 8 9 | ### Option: UserParameter ####Channel count UserParameter=fs.channels.count.current, /usr/local/freeswitch/bin/fs_cli -x "show channels count" | grep total | awk {'print $1'} UserParameter=fs.channels.count.max.5.min, /usr/local/freeswitch/bin/fs_cli -x "status" | grep 'session(s) - peak' | awk '{print $8}' ####CPS count UserParameter=fs.cps.count.current, /usr/local/freeswitch/bin/fs_cli -x "status" | grep ' session(s) - peak' | awk '{print $1}' UserParameter=fs.cps.count.max.5.min,/usr/local/freeswitch/bin/fs_cli -x "status" | grep 'session(s) per Sec out of max' | awk '{print $13}' ###Sessions count since startup UserParameter=fs.sessions.count.since.startup,/usr/local/freeswitch/bin/fs_cli -x "status" | grep "session(s) since startup" | awk {'print $1'} |
Итог
Для задачи авторизации в сети Wi-Fi по звонку отлично подойдёт любое из решений, Asterisk проще в конфигурировании, Freeswitch несколько сложнее, зато у него есть модуль curl и не нужно вызывать внешний скрипт, но скрипт написать не сложно. По производительности я не заметил разницы, наверное, потому что нагрузка была не существенная. Вот по качеству воспроизведения подсказок, по моей субъективной оценке, Freeswtich звучал лучше. По отладке и мониторингу, больше нравится Freeswitch, потому что логичнее и понятнее сообщения Freeswitch, также можно мониторить больше переменных, особенно порадовало наличие параметра Call per Second(CPS). В целом, по логической организации Freeswitch тоже больше нравится, но xml конфигурация Freeswtich несколько сложнее для восприятия, чем язык ael дайлплана Astersik, хотя со временем чтение и написание xml не вызывает никаких сложностей.
Автор: Игнат Кудрявцев
Похожие материалы:
Tags: Asterisk, Freeswitch