Про Asterisk, дума­ется, слы­шал чуть ли не каж­дый админ — он встре­чает­ся бук­валь­но на каж­дом шагу, будь то офис­ная АТС или неч­то свя­зан­ное с телеко­мом. Но если в пер­вом слу­чае его при­мене­ние прак­тичес­ки всег­да оправдан­но, то во вто­ром могут иметь мес­то некото­рые проб­лемы. Сущес­тву­ют ли аль­тер­нативы Asterisk?
 

SIP: краткое введение

Преж­де все­го сто­ит разоб­рать­ся, как работа­ет SIP в прин­ципе и что это вооб­ще за про­токол. Итак, SIP — Session Initiation Protocol, слу­жащий исклю­читель­но для целей уста­нов­ления и завер­шения сес­сии. Обмен пакета­ми от уста­нов­ления соеди­нения до его завер­шения называ­ется диало­гом. Меди­апо­ток по дан­ному про­токо­лу не переда­ется — для это­го есть про­токол RTP. Инкапсу­лиро­ван­ный же в пакете SIP SDP (Session Description Protocol) опре­деля­ет, в час­тнос­ти, и парамет­ры меди­апо­тока, такие как исполь­зуемый кодек и тип дан­ных.

Важ­но понимать, что про­хож­дение этих двух потоков — SIP/SDP и RTP (или, как говорят свя­зис­ты, сиг­нализа­ции и дан­ных) — совер­шенно незави­симо друг от дру­га. Пос­мотрим, что про­исхо­дит при нор­маль­ном вызове (очень упро­щен­но, прав­да).

  1. Вы­зыва­ющая сто­рона ини­циирует соеди­нение, посылая SIP-пакет INVITE, в нем же инкапсу­лиро­ван и SDP с информа­цией о жела­емых парамет­рах RTP. Этот пакет может прой­ти через нес­коль­ко SIP-прок­си — о них чуть ниже.
  2. В зависи­мос­ти от того, про­ходит ли вызов через SIP-прок­си или нет, вызыва­ющая сто­рона получа­ет либо ответ от SIP-прок­си TRYING (а уж прок­си тем вре­менем нап­равля­ет INVITE вызыва­емой сто­роне) и сле­дом RINGING, либо сра­зу RINGING. Пакет RINGING озна­чает, что вызыва­емая сто­рона посыла­ет сиг­нал або­нен­ту «зво­ню» и теперь нуж­но ожи­дать, условно говоря, «под­нятия труб­ки».
  3. Как толь­ко вызыва­емая сто­рона под­нима­ет труб­ку, она посыла­ет SIP-пакет с кодом 200 «OK». В этот пакет сно­ва инкапсу­лиро­вана наг­рузка SDP, содер­жащая парамет­ры, которые под­держи­вают­ся этой сто­роной. Вызыва­ющая же сто­рона, если парамет­ры сов­пада­ют, посыла­ет ответный пакет ACK.
  4. Кли­енты соеди­няют­ся по про­токо­лу RTP нап­рямую незави­симо от того, про­ходил ли пре­дыду­щий обмен пакета­ми SIP через SIP-прок­си или нет. Про­исхо­дит раз­говор.
  5. При отбое отби­вающая сто­рона посыла­ет SIP-пакет BYE, а вто­рая сто­рона посыла­ет опять же пакет ACK. Соеди­нение завер­шено.
Нормальное прохождение регистрации и одного вызова через OpenSIPS
Нор­маль­ное про­хож­дение регис­тра­ции и одно­го вызова через OpenSIPS

