Kamailio源碼淺析#0 架構和基本執行時序
來自專欄 存儲之雲淡風清
用於源碼分析的代碼最後提交版本為
f54ce325ced4ac8c0361a2c736cc199b5b641a6d(TueApr 10 13:52:14 2018 +0200)在繼續後面的討論之前,先看看官方對該項目的簡介、以及如何編譯和運行該項目;項目主頁在
kamailio官網,編譯介紹文檔在
Install Kamailio按照官方的說明(我的環境是Ubuntu
16.04 x64, 4.13.0-43-generic #48~16.04.1-Ubuntu,gcc5.4.0 20160609),按步執行,即可成功編譯。
如果不用於生產環境,僅僅是自行調試分析,完全不必走完其安裝步驟,在源碼目錄即可運行;在正式運行之前,我們需要先準備2個東西,一是kamailio必須的配置文件,另外是其運行時需載入的模塊文件(.so)。
如果按照默認編譯參數(後面章節會討論編譯參數的問題),kamailio進程會默認載入位於/usr/local/etc/kamailio/kamailio.cfg配置文件;同時默認的模塊目錄在/usr/local/lib/kamailio/modules;兩者均需自己創建。
一個可工作的示例配置文件為
<源碼根目錄>/src/modules/dispatcher/doc/dispatcher.cfg,拷貝到上述位置即可;而模塊則是./src/modules下每個子目錄隨編譯生成的的.so文件,全部拷貝到相應目錄即可;以模塊dispatcher為例,則將<源碼根目錄>/src/modules/dispatcher/dispatcher.so拷貝到/usr/local/lib/kamailio/modules。
從此,即可執行<源碼根目錄>/src/kamailio,開始源碼探索之旅。
0. kamailio架構
kamailio組織架構比較有特色的一點是,跟搭積木一樣,通過配置文件指定需要載入的模塊,以及相應的路由。
0.1 指定需載入的模塊
這裡的模塊是指符合kamailio規範的c代碼,編譯後以.so文件形式存在;
具體規範定義在
./src/core/sr_module.h L353,即結構體
kam_module_exportsstruct kam_module_exports { char* name; /**< null terminated module name */ unsigned int dlflags; /**< flags for dlopen */ kam_cmd_export_t* cmds; /**< null terminated array of theexported commands */ param_export_t* params; /**< null terminated array of theexported module parameters */ stat_export_t* stats; /**< null terminated array of theexported module statistics */ nn_export_t* nn_cmds; /**< null terminated array of theexported NN functions */ pv_export_t* items; /*!< null terminated array of theexported module items (pseudo-variables) */ proc_export_t* procs; /**< null terminated array of the additional processes required by the module */ init_function init_f; /**< Initialization function */ response_function response_f; /**< function used forresponses, returns yes or no; can be null */ destroy_function destroy_f; /**< function called when themodule should be "destroyed", e.g: on ser exit; can be null */ child_init_function init_child_f; /**< function called by allprocesses after the fork */};
還是以dispatcher模塊為例,在./src/modules/dispatcher/dispatcher.c中,我們即可找到相應定義:
struct module_exports exports= { "dispatcher", DEFAULT_DLFLAGS, /* dlopen flags */ cmds, params, 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ 0, /* extra processes */ mod_init, /* module initialization function */ 0, (destroy_function) destroy, child_init /* per-child init function */};
在運行時,kamailio主程序會根據配置文件,將這些so文件以dlopen方式載入內存,然後通過dlsym讀取相應導出符號,並完成映射工作。
0.2 指定路由策略
kamailio的路由是指,根據sip消息包action的不同,指定相應的應答策略;一個典型的sip報文頭部類似:
REGISTER sip:127.0.0.1:5060 SIP/2.0Via: SIP/2.0/UDP 192.168.1.6:5560;rport;branch=z9hG4bK599815689From: <sip:1081@127.0.0.1:5060>;tag=1627219320To: <sip:1081@127.0.0.1:5060>Call-ID: 589268322CSeq: 1 REGISTERContact: <sip:1081@127.0.0.1:5560;line=5abeba228ee5780>Max-Forwards: 69User-Agent: Linphone/3.6.1 (eXosip2/4.1.0)Expires: 900Content-Length: 0
第一行的REGISTER便是該消息的action,和http協議如出一轍;
指定相應的應答策略是指,不在代碼中將action和應答報文強耦合在一起,而是選擇通過配置文件這種方式松耦合指定,例如如下的配置節點:
route[REGISTRAR] { if(!is_method("REGISTER")) return; sl_send_reply("404", "No registrar"); exit;}
意思是先判定是否為
REGISTER方法,不是則返回;否則應答404錯誤;通過抓包我們可以印證這一點:SIP/2.0 404 No registrar Via: SIP/2.0/UDP192.168.1.6:5560;rport=5560;branch=z9hG4bK599815689;received=127.0.0.1From: <sip:1081@127.0.0.1:5060>;tag=1627219320 To:<sip:1081@127.0.0.1:5060>;tag=9dd61ff61e802d8e2bef5f14621ef3c2.6286Call-ID: 589268322 CSeq: 1 REGISTER Server: kamailio (5.2.0-dev4 (x86_64/linux)) Content-Length: 0
推薦閱讀: