oSIP協(xié)議棧及eXoSIPOrtp等使用入門_第1頁
oSIP協(xié)議棧及eXoSIPOrtp等使用入門_第2頁
oSIP協(xié)議棧及eXoSIPOrtp等使用入門_第3頁
oSIP協(xié)議棧及eXoSIPOrtp等使用入門_第4頁
oSIP協(xié)議棧及eXoSIPOrtp等使用入門_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、oSIP協(xié)議棧 及eXoSIP Ortp等 使用入門作者:不祥一直沒空仔細(xì)研究下oSIP,最近看到其版本已經(jīng)到了3.x版本,看到網(wǎng)上的許多幫助說明手冊(cè)都過于陳舊,且很多文檔內(nèi)容有點(diǎn)誤人子弟的嫌疑Linux下oSIP的編譯使用應(yīng)該是很簡(jiǎn)單的,其Install說明文檔里也介紹的比較清楚,本文主要就oSIP在Windows平臺(tái)下VC6.0開發(fā)環(huán)境下的使用作出描述。雖然oSIP的開發(fā)人員也說明了,oSIP只使用了標(biāo)準(zhǔn)C開發(fā)庫,但許多人在Windows下使用oSIP時(shí),第一步就被卡住了,得不到oSIP的LIB庫和DLL庫,也就沒有辦法將oSIP使用到自己的程序中去,所以第一步,我們將學(xué)習(xí)如何得到oSIP

2、的靜態(tài)和動(dòng)態(tài)鏈接庫,以便我們自己的程序能夠使用它們來成功編譯和執(zhí)行我們的程序。第一階段:-先創(chuàng)建新工程,網(wǎng)上許多文檔都介紹創(chuàng)建一個(gè)Win32動(dòng)態(tài)鏈接庫工程,我們這里也一樣,創(chuàng)建一個(gè)空白的工程保存。同樣,將oSIP2版本3.0.1 src目錄下的Osipparser2目錄下的所有文件都拷到我們剛創(chuàng)建的工程的根目錄下,在VC6上操作:Project-Add To Project-Files將所有的源程序和頭文件都加入到工程內(nèi),保存工程。這時(shí),我們可以嘗試編譯一下工程,你會(huì)得到許多錯(cuò)誤提示信息,其內(nèi)容無非是找不到osipparser2/xxxxx.h頭文件之類。處理:在Linux下,我們一般是將頭文

3、件,lib庫都拷到/usr/inclue;/usr/lib之類的目錄下,c源程序里直接寫#i nclude xxx.h時(shí),能直接去找到它們,在VC里,同樣的,最簡(jiǎn)單的方法就是將oSIP2源碼包中的Include目錄下的osipparser2目錄直接拷到我們的Windows下默認(rèn)包含目錄即可,這個(gè)目錄在VC6的Tool-Options-Directories里設(shè)置,(當(dāng)然,如果你知道這一步,也可以不用拷貝文件,直接在這里把oSIP源碼包所在目錄加進(jìn)來就可以了),默認(rèn)如果裝在C盤,目錄則為C:Program FilesMicrosoft Visual StudioVC98Include。這時(shí),我們

4、再次編譯我們的工程,順利編譯,生成osipparser2.dll,這時(shí),網(wǎng)上很多文檔里可能直接就說,這一步也會(huì)生成libs目錄,里面里osipparser2.lib文件,但我們這里沒有生成:)最簡(jiǎn)單的方法,不用深究,直接再創(chuàng)建一個(gè)工程,同上述創(chuàng)建動(dòng)態(tài)鏈接庫方法,創(chuàng)建一個(gè)Win32靜態(tài)鏈接庫工程,直接編譯,即可得到osipparser2.lib。-上面,我們得到了Osip的解析器開發(fā)庫,下面再編譯完整的Osip協(xié)議棧開發(fā)庫,同樣照上述方法,分別創(chuàng)建動(dòng)態(tài)鏈接庫工程和靜態(tài)鏈接庫工程,只是要拷的文件換成src下的osip目錄下文件和include下的osip目錄,得到osip2.dll和osip2.l