Те­перь сто­ит разоб­рать­ся с устрой­ством сети SIP — какие логичес­кие сущ­ности в ней вооб­ще име­ются.

  • UAC и UAS — User Agent Client и User Agent Server. Очень условно их мож­но наз­вать вызыва­ющей и вызыва­емой сто­роной. В SIP-тер­миналах и прог­рам­мных кли­ентах реали­зует­ся как UAC, так и UAS.
  • SIP-прок­си занима­ется в основном мар­шру­тиза­цией.
  • SIP-регис­тра­тор сох­раня­ет информа­цию о логичес­ком мес­тополо­жении UAC/UAS.
  • SIP-редирек­тор пре­дос­тавля­ет UAC/UAS информа­цию о мар­шру­тиза­ции и в слу­чае необ­ходимос­ти перенап­равля­ет вызов в дру­гое мес­то.
  • Сер­вер мес­тополо­жения на самом деле пред­став­ляет собой базу дан­ных, где ука­зано, какой адрес или какие адре­са соот­ветс­тву­ют тому или ино­му SIP URI. Фак­тичес­ки это лишь удоб­ная абс­трак­ция.
  • B2BUA может находить­ся на мес­те SIP-прок­си, но им не явля­ется. В слу­чае с прок­си тер­минал уста­нав­лива­ет соеди­нение с дру­гим тер­миналом нап­рямую (хоть оно и про­ходит через прок­си, но лишь до опре­делен­ного эта­па. И прок­си в общем слу­чае не изме­няет заголов­ки и тело SIP-пакета). В слу­чае с B2BUA тер­минал сна­чала уста­нав­лива­ет с ним соеди­нение, затем B2BUA уста­нав­лива­ет соеди­нение с вызыва­емым тер­миналом, и в даль­нейшем весь про­цесс про­исхо­дит исклю­читель­но через него, с исполь­зовани­ем двух незави­симых сес­сий — вызыва­ющий тер­минал-B2BUA и B2BUA-вызыва­ющий тер­минал. При­мене­ние B2BUA дает гораз­до боль­шую гиб­кость, нежели при­мене­ние обыч­ного SIP-прок­си, — хотя бы потому, что он поз­воля­ет изме­нять тело SIP-пакета. Кро­ме того, по наз­ванным выше при­чинам его при­меня­ют и при тарифи­кации вызовов. Но есть у него и недос­таток — боль­шее пот­ребле­ние памяти.

Сто­ит отме­тить, что зачас­тую логичес­кие сущ­ности объ­еди­няют­ся в одном ПО. Так, SIP-прок­си чаще все­го объ­еди­няет­ся с регис­тра­тором и редирек­тором.

SIP-прок­си сущес­тву­ют двух типов — stateless и stateful. Если ты зна­ком с iptables, думаю, объ­яснять их раз­личия нет необ­ходимос­ти. А если нет... Stateful SIP-прок­си хра­нит сос­тояние тран­закции, то есть зна­ет, какому пакету INVITE соот­ветс­тву­ет тот или иной пакет ACK. Stateless-прок­си же ничего это­го не зна­ет и тупо переда­ет пакет куда сле­дует.

И тут мы плав­но перехо­дим к воп­росу, какие еще сво­бод­ные средс­тва для работы с SIP-про­токо­лом (помимо Asterisk, о котором зна­ют все) сущес­тву­ют в *nix-сис­темах. На дан­ный момент есть два про­екта, пред­назна­чен­ные для этой цели, — Kamailio и OpenSIPS. Они име­ют обще­го пред­ка, так что под­робно опи­сывать их раз­личия смыс­ла нет. В статье будет рас­смот­рен OpenSIPS.

SEMS

OpenSIPS, в отли­чие от Asterisk, не под­держи­вает некото­рые виды услуг — он занима­ется исклю­читель­но про­токо­лом SIP. Для того же, что­бы на базе OpenSIPS соб­рать сер­вер кон­ферен­ций или, ска­жем, голосо­вую поч­ту, пот­ребу­ется исполь­зовать меди­асер­вер, такой, нап­ример, как SEMS.

SEMS раз­работан теми же людь­ми, что делали SER («дедуш­ку» OpenSIPS), и име­ет сле­дующие осо­бен­ности:

  • под­держи­вает соз­дание при­ложе­ний («желез­ных теток») и кон­ферен­ций;
  • мо­жет выс­тупать в качес­тве B2BUA/SBC (OpenSIPS это тоже уме­ет, но SEMS более заточен под подоб­ные вещи);
  • край­не мас­шта­биру­емый.

