基于Asterisk的VoIP開發(fā)指南——Asterisk模塊編寫指南
2008/06/12
1.開源項目概述
Asterisk是一個開源的軟件包,通常運行在Linux操作系統(tǒng)平臺上。Asterisk可以用三種協(xié)議來實現(xiàn)VoIP,同時可以與目前電話使用的標準硬件進行交互通信,Asterisk在實現(xiàn)VoIP時,不需要任何附加硬件,本文所采用的也是這種使用方式。但是,如果企業(yè)沒有與VoIP語音網(wǎng)關(guān)運營商建立合作關(guān)系,想要自己構(gòu)建這樣的一個平臺,那么要和數(shù)字電話設(shè)備與模擬電話設(shè)備進行交互通信,Asterisk需要一個PCI硬件的支持,這個硬件生產(chǎn)商中最著名的是Digium平臺提供的。
Asterisk 的結(jié)構(gòu)基本上是十分簡單,但是它不同于大多數(shù)的電話產(chǎn)品;旧,Asterisk擔(dān)任的是一個中間件的功能,它連接了底層的電話技術(shù)和上層的電話應(yīng)用。所以,Asterisk
具有很大的柔韌性,特殊的API接口都圍繞著PBX核心系統(tǒng)。這個核心處理著PBX內(nèi)部之間的相互聯(lián)系。每一部分都是清晰來自于協(xié)議、編碼或內(nèi)部電話使用的硬件接口的抽象。這些抽象的接口使Asterisk可以與任何的硬件和技術(shù)以及將來的硬件和軟件技術(shù)完美的結(jié)合。從圖2.5可以看出,Asterisk由內(nèi)部核心和外圍動態(tài)可加載模塊組成。內(nèi)部核心由以下六個部分組成:PBX交換核心模塊(PBX
Switching Core)、調(diào)度和I/O管理模塊(Scheduler and I/O Manager)、應(yīng)用調(diào)用模塊(Application
Launcher)、編解碼轉(zhuǎn)換模塊(Codec Translator)、動態(tài)模塊加載器模塊(Dynamic Module
Loader)和CDR生成模塊(CDR Core) 。
圖1 Asterisk結(jié)構(gòu)圖
2.Asterisk二次開發(fā)概述
Asterisk是一個開源的PBX架構(gòu);但它并不是一個成品。通常情況下,由于企業(yè)應(yīng)用的多樣性,很難有一個成型的PBX產(chǎn)品可以滿足企業(yè)的各種需求。傳統(tǒng)的PBX成品,要么功能和靈活性不足,要么配置和維護復(fù)雜;而且都具有一個致命的缺點,那就是開放性、可擴展性。
Asterisk具有傳統(tǒng)PBX無法比擬的優(yōu)點,那就是其靈活性,可擴展能力;Asterisk的擴展能力是通過開放相應(yīng)的架構(gòu)和接口來實現(xiàn)的。這就意味著Asterisk是一個組件而不是一個成型的產(chǎn)品,Asterisk的核心提供了一個基本的可運行環(huán)境,而外圍相應(yīng)的能力則可以通過加載和配置相關(guān)的插件和模塊來實現(xiàn)。
Asterisk是一個開源的PBX架構(gòu);但它并不是一個成品。Asterisk的擴展能力是通過開放相應(yīng)的架構(gòu)和接口來實現(xiàn)的。這就意味著Asterisk是一個組件而不是一個成型的產(chǎn)品,Asterisk的核心提供了一個基本的可運行環(huán)境,而外圍相應(yīng)的能力則可以通過加載和配置相關(guān)的插件和模塊來實現(xiàn)。
因此,使用Asterisk,一定會面臨二次開發(fā)問題,這些二次開發(fā)主要圍繞以下幾個方面:
(1)內(nèi)部核心模塊
- 開發(fā)擴展編解碼能力模塊
- 開發(fā)擴展相應(yīng)的通道模塊
(2)外圍動態(tài)可加載模塊
- 開發(fā)應(yīng)用部分
- 開發(fā)外圍管理部分
一般來說,Asterisk使用者很少需要去開發(fā)編解碼能力模塊和通道模塊等內(nèi)部核心模塊;而需要開發(fā)最多的情況則是外圍動態(tài)可加載模塊,即外圍管理部分和應(yīng)用開發(fā),本文也是指這些方面的開發(fā)。
3.Asterisk通道模型與呼叫流程
3.1 什么是asterisk通道?
Asterisk通道是指通過asterisk建立起來的一路通話。這類通話都包含一個incoming連接和一個outbound連接。每個電話都是通過一種通道驅(qū)動程序建立起來的,比如SIP,ZAP,IAX2等等。每一類的通道驅(qū)動,都擁有自己私有的通道數(shù)據(jù)結(jié)構(gòu),這些私有的結(jié)構(gòu)從屬于一個通用的Asterisk通道數(shù)據(jù)結(jié)構(gòu)中,具體定義在channel.h和channel.c中。
3.2 基本的呼叫流程
Asterisk PBX呼叫流程如圖2所示。
- 通過Asterisk的一個電話呼叫在一個通道驅(qū)動接口上到達,如SIP Socket。
- 通道驅(qū)動在該通道上創(chuàng)建一個PBX通道并啟動一個pbx線程
- 撥號方案被執(zhí)行,撥號方案在一些地方通過dial應(yīng)用(查看app_dial.c)
強制Asterisk創(chuàng)建一個呼出呼叫,一旦呼出,Asterisk會有以下兩個動作將發(fā)生。
- Dial創(chuàng)建一個呼出的PBX通道并請求一種通道驅(qū)動創(chuàng)建一個呼叫。
- 當呼叫被應(yīng)答時,Asterisk橋接媒體流,于是在第一個通道上的主叫可以和在第二個通道也就是呼出通道上的被叫通話。
(點擊放大)
圖2 Asterisk PBX呼叫流程
4.RADIUS協(xié)議的概述
(1)Radius協(xié)議在協(xié)議棧中的位置
Radius是一種流行的AAA協(xié)議,同時其采用的是UDP協(xié)議傳輸模式,AAA協(xié)議在協(xié)議棧中位置如圖3所示。
圖3 Radius協(xié)議在協(xié)議棧中的位置
(2)Radius協(xié)議選擇UDP作為傳輸層協(xié)議
- NAS和Radius服務(wù)器之間傳遞的是幾十上百個字節(jié)長度的數(shù)據(jù),且Radius要求特別的定時器管理機制,用戶可以容忍幾十秒的驗證等待時間。
- 當處理大量用戶,服務(wù)器端采用多線程,UDP簡化了服務(wù)器端的實現(xiàn)過程。
- TCP是必須成功建立連接后才能進行數(shù)據(jù)傳輸?shù)模@種方式在有大量用戶使用的情況下實時性不好。Radius要有重傳機制和備用服務(wù)器機制,它所采用的定時,TCP不能很好的滿足。由于數(shù)據(jù)包可能會在網(wǎng)絡(luò)上丟失,如果客戶沒有收到響應(yīng),那么可以重新發(fā)送該請求包。多次發(fā)送之后如果仍然收不到響應(yīng),RADIUS客戶可以向備用的RADIUS服務(wù)器發(fā)送請求包。
- Radius依靠自身協(xié)議保證報文重傳和服務(wù)器備份機制以確保計費可靠性。
5.認證計費功能概述
IP-PBX呼叫控制功能,主要是VoIP終端用戶的認證計費控制過程,是VoIP系統(tǒng)商業(yè)化運營的核心模塊。
Radius Client端,也叫NAS,主要的任務(wù)就是根據(jù)VoIP終端的呼叫請求攜帶的各種屬性,包括賬戶ID、被叫號碼、通話時間等,封裝成標準的Radius數(shù)據(jù)包發(fā)送到Radius
Server端,達到賬戶信息實時更新的效果。整個NAS端程序主要由兩個模塊構(gòu)成:認證模塊和計費模塊,并把這兩個模塊整合到開源IP-PBX項目
Asterisk中。
5.1 標準RADIUS協(xié)議分析
(1)Radius Packet
RADIUS數(shù)據(jù)包被包裝在UDP數(shù)據(jù)報的數(shù)據(jù)塊(Data field))中,其中的目的端口為1812,RADIUS協(xié)議包結(jié)構(gòu)如圖4所示。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Authenticator |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Attributes ...(不定長)
+-+-+-+-+-+-+-+-+-+-+-+-+-
Attribute:
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Length | Value …(不定長)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
圖4 RADIUS協(xié)議包結(jié)構(gòu)圖
(2)對Radius Packet格式各個域解釋
Code:包類型,一個字節(jié)長,指示RADIUS包的類型,包含不合法的Code的Radius包將被直接丟棄,code域主要包含了以下值類型。
1)code=1 Access-Request——認證請求數(shù)據(jù)包
本文AAA功能就是構(gòu)建code=1的認證請求數(shù)據(jù)包。
2)code=2 Access-Accept——認證響應(yīng)數(shù)據(jù)包
3) code=3 Access-Reject——認證拒絕數(shù)據(jù)包
4)code=4 Accounting-Request——計費請求數(shù)據(jù)包
本文Asterisk的AAA功能另外一個重點任務(wù)就是構(gòu)建code=4的計費請求數(shù)據(jù)包,Accounting-Request
數(shù)據(jù)包中的兩種狀態(tài)類型(Acct-Status-Type)的計費請求數(shù)據(jù)包:Start(Value=1):Client開始對指定用戶提供服務(wù),計費開始;Stop(Value=2):Client停止對指定用戶提供服務(wù),計費結(jié)束。
5)code=5 Accounting-Response——計費響應(yīng)數(shù)據(jù)包
因為是要更新賬戶信息,所以目前本文不需要處理計費響應(yīng)數(shù)據(jù)包。
Identifier:包標識符,一個字節(jié)長,用于匹配請求包和響應(yīng)包,同一組請求包和響應(yīng)包的Identifier應(yīng)相同。協(xié)議規(guī)定:
1) 在任何時間,發(fā)給同一個RADIUS服務(wù)器的不同包的Identifier域不能相同,如果出現(xiàn)相同的情況,RADIUS將認為后一個包是前一個包的拷貝而不對其進行處理。
2) Radius針對某個請求包的響應(yīng)包應(yīng)與該請求包在Identifier上相匹配(相同)。
Length:包長度,兩個字節(jié)長,說明數(shù)據(jù)包的長度,是code、identifier、length、authenticator
attribute fields的長度總和,有效范圍是20~4096,超出范圍的數(shù)據(jù)將被視為附加數(shù)據(jù)(Padding)或直接被忽略。
Authenticator:驗證字,16字節(jié)長,用于驗證消息的負載,對包進行簽名,該驗證字分為兩種。
1) 請求驗證字---Request Authenticator,用在請求報文中,必須為全局唯一的隨機值。
2) 響應(yīng)驗證字---Response Authenticator,用在響應(yīng)報文中,用于鑒別響應(yīng)報文的合法性。響應(yīng)驗證字=MD5(Code+ID+Length+請求驗證字+Attributes+Key)。
Attributes:Type指示了Atribute的類型,通用的有幾十種,在系統(tǒng)中使用到的,如表4.1所示。Asterisk
AAA模塊的構(gòu)建主要是構(gòu)建表1列出的這些屬性值的RADIUS數(shù)據(jù)包。
表1 Atribute的屬性列表
| 屬性意義 |
| 用戶賬戶ID |
| 用戶密碼 |
| Nas的ip地址 |
| 用戶接入端口號 |
| 服務(wù)類型 |
| 協(xié)議類型 |
| 為用戶提供的IP地址 |
| 過濾表的名稱 |
| 通知NAS該用戶可用的會話時長 (時長預(yù)付費) |
| 標識NAS的字符串 |
| 計費請求報文的類型 |
| Radius客戶端發(fā)送計費報文耗費的時間 |
| 計費會話標識 |
| 在計費包中標識用戶認證通過的方式 |
| 通話時長(用戶在線時長) |
|
|
5.2 選擇一個合適的Radius Client API
上個小節(jié)介紹的RADIUS數(shù)據(jù)包格式,是構(gòu)建應(yīng)用協(xié)議層數(shù)據(jù)包的封裝所關(guān)注的,在Asterisk中如果需要親自把標準RADIUS數(shù)據(jù)包的發(fā)送、接收等過程從零開始寫起,那本文就把重點放在了RADIUS
UDP數(shù)據(jù)包與服務(wù)器通信過程的編寫中了,實際本文關(guān)注的是在Asterisk中根據(jù)VoIP通信中的業(yè)務(wù)需求,構(gòu)建RADIUS認證計費模塊,重點是業(yè)務(wù)應(yīng)用層的開發(fā),即如何組織認證包、計費包的數(shù)據(jù)結(jié)構(gòu)等,而RADIUS數(shù)據(jù)包傳輸層直接調(diào)用現(xiàn)成的開源API,目前主要有兩種這樣的開源項目。
(1)pam_radius
一個PAM模塊提供了RADIUS客戶端的功能。它是從開源項目Freeradius中提取出來的,如果要使用需要對代碼做大量的修改、打補丁后才能使用。
(2)radiusclient-ng
相對比PAM的pam_radius模塊而言,radiusclient-ng的動態(tài)庫代碼不用修改就可以拿過來使用,只需安裝radiusclient-ng的動態(tài)庫,然后根據(jù)配置文件、開放的API接口修改Asterisk代碼就可以完成Asterisk
AAA模塊的構(gòu)建。
所以在本文使用radiusclient-ng開源軟件包。
貝高林的Blog
相關(guān)鏈接: