Новости
Обзоры и тесты
Техно
Советы
Разное
Главная » Советы, Техно

Получение кодов отбоя SIP и стороны завершившей вызов в Asterisk

Добавлено на 14.03.2019 – 08:49

В последних релизах Asterisk есть возможность получить коды отбоя Asterisk или SIP-код отбоя при помощи функции HANGUPCAUSE. В заметке приводится практический пример того как это сделать,а затем записать результаты в БД MySQL. Также приведен пример того, как в Asterisk узнать какая из сторон была инициатором завершения вызова.

В консоли Asterisk посмотрим описание функции HANGUPCAUSE.

CLI> core show function HANGUPCAUSE

  -= Info about function 'HANGUPCAUSE' =-

[Synopsis]
Gets per-channel hangupcause information from the channel.

[Description]
Gets technology-specific or translated Asterisk cause code information from the
channel for the specified channel that resulted from a dial.

[Syntax]
HANGUPCAUSE(channel,type)

[Arguments]
channel
    The name of the channel for which to retrieve cause information.
type
    Parameter describing which type of information is requested. Types are:
    tech - Technology-specific cause information
    ast - Translated Asterisk cause code

[See Also]
HANGUPCAUSE_KEYS, HangupCauseClear()

Всё достаточно просто. Но есть нюанс, что каналы, которые участвовали в соединении, могут не иметь коды отбоев.
Поэтому в Asterisk есть специальная функция HANGUPCAUSE_KEYS, которая содержим имена каналов, содержащие коды отбоя:

 
*CLI> core show function HANGUPCAUSE_KEYS

  -= Info about function 'HANGUPCAUSE_KEYS' =-

[Synopsis]
Gets the list of channels for which hangup causes are available.

[Description]
Returns a comma-separated list of channel names to be used with the HANGUPCAUSE
function.

[Syntax]
HANGUPCAUSE_KEYS()

[Arguments]
Not available

[See Also]
HANGUPCAUSE, HangupCauseClear()

Всё вместе это выглядит так:

 

h => {

if ($[${LEN(${HANGUPCAUSE_STRING})} = 0])
 goto stop;

NoOp(SIP cause:  ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)});
NoOp(Ast cause:  ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)});
NoOp(Hangupcause keys: ${HANGUPCAUSE_KEYS()});
Set(CDR(userfield)=${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)} | ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)} |  ${HANGUPCAUSE_KEYS()});

stop:
 NoOp(HANGUPCAUSE is empty);
};

В дайлплане удачный звонок на номер 5500:

 
    -- Channel SIP/CCM61-WC-00006071 left 'simple_bridge' basic-bridge <5e218c7f-08e4-402b-a201-9fe95e43645c>
    -- Channel SIP/AST-CC-ERT-2-00006070 left 'simple_bridge' basic-bridge <5e218c7f-08e4-402b-a201-9fe95e43645c>
  == Spawn extension (ERT-IN, 5500, 6) exited non-zero on 'SIP/AST-CC-ERT-2-00006070'
    -- Executing [h@ERT-IN:1] NoOp("SIP/AST-CC-ERT-2-00006070", "SIP cause:  SIP 200 OK") in new stack
    -- Executing [h@ERT-IN:2] NoOp("SIP/AST-CC-ERT-2-00006070", "Ast cause:  Normal Clearing") in new stack
    -- Executing [h@ERT-IN:3] NoOp("SIP/AST-CC-ERT-2-00006070", "Hangupcause keys: SIP/CCM61-WC-00006071") in new stack
    -- Executing [h@ERT-IN:4] Set("SIP/AST-CC-ERT-2-00006070", "CDR(userfield)=SIP 200 OK | Normal Clearing | SIP/CCM61-WC-00006071") in new stack

То есть в бридже у нас были каналы SIP/CCM61-WC-00006071 и SIP/AST-CC-ERT-2-00006070, первым брижд покинул Channel SIP/CCM61-WC-00006071, то есть он является инициатором отбоя, но в переменной HANGUPCAUSE_KEYS() содержится только код отбоя второго канала SIP/AST-CC-ERT-2-00006070.

