SIP協議及與Freeswitch的關係

在繼續學習 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:[email protected] SIP/2.0

請求由三部分組成。在 HTTP 中, GET 指明一個獲取資源(文件)的動作,而 /index.html 則是資源的地址,最後是協議版本號。而在 SIP 中,INVITE 表示發起一次請求,[email protected] 爲請求的地址,稱爲 SIP URI,最後也是版本號。其中,SIP URI很類似一個電子郵件,其格式爲“協議:名稱@主機”。與 HTTP 和 HTTPS 相對應,有 SIP 和 SIPS,後者是加密的;名稱可以是一串數字的電話號碼,也可以是字母表示的名稱;而主機可以是一個域名,也可以是一個IP地址。

SIP 是一個對等的協議,類似 P2P。不像傳統電話那樣必須有一箇中心的交換機,它可以在不需要服務器的情況下進行通信,只要通信雙方都彼此知道對方地址(或者,只有一方知道另一方地址),如下圖,bob 給 alice 發送一個 INVITE 請求,說“Hi, 一起吃飯吧...”,alice 說"好的,OK",電話就通了。

4-1

在 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 都會實現上述兩種功能。

設想 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 就是一個註冊服務器。

最後一種叫做背靠背用戶代理(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 只能“背對背”的工作。

4-2

從上圖可以看出,四個人其實全是 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:  To:  From: ;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: ;tag=9c709222 To: ;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:  To:  From: ;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: ;tag=9c709222 To: ;tag=rrpQj11F86jeD Call-ID: NmFjNzA3MWY1MDI3NGViMjY1N2QwZDlmZWQ5ZGY2OGE. CSeq: 2 REGISTER Contact: ;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: ;tag=c097e17f To: ;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:[email protected]:5090。如圖,alice 的電話正在振鈴:

4-4

詳細的呼叫流程圖爲:

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:[email protected]: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:[email protected] 和 sip:[email protected](默認的端口號 5060 可以省略)。

下面是 bob 呼叫 alice 的流程。需要指出,如果 bob 只是發起呼叫而不接收呼叫,他並不需要向 FreeSWITCH 註冊(有些軟交換服務器需要先註冊才能發起呼叫,但 SIP 是不強制這麼做的)。

------------------------------------------------------------------------ recv 1118 bytes from udp/[192.168.4.4]:26000 at 13:31:39.938891: ------------------------------------------------------------------------ INVITE sip:[email protected] SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-56adad736231f024-1---d8754z-;rport Max-Forwards: 70 Contact:  To: "alice" From: "Bob";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";tag=15c8325a To: "alice" 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";tag=15c8325a To: "alice" ;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:[email protected] SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-56adad736231f024-1---d8754z-;rport To: "alice" ;tag=B4pem31jHgtHS From: "Bob";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:[email protected] SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4:26000;branch=z9hG4bK-d8754z-87d60b47b6627c3a-1---d8754z-;rport Max-Forwards: 70 Contact:  To: "alice" From: "Bob";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:[email protected]",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";tag=15c8325a To: "alice" 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:[email protected]:5090;rinstance=e7d5364c81f2b879;transport=UDP SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4;rport;branch=z9hG4bKey90QUyHZQXNN Route: ;rinstance=e7d5364c81f2b879;transport=UDP Max-Forwards: 69 From: "Bob" ;tag=Dp9ZQS3SB26pg To:  Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 INVITE Contact:  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" ;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:  From: "Bob" ;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:  To: ;tag=3813e926 From: "Bob";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";tag=15c8325a To: "alice" ;tag=cDg7NyjpeSg4m Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 INVITE Contact:  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" 

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:  To: ;tag=3813e926 From: "Bob";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:[email protected]: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" ;tag=Dp9ZQS3SB26pg To: ;tag=3813e926 Call-ID: 0d74ac35-cca4-122d-81a2-2990e5b2bd3e CSeq: 130069214 ACK Contact:  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";tag=15c8325a To: "alice" ;tag=cDg7NyjpeSg4m Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 2 INVITE Contact:  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" 

與此同時,它也給 bob 送應答消息,告訴他電話已經接通了,可以跟 alice 說話了。在需要計費的情況下,應該從此時開始對 bob 的電話計費。bob 的 UA 收到該消息後啓動麥克風讓 bob 講話。

------------------------------------------------------------------------ recv 697 bytes from udp/[192.168.4.4]:26000 at 13:31:43.413025: ------------------------------------------------------------------------ ACK sip:[email protected]: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:  To: "alice";tag=cDg7NyjpeSg4m From: "Bob";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:[email protected]",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:[email protected]: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:  To: "Bob";tag=Dp9ZQS3SB26pg From: ;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: ;tag=3813e926 To: "Bob";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:[email protected]:26000 SIP/2.0 Via: SIP/2.0/UDP 192.168.4.4;rport;branch=z9hG4bKggvjUH0rS99tc Max-Forwards: 70 From: "alice" ;tag=cDg7NyjpeSg4m To: "Bob" ;tag=15c8325a Call-ID: YWEwYjNlZTZjOWZjNDg3ZjU3MjQ3MTA1ZmQ1MDM5YmQ. CSeq: 130069219 BYE Contact:  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:  To: "Bob";tag=15c8325a From: "alice";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。

4-3

整個呼叫流程圖示如下:

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:[email protected] / \ sip:[email protected] / \ / \ /-----------------\ /-----------------\ | bob | | alice | | 192.168.0.100 | | 192.168.0.200 | \-----------------/ \-----------------/ sip:[email protected] sip:[email protected]

alice 註冊到 FreeSWITCH,bob呼叫她時,使用她的服務器地址,即 sip:[email protected],FreeSWITCH 接到請求後,查找本地數據庫,發現 alice 的實際地址是 sip:[email protected],便可以建立呼叫。

SIP URI 除使用 IP 地址外,也可以使用域名,如 sip:[email protected]。更高級也更復雜的配置則需要 DNS 的 SRV 記錄,在此就不做討論了。

轉載:http://www.voip88.com/article-1154-1.html

發佈了10 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章