2011-04-15 23:21:29| 分類: FreeSWITCH |字號 訂閱html
在 繼續學習 FreeSWITCH 以前咱們有必要來學習一下 SIP 協議,由於它是 FreeSWITCH 的核心。但即便如此,講清楚 SIP 必然須要很大篇幅,本書是關於 FreeSWITCH 的,而重點不是 SIP。所以,我將僅就理解 FreeSWITCH 必需的一些概念加以通俗的解釋,更嚴肅一些的請參閱其它資料或 RFC(Request For Comments)。數據庫
SIP 的概念和相關元素
安全
會 話初始協議(Session Initiation Protocol)是一個控制發起、修改和終結交互式多媒體會話的信令協議。它是由 IETF(Internet Engineering Task Force,Internet工程任務組)在 RFC 2543 中定義的。最先發佈於 1999 年 3 月,後來在 2002 年 6 月又發佈了一個新的標準 RFC 2361。服務器
SIP 是一個基於文本的協議,在這一點上與 HTTP 和 SMTP 類似。咱們來對比一個簡單的 SIP 請求與 HTTP 請求:網絡
GET /index.html HTTP/1.1 INVITE sip:seven@freeswitch.org.cn SIP/2.0
請 求由三部分組成。在 HTTP 中, GET 指明一個獲取資源(文件)的動做,而 /index.html 則是資源的地址,最後是協議版本號。而在 SIP 中,INVITE 表示發起一次請求,seven@freeswitch.org.cn 爲請求的地址,稱爲 SIP URI,最後也是版本號。其中,SIP URI很相似一個電子郵件,其格式爲「協議:名稱@主機」。與 HTTP 和 HTTPS 相對應,有 SIP 和 SIPS,後者是加密的;名稱能夠是一串數字的電話號碼,也能夠是字母表示的名稱;而主機能夠是一個域名,也能夠是一個IP地址。session
SIP 是一個對等的協議,相似 P2P。不像傳統電話那樣必須有一箇中心的交換機,它能夠在不須要服務器的狀況下進行通訊,只要通訊雙方都彼此知道對方地址(或者,只有一方知道另外一方地 址),以下圖,bob 給 alice 發送一個 INVITE 請求,說「Hi, 一塊兒吃飯吧...」,alice 說"好的,OK",電話就通了。併發
在 SIP 網絡中,alice 和 bob 都叫作用戶代理(UA, User Agent)。UA 是在 SIP 網絡中發起或響應 SIP 處理的邏輯功能。UA是有狀態的,也就是說,它維護會話(或稱對話)的狀態。UA 有兩種功能:一種是 UAC(UA Client用戶代理客戶端),它是發起 SIP 請求的一方,如上圖的 bob。另外一種是 UAS(UA Server),它是接受請求併發送響應的一方,如上圖中的 alice。因爲 SIP 是對等的,若是 alice 呼叫 bob 時(有時候 alice 也主動叫 bob 一塊兒吃飯),alice 就稱爲 UAC,而 bob 則執行 UAS的功能。通常來講,UA 都會實現上述兩種功能。app
設 想 bob 和 alice 是經人介紹認識的,而他們還不熟悉,bob 想請 alice 吃飯就須要一箇中間人(M)傳話,而這個中間人就叫代理服務器(Proxy Server)。還有另外一種中間人叫作重定向服務器(Redirect Server),它相似於這樣的方式工做──中間人 M 告訴 bob,我也不知道 alice 在哪裏,但我老婆知道,要否則我告訴你我老婆的電話,你直接問她吧,我老婆叫 W。這樣,M 就成了一個重定向服務器,而他老婆 W 則是真正的代理服務器。這兩種服務器都是 UAS,它們主要是提供一對欲通話的 UA 之間的路由選擇功能。具備這種功能的設備一般稱爲邊界會話控制器(SBC,Service Border Controller)。學習
還 有一種 UAS 叫作註冊服務器。試想這樣一種狀況,alice 仍是個學生,沒有本身的手機,但它又但願 bob 能隨時找到她,因而當她在學校時就告訴中間人 M 說她在學校,若是有事打她能夠打宿舍的電話;而當她回家時也通知 M 說有事打家裏電話。只要 alice 換一個新的位置,它就要向 M 從新「註冊」新位置的電話,以讓 M 能隨時找到她,這時候 M 就是一個註冊服務器。ui
最 後一種叫作背靠背用戶代理(B2BUA,Back-to-Back UA)。須要指出,其實 RFC 3261 並無定義 B2BUA的功能,它只是一對 UAS 和 UAC的串聯。FreeSWITCH 就是一個典型的 B2BUA,事實上,B2BUA 的概念會貫穿本書始終,因此,在此咱們須要多花一點筆墨來解釋。
咱們來看上述故 事的另外一個版本:M 和 W 是一對恩愛夫妻。M 認識 bob 而 W 認識 alice。M 和 W 有意搓合兩個年輕人,但見面時因爲兩人太靦腆而互相沒留電話號碼。過後 bob 相知道 alice 對他感受如何,因而打電話問 M,M 不認識 alice,就轉身問老婆 W (注意此次 M 沒有直接把 W 電話給 bob),W 接着打電話給 alice,alice 說印象還不錯,W 就把這句話告訴 M, M 又轉過身告訴 bob。 M 和 W 一個面向 bob,一個對着 alice,他們兩個合在一塊兒,稱做 B2BUA。在這裏,bob 是 UAC,由於他發起請求;M 是 UAS,由於他接受 bob 的請求併爲他服務;咱們把 M 和 W 看作一個總體,他們背靠着背(站着坐着躺着都行),W 是 UAC,由於她又向 alice 發起了請求,最後 alice 是 UAS。其實這裏UAC 和 UAS 的概念也不是那麼重要,重要的是要理解這個背靠背的用戶代理。由於事情尚未完,bob 一據說 alice 對他印象還不錯,心花盛開,便想請 alice 吃飯,他告訴 M, M 告訴 W, W 又告訴 alice,alice 問去哪吃,W 又只好問 M, M 再問 bob…… 在這對年輕人掛斷電話這前, M 和 W 只能「背對背」的工做。
從 上圖能夠看出,四我的其實全是 UA。從上面故事能夠看出,雖然 FreeSWITCH 是 B2BUA,但也能夠通過特殊的配置,實現一些代理服務器和重定向服務器的功能,甚至也能夠從中間劈開,兩邊分別做爲一個普通的 UA 來工做。這沒有什麼奇怪的,在 SIP 世界中,全部 UA 都是平等的。具體到實物,則 M 和 W 就組成了實現軟交換功能的交換機,它們對外說的語言是 SIP,而在內部,它們則使用本身家的語言溝通。bob 和 alice 就分別成了咱們常見的軟電話,或者硬件的 SIP 電話。
SIP 註冊
不像普通的固定電話網中,電話的地址都是固定的。因特網是開放的,alice 的 UA 可能在家也可能在學校,或者,在世界是任何角落,只要能上網,它就能與世界通訊。爲了讓咱們的 FreeSWITCH 服務器能找到它,它必須向服務器進行註冊。一般的註冊流程是:
Alice FreeSWITCH || | REGISTER | |------------------------------->| | SIP/2.0 401 Unauthorized | |<-------------------------------| | REGISTER | |------------------------------->| | SIP/2.0 200 OK | | |
我 們用真正的註冊流程進行說明。下面的 SIP 消息是在真正的 FreeSWITCH 中 trace 出來的。其中 FreeSWITCH 服務器的 IP 地址是 192.168.4.4,使用默認的端口號 5060,在這裏,咱們使用的是 UDP 協議。 alice 使用的 UAC 是 Zoiper,端口號是 5090(在我寫做時它與 FreeSWITCH 在同一臺機器上,因此不能再使用端口 5060)。其中每一個消息短橫線之間的內容都是 FreeSWITCH 中輸出的調試信息,不是 SIP 的一部分。
------------------------------------------------------------------------ recv 584 bytes from udp/[192.168.4.4]:5090 at 12:30:57.916812: ------------- REGISTER sip:192.168.4.4;transport=UDP SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-d9ed3bbae47e568b-1---d8754z-;rport Max-Forwards: 70 Contact: <sip:alice@192.168.4.4:5090;rinstance=d42207a765c0626b;transport=UDP> To: <sip:alice@192.168.4.4;transport=UDP> From: <sip:alice@192.168.4.4;transport=UDP>;tag=9c709222 Call-ID: NmFjNzA3MWY1MDI3NGViMjY1N2QwZDlmZWQ5ZGY2OGE. CSeq: 1 REGISTER Expires: 3600 Allow: INVITE, ACK, CANCEL, BYE, NOTIFY, REFER, MESSAGE, OPTIONS, INFO, SUBSCRIBE User-Agent: Zoiper rev.5415 Allow-Events: presence Content-Length: 0
recv 代表 FreeSWITCH 收到來自 alice 的消息。咱們前面已經說進,SIP 是純文本的協議,相似 HTTP,因此很容易閱讀。
第一行的 REGISTER 表示是一條註冊消息。
Via 是 SIP 的消息路由,若是 SIP 通過好多代理服務器轉發,則會有多條 Via 記錄。
Max-forwards 指出消息最多能夠通過多少次轉發,主要是爲了防止產生死循環。
Contact 是 alice 家的地址,本例中,FreeSWITCH 應該能在 192.168.4.4 這臺機器上的 5090 端口找到她。
To 和 From 先無論。
Call-ID 是本次 SIP 會話(Session)的標誌。
CSeq 是一個序號,因爲 UDP 是不可靠的協議,在不可靠的網絡上可能丟包,因此有些包須要重發,該序號則能夠防止重發引發的消息重複。
Expires 是說明本次註冊的有效期,單位是秒。在本例中,alice 應該在一小時內再次向 FreeSWITCH 註冊,防止 FreeSWITCH 忘掉她。實際上,大部分 UA 的實現都會在幾十秒內就從新發一次註冊請求,這在 NAT 的網絡中有助於保持鏈接。
Allow 是說明 alice 的 UA 所能支持的功能,某些 UA 功能豐富,而某些 UA 僅有有限的功能。
User-Agent 是 UA 的型號。
Allow-Events 則是說明她容許哪些事件通知。
Content-Length 是消息體(Body)的長度,在這裏,只有消息頭(Header),沒有消息體,所以長度爲 0 。
.
------------------------------------------------------------------------ send 664 bytes to udp/[192.168.4.4]:5090 at 12:30:57.919364: ------------------------------------------------------------------------ SIP/2.0 401 Unauthorized Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-d9ed3bbae47e568b-1---d8754z-;rport=5090 From: <sip:alice@192.168.4.4;transport=UDP>;tag=9c709222 To: <sip:alice@192.168.4.4;transport=UDP>;tag=QFXyg6gcByvUH Call-ID: NmFjNzA3MWY1MDI3NGViMjY1N2QwZDlmZWQ5ZGY2OGE. CSeq: 1 REGISTER User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces WWW-Authenticate: Digest realm="192.168.4.4", nonce="62fb812c-71d2-4a36-93d6-e0008e6a63ee", algorithm=MD5, qop="auth" Content-Length: 0
FreeSWITCH 須要驗證 alice 的身分才容許她註冊。在 SIP 中,沒有發明新的認證方式,而是使用已有的 HTTP 摘要(Digest)方式來認證。401 消息表示未認證,它是 FreeSWITCH 對 alice 的響應。同時,它在本端生成一個認證摘要(WWW-Authenticate),一齊發送給 alice。
------------------------------------------------------------------------ recv 846 bytes from udp/[192.168.4.4]:5090 at 12:30:57.921011: ------------------------------------------------------------------------ REGISTER sip:192.168.4.4;transport=UDP SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-dae1693be9f8c10d-1---d8754z-;rport Max-Forwards: 70 Contact: <sip:alice@192.168.4.4:5090;rinstance=d42207a765c0626b;transport=UDP> To: <sip:alice@192.168.4.4;transport=UDP> From: <sip:alice@192.168.4.4;transport=UDP>;tag=9c709222 Call-ID: NmFjNzA3MWY1MDI3NGViMjY1N2QwZDlmZWQ5ZGY2OGE. CSeq: 2 REGISTER Expires: 3600 Allow: INVITE, ACK, CANCEL, BYE, NOTIFY, REFER, MESSAGE, OPTIONS, INFO, SUBSCRIBE User-Agent: Zoiper rev.5415 Authorization: Digest username="alice",realm="192.168.4.4", nonce="62fb812c-71d2-4a36-93d6-e0008e6a63ee", uri="sip:192.168.4.4;transport=UDP",response="32b5ddaea8647a3becd25cb84346b1c3", cnonce="b4c6ac7e57fc76b85df9440994e2ede8",nc=00000001,qop=auth,algorithm=MD5 Allow-Events: presence Content-Length: 0
alice 收到帶有摘要的 401 後,後新發起註冊請求,這一次,加上了根據收到的摘要和它本身的密碼生成的認證信息(Authorization)。而且,你能夠看到,CSeq 序號變成了 2。
------------------------------------------------------------------------ send 665 bytes to udp/[192.168.4.4]:5090 at 12:30:57.936940: ------------------------------------------------------------------------ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-dae1693be9f8c10d-1---d8754z-;rport=5090 From: <sip:alice@192.168.4.4;transport=UDP>;tag=9c709222 To: <sip:alice@192.168.4.4;transport=UDP>;tag=rrpQj11F86jeD Call-ID: NmFjNzA3MWY1MDI3NGViMjY1N2QwZDlmZWQ5ZGY2OGE. CSeq: 2 REGISTER Contact: <sip:alice@192.168.4.4:5090;rinstance=d42207a765c0626b;transport=UDP>;expires=3600 Date: Tue, 27 Apr 2010 12:30:57 GMT User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Content-Length: 0
FreeSWITCH 收到帶有認證的註冊消息後,覈實 alice 身份,認證經過,迴應 200 OK。 若是失敗,則迴應 403 Forbidden 或其它失敗消息,以下。
------------------------------------------------------------------------ send 542 bytes to udp/[192.168.4.4]:5090 at 13:22:49.195554: ------------------------------------------------------------------------ SIP/2.0 403 Forbidden Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-d447f43b66912a1b-1---d8754z-;rport=5090 From: <sip:alice@192.168.4.4;transport=UDP>;tag=c097e17f To: <sip:alice@192.168.4.4;transport=UDP>;tag=yeecX364pvryj Call-ID: ZjkxMGJmMjE4Y2ZiNjU5MzM5NDZkMTE5NzMzMzM0Mjc. CSeq: 2 REGISTER User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Content-Length: 0
你能夠看到,alice 的密碼是不會直接在 SIP 中傳送的,於是必定程序上保證了安全(固然仍是會有中間人,重放之類的攻擊,咱們留到後面討論)。
SIP 呼叫流程
UA 間直接呼叫
上 面咱們說過,SIP 的 UA 是平等的,若是一方知道另外一方的地址,就能夠通訊。咱們先來作一個實驗。在筆者的機器上,我啓動了兩個軟電話(UA), 一個是 bob 的 X-Lite(左),另外一個是 alice 是 Zoiper。它們的 IP 地址都是 192.168.4.4,而端口號分別是 26000 和 5090,當 bob 呼叫 alice 時,它只需直接呼叫 alice 的 SIP 地址:sip:alice@192.168.4.4:5090。如圖,alice 的電話正在振鈴:
詳細的呼叫流程圖爲:
bob alice | | | INVITE | |-------------------->| | 100 Trying | |<--------------------| | 180 Ringing | |<--------------------| | 200 OK | |<--------------------| | ACK | |-------------------->| | | |<---RTP------------->| |<---RTP------------->| |<---RTP------------->| | ... | | | | BYE | |<--------------------| | 200 OK | |-------------------->| | |
首 先 bob 向 alice 發送 INVITE 請求創建 SIP 鏈接,alice 的 UA 回 100 Trying 說我收到你的請求了,先等會,接着 alice 的電話開始振鈴,並給對回消息 180 Ringing 說我這邊已經振鈴了,alice 一會就過來接電話,bob 的 UA 收到該消息後能夠播放回鈴音。接着 alice 接了電話,她發送 200 OK 消息給 bob,該消息是對 INVITE 消息的最終響應,而先前的 100 和 180 消息都是臨時狀態,只是代表呼叫進展的狀況。 bob 收到 200 後向 alice 回 ACK 證明消息。 INVITE - 200 - ACK 完成三次握手,它們合在一塊兒稱做一個對話(Dialogue)。這時候 bob 已經在跟 alice 能通話了,他們通話的內容(語音數據)是在SIP以外的 RTP 包中傳遞的,咱們後面再詳細討論。
最後,alice 掛斷電話,向 bob 送 BYE 消息,bob 收到 BYE 後回送 200 OK,通話完畢。其中 BYE 和 200 OK 也是一個對話,而上面的全部消息,稱做一個會話(Session)。
反過來也同樣,alice 能夠直接呼叫 bob 的地址: sip:bob@192.168.4.4:26000。
上 面描述了一個最簡單的 SIP 呼叫流程。實際上,SIP 還有其它一些消息,它們大體可分爲請求和響應兩類。請求由 UAC 發出,到達 UAS 後, UAS 回送響應消息。某些響應消息須要證明(ACK),以完成三次握手。其中請求消息包括 INVITE、ACK、OPTIOS、BYE、CANCEL、REGISTER 以及一些擴展 re-INVITE、PRACK、SUBSCRIBE、NOTIFY、UPDATE、MESSAGE、REFER等。而響應消息則都包含一個狀態碼。跟 HTTP 響應相似,狀態碼有三位數字組成。其中,1xx 組的響應爲臨時狀態,代表呼叫進展的狀況;2xx 代表請求已成功處理;3xx 代表 SIP 請求須要轉向到另外一個 UAS 處理;4xx 代表請求失敗,這種失敗通常是由客戶端或網絡引發的,如密碼錯誤等;5xx 爲服務器內部錯誤;6xx 爲更嚴重的錯誤。
經過 B2BUA 呼叫
在真實世界中,bob 和 alice 確定要常常改變位置,那麼它們的 SIP 地址也會相應改變,而且,若是他們之中有一個或兩個處於 NAT 的網絡中時,直接通訊就更困難了。因此,他們一般會藉助於一個服務器來相互通訊。經過註冊到服務器上,他們均可以得到一個服務器上的 SIP 地址。註冊服務器的地址通常是不變的,所以他們的 SIP 地址就不會發生變化,於是,他們老是可以進行通訊。
我 們讓他們兩個都註冊到 FreeSWITCH 上。上面已經說過,FreeSWITCH 監聽的端口是 SIP 默認的端口 5060。bob 和 alice 註冊後,他們分別得到了一個服務器的地址(SIP URI):sip:bob@192.168.4.4 和 sip:alice@192.168.4.4(默認的端口號 5060 能夠省略)。
下面是 bob 呼叫 alice 的流程。須要指出,若是 bob 只是發起呼叫而不接收呼叫,他並不須要向 FreeSWITCH 註冊(有些軟交換服務器須要先註冊才能發起呼叫,但 SIP 是不強制這麼作的)。
------------------------------------------------------------------------ recv 1118 bytes from udp/[192.168.4.4]:26000 at 13:31:39.938891: ------------------------------------------------------------------------ INVITE sip:alice@192.168.4.4 SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-56adad736231f024-1---d8754z-;rport Max-Forwards: 70 Contact: <sip:bob@192.168.4.4:26000> To: "alice"<sip:alice@192.168.4.4> From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 1 INVITE Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO Content-Type: application/sdp User-Agent: X-Lite release 1014k stamp 47051 Content-Length: 594
上 面的消息中省略了 SDP 的內容,咱們將留到之後再探討。bob 的 UAC 經過 INVITE 消息向 FreeSWITCH 發起請求。bob 的 UAC 用的是 X-Lite(User-Agent),它運行在端口 26000 上(實際上,它默認在端口也是 5060,但因爲在個人實驗環境下它也是跟 FreeSWITCH 運行在一臺機器上,已被佔用,所以它須要選擇另外一個端口)。其中,From 爲主叫用戶的地址,To 爲被叫用戶的地址。此時 FreeSWITCH 做爲一個 UAS 接受請求並進行響應。它得知 bob 要呼叫 alice,須要在本身的數據庫中查找 alice 是否已在服務器上註冊,好知道應該怎麼找到 alice。但在此以前,它先通知 bob 它已經收到了他的請求。
------------------------------------------------------------------------ send 345 bytes to udp/[192.168.4.4]:26000 at 13:31:39.940278: ------------------------------------------------------------------------ SIP/2.0 100 Trying Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-56adad736231f024-1---d8754z-;rport=26000 From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a To: "alice"<sip:alice@192.168.4.4> Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 1 INVITE User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Content-Length: 0
FreeSWITCH 經過 100 Trying 消息告訴 bob 「我已經收到你的消息了,彆着急,我正在聯繫 alice 呢...」 該消息稱爲呼叫進展消息。
------------------------------------------------------------------------ send 826 bytes to udp/[192.168.4.4]:26000 at 13:31:39.943392: ------------------------------------------------------------------------ SIP/2.0 407 Proxy Authentication Required Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-56adad736231f024-1---d8754z-;rport=26000 From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a To: "alice" <sip:alice@192.168.4.4>;tag=B4pem31jHgtHS Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 1 INVITE User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Accept: application/sdp Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Allow-Events: talk, presence, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer Proxy-Authenticate: Digest realm="192.168.4.4", nonce="31c5c3e0-cc6e-46c8-a661-599b0c7f87d8", algorithm=MD5, qop="auth" Content-Length: 0
但就在此時,FreeSWITCH 發現 bob 並非受權用戶,於是它須要確認 bob 的身份。它經過發送帶有 Digest 驗證信息的 407 消息來通知 bob(注意,這裏與註冊流程中的 401 不一樣)。
------------------------------------------------------------------------ recv 319 bytes from udp/[192.168.4.4]:26000 at 13:31:39.945314: ------------------------------------------------------------------------ ACK sip:alice@192.168.4.4 SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-56adad736231f024-1---d8754z-;rport To: "alice" <sip:alice@192.168.4.4>;tag=B4pem31jHgtHS From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 1 ACK Content-Length: 0
bob 回送 ACK 證明消息向 FreeSWITCH 證明已收到認證要求。並從新發送 INVITE,此次,附帶了驗證信息。
------------------------------------------------------------------------ recv 1376 bytes from udp/[192.168.4.4]:26000 at 13:31:39.945526: ------------------------------------------------------------------------ INVITE sip:alice@192.168.4.4 SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-87d60b47b6627c3a-1---d8754z-;rport Max-Forwards: 70 Contact: <sip:bob@192.168.4.4:26000> To: "alice"<sip:alice@192.168.4.4> From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 INVITE Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO Content-Type: application/sdp Proxy-Authorization: Digest username="bob",realm="192.168.4.4", nonce="31c5c3e0-cc6e-46c8-a661-599b0c7f87d8", uri="sip:alice@192.168.4.4",response="327887635344405bcd545da06763c466", cnonce="c164b74f625ff2161bd8d47dba3a0ee2",nc=00000001,qop=auth, algorithm=MD5 User-Agent: X-Lite release 1014k stamp 47051 Content-Length: 594
這裏也省略了 SDP 消息體。
------------------------------------------------------------------------ send 345 bytes to udp/[192.168.4.4]:26000 at 13:31:39.946349: ------------------------------------------------------------------------ SIP/2.0 100 Trying Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-87d60b47b6627c3a-1---d8754z-;rport=26000 From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a To: "alice"<sip:alice@192.168.4.4> Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 INVITE User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Content-Length: 0
FreeSWITCH 從新回 100 Trying,告訴 bob 呼叫進展狀況。
至此,bob 與 FreeSWITCH 之間的通訊已經初步創建,這種通訊的通道稱做一個信道(channel)。該信道是由 bob 的 UA 和 FreeSWITCH 的一個 UA 構成的,咱們稱它爲 FreeSWITCH 的一條腿,叫作 a-leg。
接下來 FreeSWITCH 要創建另外一條腿,稱爲 b-leg。它經過查打本地數據庫,獲得了 alice 的位置,接着啓動一個 UA(用做 UAC),向 alice 發送 INVITE 消息。以下:
------------------------------------------------------------------------ send 1340 bytes to udp/[192.168.4.4]:5090 at 13:31:40.028988: ------------------------------------------------------------------------ INVITE sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4;rport;branch=z9hG4bKey90QUyHZQXNN Route: <sip:alice@192.168.4.4:5090>;rinstance=e7d5364c81f2b879;transport=UDP Max-Forwards: 69 From: "Bob" <sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg To: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP> Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 INVITE Contact: <sip:mod_sofia@192.168.4.4:5060> User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Allow-Events: talk, presence, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer Content-Type: application/sdp Content-Disposition: session Content-Length: 313 X-FS-Support: update_display Remote-Party-ID: "Bob" <sip:bob@192.168.4.4>;party=calling;screen=yes;privacy=off
你 能夠看到,該INVITE 的 Call-ID 與前面的不一樣,說明這是另外一個 SIP 會話(Session)。另外,它還多了一個 Remote-Party-ID,它主要是用來支持來電顯示。由於,在 alice 的話機上,但願顯示 bob 的號碼,顯示呼叫它的那個 UA(負責 b-leg的那個 UA)沒什麼意義。與普通的 POTS 電話不一樣,在 SIP 電話中,不只能顯示電話號碼(這裏是 bob),還能顯示一個可選的名字(「Bob」)。這也說明了 FreeSWITCH 這個 B2BUA 自己是一個總體,它雖然是以一個單獨的 UA 呼叫 alice,但仍是跟負責 bob 的那個 UA 有聯繫--就是這種背靠背的串聯。
------------------------------------------------------------------------ recv 309 bytes from udp/[192.168.4.4]:5090 at 13:31:40.193634: ------------------------------------------------------------------------ SIP/2.0 100 Trying Via: SIP/2.0/UDP 192.168.4.4;rport=5060;branch=z9hG4bKey90QUyHZQXNN To: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP> From: "Bob" <sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 INVITE Content-Length: 0
跟上面的流程差很少,alice回的呼叫進展。此時,alice 的 UA 開始振鈴。
------------------------------------------------------------------------ recv 431 bytes from udp/[192.168.4.4]:5090 at 13:31:40.193816: ------------------------------------------------------------------------ SIP/2.0 180 Ringing Via: SIP/2.0/UDP 192.168.4.4;rport=5060;branch=z9hG4bKey90QUyHZQXNN Contact: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP> To: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP>;tag=3813e926 From: "Bob"<sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 INVITE User-Agent: Zoiper rev.5415 Content-Length: 0
180也是呼叫進展消息,它說明,我這邊已經準備好了,alice 的電話已經響了,她聽到了一會就會接聽。
send 1125 bytes to udp/[192.168.4.4]:26000 at 13:31:40.270533: ------------------------------------------------------------------------ SIP/2.0 183 Session Progress Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-87d60b47b6627c3a-1---d8754z-;rport=26000 From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a To: "alice" <sip:alice@192.168.4.4>;tag=cDg7NyjpeSg4m Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 INVITE Contact: <sip:alice@192.168.4.4:5060;transport=udp> User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Accept: application/sdp Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Allow-Events: talk, presence, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer Content-Type: application/sdp Content-Disposition: session Content-Length: 267 Remote-Party-ID: "alice" <sip:alice@192.168.4.4>
FreeSWITCH 在收到 alice 的 180 Ringing 消息後,便告訴 bob 呼叫進展狀況,183 與 180 不一樣的是,它包含 SDP,即接下來它會向 bob 發送 RTP 的媒體流,就是回鈴音。
------------------------------------------------------------------------ recv 768 bytes from udp/[192.168.4.4]:5090 at 13:31:43.251980: ------------------------------------------------------------------------ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.4.4;rport=5060;branch=z9hG4bKey90QUyHZQXNN Contact: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP> To: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP>;tag=3813e926 From: "Bob"<sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 INVITE Allow: INVITE, ACK, CANCEL, BYE, NOTIFY, REFER, MESSAGE, OPTIONS, INFO, SUBSCRIBE Content-Type: application/sdp User-Agent: Zoiper rev.5415 Content-Length: 226
alice 接聽電話之後,其 UA 向 FreeSWITCH 送 200 OK,即應答消息。
------------------------------------------------------------------------ send 436 bytes to udp/[192.168.4.4]:5090 at 13:31:43.256692: ------------------------------------------------------------------------ ACK sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4;rport;branch=z9hG4bKF72SSpFNv0K8g Max-Forwards: 70 From: "Bob" <sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg To: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP>;tag=3813e926 Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 ACK Contact: <sip:mod_sofia@192.168.4.4:5060> Content-Length: 0
FreeSWITCH 向 alice 回送證明消息,證明已經知道了。至此,b-leg已經徹底創建完畢,多半這時 alice 已經開始說話了:「Hi, bob,你好……」
------------------------------------------------------------------------ send 1135 bytes to udp/[192.168.4.4]:26000 at 13:31:43.293311: ------------------------------------------------------------------------ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-87d60b47b6627c3a-1---d8754z-;rport=26000 From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a To: "alice" <sip:alice@192.168.4.4>;tag=cDg7NyjpeSg4m Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 INVITE Contact: <sip:alice@192.168.4.4:5060;transport=udp> User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Allow-Events: talk, presence, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer Session-Expires: 120;refresher=uas Min-SE: 120 Content-Type: application/sdp Content-Disposition: session Content-Length: 267 Remote-Party-ID: "alice" <sip:alice@192.168.4.4>
與此同時,它也給 bob 送應答消息,告訴他電話已經接通了,能夠跟 alice 說話了。在須要計費的狀況下,應該今後時開始對 bob 的電話計費。bob 的 UA 收到該消息後啓動麥克風讓 bob 講話。
------------------------------------------------------------------------ recv 697 bytes from udp/[192.168.4.4]:26000 at 13:31:43.413025: ------------------------------------------------------------------------ ACK sip:alice@192.168.4.4:5060;transport=udp SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-ef53864320037c04-1---d8754z-;rport Max-Forwards: 70 Contact: <sip:bob@192.168.4.4:26000> To: "alice"<sip:alice@192.168.4.4>;tag=cDg7NyjpeSg4m From: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 ACK Proxy-Authorization: Digest username="bob",realm="192.168.4.4", nonce="31c5c3e0-cc6e-46c8-a661-599b0c7f87d8", uri="sip:alice@192.168.4.4",response="327887635344405bcd545da06763c466", cnonce="c164b74f625ff2161bd8d47dba3a0ee2",nc=00000001,qop=auth, algorithm=MD5 User-Agent: X-Lite release 1014k stamp 47051 Content-Length: 0
bob 在收到應答消息後也須要回送證明消息。至此 a-leg 也創建完畢。雙方正常通話。
[][][][][][] 此處省略 5000 字 [][][][][]
------------------------------------------------------------------------ recv 484 bytes from udp/[192.168.4.4]:5090 at 13:31:49.949240: ------------------------------------------------------------------------ BYE sip:mod_sofia@192.168.4.4:5060 SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-2146ae0ddd113efe-1---d8754z-;rport Max-Forwards: 70 Contact: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP> To: "Bob"<sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg From: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP>;tag=3813e926 Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 2 BYE User-Agent: Zoiper rev.5415 Content-Length: 0
終於聊完了,alice 掛斷電話,發送 BYE 消息。
------------------------------------------------------------------------ send 543 bytes to udp/[192.168.4.4]:5090 at 13:31:49.950425: ------------------------------------------------------------------------ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.4.4:5090;branch=z9hG4bK-d8754z-2146ae0ddd113efe-1---d8754z-;rport=5090 From: <sip:alice@192.168.4.4:5090;rinstance=e7d5364c81f2b879;transport=UDP>;tag=3813e926 To: "Bob"<sip:bob@192.168.4.4>;tag=Dp9ZQS3SB26pg Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 2 BYE User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Content-Length: 0
FreeSWITCH 返回 OK,b-leg 釋放完畢。
------------------------------------------------------------------------ send 630 bytes to udp/[192.168.4.4]:26000 at 13:31:50.003165: ------------------------------------------------------------------------ BYE sip:bob@192.168.4.4:26000 SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4;rport;branch=z9hG4bKggvjUH0rS99tc Max-Forwards: 70 From: "alice" <sip:alice@192.168.4.4>;tag=cDg7NyjpeSg4m To: "Bob" <sip:bob@192.168.4.4>;tag=15c8325a Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 130069219 BYE Contact: <sip:alice@192.168.4.4:5060;transport=udp> User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-16981M Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Reason: Q.850;cause=16;text="NORMAL_CLEARING" Content-Length: 0
接下來 FreeSWITCH 給 bob 發送 BYE,通知要拆線了。出於對 bob 負責,它包含了掛機緣由(Hangup Cause),此處 NOMAL_CLEARING 表示正常釋放。
------------------------------------------------------------------------ recv 367 bytes from udp/[192.168.4.4]:26000 at 13:31:50.111765: ------------------------------------------------------------------------ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.4.4;rport=5060;branch=z9hG4bKggvjUH0rS99tc Contact: <sip:bob@192.168.4.4:26000> To: "Bob"<sip:bob@192.168.4.4>;tag=15c8325a From: "alice"<sip:alice@192.168.4.4>;tag=cDg7NyjpeSg4m Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 130069219 BYE User-Agent: X-Lite release 1014k stamp 47051 Content-Length: 0
bob 回送 OK,a-leg 釋放完畢,通話結束。從下圖能夠很形象地看出 FreeSWITCH 的兩條「腿」-- a-leg 和 b-leg。
整個呼叫流程圖示以下:
bob (UAC) [ UAS-UAC ] (UAS) alice | | | | | INVITE | | | |-------------------->| | | | 100 Trying | | | |<--------------------| | | | 407 Authentication Required | |<--------------------| | | | ACK | | | |-------------------->| | | | INVITE | | | |-------------------->| | | | 100 Trying | | INVITE | |<--------------------< >-------------------->| | | | 100 Trying | | | |<--------------------| | 183 Progress | | 180 Ringing | |<--------------------< |<--------------------| | | | 200 OK | | | |<--------------------| | 200 OK | | ACK | |<--------------------< >-------------------->| | ACK | | | |-------------------->| | | | | | Call Connected | | | | | | BYE | | | |<--------------------| | BYE | | 200 OK | |<--------------------< >-------------------->| | 200 OK | | | |-------------------->| | | | | | |
從流程圖能夠看出,右半部分跟上一節「UA間直接呼叫」同樣,而左半部分也相似。這就更好的說明了實際上有 4 個 UA (兩對)參與到了通訊中,而且,有兩個 Session。
再論 SIP URI
上面咱們介紹了一些 FreeSWITCH 的基本概念,並經過一個真正的呼叫流程講解了一下 SIP。因爲實驗中全部 UA 都 運行在一臺機器上,這可能會引發迷惑,若是咱們有三臺服務器,那麼狀況多是:
/---------------\ | FreeSWITCH | | 192.168.0.1 | \ --------------/ sip:bob@192.168.0.1 / \ sip:alice@192.168.0.1 / \ / \ /-----------------\ /-----------------\ | bob | | alice | | 192.168.0.100 | | 192.168.0.200 | \-----------------/ \-----------------/ sip:bob@192.168.0.100 sip:alice@192.168.0.200
alice 註冊到 FreeSWITCH,bob呼叫她時,使用她的服務器地址,即 sip:alice@192.168.0.1,FreeSWITCH 接到請求後,查找本地數據庫,發現 alice 的實際地址是 sip:alice@192.168.0.200,即可以創建呼叫。
SIP URI 除使用 IP 地址外,也可使用域名,如 sip:alice@freeswitch.org.cn。更高級也更復雜的配置則須要 DNS 的 SRV 記錄,在此就不作討論了。