Теперь, посмотрим что содержит сама переменная:

  • Translated Asterisk cause code: Normal Clearing
  • Translated Asterisk cause code: SIP 200 OK

Если вызов состоялся, а переменная пустая, то значит ни один канал не содержал кода отбоя.

Возьмём звонок на сервис, то есть по сути с одним плечом SIP, в таком случае переменная HANGUPCAUSE_KEYS() будет пустая:

[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
    -- Executing [h@WC-IN:1] NoOp("SIP/CCM61-WC-0000608c", "SIP cause:  ") in new stack
[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
    -- Executing [h@WC-IN:2] NoOp("SIP/CCM61-WC-0000608c", "Ast cause:  ") in new stack
    -- Executing [h@WC-IN:3] NoOp("SIP/CCM61-WC-0000608c", "Hangup keys: ") in new stack
[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
    -- Executing [h@WC-IN:4] Set("SIP/CCM61-WC-0000608c", "CDR(userfield)= |  |  ") in new stack

Вызов который завершился неудачей:

  -- Got SIP response 503 "Service Unavailable" back from 10.101.1.7:5060
    -- SIP/ASTERISK-ERT-1-00006090 is circuit-busy
  == Everyone is busy/congested at this time (1:0/1/0)
    -- Executing [22000@WC-IN:7] NoOp("SIP/CCM61-WC-0000608f", "CONGESTION") in new stack
    -- Executing [22000@WC-IN:8] Goto("SIP/CCM61-WC-0000608f", "sw_378_CONGESTION,10") in new stack
    -- Goto (WC-IN,sw_378_CONGESTION,10)
    -- Executing [sw_378_CONGESTION@WC-IN:10] Hangup("SIP/CCM61-WC-0000608f", "") in new stack
  == Spawn extension (WC-IN, sw_378_CONGESTION, 10) exited non-zero on 'SIP/CCM61-WC-0000608f'
    -- Executing [h@WC-IN:1] NoOp("SIP/CCM61-WC-0000608f", "SIP cause:  SIP 503 Service Unavailable") in new stack
    -- Executing [h@WC-IN:2] NoOp("SIP/CCM61-WC-0000608f", "Ast cause:  Circuit/channel congestion") in new stack
    -- Executing [h@WC-IN:3] NoOp("SIP/CCM61-WC-0000608f", "Hangup keys: SIP/ASTERISK-ERT-1-00006090") in new stack
    -- Executing [h@WC-IN:4] Set("SIP/CCM61-WC-0000608f", "CDR(userfield)=SIP 503 Service Unavailable | Circuit/channel congestion | SIP/ASTERISK-ERT-1-00006090 ") in new stack

Посмотрим что содержит сама переменная:

  • Hangup keys: SIP/ASTERISK-ERT-1-00006090
  • Translated Asterisk cause code: Circuit/channel congestion
  • Translated Asterisk cause code: SIP 503 Service Unavailable

Я заметил, что если lastapp в CDR != Hangup, а Dial, то поля в CDR которые я пытаюсь обновить CDR(userfield|dialstatus) не обновляются, вот пример с одним uniqueid и две записи:

mysql> select * from  cdr where uniqueid=1548253072.2783;
+-----+---------------------+----------------------------+--------+-------------+----------+-----------------------+-----------------------------+---------+------------------------------+----------+---------+-------------+----------+-------------+-----------------+------------+--------------------------------------------------------------+
| id  | calldate            | clid                       | src    | dst         | dcontext | channel               | dstchannel                  | lastapp | lastdata                     | duration | billsec | disposition | amaflags | accountcode | uniqueid        | dialstatus | userfield                                                    |
+-----+---------------------+----------------------------+--------+-------------+----------+-----------------------+-----------------------------+---------+------------------------------+----------+---------+-------------+----------+-------------+-----------------+------------+--------------------------------------------------------------+
| 986 | 2019-01-23 17:17:52 | "Kudr Ignat" <015166> | 015166 | 12345       | WC-IN    | SIP/CCM61-WC-00000706 | SIP/ASTERISK-ERT-1-00000707 | Dial    | SIP/ASTERISK-ERT-1/12345,,tT |        4 |       0 | BUSY        |        3 |             | 1548253072.2783 |            |                                                              |
| 987 | 2019-01-23 17:17:56 | "Kudr Ignat" <015166> | 015166 | sw_525_BUSY | WC-IN    | SIP/CCM61-WC-00000706 |                             | Hangup  |                              |        0 |       0 | BUSY        |        3 |             | 1548253072.2783 |            | SIP 486 Busy Here | User busy |  SIP/ASTERISK-ERT-1-00000707 |
+-----+---------------------+----------------------------+--------+-------------+----------+-----------------------+-----------------------------+---------+------------------------------+----------+---------+-------------+----------+-------------+-----------------+------------+--------------------------------------------------------------+
2 rows in set (0.01 sec)

Это связано с тем, что вызов хоть и попал на h, но CDR не записался на диск.
Who Hung Up? Asterisk Wiki

По ссылке описывается более сложный пример, в нём мы разбираем пременную HANGUPCAUSE_KEYS(), ведь он в теории может содержать больше имени одного канала, и тогда в моём примере попросту будет ошибка. Но у меня было максимум 1 переменная.

Приведу пример ниже:

[foo]
exten => s,1,Dial(SIP/bar)
 
exten => h,1,noop()
exten => h,n,set(HANGUPCAUSE_STRING=${HANGUPCAUSE_KEYS()})
; start loop
exten => h,n(hu_begin),noop()
 
; check exit condition (no more array to check)
exten => h,n,gotoif($[${LEN(${HANGUPCAUSE_STRING})} = 0]?hu_exit)
 
; pull the next item
exten => h,n,set(ARRAY(item)=${HANGUPCAUSE_STRING})
exten => h,n,set(HANGUPCAUSE_STRING=${HANGUPCAUSE_STRING:${LEN(${item})}})
 
; display the channel ID and cause code
exten => h,n,noop(got channel ID ${item} with pvt cause ${HANGUPCAUSE(${item},tech)})
 
; check exit condition (no more array to check)
exten => h,n,gotoif($[${LEN(${HANGUPCAUSE_STRING})} = 0]?hu_exit)
 
; we still have entries to process, so strip the leading comma
exten => h,n,set(HANGUPCAUSE_STRING=${HANGUPCAUSE_STRING:1})
; go back to the beginning of the loop
exten => h,n,goto(hu_begin)
exten => h,n(hu_exit),noop(All HANGUPCAUSE entries processed)

Можно создать свою таблицу CDR или содержащую иную информацию по вкусу и записывать в БД.
В примере ниже, по результатам вызова, в таблицу Mysql c именем cdr_custom записываются нужные переменные CDR плюс коды отбоя, ниже приводится подробный пример.

Предпологается? что мы будем использовать ранее созданное MySQL ODBC соединение.
Все поля, кроме dialstatus и REL будем брать из функции CDR().

Переменная REL формируется из функции HANGUPCAUSE:

Set(REL=${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)} | ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)} |  ${HANGUPCAUSE_KEYS()});

Переменная ${DIALSTATUS} также стандартная переменная.

${DIALSTATUS}: This is the status of the call
    CHANUNAVAIL
    CONGESTION
    NOANSWER
    BUSY
    ANSWER
    CANCEL
    DONTCALL: For the Privacy and Screening Modes. Will be set if the called
    party chooses to send the calling party to the 'Go Away' script.
    TORTURE: For the Privacy and Screening Modes. Will be set if the called
    party chooses to send the calling party to the 'torture' script.
    INVALIDARGS

Ниже строка дайлплана Asterisk:

NoOp(${CDR(uniqueid)},${CDR(start)},${CDR(clid)},${CDR(src)},${CDR(dst)},${CDR(dcontext)},${CDR(channel)},${CDR(dstchannel)},${CDR(duration)},${CDR(billsec)},${CDR(disposition)},${DIALSTATUS},${REL})

В консоли Asterisk строка выше с подставленными переменными будет выглядеть так:

1548251202.2649,2019-01-23 16:46:42,"79210001122" <79210001122>,79210001122,600,WC-IN,SIP/CCM61-WC-000006aa,SIP/AST-CC-ERT-1-000006ab,409,409,ANSWERED,ANSWER,SIP 200 OK | Normal Clearing

Теперь все эти переменные нужно записать подготовленную для этих целей таблицу MySQL при помощи функции ODBC которая будет вызаться из дайлплана на экстеншене h.