5、ib。在編譯osip2.dll這一步可能會(huì)再次得到錯(cuò)誤,內(nèi)容含義是找不到鏈接庫,所以,我們要把前面編譯得到的osipparser2.lib也拷到osip工程目錄下,并在VC6中操作:Project-Setting-Link中的Object/Library Modules:kernel32.lib user32.lib.xxx.lib之類的內(nèi)容最后增加:osipparser2.lib保存工程后再次編譯,即可成功編譯osip2.dll。-至此,我們得到了完整的oSIP開發(fā)庫,使用時(shí),只需在我們的程序里包含oSIP的頭文件,工程的鏈接參數(shù)里增加osipparser2.lib和osip2.lib即可。

6、-下面我們驗(yàn)證一下我們得到的開發(fā)庫,并大概了解一下OSIP的語法規(guī)范。在VC里創(chuàng)建win32控制臺(tái)程序工程,將libosip源碼包的SRC目錄下的Test目錄內(nèi)的C源程序隨便拷一個(gè)到工程時(shí),直接編譯(工程設(shè)置里照前文方法在link選項(xiàng)里增加osip2.lib,osipparser2.lib引用我們之前成功編譯得到的靜態(tài)庫文件)就可以運(yùn)行(帶參數(shù)運(yùn)行,參數(shù)一般為一個(gè)文本文件,同樣從Test目錄的res目錄里拷一個(gè)與源文件同名的純文本文件到工程目錄下即可)。該目錄下的若干文件基本上是測(cè)試了Osip的一些基本功能函數(shù),例如URI解析之類,可以大概了解一下oSIP的語法規(guī)范和調(diào)用方法,同時(shí)也能校驗(yàn)一下

7、之前編譯的OSIP開發(fā)庫能否正常使用,成功完成本項(xiàng)工作后,可以進(jìn)入下一步具體的oSIP的使用學(xué)習(xí)了。-由于oSIP是比較底層的SIP協(xié)議棧實(shí)現(xiàn),新手較難上手,而官方的示例大都是一些偽代碼,需要有實(shí)際的例子程序參考學(xué)習(xí),而最好的例子就是同樣官方發(fā)布的oSIP的擴(kuò)展開發(fā)庫exosip2,使用exoSIP可以很方便地快速創(chuàng)建一個(gè)完整的SIP程序(只針對(duì)性地適用于SIP終端開發(fā)用,所以我們這里只是用它快速開發(fā)一個(gè)SIP終端,用來更方便地學(xué)習(xí)oSIP,要想真正掌握SIP的開發(fā),需要掌握oSIP并熟讀RFC文檔才行,exoSIP不是我們的最終學(xué)習(xí)目的),通過成功編譯運(yùn)行一個(gè)自己動(dòng)手開發(fā)出的程序,再由淺入深

8、應(yīng)該是初學(xué)都最好的學(xué)習(xí)方法通過對(duì)使用exosip開發(fā)庫的使用創(chuàng)建自己的SIP程序,熟悉后再一個(gè)函數(shù)一個(gè)函數(shù)地深入學(xué)習(xí)exosip提供的接口函數(shù),就可以深入理解osip了,達(dá)到間接學(xué)習(xí)oSIP的目的,同時(shí)也能從eXoSIP中學(xué)習(xí)到正確使用oSIP的良好的編程風(fēng)格和語法格式。而要成功編譯ExoSIP,似乎許多人被難住了,直接在XP-sp2上,用VC6,雖然你使用了eXoSIP推薦的winsock2.h,但是會(huì)得到一個(gè)sockaddr_storage結(jié)構(gòu)不能識(shí)別的錯(cuò)誤,因?yàn)関c6自帶的開發(fā)庫太古董了,需要升級(jí)系統(tǒng)的Platform SDK,下載地址如下:.PSP2FULLInstall.htm(VC

9、6的支持已經(jīng)停止,這是VC6能使用的最新SDK)成功安裝后編譯前需加OSIP_MT宏,以啟用線程庫,否則在程序中使用eXoSIP庫時(shí)會(huì)出錯(cuò),而編譯時(shí)也會(huì)得到許多函數(shù)未定義的Warning提示,編譯得到exosip2.lib供我們使用,當(dāng)然,在此之前需要成功編譯了osip2和osipparser2,而在之后的實(shí)際使用時(shí),發(fā)現(xiàn)oSIP也需要增加OSIP_MT宏,否則OSIP_MT調(diào)用oSIP的線程庫時(shí)會(huì)出錯(cuò),所以我們需要重新編譯oSIP了:),因?yàn)閑Xosip是基于oSIP的(同上方式創(chuàng)建靜態(tài)和動(dòng)態(tài)鏈接庫工程,并需在Link中手工添加oSIP和oSIPparser的lib庫)。-創(chuàng)建新工程,可以是

10、任意工程,我們從最簡(jiǎn)單的Win32控制臺(tái)程序開始,為了成功使用oSIP,我們需要引用相關(guān)庫,調(diào)用相關(guān)頭文件,經(jīng)過多次試驗(yàn),發(fā)現(xiàn)需要引用如下的庫:exosip2.lib osip2.lib osipparser2.lib WSock32.Lib IPHlpApi.Lib WS2_32.Lib Dnsapi.lib其中,除了我們上面編譯得到的三個(gè)oSIP庫外,其它庫都是系統(tǒng)庫,其中有一些是新安裝的Platform SDK所新提供的。至此,我們有了一個(gè)簡(jiǎn)單的開發(fā)環(huán)境了,可以充分利用網(wǎng)上大量的以oSIP為基礎(chǔ)的代碼片段和官方說明文檔開始具體函數(shù)功能的測(cè)試和使用了:)-我們先進(jìn)行一個(gè)簡(jiǎn)單的純SIP信令(

11、不帶語音連接建立)的UAC的SIP終端的程序開發(fā)的試驗(yàn)(即一個(gè)只能作為主叫不能作為被叫的的SIP軟電話模型),我們創(chuàng)建一個(gè)MFC應(yīng)用程序,對(duì)話框模式,照上面的說明,設(shè)置工程包含我們上面得到的oSIP的相關(guān)開發(fā)庫及SDK的一些開發(fā)庫,并且由于默認(rèn)LIBC的沖突,需要排除MSVCRTD開發(fā)庫(其中D代表Debug模式下,沒有D表示Release模式下),直接使用eXosip的幾個(gè)主要函數(shù)就可以創(chuàng)建一個(gè)基本的SIP軟電話模型。其主要流程為:初始化eXosip庫-啟動(dòng)事件監(jiān)聽線程-向SIP Proxy注冊(cè)-向某SIP終端(電話號(hào)碼)發(fā)起呼叫-建立連接-結(jié)束連接初始化代碼:int ret=0;ret=e

12、Xosip_init();eXosip_set_user_agent(#YouToo0.1);if(0!=ret)AfxMessageBox(Couldnt initialize eXosip!n);return false;ret=eXosip_listen_addr(IPPROTO_UDP,NULL,0,AF_INET,0);if(0!=ret)eXosip_quit();AfxMessageBox(Couldnt initialize transport layer!n);return false;啟動(dòng)事件監(jiān)聽線程:AfxBeginThread(sip_uac,(void*)this);

13、向SIP Proxy注冊(cè):eXosip_clear_authentication_info();eXosip_add_authentication_info(uname,uname,upwd,md5,NULL);real_send_register(30);/*自定義函數(shù)代碼請(qǐng)見源碼*/發(fā)起呼叫(構(gòu)建假的SDP描述,實(shí)際軟電話使用它構(gòu)建RTP媒體連接):osip_message_t*invite=NULL;/*呼叫發(fā)起消息體*/int i=eXosip_call_build_initial_invite(&invite,dest_call,source_call,NULL,#YouToo te

14、st demo!);if(i!=0)AfxMessageBox(Intial INVITE failed!n);char localip128;eXosip_guess_localip(AF_INET,localip,128);snprintf(tmp,4096,v=0rno=josua 00 IN IP4%srns=conversationrnc=IN IP4%srnt=0 0rnm=audio%s RTP/AVP 08 101rna=rtpmap:0 PCMU/8000rna=rtpmap:8 PCMA/8000rna=rtpmap:101 telephone-event/8000rna=

15、fmtp:101 0-11rn,localip,localip,9900);osip_message_set_body(invite,tmp,strlen(tmp);osip_message_set_content_type(invite,application/sdp);eXosip_lock();i=eXosip_call_send_initial_invite(invite);eXosip_unlock();掛斷或取消通話:int ret;ret=eXosip_call_terminate(call_id,dialog_id);if(0!=ret)AfxMessageBox(hangup

16、/terminate Failed!);可以看到非常簡(jiǎn)單,再借助于oRTP和Mediastreamer開發(fā)庫,來快速為我們的SIP軟電話增加RTP和與系統(tǒng)語音API接口交互及語音編碼功能,即可以快速開發(fā)出一個(gè)可用的SIP軟電話,關(guān)于oRTP和Mediastreamer的相關(guān)介紹不是本文重點(diǎn),將在有空的時(shí)候考慮增加相應(yīng)使用教程,后面跟貼中可以下載基本可用的完整SIP軟電話的VC源碼工程文件供參考使用,完全CopyLeft,歡迎轉(zhuǎn)載,但請(qǐng)?jiān)谵D(zhuǎn)載時(shí)注明作者信息,謝謝!第二階段:-得到了一個(gè)SIP軟電話模型后,我們可以根據(jù)軟電話的實(shí)際運(yùn)行表現(xiàn)(結(jié)合用Ethereal抓包分析)來進(jìn)行代碼的分析,以達(dá)到利

17、用eXoSIP來輔助我們學(xué)習(xí)oSIP的最終目的(如要快速開發(fā)一個(gè)可用的SIP軟電話,請(qǐng)至前面提到的論壇去下載使用oRTP和Mediastreamer快速搭建的一個(gè)基本完整可用的SIP軟電話#YouToo 0.1版本的VC源碼工程文件作參考)?,F(xiàn)在從eXosip的初始化函數(shù)開始入手,來分析oSIP的使用,這是第二階段,第三階段就是深入學(xué)習(xí)oSIP的源碼了,但大多數(shù)情況下應(yīng)該沒有必要了,因?yàn)樵诘诙A段就有部分涉及到第三階段的工作了,而且oSIP的源碼也就大多是一些SIP數(shù)據(jù)的語法解析和狀態(tài)機(jī)的實(shí)現(xiàn),能深入理解了SIP協(xié)議后,這些只是一種實(shí)現(xiàn)方式,沒必要完全去接受,而是可以用自己的方式和風(fēng)格來實(shí)現(xiàn)一

18、套,比如,更輕量化更有適用目的性的方式,oSIP則只起參考作用了。eXosip_init()是eXosip的初始化函數(shù),我們來看看它的內(nèi)部實(shí)現(xiàn):首行是定義的osip_t*osip,這在oSIP的官方手冊(cè)里我們看到,所有使用oSIP的程序都要在最開始處聲明一個(gè)osip_t的指針,并使用osip_init(&osip)來初始化這個(gè)指針。我們可以在代碼中看到很多OSIP_TRACE,這是調(diào)試輸出宏調(diào)用了函數(shù)osip_trace,可以用ENABLE_TRACE宏來打開調(diào)試以方便我們開發(fā)調(diào)試。其它就是很多的eXosip_t的全局變量eXosip的一些初始化操作,包括最上面的memset(&eXosip,

19、0,sizeof(eXosip)完全清空和下面的類似eXosip.user_agent=osip_strdup(eXosip/EXOSIP_VERSION)的exosip變量的一些初始值設(shè)置,其中有一個(gè)eXosip.j_stop_ua=0應(yīng)該是一個(gè)狀態(tài)機(jī)開關(guān),后面可以看到很多代碼檢測(cè)這個(gè)變量來決定是否繼續(xù)流程處理,默認(rèn)置成了0表示現(xiàn)在exosip的處理流程是就緒的,即ua是not stop的。osip_set_application_context(osip,&eXosip)是比較有意思的,它讓下面的eXosip_set_callbacks(osip)給osip設(shè)置大量的回調(diào)函數(shù)時(shí),能讓osi

20、p能訪問到eXosip這個(gè)全局變量中設(shè)置的大量程序運(yùn)行時(shí)交互的信息,相當(dāng)于我們?cè)赩C下開啟一個(gè)線程時(shí),給線程傳入的一個(gè)void指針指向我們的MFC應(yīng)用程序的當(dāng)前dialog對(duì)象實(shí)例,可以用void*osip_get_application_context(osip_t*osip)這個(gè)函數(shù)來取出指針來使用,不過好象exosip中并沒有用到它,可能是留給個(gè)人自已擴(kuò)展的吧還能看到初始化代碼前面有一段WIN32平臺(tái)下的SOCK的初始化代碼,可以知道eXosip是用的原生的winsock api函數(shù),也就是我們可能以前學(xué)過的用VC和WINAPI寫sock程序時(shí)(不是MFC),用到的那段SOCK初始代碼,

21、還有一段有意思的代碼,就是jpipe()函數(shù),它們返回的是一個(gè)管道,一個(gè)有2個(gè)整型數(shù)值的數(shù)組(一個(gè)進(jìn)一個(gè)出),查看其代碼發(fā)現(xiàn),非WIN32平臺(tái)是直接使用的pipe系統(tǒng)函數(shù),而WIN32下則是用一對(duì)TCP的本地SOCK連接來模擬的管道,一個(gè)SOCK寫一個(gè)SOCK讀,這段代碼是比較有參考價(jià)值的:)j=50;while(aport+&j-0)raddr.sin_port=htons(short)aport);if(bind(s,(struct sockaddr*)&raddr,sizeof(raddr)0)OSIP_TRACE(osip_trace(_,Failed to bind one loca

22、l socket%i!n,aport);else break;含義即,依次檢測(cè)50個(gè)端口,從static int aport=10500;即1050010550端口找出一個(gè)可用的本地端口來綁定listen模擬pipe的一對(duì)sock。eXosip_set_callbacks(osip)沒有什么好看的,無非是和oSIP官方文檔介紹的一樣,設(shè)置一大堆的回調(diào)函數(shù),關(guān)鍵是回調(diào)函數(shù)的實(shí)現(xiàn),這也是許多初學(xué)者使用oSIP被卡殼的主要原因,不知道oSIP構(gòu)建的程序是怎樣跑起來的,隨便選幾個(gè)回調(diào)函數(shù)看一下eXosip是怎樣實(shí)現(xiàn)的,有許多是形如下文的函數(shù):static void cb_sndbye(int type

23、,osip_transaction_t*tr,osip_message_t*sip)OSIP_TRACE(osip_trace(_,cb_sndbye(id=%i)rn,tr-transactionid);即,只是打印一下調(diào)試,并沒有完整實(shí)現(xiàn)什么功能,我們學(xué)習(xí)時(shí),完全可以用相同的方法,定義一大堆回調(diào)函數(shù),并不忙想怎么完全實(shí)現(xiàn),先都是只打印一下調(diào)試信息,看具體的應(yīng)用邏輯根據(jù)抓包測(cè)試分析和看調(diào)試看程序走到了哪一步,調(diào)用了哪一個(gè)回調(diào),來明白具體回調(diào)函數(shù)要實(shí)現(xiàn)什么用途,再來實(shí)現(xiàn)代碼就方便多了,當(dāng)然,如果看透了RFC文檔,應(yīng)該從字面就能知道各個(gè)回調(diào)函數(shù)的用途了,這是后話,不是誰都能快速完全看懂RFC的,

24、所以我們要參考eXosip:)我們對(duì)其中的重要的回調(diào)函數(shù)進(jìn)行逐個(gè)的分析:-osip_set_cb_send_message(osip,&cb_snd_message)SIP消息發(fā)送回調(diào)函數(shù)這個(gè)函數(shù)可能是最重要的回調(diào)函數(shù)之一,消息發(fā)送,包括請(qǐng)求消息和回應(yīng)消息,一般情況下,狀態(tài)機(jī)的狀態(tài)就是由它控制的,發(fā)起一個(gè)消息初始化一個(gè)狀態(tài)機(jī),回應(yīng)一個(gè)消息對(duì)狀態(tài)機(jī)修改,終結(jié)消息發(fā)送結(jié)束狀態(tài)機(jī)看cb_snd_message的函數(shù)實(shí)現(xiàn),要以發(fā)現(xiàn),其主要代碼是對(duì)參數(shù)中的要發(fā)送的消息osip_message_t*sip進(jìn)行分析,找出消息要發(fā)送的真實(shí)char*host,int port的值(這些參數(shù)可以省略,但要發(fā)送消息

25、肯定需要host和port,所以要從sip中解析),最后根據(jù)sip中解析出的傳輸方式是TCP還是UDP選擇最終進(jìn)行消息發(fā)送處理的函數(shù)cb_udp_snd_message,cb_tcp_snd_message處理(它們的參數(shù)一致,即本函數(shù)只是補(bǔ)全一些省略的參數(shù)并對(duì)消息進(jìn)行合法性檢查)。*畢竟eXosip是一個(gè)通用的開發(fā)庫,它考慮了要支持TCP,UDP,TCPs,IPV4,IPV6,WIN32,*nix,WINCE等等多樣化的復(fù)雜環(huán)境,所以,我們可以略過我們暫時(shí)不需要的部分,比如,IPV6相關(guān)的代碼實(shí)現(xiàn)等。由于我們大多數(shù)情況下SIP是用的UDP,所以先來看一下cb_udp_snd_message的

26、實(shí)現(xiàn),它從全局變量exosip中獲取可用的sock,并盡最大能力解析出host和port(?難道前面的函數(shù)還不夠解析徹底?如最終仍無port信息則默認(rèn)設(shè)置為5060),使用osip_message_to_str(sip,&message,&length)函數(shù)將要發(fā)送的格式化的SIP消息轉(zhuǎn)換成能用SOCK傳輸?shù)暮?jiǎn)單數(shù)據(jù)并發(fā)送即完成消息發(fā)送,代碼中有許多復(fù)雜的環(huán)境探測(cè)和錯(cuò)誤控制等等等等,我們可以暫時(shí)不用過多關(guān)注,可以繼續(xù)向下,結(jié)尾處有一個(gè)keeplive相關(guān)代碼,從代碼字面分析,可能是SIP的Register消息的自動(dòng)重發(fā)相關(guān)代碼,可以在后面再細(xì)化分析。cb_tcp_snd_essage的函數(shù)實(shí)現(xiàn)

27、要比上文的udp的實(shí)現(xiàn)簡(jiǎn)單很多,主要是環(huán)境探測(cè)錯(cuò)誤控制方面,因?yàn)楫吘箃cp是穩(wěn)定連接的,對(duì)比一下代碼,可以看到主要流程還是將SIP消息轉(zhuǎn)換后,發(fā)送到從SIP消息中解析出的host和port對(duì)應(yīng)的目標(biāo)??赐陜蓚€(gè)函數(shù),可以知道,eXosip需要有兩個(gè)sock,是一個(gè)數(shù)組,0是給UDP用的,1是給TCP用的,要用SOCK當(dāng)然要初始化,就是下文要介紹的eXosip的網(wǎng)絡(luò)相關(guān)的初始化了,上面的exosip_init可以看成是這個(gè)開發(fā)庫的系統(tǒng)初始化吧:)至些,我們應(yīng)該知道了oSIP開發(fā)的SIP應(yīng)用程序的消息是從哪里發(fā)出的吧,對(duì)了,就是從這個(gè)回調(diào)函數(shù)里,所謂萬事開頭難,就象開發(fā)WIN32應(yīng)用程序時(shí),找到了W

28、IN32程序的main函數(shù)入口下面的工作就好辦了,下面就都是為一些事件消息開發(fā)對(duì)應(yīng)的處理函數(shù)而已了:)osip_set_kill_transaction_callback事務(wù)終結(jié)回調(diào)函數(shù)對(duì)應(yīng)ICT,IST,NICT,NIST客戶/服務(wù)器注冊(cè)/非注冊(cè)事務(wù)狀態(tài)機(jī)的終結(jié),主要是使用osip_remove_transaction(eXosip.j_osip,tr)將當(dāng)前tr事務(wù)刪除,再加上一系列的清理工作,其中,NICT即客戶端的非Invite事務(wù)的清理比較復(fù)雜一些,要處理的內(nèi)容也比較多,可以根據(jù)實(shí)際應(yīng)用的情況進(jìn)行有必要的清理工作:)cb_transport_error傳輸失敗處理回調(diào)對(duì)應(yīng)于上面說到的

29、四種事務(wù)狀態(tài)機(jī),如果它們?cè)谔幚頃r(shí)失敗,則在這時(shí)進(jìn)行統(tǒng)一處理。從代碼可知,只是在NOTIFY,SUBSCRIBE,OPTION操作失敗才進(jìn)行處理,其它錯(cuò)誤可直接忽略。osip_set_message_callback消息發(fā)送處理回調(diào)根據(jù)type不同,表示不同的消息發(fā)送狀態(tài)OSIP_XXX_AGAIN重發(fā)相關(guān)消息OSIP_ICT_INVITE_SENT發(fā)起呼叫OSIP_ICT_ACK_SENT ACK回應(yīng)OSIP_NICT_REGISTER_SENT發(fā)起注冊(cè)O(shè)SIP_NICT_BYE_SENT BYE發(fā)出OSIP_NICT_CANCEL_SENT Cancel發(fā)出OSIP_NICT_INFO_SE

30、NT,OSIP_NICT_OPTIONS_SENT,OSIP_NICT_SUBSCRIBE_SENT,OSIP_NICT_NOTIFY_SENT,OSIP_NICT_UNKNOWN_REQUEST_SENT我們可以看到,eXosip沒有對(duì)它們作任何處理,我們可以根據(jù)自己需要,比如,重發(fā)2xx消息前記錄一下日志之類的,擴(kuò)展一下retransmission的處理方式,發(fā)起Invite前記錄一下通話日志等等。OSIP_ICT_STATUS_1XX_RECEIVED uac收到1xx消息,一般是表示對(duì)端正在處理中,這時(shí),主要是設(shè)置一下事務(wù)狀態(tài)機(jī)的狀態(tài)值,并對(duì)會(huì)話中的osip的一些參數(shù)根據(jù)返回值進(jìn)行相應(yīng)

31、設(shè)置,里面有許多條件判斷,但我們常用的一般是100,180,183的判斷而已,暫時(shí)可以忽略里面復(fù)雜的判斷代碼。OSIP_ICT_STATUS_2XX_RECEIVED uac收到2xx消息,這里主要跟蹤一下Register情況下的2xx,表示注冊(cè)成功,這時(shí)會(huì)更新一下exosip的注冊(cè)字段值,以便讓eXosip能自動(dòng)維護(hù)uac的注冊(cè),BYE的2xx回應(yīng)是終結(jié)消息,Invite的2xx回應(yīng),則主要是初始化一下會(huì)話相關(guān)的數(shù)據(jù),表示已成功建立連接。其它4xx,5xx,6xx則分別是對(duì)應(yīng)的處理,根據(jù)實(shí)現(xiàn)情況進(jìn)行概要的查看即可。report_event(je,sip)是代碼中用來進(jìn)行事件處理的一個(gè)函數(shù),跟

32、蹤后發(fā)現(xiàn),其最終是使用了我們上文提到的jpipe管道,以便在狀態(tài)機(jī)外實(shí)時(shí)觀測(cè)狀態(tài)機(jī)內(nèi)的處理信息。OSIP_NIST_STATUS_XXX_SENT即對(duì)應(yīng)于上面的uac的處理,這里是uas的對(duì)應(yīng)的消息處理,相比較于uac簡(jiǎn)單一點(diǎn)。前面簡(jiǎn)單介紹了一下大量的回調(diào)函數(shù)及它們的概要處理邏輯,可能會(huì)比較混亂,暫時(shí)不用管它,只需要記得一個(gè)大概的形象,知道一個(gè)SIP處理程序是通過osip_set_cb_send_message回調(diào)函數(shù)來實(shí)現(xiàn)真實(shí)地發(fā)送各種SIP消息,并且SIP的標(biāo)準(zhǔn)事務(wù)模型是由oSIP實(shí)現(xiàn)好了,我們只需要給不同的事務(wù)狀態(tài)設(shè)置不同的回調(diào)處理函數(shù)來處理事務(wù),具體的狀態(tài)變化和內(nèi)部邏輯不用管就可以了。

33、下面來說一下消息處理回調(diào)函數(shù)用到的SOCK的初始化函數(shù),即我們上面說的除了系統(tǒng)初始化外的網(wǎng)絡(luò)初始化函數(shù)eXosip_listen_addr:從上文知道了,系統(tǒng)將初始化兩個(gè)SOCK,一個(gè)UDP一個(gè)TCP,但查看代碼發(fā)現(xiàn)還有第三個(gè),TCPs的,但好象還不能實(shí)用,現(xiàn)在不管它,代碼首先是根據(jù)傳輸是UDP還是TCP來設(shè)置對(duì)應(yīng)的數(shù)組值,并且如果沒有提供IP地址和端口號(hào),系統(tǒng)會(huì)自動(dòng)取出本機(jī)網(wǎng)絡(luò)接口并創(chuàng)建可用的SOCK(http_port的方式暫不用考慮)。SOCK初始化后,如何開始SIP事務(wù)的呢?看到這個(gè)調(diào)用eXosip.j_thread=(void*)osip_thread_create(20000,_e

34、Xosip_thread,NULL),對(duì)的,這里啟用了一個(gè)線程,即,eXosip是調(diào)用oSIP的線程函數(shù)(沒用系統(tǒng)提供的線程函數(shù),是為了跨平臺(tái))進(jìn)行事務(wù)處理的狀態(tài)機(jī)邏輯是在一個(gè)線程中處理的,這樣就明白了為什么一直沒能看到順序執(zhí)行下來的程序啟動(dòng)代碼了,接下去看,線程實(shí)際處理函數(shù)是_eXosip_thread,這里面的代碼中,我們看到了上文提到的狀態(tài)機(jī)控制開關(guān)變量while(eXosip.j_stop_ua=0),即,當(dāng)j_stop_ua設(shè)置為1時(shí),osip_thread_exit()結(jié)束事務(wù)處理即程序終結(jié),再接下去看,_eXosip_execute是最終的處理函數(shù)了,而且它在程序未終結(jié)情況下是一

35、直邏輯在執(zhí)行??吹絖eXosip_execute的代碼中有很多時(shí)間函數(shù)和變量,仔細(xì)看,調(diào)用了osip_timers_gettimeout而不是系統(tǒng)API為了跨平臺(tái),來實(shí)現(xiàn)定時(shí)器功能,除去一些控制代碼,主要處理函數(shù)是eXosip_read_message(1,lower_tv.tv_sec,lower_tv.tv_usec),即取出消息,1表示只取出一條消息,其代碼量非常的大,但同樣的,其中也許多的控制代碼和錯(cuò)誤檢測(cè)代碼,我們?cè)诓榭磿r(shí)可以暫時(shí)忽略掉它們。根據(jù)jpipe_read(eXosip.j_socketctl,buf2,499),我們可以估計(jì),buf2中應(yīng)該是保存的我們的控制管道的數(shù)據(jù),具

36、體作用至些還沒有表現(xiàn)出來,應(yīng)該是用來反映一些狀態(tài)機(jī)內(nèi)部的警示之類的信息,實(shí)際的SIP的處理的狀態(tài)機(jī)的數(shù)據(jù)是存放在buf中,使用_eXosip_recvfrom獲取的,獲取后sipevent=osip_parse(buf,i)解析,使用osip_find_transaction_and_add_event(eXosip.j_osip,sipevent)來查詢事件對(duì)應(yīng)的事務(wù)狀態(tài)機(jī),找到后就如同其注解所說明的,/*handled by oSIP!*/,即我們上文設(shè)置的那一大堆回調(diào)函數(shù),至此,我們知道了整個(gè)SIP應(yīng)用所處理的大概流程了。如果沒有找到事務(wù)狀態(tài)機(jī)呢?直接丟棄嗎?不是的,如果這是一個(gè)回應(yīng)消息

37、,但沒有事務(wù)狀態(tài)機(jī)處理它,那它是一個(gè)錯(cuò)誤的,要進(jìn)行清理后才能丟棄,而如果是一個(gè)請(qǐng)求,那更不能丟棄了,因?yàn)閁AS事務(wù)狀態(tài)機(jī)要由它來啟動(dòng)創(chuàng)建的。先來看錯(cuò)誤的回應(yīng)消息的處理函數(shù)eXosip_process_response_out_of_transaction,可以看到其代碼就是一大堆的賦值語句,XXX=NULL,即將一大堆的運(yùn)行時(shí)變量清空,再調(diào)用osip_event_free清空事件,或者就是一些復(fù)雜的情況下,需要通過解析現(xiàn)在的運(yùn)行時(shí)數(shù)據(jù),從中分析出可能的正在等待回應(yīng)的對(duì)端,并發(fā)送相關(guān)終結(jié)通知消息等等,可以根據(jù)實(shí)際需要進(jìn)行簡(jiǎn)化。請(qǐng)求事件處理eXosip_process_newrequest,首先是

38、對(duì)事件進(jìn)行探測(cè),MSG_IS_INVITE、MSG_IS_ACK、MSG_IS_REQUEST,對(duì)事件進(jìn)行所屬狀態(tài)機(jī)分類,隨后使用_eXosip_transaction_init(&transaction,(osip_fsm_type_t)tx_type,eXosip.j_osip,evt-sip)根據(jù)探測(cè)結(jié)果進(jìn)行狀態(tài)機(jī)初始化,實(shí)際調(diào)用的是osip_transaction_init,初始化后即將事件入狀態(tài)機(jī)osip_transaction_add_event(transaction,evt),由狀態(tài)機(jī)自動(dòng)處理后調(diào)用相應(yīng)回調(diào)函數(shù)處理邏輯了。線程調(diào)用的事件處理函數(shù)代碼最后是if(eXosip.keep_alive 0)_eXosip_keep_alive();這段代碼印證了上文提到了,keep_alive是用來設(shè)置是否自動(dòng)重新注冊(cè),由_eXosip_keep_alive函數(shù)來實(shí)現(xiàn)自動(dòng)將eXosip全局變量中保存的注冊(cè)消息解析后自

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論