SIP 嚴格路由和鬆散路由以及RFC3261例子分析

一、請求路由

1、參考IP中的概念:嚴格路由是must,鬆弛路由是preferred.

嚴格路由:

     實際指發送者指明瞭必須經過的路由,如果下一跳路由找不到就返回錯誤;

鬆弛路由:

    只是指出一個routelist,但並不要求消息必須嚴格經過任意兩個相鄰路由記錄,可以經過其他路由器後再到下一跳指定地點。

Eg:如路由指定A-B
     嚴格路由要求到了A後下一跳必須是B
    鬆弛路由要求到了A後可以先到C再到B,只要B即可。

2、SIP中的路由:嚴格路由和鬆散路由
我們經常可以看到在Router字段中設置的SIP URI經常有一個lr的屬性,例如<sip:a.b.c.d;lr>,這就是表示這個地址所在的ProxyServer是一個Loose Router,如果沒有lr屬性,它就是一個StrictRouter。


嚴格路由(Strict Routing):可以理解爲比較“死板”的理由機制,這種路由機制在SIP協議的前身RFC 2534中定義,其機制非常簡單。

處理步驟:

S_1、接收到的消息的request-URI必須是自己的URI

S_2、把第一個Route頭域“彈”出來,並把其中的URI作爲新的request-RUI.

S_3、然後把該消息路由到新的request-URI。

鬆散路由(Loose Routing,lr):該路由機制較爲靈活,也是SIP路由機制的靈魂所在,在SIP根本大典RFC 3261中定義。

處理步驟:

L_1、Proxy首先會檢查消息的request-URI是不是自己屬於自己所負責的域。如果是,它就會通過定位服務將該地址“翻譯”成具體的聯繫地址

          並以此替換掉原來的request-URI;否則,它不會動request-URI。

L_2、Proxy檢查路由表中的第一個地址是否爲自己,如果是則從表中刪除。

L_3、Loose Router首先會檢查Request URI是否爲自己插入到路由表中的地址, 如果不是,則不作處理;如果是,則取出Route字段的最後

          一個地址作爲Request URI地址,並從Route字段中刪去最後一個地址。

L_4、Loose Router檢查下一跳是否爲Strict Router。如果不是,不處理;否則,將Request URI插入到路由表表尾,並用下一跳地址

       (Strict Router的地址)更新Request URI。

L_5、如果路由表爲空,則路由給Request URI(如果路由表非空,且request-uri不是自身,那麼應該路由到最上面的路由表去???)。

總結:Route的優先級高於request-URI的

        可以看到步驟L_3、L_4其實是Loose Router爲了兼容Strict Router而做的額外工作.

(如:步驟L_4中如果下一跳爲Strict Router,那麼必須將下一跳的Strict Router地址更新request-URI,這樣這樣下一條在受到消息時,檢查request-URI時纔會和自己匹配,不至於發生錯誤,因爲StrictRouter要求request-URI必須是自己的URI)。

3、SIP中Route和Record-Route頭域。

SIP中的Via頭域是爲了給一個請求消息的響應消息留後路,而Record-Route就是爲了給該請求消息之後的請求消息留後路。

【說明】

一個SIP消息每經過一個Proxy(包括主叫),都會被加上一個Via頭域,當消息到達被叫後,Via頭域就記錄了請求消息經過的完整路徑。被叫將這些Via頭域原樣copy到響應消息中(包括各Via的參數,以及各Via的順序),然後下發給第一個Via中的URI,每個Proxy轉發響應消息前都會把第一個Via(也就是它自己添加的Via)刪除,然後將消息轉發給新的第一個Via中的URI,直到消息到達主叫。

而在一個請求消息的傳輸過程中,Proxy也可能(純粹自願,如果它希望還能接收到本次會話的後續請求消息的話)會添加一個Record-Route頭域,這樣當消息到達被叫后里面就有會有0個或若干個Record-Route頭域。被叫會將這些Record-Route頭域併入路由集,並併入自己的路由集,隨後被叫在發送請求(和Record-Route屬於同一個dialog裏面)消息時就會使用該路由集構造一系列Route頭域,以便對消息進行路由。

然後,被叫會像上面對待Via頭域一樣,將Record-Route頭域全部原樣copy到響應消息中返回給主叫。

主叫收到響應消息後也會將這些Record-Route頭域併入路由集,只是它會將其反序。該會話中的後續請求(和Record-Route屬於同一個dialog裏面)消息的Route頭域就會通過路由集構造。

【注意】

Record-Route頭域不用來路由,而只是起到傳遞信息的作用

Record-Route頭域不是路由集的唯一來源,路由集還可以通過手工配置等方式得到。

二:應答消息路由
SIP應答消息的路由機制,相對請求來說,比較簡單,基本思想就是,請求從哪裏來,應答回哪裏去。那是如何實現的呢?很簡單,Via頭域就是完成這個差事的。Via頭域表說明了SIP請求實際的路由過程,用於應答消息的回程路由。

三:RFC3261例子解析:

下面就以RFC 3261中的兩個實例解釋,包括每個步驟的解析。

路由示例1:

場景:

兩個UE間有兩個Proxy,U1 -> P1 -> P2 -> U2,並且兩個Proxy都樂意添加Record-Route頭域。

消息流:

【說明】由於我們在此只關心SIP路由機制,因此下面消息中跟路由機制無關的頭域都省略了。

U1發出一個INVITE請求給P1(P1是U1的外撥代理服務器):

INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]

P1不負責域domain.com,消息中也沒有Route頭域,因此通過DNS查詢得到負責該域的Proxy的地址並且把消息轉發過去。這裏P1在轉發前就添加了一個Record-Route頭域,裏面有一個lr參數,說明P1是一個鬆散路由器,遵循RFC3261中的路由機制。


INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: sip:p1.example.com;lr

P2負責域domain.com,因此它通過定位服務得到[email protected] 對應的設備地址是[email protected],因此用新的URI重寫request-URI。消息中沒有Route頭域,因此它就把該消息轉發給request-URI中的URI,轉發前它也增加了一個Record-Route頭域,並且也有lr參數。

INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: <sip:p2.domain.com;lr>
Record-Route: <sip:p1.example.com;lr>

位於u2.domain.com的被叫收到了該INVITE消息,並且返回一個200 OK響應。其中就包括了INVITE中的Record-Route頭域。

SIP/2.0 200 OK
Contact: sip:[email protected]
Record-Route: <sip:p2.domain.com;lr>
Record-Route: sip:p1.example.com;lr

被叫此時也就有了自己的路由集:

(<sip:p2.domain.com;lr>,<sip:p1.example.com;lr>)

並且它本次會話的遠端目的地址設置爲INVITE中Contact中的URI:

[email protected]

此後被叫在該會話中的請求消息就發到這個URI。同樣,被叫在200OK響應中也攜帶了自己的聯繫地址,主叫收到該響應消息後也會把本次會話的遠端目的地址設置爲:

[email protected]

此後主機在該會話中的請求消息就發到這個URI。

同樣,主叫也有了自己的路由集,只是跟被叫的是反序的:

(<sip:p1.example.com;lr>,<sip:p2.domain.com;lr>)

通話完畢後,我們假設主叫先掛機,則主叫發出BYE請求:

BYEsip:[email protected] SIP/2.0
Route: <sip:p1.example.com;lr>,sip:p2.domain.com;lr


可以看到,BYE的Route頭域正是主機的路由集構造來的。

由於p1在第一個Route中,因此BYE首先發給P1。

P1收到該消息後,發現request-URI中的URI不屬於自己負責的域,而消息有Route頭域,並且第一個Route頭域中的URI正是自己,因此刪除之(步驟L_2),並且把消息轉發給新的第一個Route頭域中的URI,也就是P2:

BYEsip:[email protected] SIP/2.0
Route: sip:p2.domain.com;lr

P2收到該消息後,發現request-URI中的URI不屬於自己負責的域(P2負責的是domain.com,而不是u2.domain.com),第一個Route頭域中的URI正是自己,因此刪除之,此時已經沒有Route頭域了,因此就轉發給了request-URI中的URI(步驟L_5)。

被叫就會收到BYE消息:

BYEsip:[email protected] SIP/2.0

路由示例2:

如果說上面的示例主要關注的是路由流程,那麼本示例關注的則是嚴格路由與鬆散路由的區別。

場景:

U1->P1->P2->P3->P4->U2

其中,P3是嚴格路由的,其餘Proxy都是鬆散路由的,並且4個Proxy都很樂意增加Record-Route頭域。

消息流:

我們直接給出了到達被叫的INVITE消息:

INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: <sip:p4.domain.com;lr>
Record-Route: <sip:p3.middle.com>Record-Route:<sip:p2.example.com;lr>
Record-Route: <sip:p1.example.com;lr>

這中間的其他消息我們就不過問了,直接看一下被叫最後發出的BYE消息大概是什麼樣子:

BYEsip:[email protected] SIP/2.0
Route: <sip:p4.domain.com;lr>
Route: <sip:p3.middle.com>
Route: <sip:p2.example.com;lr>
Route: sip:p1.example.com;lr

因爲P4在第一個Route裏,因此被叫將BYE消息發給了P4(route 優先級大於request-uri)。

P4收到該消息後,發現自己不負責域u1.example.com,但是第一個Route頭域中的URI正是自己,因此刪除之(步驟L_2)。

P4還發現新的第一個Route頭域中的URI是一個嚴格路由器,因此它把request-URI中的URI添加到最後一個Route的位置,並且將第一個Route“彈出”並且覆蓋原來的request-URI(步驟_4)。

然後將消息轉發給當前的request-URI,也就是P3。

BYE sip:p3.middle.com SIP/2.0
Route: <sip:p2.example.com;lr>
Route: <sip:p1.example.com;lr>
Route: sip:[email protected]

P3收到該消息後,直接把消息作出如下變換並且發給P2:(步驟S_1 S_2 S_3嚴格路由操作,因爲P3是嚴格路由)

BYE sip:p2.example.com;lr SIP/2.0
Route: <sip:p1.example.com;lr>
Route: sip:[email protected]

P2收到該消息後,發現消息中的request-URI是自己的,因此在進一步處理先首先對消息做如下變換(步驟L_3):

BYEsip:[email protected] SIP/2.0
Route: sip:p1.example.com;lr


然後,P2發現自己不負責域u1.example.com,第一個Route中的URI也不是自己的,因此將消息轉發給該Route去,也就是P1。

P1收到該消息後,發現自己不負責域u1.example.com,但是第一個Route頭域中的URI正是自己,因此刪除之。消息變成下面的樣子:

BYEsip:[email protected] SIP/2.0


既然Route頭域已經是空,因此P1把消息發給u1.example.com。

四:備註:

      Loose Routing爲了實現對Strict Routing的兼容,做了很多額外的工作.

注:本文在網上收集資料以及RFC3261的進程進行整理和修改,轉載請標明出處.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章