Приветстувую уважаемые читатели блога. В этой статье мы будем разбираться в основах телекомуникационных программных средств, которые в частности применяются во встраиваемых системах. Основным таким средством есть сервер VOIP-телефонии (VOIP, Voice over IP), в нашем случае это открытое ПО Asterisk, разрабатываемое фирмой Digium Inc и написанное на языке Си. Основной функций сервера VOIP есть возможность подключения различных клиентов и маршрутизация звонков между ними. Клиентом в данном случае может быть как программный телефон (так называемый Софт-фон, например Microsip или Ekiga), так и аппаратный телефон. Также в качестве клиента может быть и дроугой сервер VOIP, например внутри VOIP-телефона может стоять микропроцессор на котором запущен Linux с Asterisk умеющий не просто маршрутизировать звонок а обрабатывать его (то есть передавать голос удаленного абонента в наушник телефонной трубки и отправлять голос абонента-пользователя из микрофона обартно канал).

Я буду использовать Asterisk 13 LTS (13.1-cert2) и ОС Linux Ubuntu запущеную в виртуальной машине (С сетевым мостом на используемый сетевой адаптер, чтобы виртуалка получала айпи по DHCP из той же сети что и основной компьютер). Для тестирования с Windows будет использован программный телефон Microsip, который будет подключаться к Asterisk на виртуальной машине.

В качестве сигнального протокола (которых есть определенное множество) мы используем обычный SIP (Session Initiation Protocol). Сигнальный протокол это по сути перечень команд которые сигнализируют клиентов о определенных событиях, скажем о подключении клиента к серверу (правильнее это называется регистрацией на сервере), или извещение клиента или сервера о поступлении звонка.  

Установим Asterisk собрав из исходников:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install aptitude

# качаем исходники астера и устанавливаем зависимости скриптом
mkdir ~/aster && cd ~/aster wget http://downloads.asterisk.org/pub/telephony/certified-asterisk/certified-asterisk-13.1-current.tar.gz tar -xf certified-asterisk-13.1-current.tar.gz cd certified-asterisk-13.1-cert2/contrib/scripts/ sudo ./install_prereq install

# ок, возвращаемся к сборке астера cd ~/aster/certified-asterisk-13.1-cert2/ ./configure make
make menuconfig # тут нужно зайти на вкладку Channel Drivers и выбрать справа chan_sip. sudo make install sudo service asterisk start sudo asterisk -r

Предпоследняя команда загружает сервис астериск а последняя заходит в так называемую консоль астериска. Запомните ее - она не раз понадобится, так как все комманды  управления астериском наиболее удобно выполнять в его консоле. Сам же Asterisk работает в виде сервиса, то есть всегда запущен, по этому выходя из консоли астериска не стоит думать что вы его закрыли - он как ему и положено все еще продолжает работать.

Обычно этих действий вполне достаточно для старта, однако для некоторых дополнительных возможностей вам могут понадобится дополнительные телодвижения. К примеру, если вместо обычного chan_sip вы вдруг захотите использовать chan_pjsip то перед выполнением configure астера нужно дополнительно собрать pjproject:

cd ~/aster/
wget http://www.pjsip.org/release/2.4.5/pjproject-2.4.5.tar.bz2
tar -xjvf pjproject-2.4.5.tar.bz2
cd pjproject-2.4.5/
./configure --prefix=/usr --enable-shared --disable-sound --disable-resample --disable-video --disable-opencore-amr CFLAGS='-O2 -DNDEBUG'
sudo make install
sudo ldconfig

Настройка Peer-а (sip.conf)

Что ж, организуем подключение софт-фона, запущеного на другом хосте к нашему Asterisk (я буду подключать с основного PC на виртуалку). Прежде всего для этого на сервере (на виртуалке) нужно прописать аккаунт пира (англ. Peer - участник) в файле sip.conf. Пусть это будет tester с паролем 123. Отдельный участник прописывается в секции (начинается с квадратных кавычек). Итак очистим дефолтное содержимое конфига и пропишем:

sudo vim /etc/asterisk/sip.conf

-------------------------------

[tester]
type=friend
context=from-sip ; контекст в который попадут звонки от этого учасника
username=tester ; логин, который должен быть настроен на софт-фоне
secret=123
host=dynamic
nat=no ; не используется nat межу софтфоном tester-а и Asterisk
disallow=all ; запретить все аудио кодеки, дальше разрешим нужные
allow=ulaw ; разрешим ULaw кодек
;allow=g729 ; g729 - кодек с хорошим качеством и сжатием но есть особенности с лицензией (в режеме Pass-thru лицензия ненужна)

После этого нужно зайти в консоль астериска и выполнить 

sip reload

Чтобы проверить прописался ли аккаунт введите в консоли астера:

sip show peers 

Должно появится:

Name/username Host Dyn Forcerport Comedia ACL Port Status Description 
tester/tester (Unspecified) D No No 0 Unmonitored 
1 sip peers [Monitored: 0 online, 0 offline Unmonitored: 0 online, 1 offline]

Как видно есть один sip peer

Теперь можем настроить софт-телефон и подключится к серверу. Я буду использовать Microsip в Windows. Зпустив нужно добавить аккаунт Menu -> Add account и указать нужные настройки:

  • Sip server: 192.168.1.5 (адрес виртуалки)
  • Sip proxy: 192.168.1.5
  • User: tester
  • Domain: tester_domain
  • Password: 123

Если все ок то внизу Microsip вы должны увидеть статус Online.

Как работает SIP

Возможно вам будет инетересно увидеть sip изнутри, это можно легко организовать через tcpdump. 

Давайте закромем Microsip, запустим мониторинг на порту 5060 (дефолтный для SIP), не забудьте проверить как называется интерфейс (у меня eth0), по которому будет заходить траффик:

sudo tcpdump -i eth0 -n -s 0 port 5060 -vvv

и запустим софт-фон по новой. При этом мы поймаем четыре сообщения. Сначала клиент отсылает запрос, что мол он sip:[email protected]_domain (From) с айпи адреса 192.168.1.111 хочет зарегаться (REGISTER sip:192.168.1.5 SIP/2.0):

23:48:21.803371 IP (tos 0x0, ttl 128, id 29986, offset 0, flags [none], proto UDP (17), length 550)
192.168.1.111.49662 > 192.168.1.5.5060: [udp sum ok] SIP, length: 522
REGISTER sip:192.168.1.5 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.111:49662;rport;branch=z9hG4bKPjc83762ddf70340b68844b25469cc6175
Max-Forwards: 70
From: <sip:[email protected]_domain>;tag=c4f3d298088a4373927ab4e5f55def0b
To: <sip:[email protected]_domain>
Call-ID: 76c0d7f9ae624c9a954d828c86f388cd
CSeq: 33440 REGISTER
User-Agent: MicroSIP/3.10.5
Contact: <sip:[email protected]:49662;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length: 0

Затем сервер отвечает что клиент пока не может зарегаться так как неавторизирован (401 Unauthorized), но предлогает сделать это указац WWW-Authenticate:

23:48:21.803633 IP (tos 0x0, ttl 64, id 59134, offset 0, flags [none], proto UDP (17), length 609)
192.168.1.5.5060 > 192.168.1.111.49662: [bad udp cksum 0x8623 -> 0xed75!] SIP, length: 581
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.1.111:49662;branch=z9hG4bKPjc83762ddf70340b68844b25469cc6175;received=192.168.1.111;rport=49662
From: <sip:[email protected]_domain>;tag=c4f3d298088a4373927ab4e5f55def0b
To: <sip:[email protected]_domain>;tag=as27da39b7
Call-ID: 76c0d7f9ae624c9a954d828c86f388cd
CSeq: 33440 REGISTER
Server: Asterisk PBX 13.1-cert2
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
WWW-Authenticate: Digest algorithm=MD5, realm="asterisk", nonce="62eb5dcb"
Content-Length: 0

Клиент опять шлет запрос на регистрацию но уже с парамитрами авторизации (Authorization)

23:48:21.803948 IP (tos 0x0, ttl 128, id 29987, offset 0, flags [none], proto UDP (17), length 710)
192.168.1.111.49662 > 192.168.1.5.5060: [udp sum ok] SIP, length: 682
REGISTER sip:192.168.1.5 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.111:49662;rport;branch=z9hG4bKPj0f432a0c343a4673b1a9edf7fa077f71
Max-Forwards: 70
From: <sip:[email protected]_domain>;tag=c4f3d298088a4373927ab4e5f55def0b
To: <sip:[email protected]_domain>
Call-ID: 76c0d7f9ae624c9a954d828c86f388cd
CSeq: 33441 REGISTER
User-Agent: MicroSIP/3.10.5
Contact: <sip:[email protected]:49662;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Authorization: Digest username="tester", realm="asterisk", nonce="62eb5dcb", uri="sip:192.168.1.5", response="8ee065af3e3bb482bf0bb276c9cdf3ed", algorithm=MD5
Content-Length: 0

После чего мы видим 200 Ok

23:48:21.804312 IP (tos 0x0, ttl 64, id 59135, offset 0, flags [none], proto UDP (17), length 632)
192.168.1.5.5060 > 192.168.1.111.49662: [bad udp cksum 0x863a -> 0x27a9!] SIP, length: 604
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.111:49662;branch=z9hG4bKPj0f432a0c343a4673b1a9edf7fa077f71;received=192.168.1.111;rport=49662
From: <sip:[email protected]_domain>;tag=c4f3d298088a4373927ab4e5f55def0b
To: <sip:[email protected]_domain>;tag=as27da39b7
Call-ID: 76c0d7f9ae624c9a954d828c86f388cd
CSeq: 33441 REGISTER
Server: Asterisk PBX 13.1-cert2
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Expires: 300
Contact: <sip:[email protected]:49662;ob>;expires=300
Date: Sun, 03 Jan 2016 21:48:21 GMT
Content-Length: 0

Собственно это и есть вся процедура регистрации после которой вы видите Online статус на телефоне, а на сервере при этом sip show peers должен начать показывать (Unmonitored: 1 online)

Name/username Host Dyn Forcerport Comedia ACL Port Status Description 
tester/tester 192.168.1.111 D No No 49662 Unmonitored 
1 sip peers [Monitored: 0 online, 0 offline Unmonitored: 1 online, 0 offline]

Таким нехитрым способом вы можете исследовать любую процедуру SIP, что нередко может помочь выявить причину той или иной проблемы.

Диалплан (extensions.conf)

Основной конфигурационный элемент любого сервера VOIP это план набора номера (англ. Dial - набор). Диалплан задает последовательность действий которые нужно выполнить при поступлении звонка на номер подходящий под определенный шаблон. Шаблон набора принято называть екстеншеном (англ. Extension - расширение, добавочный номер), видимо такое название сложилось исторически, так как в классической телефонии екстеншеном обычно называют начальный добавочный цифровой префикс, например маршрутизация звонков на страны выполняется исходя из кода страны, выбор оператора телефонии тоже происходит по коду оператора. Диалплан задается отдельно для контекста, а контекст звонка определяется в sip.conf. Как вы догадались контекст позволяет разделить возможности разным пользователям. 

Как вы помните звонки от нашего тестера попадают в контекст тест. Давайте определим один единственный номер в этом контексте, 1234. Когда этот абонент позвонит по этому номеру, астериск сразу поднимит трубку, проиграет какой-нибудь звук и положит трубку.

sudo vim /etc/asterisk/extensions.conf
--------------------------------------
[from-sip] exten => 1234,1,Answer exten => 1234,2,Playback(tt-weasels) exten => 1234,3,Hangup

В квадратных скобках указан контекст для диалплана который мы пишем. После символов => в строке диалплана указывается екстеншен (в нашем случае задан жестко '1234', хотя тут можно использовать разные  спец-символы которые позволяют задавать "настоящие" шаблоны). Далее через запятую указывается номер комманды, именно этот номер выполняет порядок выполнения диалплана а не порядок строк, ну и через следующую запятую указана комманда. После внесения изменений в диалплан необходимо зайти в консоль астериска и перечитать диалплан:

dialplan reload

Теперь если вы позвоните с софт-фона на номер 1234 то услышите что-то про хорьков и удаленный астериск положит трубку. Звонок на любой другой номер буде отклонен посколльку  в контексте  from-sip присутствуют комманды только для екстеншена 1234.

Маршрутизация звонков между абоненентами

Мало толку от того что один абонент звонит на VOIP-сервер и тот сразу запускает на нем какой-то автоответчик. Поэтому давайте подключим к нашему серверу еще одного абонента и сделаем так чтобы он могзвонить и принимать звонки от участника tester.

Прежде всего нам нужен еще один peer, добавим его сразу после существующего: 

[tester2]
type=friend
context=from-sip
username=tester2
secret=345
host=dynamic
nat=no
disallow=all
allow=ulaw

Незабудьте перезагрузить sip в консоле астериска. В качестве второго клиента можно использовать Microsip с любой другой машини в локальной сети (например еще одну виртуалку), либо любой другой клиет. Также если у вас интрнет с анонсируемым (белым) айпи-адресом, то можете пробросить на виртуалку UDP порты 5060 (для SIP), и диапазон 10000:20000 на айпи виртуалки (в моем случае 192.168.1.5), и дать свой белый айпи друзьям, чтобы они прописали его в настройки Microsip и таким образом оргонизовать небольшую Voip-сеть.

Я же использую еще одну виртуалку с Microsip. Звонки пользователя tester2 также попадают в контекст from-sip, поэтому он тоже должен дозвониться до 1234, в чем вы можете убедиться. Осталось настроить примитивную маршрутизацию между абонентами в extensions.conf:

[from-sip]
exten => 1234,1,Answer
exten => 1234,2,Playback(tt-weasels)
exten => 1234,3,Hangup

exten => 111,1,Dial(SIP/tester)
exten => 111,2,Hangup

exten => 112,1,Dial(SIP/tester2)
exten => 112,2,Hangup

Теперь начав звонок пользователем tester2 на номер 111 у пользователя tester в Microsip должен появится рингтон вызова и  должно появиться окно входящего звонка:

Кнопка Answer поднимает трубку. При этом начнется разговор и Microsip будет выглядить так:

 На этом все, надеюсь статья поможет начать разбираться с Asterisk.

Advanced

Зачем нужна регистрация?

Один из интерестных ньюансов регистрации пиров заключается в том что она не обязательна. В примере мы использовали регистрацию дл обоих пиров, однако это не всегда оязательно. Не принимая во внимание аспекты безопастности, технически регистрация на воип сервере нужна всего лишь для того чтобы клиент сообщил серверу что он готов обработать(принимать) звонок на таком-то сетевом адресе(связка айпи:порт), то есть по сути пир сообщает серверу что он является ресурсом икоторый может принимать звонки. А вот послать звонок на сервер можно без регистрации. Таким образом мы бы могли настроить пиров так чтобы пир tester2 мог слать звонки без регистрации а вот tester все же должен зарегитрироваться на сервере что бы принять звонок .