Na šablony už jsme narazili v minulých dílech seriálu. Díky nim není nutné psát do konfiguračního souboru instrukce pro každé telefonní číslo zvlášť. Pomocí šablony můžete jedním pravidlem ošetřit celý blok telefonních čísel naráz. Použití šablon není vždy intuitivní, často dokáží překvapit. Právě proto si zaslouží speciální díl.
Testování konfigurace
V tomto článku budeme pro testovací účely často používat příkaz NoOp. Náš nejjednodušší dialplan (v souboru extensions.conf) vypadá takto:
[internal] exten => 999,1,NoOp(text1) exten => 999,2,NoOp(text2) exten => 999,3,Busy()
Příkaz NoOp() nic nedělá. Při vhodném nastavení úrovně logování se na konzoli Asterisku vypisují příkazy, které Asterisk provádí, včetně jejich parametrů. Příkaz NoOp se tak dá použít pro zobrazení parametru na konzoli. Aby se prováděné příkazy vypisovaly, je potřeba nastavit verbosity na hodnotu 3 nebo víc.
astest:/etc/asterisk# rasterisk ... Connected to Asterisk 1.4.21.2~dfsg-3 currently running on astest (pid = 2152) astest*CLI> core set verbose 3 Verbosity was 0 and is now 3 astest*CLI>
Shellový příkaz rasterisk spustí konzoli Asterisku. Pokud konzoli ukončíte (příkazem quit, nebo stiskem Ctrl+C), bude si Asterisk nastavenou hodnotu verbosity pamatovat i při příštím přihlášení.
astest*CLI> core set verbose 3 Verbosity was 0 and is now 3 astest*CLI> quit astest:/etc/asterisk# rasterisk ... Connected to Asterisk 1.4.21.2~dfsg-3 currently running on astest (pid = 2152) Verbosity is at least 3 astest*CLI>
Všimněte si předposledního řádku (Verbosity is at least 3), který při prvním spuštění konzole chyběl. Nevypisuje se, pokud je hodnota verbosity rovna nule, což znamená, že je logování vypnuté. Logování lze vypnout buď nastavením na nulu, nebo na speciální hodnotu off.
astest*CLI> core set verbose 0 Verbosity is now OFF astest*CLI> core set verbose 3 Verbosity was 0 and is now 3 astest*CLI> core set verbose off Verbosity is now OFF astest*CLI>
Často bývá pohodlnější nastavit úroveň logování z příkazové řádky shellu při spouštění příkazu rasterisk.
rasterisk -vvv
Kolik v zadáte na příkazové řádce, takovou budete mít úroveň logování (to neplatí pro nulový počet v).
V našem případě, pokud je nastaveno logování alespoň na úroveň 3, vypíše Asterisk na svoji konzoli průběh hovoru následovně:
-- Executing [999@internal:1] NoOp("SIP/novak-0996dff8", "text1") in new stack
-- Executing [999@internal:2] NoOp("SIP/novak-0996dff8", "text2") in new stack
-- Executing [999@internal:3] Busy("SIP/novak-0996dff8", "") in new stack
== Spawn extension (internal, 999, 3) exited non-zero on 'SIP/novak-0996dff8'
Pokud budete konfiguraci zkoušet, nezapomeňte na příkaz dialplan reload po každé změně souboru extensions.conf. V konzoli Asterisku můžete zobrazit aktuální dialplan příkazem dialplan show. Volitelně můžete přidat jméno kontextu, který se má zobrazit (bez něj se zobrazí všechny).
astest*CLI> dialplan show internal
[ Context 'internal' created by 'pbx_config' ]
'999' => 1. NoOp(text1) [pbx_config]
2. NoOp(text2) [pbx_config]
3. Busy() [pbx_config]
-= 1 extension (3 priorities) in 1 context. =-
astest*CLI>
Zpracování dialplanu
Číslujete-li v dialplanu pravidla ručně (a ne pomocí velmi vhodné zkratky n, viz třetí díl), pak nezáleží na pořadí řádků. Následující konfiguraci zpracuje Asterisk úplně stejně jako při původním uspořádání:
[internal] exten => 999,3,Busy() exten => 999,1,NoOp(text1) exten => 999,2,NoOp(text2)
Můžete se o tom přesvědčit příkazem dialplan show. Asterisk si pravidla seřadí podle priorit.
Šablony
Každé pravidlo má takzvané jméno (například 999), které Asterisk porovnává s volaným číslem. Najde-li shodu, pravidlo je použitelné. Speciálním případem jména je šablona, která může odpovídat více telefonním číslům. Šablona se od obyčejného čísla liší podtržítkem na začátku. Některé znaky uvnitř šablony mají speciální význam:
- X
- odpovídá číslicím 0 až 9
- Z
- odpovídá číslicím 1 až 9
- N
- odpovídá číslicím 2 až 9
- [1237-9]
- odpovídá číslicím nebo písmenům uvedeným v závorce (v tomto případě 1,2,3,7,8,9), pomlčka značí interval (7 až 9)
- .
- tečka, jeden nebo více libovolných znaků
- !
- vykřičník, odpovídá libovolnému (i nulovému) počtu libovolných znaků
Varování: nepoužívejte šablonu _., která odpovídá čemukoliv. Odpovídá totiž i speciálním jménům pravidel i, h apod.
Jednomu telefonnímu číslu může odpovídat více pravidel, například:
[internal] exten => _ZXX,1,Answer() exten => 999,1,Busy() exten => _9X9,1,NoOp(zprava)
Číslo 999 odpovídá všem třem pravidlům. Asterisk celkem rozumně pro 999 použije prostřední pravidlo a provede příkaz Busy. Asterisk totiž pravidla setřídí podle obecnosti šablony a pak postupně zkouší jedno pravidlo po druhém, nejobecnější nakonec. Obyčejná jména, tj. ne-šablony, jsou vždy na začátku seznamu. První shoda v setříděném seznamu platí. Přesný algoritmus třídění je relativně komplikovaný. Nejjistější je použít příkaz dialplan show, který ukazuje pravidla tak, jak si je Asterisk setřídil:
astest*CLI> dialplan show internal [ Context 'internal' created by 'pbx_config' ] '999' => 1. Busy() [pbx_config] '_9X9' => 1. NoOp(zprava) [pbx_config] '_ZXX' => 1. Answer() [pbx_config] -= 3 extensions (3 priorities) in 1 context. =- astest*CLI>
Algoritmus zpracování pravidel
Asterisk nejprve určí kontext, do kterého hovor patří. Obvykle je kontext nastavený v konfiguraci extension (v našich příkladech je kontext internal). Dále nastaví aktuální prioritu na hodnotu 1 a pokračuje následujícími kroky:
- Najde v daném kontextu všechna pravidla, která mají prioritu stejnou jako je aktuální priorita.
- Nalezená pravidla setřídí podle toho, jakou mají šablonu. Obecnější šablony (ty na které se hodí víc čísel) jsou po setřídění spíše na konci seznamu.
- Projde setříděný seznam pravidel a provede příkaz prvního pravidla, které má šablonu odpovídající volanému číslu.
- Neukončil-li provedený příkaz hovor, zvýší aktuální prioritu o 1 a pokračuje bodem 1.
Nenajde-li Asterisk žádné odpovídající pravidlo, ukončí hovor. Varování: Asterisk dokáže vždy překvapit, raději v dialplanu ukončujte hovory explicitně.
Příklad
[internal] exten => 999,1,NoOp(text1) exten => 888,1,NoOp(zprava1) exten => _XXX,2,Answer() exten => 999,3,NoOp(text2) exten => 888,3,NoOp(zprava2)
Nejprve si probereme co se stane, vytočí-li nějaký účastník číslo 999. Asterisk bude hledat odpovídající pravidlo s prioritou 1 a provede NoOp(text1). Potom zvýší aktuální prioritu na 2, bude hledat pravidlo odpovídající číslu 999 s prioritou 2 a najde pravidlo s příkazem Answer. Nakonec zvýší aktuální prioritu na 3 a provede příkaz NoOp(text2). Volání na 888 se zpracuje podobně. Prostřední pravidlo s šablonou _XXX je společné pro 888 i 999. Stojí za povšimnutí, že příkaz dialplan show nezobrazí pravidla v pořadí zpracování, ale v pořadí daném obecností šablon.
astest*CLI> dialplan show internal
[ Context 'internal' created by 'pbx_config' ]
'888' => 1. NoOp(zprava1) [pbx_config]
3. NoOp(zprava2) [pbx_config]
'999' => 1. NoOp(text1) [pbx_config]
3. NoOp(text2) [pbx_config]
'_XXX' => 2. Answer() [pbx_config]
Volání na 999 a 888 (v tomto pořadí) je na konzoli Asterisku vidět následovně:
-- Executing [999@internal:1] NoOp("SIP/novak-08d911b0", "text1") in new stack
-- Executing [999@internal:2] Answer("SIP/novak-08d911b0", "") in new stack
-- Executing [999@internal:3] NoOp("SIP/novak-08d911b0", "text2") in new stack
== Auto fallthrough, channel 'SIP/novak-08d911b0' status is 'UNKNOWN'
-- Executing [888@internal:1] NoOp("SIP/novak-08d911b0", "zprava1") in new stack
-- Executing [888@internal:2] Answer("SIP/novak-08d911b0", "") in new stack
-- Executing [888@internal:3] NoOp("SIP/novak-08d911b0", "zprava2") in new stack
== Auto fallthrough, channel 'SIP/novak-08d911b0' status is 'UNKNOWN'
Nyní už by mělo být jasné jak funguje dialplan z minulého dílu
exten =>_XXXXXXXXX/novak,1,Set(CALLERID(number)=420999888200)
exten =>_XXXXXXXXX/cerny,1,Set(CALLERID(number)=420999888201)
exten =>_XXXXXXXXX,2,Dial(SIP/420${EXTEN}@muj_trunk)
Připomeňme, že díky řetězeci za lomítkem (např. novak) se pravidlo použije jen pokud volání pochází z extension novak. Následující dialplan by panu Novákovi nefungoval.
exten =>_XXXXXXXXX/novak,1,Set(CALLERID(number)=420999888200)
exten =>_XXXXXXXXX/novak,2,Dial(SIP/420${EXTEN}@muj_trunk)
Příkaz Dial by se neprovedl. Podstata problému je zřejmá z upravené varianty, která už je funkční:
exten =>_XXXXXXXXX/novak,1,Set(CALLERID(number)=420999888200)
exten =>_XXXXXXXXX/420999888200,2,Dial(SIP/420${EXTEN}@muj_trunk)
Přepsáním proměnné CALLERID(number) se efektivně změní jméno extension, které rozhoduje o použití pravidla s lomítkem ve jménu.
Závěr
To je pro tento díl vše. Příště si objasníme jak Asterisk zpracovává příchozí SIPové volání z internetu.