Создадим новую таблицу cdr_custom в БД MySQL

 
mysql> use ertx_ast_cdr;
mysql> CREATE TABLE cdr_custom ( 
        id int(11) unsigned NOT NULL auto_increment PRIMARY KEY,
        uniqueid varchar(32) NOT NULL default '', 
        calldate datetime NOT NULL default '0000-00-00 00:00:00', 
        clid varchar(80) NOT NULL default '', 
        src varchar(80) NOT NULL default '', 
        dst varchar(80) NOT NULL default '', 
        dcontext varchar(80) NOT NULL default '', 
        channel varchar(80) NOT NULL default '', 
        dstchannel varchar(80) NOT NULL default '', 
        duration int(11) NOT NULL default '0', 
        billsec int(11) NOT NULL default '0', 
        disposition varchar(45) NOT NULL default '', 
        dialstatus varchar(17) NOT NULL default '' ,cause varchar(120) NOT NULL default '' );

mysql> desc cdr_custom;
+-------------+------------------+------+-----+---------------------+----------------+
| Field       | Type             | Null | Key | Default             | Extra          |
+-------------+------------------+------+-----+---------------------+----------------+
| id          | int(11) unsigned | NO   | PRI | NULL                | auto_increment |
| uniqueid    | varchar(32)      | NO   |     |                     |                |
| calldate    | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
| clid        | varchar(80)      | NO   |     |                     |                |
| src         | varchar(80)      | NO   |     |                     |                |
| dst         | varchar(80)      | NO   |     |                     |                |
| dcontext    | varchar(80)      | NO   |     |                     |                |
| channel     | varchar(80)      | NO   |     |                     |                |
| dstchannel  | varchar(80)      | NO   |     |                     |                |
| duration    | int(11)          | NO   |     | 0                   |                |
| billsec     | int(11)          | NO   |     | 0                   |                |
| disposition | varchar(45)      | NO   |     |                     |                |
| dialstatus  | varchar(17)      | NO   |     |                     |                |
| cause       | varchar(120)     | NO   |     |                     |                |
+-------------+------------------+------+-----+---------------------+----------------+
14 rows in set (0.00 sec)

Теперь создадим функцию в /etc/asterisk/func_odbc.conf

[INSERT_CUSTOM_CDR]
dsn=asterisk
writesql=INSERT INTO cdr_custom (uniqueid,calldate,clid,src,dst,dcontext,channel,dstchannel,duration,billsec,disposition,dialstatus,cause) VALUES ('${ARG1}','${ARG2}','${ARG3}','${ARG4}','${ARG5}','${ARG6}','${ARG7}','${ARG8}','${ARG9}','${ARG10}','${ARG11}','${ARG12}','${ARG13}')

Настала очередь dialplan.

Ловим вызова на специальном экстеншене h куда попадает вызов после заверешния:

>h => {
Set(REL=${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)} | ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)} |  ${HANGUPCAUSE_KEYS()});
Set(ODBC_INSERT_CUSTOM_CDR(${CDR(uniqueid)},${CDR(start)},${CDR(clid)},${CDR(src)},${CDR(dst)},${CDR(dcontext)},${CDR(channel)},${CDR(dstchannel)},${CDR(duration)},${CDR(billsec)},${CDR(disposition)},${DIALSTATUS},${REL})=);