Ес­ли понадо­бит­ся замена Asterisk не толь­ко как SIP-прок­си, но и как меди­асер­вера, SEMS выг­лядит неп­лохим вари­антом.

 

Что такое OpenSIPS? Установка

OpenSIPS обес­печива­ет фун­кци­ональ­ность прак­тичес­ки всех сер­верных ком­понен­тов, которые были упо­мяну­ты выше, — от SIP-прок­си до B2BUA. Отли­чие же его от Asterisk’а зак­люча­ется, во‑пер­вых, в том, что OpenSIPS манипу­лиру­ет пакета­ми и сес­сиями SIP на более низ­ком уров­не, чем это дела­ет Asterisk, а во‑вто­рых, Asterisk по сути явля­ется ком­бай­ном, нап­ример содер­жит в себе, помимо SIP, меди­асер­вер. Кро­ме того, Asterisk не под­держи­вает мас­шта­биро­вание.

OpenSIPS име­ет дав­нюю исто­рию: как минимум он (если счи­тать и его пред­шес­твен­ников) не млад­ше Asterisk, а с уче­том того, что SIP для пос­ледне­го нерод­ной, воз­можно, даже и стар­ше. Он так­же под­держи­вает и модуль­ную архи­тек­туру, при этом модулей там пре­дос­таточ­но. В нас­тоящий момент с нуля раз­рабаты­вает­ся вет­ка 2.0, которая будет иметь дру­гую архи­тек­туру, — текущая зак­ладыва­лась без уче­та час­ти сов­ремен­ных реалий, которые в те вре­мена еще и не прог­нозиро­вались. Одна­ко дан­ная вет­ка находит­ся в сос­тоянии активной раз­работ­ки, а я пред­почитаю ста­биль­ные вер­сии, поэто­му здесь будет опи­сана вер­сия 1.11.3, которая, кста­ти, явля­ется LTS.

Итак, поеха­ли уста­нав­ливать:

$ wget -qO - http://apt.opensips.org/key.asc | sudo apt-key add -
$ sudo sh -c "echo 'deb http://apt.opensips.org/ stable111 main' > /etc/apt/sources.list.d/opensips.list"
$ sudo apt-get update
$ sudo apt-get install opensips opensips-console
 

Начальная настройка OpenSIPS

В фай­ле /etc/opensips/opensipsctlrc нуж­но нас­тро­ить имя или адрес SIP-домена:

SIP_DOMAIN=192.168.56.103

Имя SIP-домена не обя­затель­но дол­жно сов­падать с DNS-име­нем хос­та, на котором запущен OpenSIPS, одна­ко некото­рые SIP-тер­миналы не поз­воля­ют ука­зывать его отдель­но. В тес­товом слу­чае это не нас­толь­ко кри­тич­но, но, если сер­вер будет находить­ся в про­дак­шене, этот момент луч­ше учесть. Так­же для нор­маль­ной работы все рав­но рекомен­дует­ся DNS-сер­вер со скон­фигури­рован­ными полями NAPTR и SRV. В общем‑то, базовая нас­трой­ка на этом закон­чена, пора перехо­дить к написа­нию скрип­та мар­шру­тиза­ции.

 

Скрипт маршрутизации

Ос­новной кон­фигура­цион­ный файл OpenSIPS (в моем слу­чае он был рас­положен по пути /etc/opensips/opensips.cfg) делит­ся на три час­ти:

  • Гло­баль­ные парамет­ры, такие как логиро­вание с отладкой, адре­са, на которых OpenSIPS слу­шает, нас­трой­ка количес­тва дочер­них про­цес­сов.
  • Па­рамет­ры модулей. Сюда отно­сят­ся путь к катало­гу с модуля­ми, спи­сок самих заг­ружа­емых модулей и их парамет­ры, нап­ример для модуля тран­закций tm пре­дус­мотре­на нас­трой­ка самых раз­нооб­разных тай­меров.
  • На­конец, логика мар­шру­тиза­ции. Имен­но здесь находит­ся самая вкус­ная часть OpenSIPS. Каж­дый SIP-пакет, при­ходя­щий на (и про­ходя­щий через) OpenSIPS, обра­баты­вает­ся в соот­ветс­твии с дан­ной логикой. Разуме­ется, имен­но поэто­му она может быть дос­таточ­но слож­ной. Как пра­вило, здесь име­ются нес­коль­ко мар­шру­тов — основной, ана­логич­ный точ­ке вхо­да в какую‑либо прог­рамму и нес­коль­ко допол­нитель­ных, нап­равле­ние на которых вызыва­ется из основно­го. Допол­нитель­ные мар­шру­ты ана­логич­ны фун­кци­ям в про­цедур­ных язы­ках прог­рамми­рова­ния.

В прин­ципе, для соз­дания базово­го кон­фигура­цион­ного фай­ла мож­но исполь­зовать коман­ду osipsconfig, но его, тем не менее, при­дет­ся пра­вить руч­ками. Ниже будут при­веде­ны наибо­лее важ­ные час­ти из фай­ла кон­фигура­ции с ком­мента­риями (к сло­ву, допус­тимы как однос­троч­ные ком­мента­рии в *nix-сти­ле, так и мно­гос­троч­ные в сти­ле C++). Итак, часть сек­ции гло­баль­ных парамет­ров:

Утилита osipsconfig, служащая для создания шаблона конфигурации OpenSIPS
Ути­лита osipsconfig, слу­жащая для соз­дания шаб­лона кон­фигура­ции OpenSIPS
# Указываем, на каком адресе и порте будет слушать OpenSIPS
listen=udp:192.168.56.103:5060
# Отключаем поддержку TCP и TLS
disable_tcp=yes
disable_tls=yes

А теперь пос­мотрим некото­рые парамет­ры модулей:

# Путь к модулям
mpath="/usr/lib/opensips/modules"
# Загружаем модули sl и tm
loadmodule "sl.so"
loadmodule "tm.so"
# Настраиваем параметры модуля tm
modparam("tm", "fr_timeout", 5)
modparam("tm", "fr_inv_timeout", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)
# Загружаем модуль-обертку SIGNALING
loadmodule "signaling.so"
<...>

По­жалуй, сто­ит обра­тить вни­мание на дан­ные модули. Пер­вым заг­ружа­ется модуль sl, который отве­чает за stateless-прок­си. Парамет­ры его мы не тро­гаем. Сле­дующая строч­ка заг­ружа­ет модуль tm, который отве­чает за stateful-прок­си, — и уж тут как раз некото­рые парамет­ры нуж­но изме­нить. Рас­смот­рим, что они озна­чают:

  • fr_timeeout — интервал меж­ду зап­росом и пред­варитель­ным отве­том (таким как trying). Тран­закция на момент пред­варитель­ного отве­та еще не завер­шена. Этот тайм‑аут исте­кает, если нет никако­го отве­та, в слу­чае же наличия пред­варитель­ного отве­та он сбра­сыва­ется. В секун­дах.
  • fr_inv_timeout — интервал меж­ду пред­варитель­ным и окон­чатель­ным отве­том. Тайм‑аут исте­кает, если с момен­та получе­ния пред­варитель­ного отве­та окон­чатель­ного так и не приш­ло. Опять же в секун­дах.
  • restart_fr_on_each_reply — ука­зыва­ет, дол­жен ли fr_timeout начинать отсчет сна­чала, если вызыва­емая сто­рона регуляр­но шлет пред­варитель­ные отве­ты. Нулевое зна­чение — false, любое дру­гое — true.
  • onreply_avp_mode — как будут обра­баты­вать­ся AVP (Atribute-Value pair) в мар­шру­те Reply. Если не вда­вать­ся в под­робнос­ти, 1 озна­чает, что AVP, отно­сящи­еся к дан­ному мар­шру­ту, мож­но будет видеть и исполь­зовать и в некото­рых дру­гих вет­вях скрип­та мар­шру­тиза­ции. Это, тем не менее, сни­жает про­изво­дитель­ность.

Мо­дуль SIGNALING пред­став­ляет собой обер­тку вок­руг модулей tm и sl для удобс­тва работы.

Те­перь наконец мож­но перей­ти к раз­бору струк­туры пос­ледней сек­ции, которая, собс­твен­но, и явля­ется скрип­том обра­бот­ки зап­росов. Пер­вым идет так называ­емый main route block, в который попада­ют все пакеты. Как уже говори­лось выше, этот блок ана­логи­чен точ­ке вхо­да в стан­дар­тные прог­раммы. Рас­смот­рим, что он дела­ет:

  1. Па­кет вхо­дит в дан­ный блок, и про­исхо­дят некото­рые про­вер­ки.
  2. Ес­ли пакет не пред­назна­чен нам, мы его нап­равля­ем в блок relay.
  3. А если же он при­шел к нам, мы, в зависи­мос­ти от нужд, совер­шаем какие‑то дей­ствия. Отме­чу, что здесь мож­но нап­равлять поток обра­бот­ки в дру­гие бло­ки, ана­логич­но тому, как в прог­рамме на си из фун­кции main() мож­но вызывать дру­гие фун­кции, опи­сан­ные в коде прог­раммы.

Кро­ме бло­ка типа route (к которо­му отно­сит­ся и наз­ванный выше и который обра­баты­вает вхо­дящие зап­росы), сущес­тву­ет еще нес­коль­ко типов бло­ков мар­шру­тиза­ции. Опи­шу некото­рые из них:

  • branch_route — поз­воля­ет задавать дей­ствия в пре­делах одной тран­закции. Понят­но, что это акту­аль­но лишь в слу­чае stateful-мар­шру­тиза­ции.
  • failure_route — обра­баты­вает получен­ные отри­цатель­ные (с кодом боль­шим или рав­ным 300) отве­ты — при­чем отве­ты как при­ходя­щие извне, так и генери­руемые самим OpenSIPS. Опять же акту­аль­но толь­ко для stateful-мар­шру­тиза­ции.
  • onreply_route — обра­баты­вает все нор­маль­ные отве­ты. Может быть как stateful — в слу­чае если мы спе­циаль­но ука­зыва­ем, что ответ при­над­лежит какой‑либо тран­закции, так и stateless — если ука­зыва­ем, что мар­шру­тиза­ция гло­баль­ная.
  • error_route — обра­баты­вает ошиб­ки при пар­синге SIP-пакетов.

Пос­коль­ку даже самый прос­той скрипт мар­шру­тиза­ции, который поч­ти ничем не занима­ется (реали­зует толь­ко базовый регис­тра­тор и редирек­тор), дос­таточ­но сло­жен, мы его раз­берем по кос­точкам:

# Точка входа
route{
# Следующий условный оператор осуществляет проверку поля заголовка MaxForwards счетчик «прыжков» маршрутизации. Если его значение равно нулю, посылается ответ 483 и прекращается обработка данного пакета. Помимо этого, функция mf_process_maxfwd_header() смотрит, а имеется ли вообще такой заголовок в пакете, если нет, то он создается и устанавливается в заданное значение в данном случае 10.
if (!mf_process_maxfwd_header("70")) {
sl_send_reply("483","Too Many Hops");
exit;
}
# Далее мы проверяем наличие тега у поля To, который показывает, относится ли данный пакет к какому-либо диалогу.
if (has_totag()) {
# Пакет OPTIONS, помимо собственно запроса доступных опций, обычно используется в качестве средства проверки соединения. Следующая проверка служит для того, чтобы удостовериться, действительно ли пакет предназначен именно нашему прокси.
if (is_method("OPTIONS") && uri==myself && (! uri=~"sip:.*[@]+.*")) {
options_reply();
exit;
}
# Смотрим, есть ли в пакете указание, куда его маршрутизировать дальше. Функция loose_route() сама по себе очень многозначная (как и многие другие функции), и, если таковое указание имеется, она действует в соответствии с секцией 16.12 RFC 3261 за некоторыми исключениями (о них лучше почитать в документации).
if (loose_route()) {
# В серьезных скриптах маршрутизации здесь и спрятана вся логика например, осуществляется аккаунтинг. Однако, поскольку скрипт у нас исключительно простой, пакет мы просто маршрутизируем по направлению, которое в нем и задано.
route(relay);
} else {
# В случае же, если пакет не содержит маршрута, мы смотрим, не является ли он пакетом ACK, пришедшим в ответ на сообщение об ошибке, и переправляем его куда следует.
if (is_method("ACK")) {
if ( t_check_trans() ) {
t_relay();
exit;
} else {
# Если же данный запрос ACK не принадлежит никакой транзакции, мы просто его игнорируем
exit;
}
}
# В остальных же случаях мы отправляем сообщение с кодом "404", аналогичное подобному же в HTTP.
sl_send_reply("404","Not here");
}
exit;
}
# Обрабатываем запросы, не относящиеся к заданному диалогу.
# Запрос CANCEL мы не трогаем и пересылаем дальше.
if (is_method("CANCEL")) {
if (t_check_trans()) {
t_relay();
}
exit;
}
# Функция t_check_trans() тоже имеет двойное назначение если запрос не относится ни к ACK, ни к CANCEL, но относится к какой-то транзакции ретрансляции, она его ретранслирует дальше, что следующая строчка и делает.
t_check_trans();
# Фильтруем пакеты, у которых есть поле Route, но не задано поле To (за исключением пакета ACK) и логируем о подобных попытках
if (loose_route()) {
xlog("L_ERR",
"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
if (!is_method("ACK")) {
sl_send_reply("403", "Preloaded Route denied");
}
}
# Если запрос адресован не нам, добавляем поле Record-Route для принудительной маршрутизации SIP-трафика через наш прокси
if (!is_method("REGISTER|MESSAGE")) {
record_route();
}
# Если в запросе не фигурирует URI, который хоть как-то относится к нашему серверу, мы его отправляем в route(relay)
if (!uri==myself) {
route(relay);
}
# Поддержку presence (сообщений о статусе присутствия абонента) тоже не реализуем, для чего отключаем методы PUBLISH и SUBSCRIBE
if (is_method("PUBLISH|SUBSCRIBE")) {
sl_send_reply("503", "Service Unavailable");
exit;
}
# Обработка запроса REGISTER. Для упрощения скрипта мы даем возможность регистрироваться всем, безо всякой аутентификации. Кроме того, база местоположений по тем же соображениям временная, в настоящую БД ничего не пишется.
if (is_method("REGISTER")) {
if (!save("location", "m")) {
sl_reply_error();
}
exit;
}
# Функция lookup() проверяет, есть ли у нас в базе местоположений данный пользователь. Если его нет, мы создаем новую транзакцию и возвращаем "404". Опять же в серьезных скриптах здесь еще и проверяются поддерживаемые клиентом методы, чего мы не делаем.
if (!lookup("location")) {
t_newtran();
t_reply("404", "Not Found");
exit;
}
route(relay);
}
# Блок relay, который и обрабатывает все проходящие пакеты
route[relay] {
# В случае INVITE мы смотрим, есть ли отрицательный результат транзакции, и, если есть, отправляем в соответствующий блок
if (is_method("INVITE")) {
t_on_failure("fail");
}
# Наконец, пропускаем пакет дальше и, если он почему-либо не проходит, выдаем ошибку "500"
if (!t_relay()) {
send_reply("500", "Internal Server Error");
}
}
# Блок fail, о котором было упомянуто выше
failure_route[fail] {
# Если транзакция была отменена, мы просто выходим из блока
if (t_was_cancelled()) {
exit;
}
}

По завер­шению кон­фигури­рова­ния нуж­но про­верить кон­фиг на наличие син­такси­чес­ких оши­бок с помощью сле­дующей коман­ды:

# sudo opensips -C

За­тем вклю­чаем воз­можность запус­ка OpenSIPS в фай­ле /etc/default/opensips:

RUN_OPENSIPS=yes

И стар­туем его:

$ sudo service opensips start

Мож­но прис­тупать к тес­тирова­нию.

info

Для управле­ния OpenSIPS сущес­тву­ет Web-GUI — OpenSIPS-CP.

 

Тестирование конфигурации

Для тес­тирова­ния исполь­зуем два кли­ента, запущен­ные на двух машинах. Я исполь­зовал Linphone и Twinkle. В пер­вом для добав­ления учет­ной записи откры­ваем нас­трой­ки (Linphone → Preferences) и перехо­дим на вклад­ку Manage SIP Accounts, где и добав­ляем с помощью кноп­ки Add. В поле Your SIP identity ста­вим SIP-иден­тифика­тор (вида sip:имя_поль­зовате­ля@SIP-домен), а в поле SIP Proxy address пишем адрес (не SIP-домен!) SIP-прок­си.

Конфигурация учетной записи в Linphone
Кон­фигура­ция учет­ной записи в Linphone

В слу­чае же с Twinkle при пер­вом запус­ке будет пред­ложено соз­дать учет­ную запись. Назови про­филь и выбери тип Wizard для соз­дания учет­ной записи. Далее вби­ваем все нуж­ное. Единс­твен­ное отли­чие от Linphone сос­тоит в том, что в Twinkle имя поль­зовате­ля пишет­ся отдель­но от домена.

Создание профиля в Twinkle
Соз­дание про­филя в Twinkle

Пос­ле регис­тра­ции, что­бы убе­дить­ся, что кли­енты дос­тупны, мож­но пос­мотреть спи­сок мес­тополо­жений поль­зовате­лей на сер­вере, для чего нуж­но наб­рать MI-коман­ду:

# sudo opensipsctl fifo ul_dump

Эта коман­да вызыва­ет фун­кцию MI (интерфей­са управле­ния) модуля usrloc — ul_dump, которая и выводит спи­сок поль­зовате­лей, фак­тичес­ки зарегис­три­рован­ных на сер­вере.

Список зарегистрированных пользователей на OpenSIPS
Спи­сок зарегис­три­рован­ных поль­зовате­лей на OpenSIPS

Пос­ле это­го уже мож­но зво­нить. С этим не дол­жно воз­никнуть осо­бых проб­лем, но если они все‑таки будут — исполь­зуй фун­кцию xlog() для логиро­вания и tcpdump/Wireshark для иссле­дова­ния пакетов.

Вызов абонента с помощью Linphone
Вы­зов або­нен­та с помощью Linphone
Главное окно Twinkle
Глав­ное окно Twinkle
 

Заключение

OpenSIPS поз­воля­ет манипу­лиро­вать с пакета­ми SIP чрез­вычай­но гиб­ко. Одна­ко порог вхож­дения в него дос­таточ­но высокий — тре­бует­ся не толь­ко дос­кональ­но знать про­токол, но и понимать, что дела­ет та или иная фун­кция, и иметь пред­став­ление, для чего в общем может понадо­бить­ся какой‑либо модуль, даже сам спи­сок которых выг­лядит вну­шитель­но.

В статье, разуме­ется, был зат­ронут лишь самый минимум из того, что уме­ет OpenSIPS, — не были рас­смот­рены ни авто­риза­ция при регис­тра­ции, ни акка­унтинг, ни, тем более, нас­трой­ка OpenSIPS в качес­тве B2BUA. Тем не менее общее пред­став­ление о воз­можнос­тях OpenSIPS и о син­такси­се его фай­ла кон­фигура­ции у тебя дол­жно сло­жить­ся. Ну а в том слу­чае, если тебе это нуж­но, — даль­ше смо­жешь разоб­рать­ся и сам.

Оставить мнение