{

Причём обращаю внимание, что для записи значений из dialplan в ODBC нужно использовать SET!!!

Если в дайлплане используется case

Тогда в CDR в столбце dst может быть вместо Б-номера может быть значение sw_564_CHANUNAVAIL или что-то похожее вместо Б-номера:

mysql> select * from ertx_ast_cdr.cdr_custom where src in ('49000','015136') and calldate >= '2019-03-06 09:00:00';
+-------+------------------+---------------------+---------------------------+--------+--------------------+----------+-----------------------+-----------------------------+----------+---------+-------------+------------+------------------------------------------------------------------+
| id    | uniqueid         | calldate            | clid                      | src    | dst                | dcontext | channel               | dstchannel                  | duration | billsec | disposition | dialstatus | cause                                                            |
+-------+------------------+---------------------+---------------------------+--------+--------------------+----------+-----------------------+-----------------------------+----------+---------+-------------+------------+------------------------------------------------------------------+
| 27633 | 1551942737.86893 | 2019-03-07 10:12:17 | Kudryavcev Ignat <015136> | 015136 | 450000              | WC-IN    | SIP/CCM61-WC-0000de97 | SIP/ASTERISK-ERT-1-0000de98 |        2 |       0 | NO ANSWER   | CANCEL     | SIP 180 Ringing | Normal Clearing |  SIP/ASTERISK-ERT-1-0000de98 |
| 27634 | 1551942783.86900 | 2019-03-07 10:13:03 | Kudryavcev Ignat <015136> | 015136 | sw_564_CHANUNAVAIL | WC-IN    | SIP/CCM61-WC-0000de9d |                             |        0 |       0 | CONGESTION  | CONGESTION |  |  |  SIP/ASTERISK-ERT-2-0000de9f                               |
| 27635 | 1551942795.86906 | 2019-03-07 10:13:15 | Kudryavcev Ignat <015136> | 015136 | 450000              | WC-IN    | SIP/CCM61-WC-0000dea0 | SIP/ASTERISK-ERT-1-0000dea1 |        2 |       0 | NO ANSWER   | CANCEL     | SIP 180 Ringing | Normal Clearing |  SIP/ASTERISK-ERT-1-0000dea1 |
| 27636 | 1551942821.86912 | 2019-03-07 10:13:41 | Kudryavcev Ignat <015136> | 015136 | sw_577_BUSY        | WC-IN    | SIP/CCM61-WC-0000dea5 |                             |        0 |       0 | BUSY        | BUSY       | SIP 486 Busy here | User busy |  SIP/ASTERISK-ERT-1-0000dea6     |

Ниже пример Dialplan в котором может возникнуть такая ситуация:

 
_[56]XX => {
            NoOp(Call from Westcall);
            //Set(CALLERID(num)=01${CALLERID(num)});
            Set(CALLERID(num)=${IF($[${LEN(${CALLERID(num)})} = 4]?01${CALLERID(num)}:${CALLERID(num)})});
            Verbose(!!! DEBUG Call from Westcall to ERTEL from ${CALLERID(num)} ${CALLERID(name)} --called-number-> ${EXTEN} !!!);
            Verbose(!!! ${CALLERID(all)} !!!);
            Set(_REAL_DST=${EXTEN});
            Dial(SIP/${EXTEN}@AST-CC-ERT-1,,tT);
            //Dial(SIP/5136@10.10.10.10);
            NoOp(${DIALSTATUS});
            switch(${DIALSTATUS}) {
        case BUSY:
                  Hangup;
        case ANSWER:
                  Hangup;
        case NOANSWER:
                  Hangup;
        case CONGESTION:
                  Hangup;
        default:
                  Dial(SIP/${EXTEN}@AST-CC-ERT-2,,tT);
                  Hangup;

В данном примере, мы пытаемся перемаршрутизировать вызов на резервный сервер в зависимости от ответа основного.
Поэтому сохраним набранный номер в переменную Set(_REAL_DST=${EXTEN});

Затем при сохранении CDR заменим сохранение dst как ${CDR(dst)} на ${REAL_DST}

На Asterisk перезагрузить func_odbc.so и dailplan(dialplan reload/ael reload)

 
voip-gate-aster*CLI> module reload func_odbc.so
Module 'func_odbc.so' reloaded successfully.
    -- Reloading module 'func_odbc.so' (ODBC lookups)
  == Parsing '/etc/asterisk/func_odbc.conf': Found
  == Unregistered custom function ODBC_PRESENCE
  == Unregistered custom function ODBC_ANTIGF
  == Unregistered custom function ODBC_SQL
  == Registered custom function 'ODBC_SQL'
  == Registered custom function 'ODBC_ANTIGF'
  == Registered custom function 'ODBC_PRESENCE'
  == Registered custom function 'ODBC_INSERT_CUSTOM_CDR'
  
  voip-gate-aster*CLI> odbc write ODBC_
ODBC_ANTIGF      ODBC_PRESENCE    ODBC_INSERT_CUSTOM_CDR  ODBC_SQL

Запустим в dialplan:

 -- Executing [h@WC-IN:1] Set("SIP/CCM61-WC-000006fa", "REL=SIP 200 OK | Normal Clearing |  SIP/ASTERISK-ERT-1-000006fb") in new stack
    -- Executing [h@WC-IN:2] Set("SIP/CCM61-WC-000006fa", "ODBC_INSERT_CUSTOM_CDR(1548252647.2763,2019-01-23 17:10:47,"" <015139>,015139,450000,WC-IN,SIP/CCM61-WC-000006fa,SIP/ASTERISK-ERT-1-000006fb,1,1,ANSWERED,ANSWER,SIP 200 OK | Normal Clearing |  SIP/ASTERISK-ERT-1-000006fb)=") in new stack

В таблице CDR:

mysql> select * from  cdr_custom  order by id desc limit 2;
+-----+-----------------+---------------------+---------------------------+-------------+-------+----------+---------------------------+-----------------------------+----------+---------+-------------+------------+-------------------------------------------------------------+
| id  | uniqueid        | calldate            | clid                      | src         | dst   | dcontext | channel                   | dstchannel                  | duration | billsec | disposition | dialstatus | cause                                                       |
+-----+-----------------+---------------------+---------------------------+-------------+-------+----------+---------------------------+-----------------------------+----------+---------+-------------+------------+-------------------------------------------------------------+
| 230 | 1548253896.2820 | 2019-01-23 17:31:36 | Kudr Ignat <015040>   | 015040      | 450000 | WC-IN    | SIP/CCM61-WC-0000071c     | SIP/ASTERISK-ERT-1-0000071d |       56 |      36 | ANSWERED    | ANSWER     | SIP 200 OK | Normal Clearing |  SIP/ASTERISK-ERT-1-0000071d |
| 229 | 1548253402.2799 | 2019-01-23 17:23:22 | 79053332211 <79053332211> | 79053332211 | 5500  | ERT-IN   | SIP/AST-CC-ERT-2-0000070e | SIP/CCM61-WC-0000070f       |      348 |     348 | ANSWERED    | ANSWER     | SIP 200 OK | Normal Clearing |  SIP/CCM61-WC-0000070f       |
+-----+-----------------+---------------------+---------------------------+-------------+-------+----------+---------------------------+-----------------------------+----------+---------+-------------+------------+-------------------------------------------------------------+
2 rows in set (0.00 sec)
</span>

Как в Asterisk узнать какая из сторон была инициатором отбоя?

Пример дайлплана:


exten => _1XX,1,Set(HANGUPSIDE=originator)
exten => _1XX,2,Dial(SIP/${EXTEN},,g)
exten => _1XX,3,Set(HANGUPSIDE=terminator)
exten => _1XX,4,NoOp(${HANGUPSIDE})
exten => h,1,NoOp(${HANGUPSIDE})

В первом шаге, мы устанавливам что по умолчания в переменной HANGUPSIDE оригинатор завершит вызов.
На втором шаге мы отправляем вызов терминатору, но указываем, в приложении Dial опцию g.
Что такое опция g описано в Help Asterisk:

    g: Proceed with dialplan execution at the next priority in the current
    extension if the destination channel hangs up.

Без опций, приложение Dial, после отбоя любой из сторон передаёт вызов сразу же на экстеншен h текущего контекста, выполнение следующего шага дайлплана не происходит.
Если поставить опцию g, то следующий шаг дайлплана после Dial будет выполняться если терминирующий канал первым завершил вызов, в данном случае установка переменной HANGUPSIDE равной terminator.
Таким образом легко установить какая из причин является инициатором завершение, что иногда может очень сильно помочь в диагностике проблем.

Автор: Игнат Кудрявцев

Tags: , ,

Оставить комментарий

Напишите Ваш комментарий ниже. Также Вы можете подписаться на комментарии к материалу через RSS

Вы можете использовать следующие теги:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

Мы поддерживаем Gravatar.

Контроль спама: *