SIP協議詳解(中文)-5

事務分爲客戶端和服務端兩方。客戶端的事務是客戶端事務,服務器端的事務就是服務端事務。客戶端事務發出請求,並且服務端事務送回應答。客戶端和服務端事務都是邏輯上的概念,他們可以被無數部件所包含。特別是,他們在UA中和有狀態的proxy服務器中存在。以第四節的例子來說明。在這個例子中,UAC執行客戶端事務,它的外發proxy執行服務端事務。外發proxy同時也執行客戶端事務,把請求發送到一個那發proxy的服務端事務。這個proxy也同時執行一個客戶端事務,把請求發到一個UAS的服務端事務上去。這個在圖四中比較明白:

+---------+         +---------+            +---------+         +---------+
|        +-+|Request |+-+     +-+|Request    |+-+    +-+|Request |+-+        |
|        |C||------->||S|     |C||------->    ||S|    |C||------->||S|        |
|        |l||         ||e|     |l||            ||e|    |l||         ||e|        |
|        |i||         ||r|     |i||            ||r|    |i||         ||r|        |
|        |e||         ||v|     |e||            ||v|    |e||         ||v|        |
|        |n||         ||e|     |n||            ||e|    |n||         ||e|        |
|        |t||         ||r|     |t||            ||r|    |t||         ||r|        |
|        | ||         || |     | ||            || |    | ||         || |        |
|        |T||         ||T|     |T||            ||T|    |T||         ||T|        |
|        |r||         ||r|     |r||            ||r|    |r||         ||r|        |
|        |a||         ||a|     |a||            ||a|    |a||         ||a|        |
|        |n||         ||n|     |n||            ||n|    |n||         ||n|        |
|        |s||Response||s|     |s||Response    ||s|    |s||Response||s|        |
|        +-+|<-------|+-+     +-+|<-------    |+-+    +-+|<-------|+-+        |
+---------+         +---------+            +---------+         +---------+
UAC                Outbound            Inbound               UAS
Proxy                Proxy
圖4: 事務關係
無狀態的proxy並沒有客戶端或者服務端的事務。事務是一邊基於UA或者有狀態的proxy,另外一邊也基於UA或者有狀態的proxy。在SIP事務範疇下,無狀態的proxy是用作透明轉發很有效。客戶端事務的用處是用於從一個元素中接收一個請求,這個客戶端是內嵌的(這個元素就是”事務用戶”或者TU;它可以是一個UA或者有狀態的proxy),並且可靠的把這個請求傳送到一個服務端事務。

客戶端事務也負責接收應答並且把應答轉交TU處理,過濾掉重發的應答或者不允許的應答(比如給ACK的應答)。另外,在INVITE請求的情況下,客戶端事務也負責產生給2xx應答的ACK請求。

類似的,服務端事務也負責從通訊層接收請求並且轉發這個請求到TU。服務端事務過濾重發的請求。並且服務端事務從TU接收應答並且轉發到通訊層來發送。在INVITE事務的情況下,它需要接收給非2xx應答的終結應答的ACK請求。

2xx應答和它的ACK請求通過特定的方式來接收和處理。這個應答只會被UAS重發,並且它的ACK只由UAC產生。由於呼叫者知道整個已經接收呼叫的用戶集合,所以需要這種端到端的處理。由於這樣的特別處理,2xx應答的重發是基於UA核心的,並非基於通訊層。類似的,給2xx應答的ACK處理也是由UA核心處理的,每個路徑上的proxy僅僅轉發這些INVITE的2xx應答以及他們的ACK。

17.1 客戶端事務
客戶端事務是通過維持一個狀態機來提供服務的。

TU和客戶端事務通過一個簡單的接口進行通訊。當TU希望初始化一個新的事務,它創建一個客戶端事務並且通過設置ip地址,端口和transport來把一個SIP請求交給它傳送。然後客戶端事務開始執行它自己的狀態機。合乎規格的應答會從客戶端事務傳送給TU。

總共有兩種類型的客戶端事務狀態機,根據TU傳遞的請求的方法不同來區分的。一個用於處理INVITE請求。這種狀態機對應的是一個INVITE客戶事務。另外一個是用來處理其他所有的非INVITE請求的。它對應的是非INVITE客戶事務。對於ACK來說,是不存在客戶事務的。如果TU希望送一個ACK請求,它直接交給通訊層進行通訊處理。

INVITE事務和其他事務是不同的,因爲它的時間週期很長。通常,對於INVITE請求的應答來說,都需要人的參與,這樣會導致在應答INVITE請求之前會有很長的延時。在三方握手(人,兩方機器)的時候也會有很長的延時。在另一方面,其他請求的響應都是很快就完成的。因爲其他非INVITE請求事務是雙方的握手,TU能夠立刻對非INVITE請求作出應答。

17.1.1 INVITE客戶事務
17.1.1.1 INVITE事務概述
INVITE請求包含了一個三方的握手。客戶端事務發送一個INVITE,服務端事務回送一個應答,客戶端事務發送一個ACK。對於非可靠傳輸(比如UDP),客戶端事務每隔T1重發請求,每次重發後間隔時間加倍。T1是一個估計的循環時間(round-trip time,RTT),缺省設置成爲500ms。幾乎所有的事務定時器都以T1爲單位,並且調整T1的值也就調整了那些定時器的值。請求不會在可靠的通訊協議上重新發送。在接收到1xx應答以後,重發機制完全停止,並且客戶端等待更進一步的應答。服務端事務可以發送附加的1xx應答,這個應答並非由服務端事務可靠傳輸。最後,服務端事務會發送一個終結應答。對於非可靠的傳輸協議,應答會間隔時間來重發,對於可靠的傳輸協議,它只發送1次。對於客戶端事務所接收的每一個終結應答,客戶端事務都發送一個ACK,用於終止應答的重發送。

17.1.1.2 正式的描述
INVITE客戶端事務的狀態機在圖5中展示。初始狀態,”calling”,必須保證TU是用INVITE請求來初始化一個新的客戶端事務。客戶端事務必須把請求發送到通訊層來進行發送(18節)。如果使用的是非可靠傳輸的通訊層,客戶端事務必須啓動一個定時器A並且由缺省值T1組成。如果是一個可靠的通訊協議,那麼客戶端事務不應當啓動定時器A(定時器A控制請求的重發送)。對於任何通訊協議來說,客戶端事務必須啓動一個定時器B並且有着64×T1秒的缺省值(定時器B控制事務的超時)。

當定時器A觸發了,客戶端事務必須重發這個請求,把請求交給通訊層進行發送,並且重新設置定時器爲2*T1。在傳輸層中重傳的定義是指把剛纔通過傳輸層發送的消息,再次交給傳輸層重新發送一次。

當定時器A在2×T1後觸發了,請求必須再次重傳(如果客戶端事務依舊還是在這個狀態的話)。這個處理必須持續下去,這樣請求才能每重發一次以後定時器延時1倍。重發機制只有當客戶端事務在”calling”狀態的時候才能進行。

缺省的T1是500ms。T1是一個RTT的估計時間,是在客戶端和服務端的一個事務處理的估計時間。節點可以(不推薦)使用更小的T1值,比如私有網絡,並不接到INTERNET的網絡可以設置小一點。T1也可以設置成爲大一點的值,並且我們建議如果當我們知道RTT值比較大的時候(比如高延時的網絡)應當設置T1成爲大一點的值。不管T1如何取值,本節要求的重傳機制要求的指數延時是必須使用的。

當定時器B觸發的時候,如果客戶端事務是依舊在”calling”狀態,那麼客戶端事務應當通知TU發生了超時。客戶端事務必須不能產生ACK。64×T1是和在不可靠通訊鏈路上傳輸7個請求的時間相同。

如果客戶端事務在”calling”狀態接收到一個臨時應答,那麼就把狀態切換到”proceeding”狀態,客戶端事務不應當再次重新發送請求了。進一步說,臨時應答必須傳送給TU。在”proceeding”狀態的任何臨時應答都必須傳送給TU。

當在”calling”或者”proceeding”狀態的時候,如果接收到一個應答碼是300-699的應答,那麼就必須把狀態切換到”Completed”。客戶端事務必須把收到的應答轉給TU,並且客戶端事務必須傳生ACK請求,即使通訊層是可靠傳輸的(在17.1.1.3節中有描述怎樣根據應答創建一個ACK請求)並且把ACK交給傳輸層進行傳送。ACK必須和原始請求發送到相同的地址,端口和用同樣的transport。當客戶端事務進入”Completed”狀態的時候,應當開始一個定時器D,缺省值是在非可靠通訊上是至少32秒,在可靠通訊上是0秒。定時器D反應了服務端事務在非可靠傳輸的情況下,在”completed”狀態維持的時間。這個是和INVITE請求服務端事務定時器H相同的,定時器H的缺省值是64*T1。不過,客戶端事務不知道服務端事務使用的T1值,所以我們用絕對值32秒來代替T1用作定時器D的缺省值。

在”completed”狀態下,受到的任何終結應答的重傳都應當產生一個ACK應答到通訊層來重新發送,但是新近收到的應答卻不能傳送給TU。一個應答是否是重傳的定義是根據這個應答是否和客戶端事務按照17.1.3定義的規則匹配。



























圖5: INVITE客戶端事務

如果在客戶端事務狀態是”Completed”的時候,定時器D觸發,那麼客戶端事務必須轉到終結狀態。當客戶端狀態是”calling”或者”proceeding”狀態的時候,接收到一個2xx應答必須導致客戶端事務進入”terminated”狀態,並且應答必須交給TU處理。處理這個應答的方法依賴於TU是否是一個proxy核心還是是UAC核心。UAC核心會給應答產生ACK,proxy核心會轉發一個200(OK)應答到上行隊列。這個在proxy和UAC之間,對200(OK)的不同的處理是導致對應答的處理不在事務層進行的原因。

當客戶端事務進入”terminate”狀態以後,客戶端事務必須立刻銷燬。這樣才能保證正確操作。原因是當給一個INVITE請求的2xx應答的不同處理;對於proxy轉發的時候和對UAC處理ACK的時候是不一樣的。因此,每一個2xx都需要交給proxy 核心(這樣才能被轉發),或者交給UAC核心(這樣才能被ACK確認)。這期間沒有事務層的處理。無論應答是否由通訊層收到,如果通訊層找不到匹配的客戶端事務(用17.1.3的方式),那麼應答就應當交給核心處理。這是由於與之匹配的客戶端事務已經被第一個2xx應答所銷燬,後續的2xx應當就匹配不成功了,於是就交給核心來處理。

17.1.1.3 構造ACK請求
本節定義了在客戶端事務中構造ACK請求的方法。UAC核心爲2xx應答產生ACK請求必須使用13節描述的方法,而不是用下邊的方法。

在客戶端事務中構造的ACK請求必須包括與原始請求相同的Call-ID, From, Request-URI頭域值(就是說和在客戶端事務發到通訊層的請求中的這些頭域值相同)。在ACK請求中的To頭域必須和被確認的應答的To頭域值相同,因此通常和原始請求有所不同,不同點在增加了附加的tag參數。ACK必須包含一個單個的Via頭域,並且必須和原始請求的最上邊一個Via頭域值相等。ACK的Cseq頭域必須包含和原始請求的Cseq的序列號相同,但是方法參數應當是”ACK”。

如果INVITE請求的應答是有Route頭域的,這些Route頭域必須也在ACK中。這是確保ACK能夠正確路由通過下行隊列的無狀態的proxy。

雖然請求可以包含一個包體,但是ACK的包體卻比較特別,因爲請求不能因爲不能理解包體而拒絕這個請求。因此,我們不建議在給非2xx應答的ACK請求中放置包體,但是如果放置了,並且假設給INVITE的應答不是415應答,那麼包體的類型應當嚴格和INVITE請求中定義的那樣。如果是415應答,那麼ACK的包體應當和415應答中的Accept列出的類型一致。

例如:有如下請求
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=88sja8x
Max-Forwards: 70
Call-ID: 987asjd97y7atg
Cseq: 986759 INVITE

給非2xx終結應答的ACK請求應當是:
ACK sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
To: Bob <sip:[email protected]>;tag=99sa0xk
From: Alice <sip:[email protected]>;tag=88sja8x
Max-Forwards: 70
Call-ID: 987asjd97y7atg
Cseq: 986759 ACK

17.1.2 非INVITE客戶端事務
17.1.2.1 非INVITE事務概覽
非INVITE事務並不使用ACK。他們只是簡單的請求-應答的交互。對於非可靠的通訊來說,請求是間隔倍增T1的時間重新傳輸(直到間隔時間達到T2)。如果收到了一個臨時應答,在非可靠通訊上,重傳繼續知道達到T2。只有當重傳的請求收到的時候,服務端事務會重傳其發出的最後一個應答,既可以是臨時的應答也可以是終結應答。這就是爲什麼請求在收到一個臨時應答之後還需要一直重傳的原因;他們能夠確保收到一個終結應答。

不像INVITE事務,非INVITE事務不需要對2xx應答做特別處理。UAC對一個非INVITE請求來說,只會產生一個單個的2xx應答。

17.1.2.2 正式的描述
在圖6中講述了非INVITE客戶端事務的狀態機。這個狀態機和INVITE客戶端事務的狀態機非常像。

當TU用請求來初始化一個新的客戶端事務的時候,首先進入的是“trying”狀態。當進入這個狀態的時候,客戶端事務應當初始化一個定時器F,這個定時器F應當有一個初始值64×T1秒。這個請求必須交給通訊層來發送。如果使用的是非可靠傳輸的通訊協議,客戶端事務必須還設置定時器E,初始值是T1。如果定時器E觸發了,並且還是在”trying”狀態,那麼定時器需要設置成爲MIN(2*T1,T2),並且重新發送;如果再次觸發了,那麼就再設置成爲MIN(4*T1,T2),每次都是倍增,知道T2。這個過程會一直繼續,直到重發的間距是T2爲止。缺省的T2是4秒,並且它大概是一個在沒有立刻響應的情況下,非INVITE服務端事務處理一個請求的時間。根據缺省的T1和T2,那麼間隔就會是:500ms,1s,2s,4s,4s,4s以次類推。

如果定時器F觸發了,並且客戶端事務依舊是在”trying”狀態,那麼客戶端事務應當通知TU這個超時,並且轉入”terminate”狀態。如果在”trying”狀態的時候收到了一個臨時應答,那麼這個應答必須轉給TU處理,並且客戶端事務轉到”proceeding”狀態。如果在”trying”狀態收到了一個終結應答(200-699的應答碼),那麼應答必須交給TU,並且客戶端事務必須轉到”Completed”狀態。

如果定時器E在”Proceeding”狀態觸發了,那麼請求必須交給通訊層進行傳輸,並且定時器E必須重新設置成爲T2秒。如果定時器F在”Proceeding”狀態觸發了,那麼必須通知TU超時了,並且客戶端事務必須轉到終結狀態。如果在”Proceeding”狀態的時候收到了一個終結應答(狀態碼200-699),這個應答必須發送給TU,並且客戶端事務必須轉到”Completed”狀態。

一旦客戶端事務進入”Completed”狀態,對於非可靠傳輸的情況,客戶端事務必須設置一個定時器K=T4秒,對於可靠傳輸的情況,設置定時器K=0秒。這個”Completed”狀態維持的目的是爲了緩衝可能會收到的其他重發的應答(這是爲什麼客戶端事務在這裏爲非可靠傳輸維持一段時間的原因)。T4代表了網絡在客戶端和服務端事務中傳輸信息可能的時間。缺省的值T4=5秒。當應答具有相同的事務匹配的時候,根據17.1.3的判定,這個應答就是重發的應答。如果定時器K在這個狀態被觸發,客戶端事務必須轉到”Terminate”狀態。

當事務進入終結狀態,就必須立刻終止了。

17.1.3 客戶端事務匹配應答
當客戶端事務的通訊層收到一個應答,他必須決定是否由客戶端事務來處理這個應答,這樣17.1.1和17.1.2才能夠正確執行。在Via頭域的最上邊的branch參數就是用來做這個的。一個應答和一個客戶端事務匹配的話,就有兩個條件:
1、    如果應答Via最上邊的branch參數和創建這個客戶端事務的請求的Via最上邊的branch參數相同。
2、    如果Cseq頭域的方法參數和創建事務的請求的方法相同。這是因爲CANCEL方法的事務和源請求的事務不同,但是卻有相同的branch參數所決定的。

如果一個請求是廣播發送的,他可能從不同的服務器上得到不同的應答。這些應答的最上邊的Via都有相同的branch參數,但是在To tag中是不同的。當收到了第一個應答,基於上邊的規則,將會判定是這個客戶端事務的應答,其他的應答將會視同爲重發。這並不是錯誤的情況;多點傳送SIP只是提供了一個根本的”尋找最接近的單點”服務的方法,這樣就限定了只需要處理一個單個應答。詳情參見18.1.1。



17.1.4 處理通訊錯誤。






























圖6:非INVITE客戶端事務
當客戶端事務發送一個請求到通訊層發送的時候,如果通訊層報告發送失敗,那麼需要執行下列步驟。

客戶端事務應當通知TU這個通訊失敗,並且客戶端事務應當直接轉到”Terminate”狀態。TU處理通訊失敗的機制在附件[4]中描述。

17.2 服務端事務
服務端事務是用來傳輸請求到TU並且可靠的傳輸應答的。它是通過狀態機來實現的。服務端事務是當請求到達的時候由核心創建的,事務的處理也是主要圍繞着對應請求的(也就是說並非全部都是和對應請求相關)。

和客戶端事務對應的,狀態機依賴於是否接收的請求是INVITE請求。

17.2.1 INVITE服務端事務
INVITE服務端事務的狀態圖在圖7表達。

當爲一個請求創建了服務端事務的時候,服務端事務進入”proceeding”狀態。除非服務端事務知道TU在200ms之內會生成臨時或者終結應答(在這種情況下,TU可能會產生100Trying應答),他必須生成100(Trying)應答。這個臨時應答是用來停止客戶端重發請求的,這個可以避免網絡風暴。這個100(Trying)應答是根據8.2.6節描述的步驟構造的,除此之外: 如果接收的請求頭中的To頭域沒有tag標誌,那麼原來描述的可以增加tag標記,更改成爲不應該增加tag標誌。這個請求必須交給TU處理。

TU可以給服務端事務任意數量個臨時應答。只要服務端事務在”proceeding”狀態,每個臨時應答都應當交給通訊層發送。這些臨時應答並非被通訊層可靠的發送(他們並不重新發送臨時應答)並且臨時應答並不改變服務端事務的狀態。如果在”proceeding”狀態,收到一個請求的重發請求,那麼就需要把從TU最近收到的那個臨時應答重新交給通訊層發送一次。請求是否是重發的請求,是基於17.2.3來判定的匹配相同服務端事務的請求。

如果,在”proceeding”狀態,TU發送了一個2xx應答給服務端事務,服務端事務必須把這個應答交給通訊層進行發送。這個並非由服務端事務進行重發;對於2xx應答的重發是由TU處理的。服務端事務必須轉到”Terminated”狀態。

當在”Proceeding”狀態的時候,如果TU交給服務端事務一個300到699的應答,那麼應答必須交給通訊層進行發送,並且狀態機必須進入”Completed”狀態。對於非可靠傳輸的情況,必須設置定時器G=T1秒,對於可靠傳輸的情況,不設置定時器G(=0的情況就是不設置)
這個是和RFC2543所不同的,2543要求應答都要重發,甚至在可靠傳輸的情況下。

當進入了”Completed”狀態,必須爲所有的傳輸,設置一個定時器H=64×T1秒。定時器H決定何時服務端事務取消重發應答。這個值和定時器B的取值一樣,是等同於客戶端事務會重試發送請求的時間。如果定時器G觸發了,那麼應答會交給通訊層再次發送,並且定時器設置成爲MIN(2*T1,T2)秒。依此類推,當定時器G再次觸發,那麼定時器G的值會翻倍,直到T2。這個和非INVITE客戶端事務的”trying”請求的重發機制是一樣的。進一步說,當在”Completed”狀態的時候,如果接收到重發的請求,服務端事務應當把應答交給通訊層再次發送。

當服務端事務在”Completed”狀態的時候,如果收到了一個ACK請求,服務端事務必須轉到”Confirmed”狀態。因爲定時器G會在這個狀態被忽略,所有的應答重發都會被終止。

如果在”completed”狀態的時候,定時器H觸發了,就意味着沒有收到ACK請求。在這個情況下,服務端事務必須轉到”Terminated”狀態,並且必須通知TU事務失敗。































圖7:INVITE服務端事務

設定”Confirmed”狀態的目的是爲了處理任何附加的ACK消息,這是由重發的終結應答所觸發的。當進入這個狀態,如果是在不可靠傳輸協議,那麼就要設定一個定時器I=T4秒,如果是可靠傳輸協議,那麼就設定I=0。當定時器I觸發了,服務端事務必須轉到”Terminated”狀態。

當服務端事務狀態處於”Terminated”狀態,這個事務必須立刻銷燬。和客戶端事務一樣,這是爲了保證給INVITE的2xx應答的可靠性。

17.2.2 非INVITE服務端事務
對非INVITE服務端事務的狀態機是在圖8中表示。

 

當收到一個不是INVITE或者ACK的請求的時候,狀態機會初始化成爲”trying”狀態。並且這個請求會交給TU處理。當在”trying”狀態,任何重發的請求會被忽略。一個請求在通過17.2.3節的步驟,匹配現有的服務端事務,將被認爲是重發的請求。

當處於”trying”狀態,如果TU交給服務端事務一個臨時應答,服務端事務應當進入”Proceeding”狀態。這個應答必須交給通訊層進行發送。在”Proceeding”狀態下從TU收到的任何應答都必須交給通訊層進行發送。如果一個重發的請求在”proceeding”狀態下收到了,那麼最近發出的一個臨時應答應當再次交給通訊層進行重發。如果在”Proceeding”狀態下,TU交給服務端事務一個終結應答(應答碼是200-699),那麼服務端事務必須進入”Completed”狀態,並且應答必須交給通訊層進行發送。

當服務端事務進入了”Completed”狀態,對於不可靠傳輸協議來說,必須設定一個定時器J=64×T1秒,對於可靠傳輸來說,設定爲0秒(就是不設定定時器)。當在”Completed”狀態下,當服務端事務收到了一個重發的請求的時候,服務端事務必須交給通訊層終結應答來重新發送。在”Completed”狀態下,任何其他TU傳遞下來給服務端事務的終結應答都必須被拋棄。服務端事務保持這個狀態直到定時器J觸發,當定時器J觸發了以後,服務端事務必須進入”Terminated”狀態。

17.2.3 爲服務端事務匹配請求。
當服務端從網絡上收到一個請求以後,他必須和現有的事務進行判定。這個是根據下邊的規則來判定的。

首先要檢查請求中的Via頭域的最上一個branch參數。如果他以”z9hG4bk”開頭,那麼這個請求一定是由客戶端事務根據本規範產生的。因此,branch參數在該客戶端發出的所有的事務中都是唯一的。根據下列規則我們可以判定請求是否和事務匹配:

1、    請求中的最上的Via頭域的branch參數和創建本事務的請求的最上的Via頭域的branch參數一樣,並且:
2、    請求的最上的Via頭域的sent-by參數和創建本事務的請求的最上的Via頭域的send-by參數一樣,並且:
3、    請求的方法和創建本事務的方法一樣。這有一個例外,就是ACK,ACK對應的創建本事務的請求方法是INVITE。
這個匹配規則用於INVITE和非INVITE事務。

send-by參數被用於匹配過程,這是因爲有可能存在無意/惡意的相同的不同客戶端傳來的branch參數。

如果最上的Via頭域的branch參數不存在,或者沒有包含那個”z9hG4bk”,那麼就用下列步驟進行判定。這是爲了和RFC2543進行兼容的。

如果是INVITE請求,並且這個INVITE請求的Request-URI,To tag,From tag,Call-ID,Cseq,和最上的Via頭域都和創建事務的INVITE請求的這些字段匹配,那麼這個INVITE請求就是匹配這個事務的INVITE請求。在這個情況下,INVITE就是創建這個事務的INVITE請求的一個重發。ACK請求在匹配創建事務的INVITE請求的Request-URI, From tag, Call-ID ,Cseq序列號(非方法字段), 最上的Via頭域,並且To tag和服務端事務發出的應答的To tag相同,這個ACK就是這個事務的ACK。當這些頭域比較完成,那麼這個匹配也就完成了。在ACK比較中包含To tag的比較是爲了在proxy上能夠區別給2xx的ACK和給其他應答的ACK,這個proxy可能會轉發全部的應答(這個會在某種罕見的情況下發生。特別是,當一個proxy分支一個請求,接着宕機了,應答會轉發到別的proxy,這個proxy可能會終止轉發多重應答到上行隊列)。一個匹配INVITE請求事務的ACK請求,如果這個INVITE請求已經被前一個ACK請求所匹配,那麼這個ACK請求就是上一個ACK請求的重發。




























圖8: 非INVITE 服務端事務

對於所有的其他請求方法,如果請求的Request-URI,To tag,From tag,Call-ID, Cseq(包括Cseq中的方法字段),以及Via頭域的最上值,都和創建服務端事務的請求想匹配,那麼這個請求就是這個事務的匹配請求。匹配是基於針對每一個頭域值的判定進行的。當非INVITE請求和現有事務匹配了,那麼它就是創建這個事務的請求的一個重發。

由於匹配規則中包含了Request-URI,服務器不能匹配應答對應到事務。所以當TU傳送了一個應答到服務端事務,它必須爲這個應答指定傳送到那個服務端事務。

17.2.4 處理通訊錯誤
當服務端事務發送一個應答到通訊層要發送的時候,如果通訊層報告發送失敗,那麼就需要執行下列的步驟:

首先,附件[4]的步驟需要執行,這就是說需要把應答發送一個備份的地點。如果這個也失敗了,基於[4]中對失敗的定義,服務端事務應當通知TU發送失敗,並且把狀態切換到終止狀態。

18 通訊(transport)
通訊層負責請求和應答在網絡上的實際傳輸。這包括了在面向連接的通訊方式下的請求和應答所使用的連接管理。

通訊層負責管理像TCP/SCTP之類通訊協議的長連接,或者在這些協議上的TLS連接,並且包括管理打開這些連接的使用者的管理。這包括了客戶端或者服務端通訊層打開的連接,這樣在客戶端服務端通訊函數可以共享這些連接。這些連接採用一組用遠端的地址,端口,通訊協議標誌的索引來進行管理。當通訊層打開了一個連接,這個連接的索引就設置成爲遠端的IP,端口,還有打開這個連接的通訊層的實例 。當通訊層接收了一個連接,那麼這個連接的索引就被設置成爲連接方的源IP地址,port,還有通訊層的實例transport。注意,由於源端口port通常是臨時創建的,但是由於通過附件[4]的步驟不能知道它是臨時創建的還是配置的,所以通訊層被動接收的連接通常是不被重複使用的。這就是說,如果兩個proxy再一個”peering”(點對點)的關係中,使用一個面向連接的通訊協議通常有兩個連接要使用,每個都是自己作爲主動方連接的。

我們建議在實現中,當發送(或者接收)完成最後一個消息之後,依舊維持這個連接一段時間(這段時間可以是實現自己定義的時間)。這段時間應當是至少等於本節點的事務從創建到結束的最長時間。這是爲了讓事務能夠在他們所創建的同一個連接上完成(比如,在這個連接上完成請求,應答的處理,在INVITE的情況下的給非2xx的ACK應答等等)。這通常意味着至少64×T1秒(參見17.1.1.1中關於T1的定義)。不過,如果當本程序的TU使用的是一個比較大的定時器C(參見16.6節11步)的時候,也可以選取一個比較大的值。

所有的SIP元素都必須實現基於UDP和TCP的通訊。SIP元素還可以實現其他的協議。

要求UA支持TCP是對RFC2543的一個重要改進。這是由於需要處理更大的消息,就像接下來講到的那樣,必須使用到TCP協議。因此,即使是SIP元素不要發送大的消息,但是由於它可能收到大消息並且處理這些消息,所以,要求支持TCP。

18.1 客戶Clients
18.1.1 發送請求
通訊層的客戶端負責發送請求和接收應答。通訊層的用戶把請求交給通訊層的實例進行處理,包括IP地址端口,通訊層實例,還有可能有多點廣播的TTL。

如果請求的大小和MTU差是在200個字節以內的,或者它是大於1300字節的,並且路徑MTU的大小是未知的,那麼請求必須遵循RFC2914[43]控制阻塞的傳輸協議,比如使用TCP。如果這導致了Via最上邊指定的通訊協議的改變,那麼Via最上邊的值就必須也隨之改變。這使得在UDP傳輸上的消息的分割,並且也提供了大消息的傳輸阻塞控制。不過,在實現上,必須能夠支持達到最大包大小的消息的處理。對於UDP來說,包含了IP和UDP頭的大小是65535個字節。

在消息的大小和MTU之間的200個字節的”buffer”,提供了一個機制使得在SIP的應答中,可以超過請求的大小。比如在INVITE請求的應答中,增加了Record-Route頭域值。有了這個額外的buffer,應答可以大概比請求大170個字節,而且在Ipv4上不用進行分塊傳輸(假設沒有IPSec,大概IP/UDP會使用30個字節)。當MTU是未知的時候,選取1300是基於假設Ethernet的MTU是1500字節的基礎上。

如果SIP元素是因爲消息大小的限制,所以基於TCP發送一個請求,並且消息如果不是因爲大小的限制,會使用UDP來發送,並且如果建立連接產生一個ICMP 協議不支持的錯誤,或者導致TCP reset,那麼這個元素就應當用UDP重試這個請求。這只是爲了向後兼容RFC 2543針對不支持TCP的實現。在本規範以後的改動中,這部分內容會有修訂。

如果客戶端向多個地址發送請求,那麼必須增加”maddr”參數到Via頭域值上,並且這個參數值指定多個目的地址,對於Ipv4來說,應當增加”ttl”參數=1,IPV6的多點傳送在本規範中沒有定義,會在後續的標準中描述。

這些規則定義了SIP的多點傳送。首要的目的是爲了提供”尋找最接近的單點”服務(”single-hop-discovery-like”),這個服務將請求轉發到一組類似的服務器,並且只需要處理其中任意一個服務器的應答。這個功能主要用於註冊服務。實際上,基於17.1.3的事務處理規則,客戶端事務會接收第一個應答,並且因爲其他應答包含同樣的Via的branch參數,而視這些應答爲重發應答。

在請求發送嵌,客戶端通訊層必須在Via頭域中增加一個”sent-by”欄。這個字段包含了一個IP地址或者主機名,端口。我們推薦使用FQDN方法描述這個主機名。這個字段在某些特定情況下,用於發送應答。如果端口不存在,缺省的值依賴於通訊協議。對於UDP,TCP和SCTP來說是5060,TLS是5061。

對於可靠傳輸協議,應答通常簡單的通過連接發送,並且這個連接是收到對應請求的連接。因此,客戶端傳輸層必須準備在發出請求的同一個連接上接收應答。在出現錯誤的情況下,服務端可能會嘗試新建立一個連接來發送應答。爲了能夠處理這種情況,通訊層必須準備接收一個從源IP建立的新連接,這個連接的IP是請求發起的源IP,port是在”sent-by”字段中指定的port。這也同樣要求準備接收從任意地址和端口來得新連接上接收應答,這個端口是由服務器根據附件[4]的5節所講述的步驟來選取的。

對於非可靠的傳輸協議,客戶端通訊層必須準備從發送請求的那個原始IP地址上接收應答。(因爲應答會送到原始地址去),並且端口號是在”sent-by”字段的端口好。進一步說,和可靠傳輸一樣,早某些情況下,應答會發往不同的地方。客戶端必須能夠準備從其他地址和端口上接收應答,這個端口是由服務器根據附件[4]的5節所講述的步驟來選取的。

對於多點傳送的情況來說,客戶端通訊層必須準備從相同的多點傳輸組上接收應答,這個組的地址和端口和發出請求的組相同(就是說,它必須是發送請求的那個多點傳輸組的一個成員)。

如果請求發送的目的IP地址,端口和transport都和現有的一個連接相同,那麼建議使用這個連接來發送請求,同時也允許新建立一個連接來發送。

如果請求通過多點發送,那麼它發送的一組地址,端口和TTL都是由通訊層的用戶提供。如果請求是通過不可靠通訊協議發送,那麼發送的IP地址和端口也是由通訊層的用戶提供。

18.1.2 接收應答
當應答接收到的時候,客戶端通訊層檢查最上的Via頭域值。如果”sent-by”參數不符合客戶端通訊層在請求中插入的值,那麼這個應答必須悄悄丟棄。

如果由任何客戶端事務存在,客戶端通訊層使用17.1.3的步驟來匹配現存的事務和這個接收到的應答。如果匹配到了,應答必須交給事務層進行處理。否則,應答必須交給核心去處理(無論是有狀態的proxy,還是無狀態的proxy,還是UA的核心)。處理這些”stray”(迷路)的應答是基於核心的策略的(如果是proxy就會轉發,如果是UA就會忽略,等等)。

18.2 服務端
18.2.1 接收請求
一個服務器應當能夠接收從任何IP地址、端口和協議上過來的請求。他們是通過對這個服務器的SIP或者SIPS URI(附件[4])的DNS查找,得到這個服務器的地址然後連接和發送的請求的。在這裏,”handing out”(發佈)包含了在REGISTER請求或者轉發應答的Contact頭域中放一個URI,或者在請求或者應答的”Record-Route”頭域中放一個URI。這個URI可以通過放在網頁或者名片上被”handing out”(發佈)。同樣的我們也建議服務器在公網上監聽缺省的SIP端口(TCP/UDP是5060,5061是在TCP上的TLS)。如果是在局域網上,或者私有網上,或者一個物理服務器上運行好幾個服務實例,那就很自然的可以設置成不同的。對於服務器監聽UDP的任何端口和界面,都必須在TCP上也進行同樣的監聽。這是因爲可能消息還需要通過TCP進行傳輸,比如消息過大的情況。所以,在相反的情況下就不需要了。如果一個服務器在TCP監聽了,那麼它不一定需要在UDP上也進行相應的監聽。當然服務器也可以因爲某些原因在特定地址和端口上監聽UDP。當服務端事務從任意一個通訊層上接收到一個請求的時候,它必須檢查最上的Via頭域的”sent-by”參數。如果”sent-by”參數的主機部分包含了一個主機名,或者它包含的IP地址和包的源地址不同,服務器必須增加一個”received”參數到這個Via頭域值中。這個參數必須包含收到的包的原地址。由於服務端必須把應答發送給收到請求的那個源IP地址,所以這個可以用來幫助服務端通訊層發送應答。

一個服務端通訊層收到的請求可能是這樣的(部分):

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP bobspc.biloxi.com:5060

請求是從源IP:192.0.2.4收到的。在請求轉交到上層之前,通訊層增加了一個”received”參數,這樣請求的部分就是:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP bobspc.biloxi.com:5060;received=192.0.2.4

接着,服務端通訊層嘗試和服務端事務做匹配。這個使用的是17.2.3節定義的規則。如果匹配上一個服務端事務,那麼請求就交給那個事務去處理。如果沒有匹配到事務,請求就交給核心去處理,可能會創建一個新的服務端事務來處理。注意當UAS核心給INVITE請求發送一個2xx應答的時候,服務端事務已經銷燬了。這就是說,當ACK收到的時候,不會有匹配的服務端事務,並且基於這個規則,ACK回交給UAS核心來處理。

18.2.2 發送應答
服務端事務使用最上邊的Via頭域值來決定把應答發送到哪裏。它必須遵從如下步驟來發送:
o 如果”sent-protocol”是一個可靠的傳輸協議比如TCP或者SCTP,或者在其上的TLS,應答必須用現存的到原始請求(創建這個事務的請求)的連接進行發送(如果連接還存在的情況下)。這個要求服務端通訊層保留服務端事務和通訊層連接的相關性。如果連接不存在了,服務端應當創建一個新的連接,如果存在”received”參數,就用對應的在”received”參數中指定的IP地址。如果存
在”sent-by”參數,那麼就用”sent-by”指定的port,如果不存在,那麼就用缺省的port。如果對應的連接已經失效,那麼服務器應當採用附件[4]的步驟來決定使用那個IP地址和端口來建立連接並且發送應答。

o 否則,如果Via頭域包含一個”maddr”參數,就必須把應答轉發到maddr所指明的地址,並且使用”sent-by”所指定的端口,如果沒有sent-by參數,那麼就使用5060缺省參數。如果地址是一個多點地址,應答應當使用”ttl”參數所指定的TTL,或者如果沒有指定”ttl”參數,則使用TTL=1的參數。

o 否則(對於非可靠傳輸),如果Via的最上頭域包含一個”received”參數,那麼應答必須發送到”received”參數所指定的地址,並且使用”sent-by”所指定的端口,如果沒有sent-by參數,那麼就使用5060缺省參數。如果這步失敗了,比如,如果得到一個ICMP”端口不能到達”的錯誤,那麼就應當根據附件[4]的第5節的步驟來決定應當把應答發送到哪裏。

o 否則,如果沒有receiver-標記,那麼應答應當使用附件[4]的第5節指定的步驟,送到”sent-by”參數指定的地址。

18.3 分塊
在面向消息的通訊協議中(比如UDP),如果消息有一個Content-Length頭域,那麼消息體就有可能包含很多字節。並且收到的包中除了這個消息體的Content-Length字節意外,還有通訊層附加的通訊包字節,那麼這部分額外的字節應當被丟棄。如果通訊包在沒有收到完整的Content-Length字節的消息體就終止了,這就意味着出錯了。如果這個消息是一個應答,那麼這個消息必須被丟棄。如果消息是一個請求,那麼本程序應當給出一個400(Bad Request)應答。如果消息沒有包含一個Content-Length頭域,消息體的結束點就是消息體的結束點。

在面向流的通訊協議中(比如TCP),Content-Length頭域標誌這包體的大小。在面向流的通訊協議中,必須使用Content-Length字段。

18.4 錯誤處理
錯誤的處理取決於出現錯誤的消息是請求還是應答。

如果通訊層的用戶要求在一個非可靠傳輸協議上發送一個消息,並且結果是一個ICMP錯誤,那麼錯誤處理的方法依賴於ICMP錯誤類型。當通訊層遇到主機、網絡、端口或者協議無法到達的錯誤,或者參數錯誤的時候,應當通知通訊層的用戶發送失敗。Source quench和TTL exceeded ICMP錯誤應當被忽略。

如果通訊層用戶要求在一個可靠傳輸協議上發送一個請求,並且結果是一個連接錯誤,通訊層應當通知通訊層用戶這個發送錯誤

19 常見消息部件(Common Message Components)
在SIP消息中,有一些很長用的部件。(甚至在SIP消息外這些部件也存在)。這些部件值得我們單獨討論一下。

19.1 SIP和SIPS統一資源標記
SIP或者SIPS 的URI用來標記一個通訊用的資源。就像其他所有的URI一樣,SIP和SIPS URI可以放在網頁上,email消息裏,或者打印出來的名片上等等。在這些URI裏邊包含了足夠的信息來發起和維持到這個資源的一個通訊會話。

一個通訊資源的例子包含下列內容:

o 一個在線服務的用戶
o 一個多線電話
o 消息系統中的郵箱
o 網關服務的PSTN電話號碼
o 一個組織中的一個部門(比如”銷售”,或者”helpdesk”)

SIPS URI定義了對資源的訪問是安全的。這就意味着,特別是,在UAC和這個資源的主機之間的通訊是基於TLS的。從資源的主機到用戶之間的通訊是加密安全的,這個安全機制是依賴於主機的實現的。任何用SIP URI描述的資源,只要想通過加密的形式進行通訊,都可以通過簡單改變一下資源描述府就可以”升級”成爲一個SIPS URI。

19.1.1 SIP和SIPS部件
“sip:”和”sips:”描述符是遵循RFC2396[5]的規範定義的。他們使用類似mailto URL的格式定義,允許有SIP請求頭域字段和SIP消息體的規範。這使得在網頁上或者email中,可以用URI來初始化一個會話,這個會話有特定的主題,媒體類別,緊急類型。這個SIP或者SIPS URI的格式規範在25節定義。一個SIP URI的通常格式是這樣的:

sip: user:password@host:port;uri-parameters?headers

這個和SIPS URI的格式是相同的,只是SIPS用”sips”來代替sip。這些符號,和符號的擴展,具有下列意義:

user: 這是在主機的特定資源地址。”主機”(host)在這裏通常指的是一個域名。URI中的”userinfo”包含了這個用戶域,口令域,並且包含其後的一個@。URI的用戶信息部分是可選的,或者說是可以沒有的;當目的主機沒有用戶的概念或者主機本身就是資源的目標,那麼這個URI的用戶信息部分就是可以沒有的。如果在SIP或者SIPS URI中有@,那麼用戶部分必須不能爲空的。如果主機部分可以處理電話號碼地址,比如說是一個internet電話網關,那麼根據RFC2806[9]定義的電話號碼域應當出現在用戶信息部分。在19.1.2節有關於在SIP或者SIPS URI中的電話號碼描述域的額外說明

password:password字段是和用戶相關的。SIP或者SIPS URI語法允許增加password這個字段,這種用法我們是不推薦的,因爲把身份認證信息放在明碼錶示的地方(比如URI)會帶來很大的安全風險。比如,通訊層在這個字段用了一個PIN碼,那麼就會暴露這個PIN碼而帶來安全隱患。

注意密碼字段只是一個用戶信息擴展的一部分。實現上並沒有標記一個特別的密碼部分,可以簡單的把”user:password”當作一個簡單的用戶串來對待。

host:主機提供了SIP資源。host部分包含了一個完整的主機名字或者IPV4/IPV6的地址。我們強烈建議如果可能,就使用完整格式的主機名字。

port: 端口號是請求將被送出的端口。

URI 參數:請求將使用這個URI來構造。

URI參數在hostport部件之後增加,用分號分開。
URI參數有如下格式:

參數名’=’參數值

雖然在同一個URI中允許有任意多個URI的參數,但是同一個參數名只能出現1次。

這個擴展機制包括了transport,maddr,ttl,user,method和lr參數

transport參數決定在[4]中定義的發送SIP消息的通訊機制。SIP可以使用任何網絡通訊協議。參數名字是爲UDP(RFC 768[14]),TCP(RFC 761 [15])和SCTP(RFC2960[16])定義的。對於一個SIPS URI,transport參數必須指向一個可靠的通訊協議。

maddr參數指明瞭聯繫這個用戶的服務器的地址,它會覆蓋在host域中的地址。當給定了一個maddr參數,URI中的port和transport部件將會在maddr中指出。[4]描述了正確的transport,maddr,hostport規範,用於獲得發送請求到目的地所需要的目的地址,端口,通訊協議。

maddr字段用作簡單的去掉源路由的方法來使用的。它允許一個URI指定一個必須經過的proxy來到達目的地。我們強烈建議不要把maddr參數用於這個目的(我們反對把maddr用於這個機制)。在實現上應當使用本文中描述的Route機制,如果有需要,則建立一個pre-existing(預先設置的)路由集合(參見8.1.1.1)。它提供了一個完整的URI來描述需要經過的節點。

ttl參數決定了UDP多點報文的生存週期,並且只能用於maddr是一個多點地址並且通訊協議是UDP的情況。例如,爲了指定一個到[email protected]的呼叫,使用多點廣播到239.255.255.1,並且ttl=15,那麼應該使用下邊的一個URI:

sip:[email protected];maddr=239.255.255.1;ttl=15

有效的電話描述(telephone-subscriber)的字串一個集合是有效的用戶字串的子集。我們用用戶URI參數來區別電話號碼和用戶名(長得像電話號碼的用戶名)。如果用戶串使用了電話號碼描述的字串,用戶參數值”phone”應當增加。即使沒有這個參數,如果本地用戶名的命名限制機制允許的情況下,SIP和SIPS URI的接受方也可以把這個@以前的部分解釋爲電話號碼。

從URI中構建SIP請求所需要的method域,可以由method參數指定。

如果指定了lr參數,就標誌着這個資源的擁有者是根據本規範來實現的路由機制。這個參數回用於proxy放在Record-Route頭域的URI中,也可以出現在pre-existing(預先設置)的路由集合中。

這個參數是用來和RFC2543定義中的嚴格路由機制向後兼容所使用的,並且rfc2543bis 改變爲bis-05。如果一個元素準備發送一個基於沒有包含這個參數的URI請求,那麼我們可以假定這個請求的接受方是根據嚴格路由的規範實現的,並且會重新規格化這個消息來保護在Request-URI中的內容。

由於URI參數機制是可以擴展的,SIP元素應當悄悄跳過那些不認識的uri參數。
Headers:頭域是從給定URI創造的請求的頭域部分。
在SIP請求中的頭域可以在URI中用”?”來給出。頭域名(hname)和頭域值(hvalue)都是用&符號間隔的頭域名=頭域值的格式。特定的頭域名”body”的頭域值就是SIP請求的消息體。

表1總結了在URI的不同情況下SIP和SIPS URI的部件用法。擴展的列描述了在SIP消息歪的URI,例如在網頁上或者名片上的情況。項目中的’m’是強制必須的意思,’o’是可選的,’-‘是不允許的。處理URI的元素應當忽略掉URI中出現的任何不允許的部件。在表格中的第二列是如果該元素不存在的時候的缺省值。’--'表示本元素不是可選的,或者沒有缺省值的意思。

在Contact頭域中的URI在頭域出現的不同地方有着不同的約束。一個是在消息建立和維持一個對話的時候(INVITE請求以及它對應的200(OK)應答),一個是在註冊和轉發消息的時候(REGISTER,以及對應的200(ok)應答,以及給任何方法的3xx系列的應答)
19.1.2 Character Escaping Requirements(字符轉碼要求)
   default    Req-URI    To    From    reg./redir.Contact    dialogContactR-R/Route    external
user    - -    o    o    o    o    o    o
password    - -    o    o    o    o    o    o
host    - -    m    m    m    m    m    m
port    (1)    o    -    -    o    o    o
user-param    ip    o    o    o    o    o    o
method    INVITE    -    -    -    -    -    o
maddr-param    - -    o    -    -    o    o    o
ttl-param    1    o    -    -    o    -    o
transp.-param    (2)    o    -    -    o    o    o
lr-param    - -    o    -    -    -    o    o
other-param    - -    o    o    o    o    o    o
headers    - -    -    -    -    o    -    o

(1):缺省的通訊端口是依賴於通訊協議的。對於使用UDP,TCP,SCTP的sip來說,是5060,對於使用基於TCP的TLS來說,是5061。
(2)缺省的通訊協議是和sip/sips相關的,對於sip來說,是UDP,對於sips來說,是TCP。

表1:對於SIP頭域值,Request-URI及其引用的使用和缺省值。

基於RFC2396[5]的要求和指引,當需要把字符串封裝到SIP URI的時候,使用””%” HEX HEX”機制來進行轉碼。根據RFC2396[5]:

任何指定URI部件保留的字符集都是由這個部件定義的。通常,如果URI的語義由於組成字符被它的US-ACII編碼[5]的escape碼替代而改變的時候,這個字符就是保留字符。除了USASCII字符(RFC2396[5])之外,比如空格和控制字符,以及URI所使用的分隔符,必須進行轉碼。URI必須不能包含任何未經轉碼的空白和控制字符。

對於每一個部件來說,由BNF擴展的合法字符集合規定了那些字符是可以不經轉碼的。其他字符都必須經過轉碼。

比如,”@”不是user部件的字符集中的字符,所以,userj@sOn,必須把@符號進行編碼,成爲”j%40sOn”

在25節中的hname和hvalue的符號展示了在URI的保留字符中,在頭域名和頭域值中所有需要被轉碼的字符集合。

user部件的電話描述(telephone-subscriber)部分由特別的轉碼考慮。在RFC2806[9]關於電話描述部分中未被保留的字符集,由很多字符組成,他們在SIP URI中的不同語法部分的時候,都需要做轉碼。在電話描述中出現的任何字符,只要不在BNF針對user部分的擴展規則中出現的,都需要做轉碼。

注意在SIP或者SIPS URI中,host部分不允許做字符的轉碼(%不在它的擴展部分中)。在以後的Inernationalized Domain Names完成以後,這個限制可能就會改了。當前實現中不允許把在host部分收到的轉碼字符進行轉碼處理。因爲這個轉碼處理和IDN要求的處理不一樣。

19.1.3 SIP和SIPS URI例子
sip:[email protected]
sip:alice:[email protected];transport=tcp
sip:[email protected]?subject=project%20x&priority=urgent
sip:+1-212-555-1212:[email protected];user=phone
sips:[email protected]
sip:[email protected]
sip:atlanta.com;method=REGISTER?to=alice%40atlanta.com
sip:alice;[email protected]

最後一個URI例子有一個user域”alice;day=Tuesday”。上邊定義的轉碼規則中允許”;”在這個字段中不進行轉碼。在本協議的設計概念中,這個字段是不透明的。這個字段的值只對負責這個資源的SIP元素有用。

19.1.4 URI比較
在本規範中,部分操作需要比較兩個SIP或者SIPS URI是否相等。比如,在這個規範中,註冊服務器需要比較在REGISTER 請求中綁定的Contact URI(參見10.3)。SIP和SIPS URI根據如下步驟進行比較:

o SIP和SIPS URI永遠不等。
o SIP/SIPS URI的userinfo是大小寫敏感的。這包括了含有password或者按照電話描述格式的userinfo的比較。對於URI的其他部分的比較,除了有特別指出之外,都是大小寫不敏感的。
o 參數的順序和頭域的順序對於比較SIP/SIPS URI不起作用。
o 在保留字符集之外的字符(參見RFC2396[5]),等同於他們的””%” HEX HEX”格式。
o IP地址就算是等同於通過DNS查找到的主機名對應的IP地址,IP地址也不能和主機名等同。
o 兩個URI如果相同,那麼user,password,host,port部分必須相同。

有user部分的URI和沒有user部分的URI是不相等的。有password部分的URI和沒有password部分的URI也是不同的。

一個不帶可選部件的URI和帶了這些部件但是值是缺省值的URI是不等的。例如,如果一個URI省略了port部件,並不等於一個定義了5060port部件的URI。同樣的規則適用域transport-參數,ttl-參數,user-參數,method部件等等。

定義sip:user@host,和定義sip:user@host:5060(根據RFC2543的變體)不相等。當從URI中取得地址的時候,相同的URI可以取得相同的地址。sip:user@host:5060始終可以得到端口5060。URI: sip:user@host根據[4]所定義的DNS SRV機制,可能可以得出其他的端口來。

o URI uri參數部件按照如下規則進行比較
-    任何在兩個URI中出現的uri參數都必須一樣
-    user,ttl,或者方法uri參數如果只在一方出現,即使和缺省值相等,也判定爲兩個URI不相等。
-    包含maddr參數的URI和沒有包含maddr參數的不相等。
-    其他uri參數,如果在一方出現,則在比較的時候忽略。

o URI頭部件的比較是不能忽略的。任何在header部分出現的域都必須在雙方URI中進行匹配和比較。比較規則參見20節。

下列URI是相等的:
sip:%[email protected];transport=TCP
sip:[email protected];Transport=tcp

sip:[email protected]
sip:[email protected];newparam=5
sip:[email protected];security=on

sip:biloxi.com;transport=tcp;method=REGISTER?to=sip:bob%40biloxi.com
sip:biloxi.com;method=REGISTER;transport=tcp?to=sip:bob%40biloxi.com

sip:[email protected]?subject=project%20x&priority=urgent
sip:[email protected]?priority=urgent&subject=project%20x

下列URI是不相等的:

SIP:[email protected];Transport=udp         (用戶名不同)
sip:[email protected];Transport=UDP


sip:[email protected]                (端口不同)
sip:[email protected]:5060

sip:[email protected]            (通訊協議不同)
sip:[email protected];transport=udp

sip:[email protected]            (通訊協議和端口不同)
sip:[email protected]:6000;transport=tcp

sip:[email protected]        (header部件不同)
sip:[email protected]?Subject=next%20meeting

sip:[email protected]        (就算是phone21.boxesbybob.com
sip:[email protected]            解析到192.0.2.4也不能算相等的。)

注意相等性是不能傳遞的。
比如 sip:[email protected] 和sip:[email protected];security=on相等
sip:[email protected] 和 sip:[email protected];security=off相等
但是:
sip:[email protected];security=on和sip:[email protected];security=off不等。

19.1.5 從URI中產生請求
對於實現而言,需要能夠直接從一個URI來構造請求。URI可以是從名片,網頁,或者甚至從某些協議內部得到(比如登記的聯繫信息等等)。

協議的實現必須包括構造請求的Request-URI中的transport,maddr,ttl,或者user參數。如果URI包含了method參數,那麼它的值必須和構造的請求的方法一樣。並且method參數不能放在Request-URI中。不認識的URI參數必須放在消息的Request-URI中。

實現中應當把URI中出現的header或者包體部分包含入消息本身,並且當作是請求自己的組成部分。

在實現中,不應當保留那些明顯危險的頭域字段:From,Call-ID,Cseq,Via和Record-Route。

並且實現中,也不應當保留任何請求的Route頭域值,這樣可以避免無知的客戶端進行惡意攻擊。

實現中也不應當保留那些可能會導致錯誤登記地址或者誤導能力的頭域字段,這些包括:Accept,Accept-Encoding,Accept-Language,Allow,Contact(在對話中使用),Organization,Supported,和User-Agent。

實現上應當檢查每一個請求中所描述的頭域的正確性,包括:Content-Disposition, Content-Encoding,Content-Language, Content-Length, Content-Type, Date, Mime-Version, Timestamp。

如果從給定URI構造的請求不是一個合法的SIP請求,那麼這個URI就是非法的URI。實現上禁止處理和傳送非法的SIP請求。它應當嘗試追查爲何會有一個非法的URI。

很多情況都可以得到一個非法的請求。這包括但是不限於,頭域的語法錯誤,非法的URI參數合併,或者錯誤的消息體描述等等。

發送從URI構造的請求可能會導致實現上的能力不夠。比如:URI可能指定了尚未實現的通訊協議或者通訊擴展。那個這個具體的實現上來說,應當拒絕發送這些請求,而不是修改這個請求來適應具體實現的處理能力。對於具體實現來說,它不能發送包含它自己不能理解的擴展部分的請求。

比如,從一個包含了未知的或者擺明了不支持的Request頭域參數或者method參數的URI中,構造的請求就是不能發送的。

19.1.6 關聯SIP URI和tel URL
如果tel URL(RFC 2806[9])轉換成爲一個SIP或者SIPS URI,那麼tel URL的整個電話描述(telephone-subscriber),機器參數,都需要放在SIP或者SIPS URI的userinfo部分。

因此:tel:+358-555-1234567;postd=pp22 會變成:
sip:+358-555-1234567;[email protected];user=phone
或者
sips:+358-555-1234567;[email protected];user=phone
而不是
sip:+[email protected];postd=pp22;user=phone
或者
sips:+[email protected];postd=pp22;user=phone

通常來說,相等的”tel”URL轉換成爲SIP或者SIPS URI以後,不一定能得到相同的SIP或者SIPS URI。因爲SIP和SIPS URI的userinfo部分是根據大小寫敏感的字串。由大小寫不敏感的tel URL以及重新排序的tel URL參數並不改變tel URL的相等性,但是在轉換成爲SIP或者SIPS URI之後,卻影響了他們的相等性。

例如:
tel:+358-555-1234567;postd=pp22
tel:+358-555-1234567;POSTD=PP22
是等價的,但是
sip:+358-555-1234567;[email protected];user=phone
sip:+358-555-1234567;[email protected];user=phone
卻是不等價的。

類似的:
tel:+358-555-1234567;postd=pp22;isub=1411
tel:+358-555-1234567;isub=1411;postd=pp22
是等價的,但是
sip:+358-555-1234567;postd=pp22;[email protected];user=phone
sip:+358-555-1234567;isub=1411;[email protected];user=phone
卻不等價

爲了避免這個問題,在構造放在SIP或者SIPS URI中的userinfo部分的電話描述域的時候,應當轉換大小寫不敏感的電話描述域爲小寫,並且除了isdn-subaddress和post-dial,把電話描述的參數按照參數名進行排序, 因爲他們需要按順序出現在參數的第一個。(在下邊是除了未來擴展參數意外的全部tel URL大小寫不敏感的部分)。

根據上邊的描述,全部:
tel:+358-555-1234567;postd=pp22
tel:+358-555-1234567;POSTD=PP22

轉換成爲
sip:+358-555-1234567;[email protected];user=phone

並且全部:
tel:+358-555-1234567;tsp=a.b;phone-context=5
tel:+358-555-1234567;phone-context=5;tsp=a.b
轉換成爲:
sip:+358-555-1234567;phone-context=5;[email protected];user=phone

19.2 Option Tags
Option tags是一個唯一標誌,用來指明SIP中的新options(擴展)的。這些tags在Require(20.32節),Proxy-Require(20.29節),Supported(20.37節)和Unsupported(20.40節)頭域中使用。注意這些options是以option-tag=的形式作爲這些頭域的參數存在的(25節有關定義符號)。

Option tags是根據標準的RFC擴展定義的。這是和過去的試驗有所不同,這是協會爲了保證多個廠商之間能夠持續互相協作(20.32節、20.37節的討論)。option tags的IANA註冊可以保證查找很容易。

19.3 Tags
“tag”參數用於SIP消息中的To和From頭域。它作爲一個通用的機制的一部分來唯一標誌一個對話,這個機制用Call-ID和兩個從對話參與者的tag來標誌一個對話。當UA在對話外發出一個請求時,它只包含了From tag,提供了對話ID的”一半”。對話根據應答創建完成,這個應答在To頭域中提供了對話ID的另一半。SIP請求的分支意味着一個單個請求可以創建多個對話。這個也解釋了爲何需要對話兩方的標誌;如果沒有被叫方的標誌,呼叫方不能分辯和消除由單個請求創建的多個對話。

當UA產生一個tag並且增加進一個請求或者應答的時候,它必須是一個全局唯一的,並且是密碼隨機數起碼是32位的隨機數。這個要求是爲了讓UA能夠在同一個INVITE請求中,在給這個INVITE的應答中,在To頭域產生一個不同的tag,和原始INVITE請求在From頭域中產生的tag不同。這是因爲UA可以邀請自己到一個會話,常見的是在PSTN網關的”hairpinning”(髮夾)呼叫。類似的,對不同呼叫的兩個INVITE也有不同的From tag,並且給這兩個呼叫的兩個應答也有不同的To tag。

在全局唯一要求之外,產生tag的算法是實現相關的。Tag對於容錯系統比較有用,在容錯系統下,當主服務器故障的時候,對話會在另外一個服務器上進行恢復。UAS可以產生一個tag,讓備用服務器能夠認識到這個請求是在故障服務器上的對話,並且能夠決定是否恢復對話和對話相關的狀態。

20 頭域
頭域的語法描述在7.3節。本節列出了頭域的全部列表,包括了語法註釋,含義,和用法。通過本節,我們使用[HX.Y]指當前HTTP/1.1 的RFC2616[8]的規範的X.Y節。每個頭域都有示例給出。

關於與方法和proxy處理有關的頭域字段在表2和表3中有處理。

“where”列描述了在頭域中能夠使用的請求和應答的類型。這列的值是:
R:頭域只能在請求中出現;
r:頭域只能在應答中出現;
2xx,4xx,等等:一個數字的值區間表示頭域能夠使用的應答代碼。
c:頭域是從請求拷貝到應答的。
如果”where”欄目是空白,表示頭域可以在所有的請求和應答中出現。

“proxy”列描述了proxy在頭域上的操作
a:如果頭域不存在,proxy可以增加或者連接頭域
m:proxy可以修改現存的頭域值
d:proxy可以刪除頭域值
r:proxy必須能讀取這個頭域,因此這個頭域不能加密。

接下來6個欄目與在某一個方法中出現的頭域有關:
c:條件;對頭域的要求依賴於消息的內容
m:頭域是強制要有的。
m*:頭域應當被髮送,但是客戶端/服務端都需要準備接收沒有這個頭域的消息。
o:頭域是可選的。
t:頭域應當被髮送,但是客戶端/服務端都需要準備接收沒有這個頭域的消息。客戶端/服務端都需要準備接收沒有這個頭域的消息。如果通訊的協議是基於面向流的協議(比如TCP),那麼頭域值必須被髮送。
*:如果消息體不爲空,那麼頭域值就緒要的。(細節請參見20.14,20.15和7.4節)
-:這個頭域是不適用的。

“Optional”意味着這個元素可以在請求或者應答中包含這個頭域,並且UA可以忽略在請求或者應答中存在的這個頭域(這條規則有一個例外,就是Require頭域,在20.32節有描述)。”mandatory”(強制)頭域是必須在請求中存在的頭域,並且也必須是UAS接收到一個請求時能夠理解的頭域。一個強制頭域必須也在應答中出現,並且UAC也能處理這個頭域。”Not applicable”(不適用)意味着頭域不能在請求中出現。如果一個UAC錯誤的把這個頭域放在請求中,在UAS收到的時候必須被忽略。同樣的,如果應答中的”不適用”的頭域,也就是說UAS不能在應答中放置的頭域,如果出現了,那麼UAC也必須在應答中忽略掉這個頭域。

一個UA必須忽略他們所不能處理的擴展的頭參數。

本規範也定義了常用的頭域名的縮寫,用於縮小消息的大小。

在Contact,From,To頭域中都包含一個URI。如果這個URI包含一個逗號,問號或者分毫,那麼這個URI必須使用尖括號括起來(<和>)。所有的URI參數都必須在這些括號內。如果URI並非用尖括號括起來的,那麼用分號分開的參數將被視同與header參數而不是URI參數。

20.1 Accept
Accept頭域的語法定義遵從[H14.1]。除了如果沒有Accept頭域,服務器應當認爲Accept缺省值是application/sdp以外,語義也是和HTTP/1.1類似的語義。

空的Accept頭域意味着不接受任何格式。Header field    where    proxy    ACK    BYE    CAN    INV    OPT    REG
Accept    R        -    o    -    o    m*    o
Accept    2xx        -    -    -    o    m*    o
Accept    415        -    c    -    c    c    c
Accept-Encoding    R        -    o    -    o    o    o
Accept-Encoding    2xx        -    -    -    o    m*    o
Accept-Encoding    415        -    c    -    c    c    c
Accept-Language    R        -    o    -    o    o    o
Accept-Language    2xx        -    -    -    o    m*    o
Accept-Language    415        -    c    -    c    c    c
Alert-Info    R    ar    -    -    -    o    -    -
Alter-Info    180    ar    -    -    -    o    -    -
Allow    R        -    o    -    o    o    o
Allow    2xx        -    o    -    m*    m*    o
Allow    r        -    o    -    o    o    o
Allow    405        -    m    -    m    m    m
Authentication-Info    2xx        -    o    -    o    o    o
Authorization    R        o    o    o    o    o    o
Call-ID    c    r    m    m    m    m    m    m
Call-Info        ar    -    -    -    o    o    o
Contact    R        o    -    -    m    o    o
Contact    1xx        -    -    -    o    -    -
Contact    2xx        -    -    -    m    o    o
Contact    3xx    d    -    o    -    o    o    o
Contact    485        -    o    -    o    o    o
Content-Disposition            o    o    -    o    o    o
Content-Encoding            o    o    -    o    o    o
Content-Language            o    o    -    o    o    o
Content-Length        ar    t    t    t    t    t    t
Content-Type            *    *    -    *    *    *
Cseq    c    r    m    m    m    m    m    m
Date        a    o    o    o    o    o    o
Error-Info    300-699    a    -    o    o    o    o    o
Expires            -    -    -    o    -    o
From    c    r    m    m    m    m    m    m
In-Reply-To    R        -    -    -    o    -    -
Max-Forwards    R    amr    m    m    m    m    m    m
Min-Expires    423        -    -    -    -    -    m
MIME-Version            o    o    -    o    o    o
Organization        ar    -    -    -    o    o    o
表2: 頭域概覽,A-O


Header field    where    proxy    ACK    BYE    CAN    INV    OPT    REG
Priority    R    ar    -    -    -    o    -    -
Proxy-Authenticate    407    ar    -    m    -    m    m    m
Proxy-Authenticate    401    ar    -    o    o    o    o    o
Proxy-Authorization    R    dr    o    o    -    o    o    o
Proxy-Require    R    ar    -    o    -    o    o    o
Record-Route    R    ar    o    o    o    o    o    o
Record-Route    2xx,18x    mr    -    o    o    o    o    -
Reply-To            -    -    -    o    -    -
Require        ar    -    c    -    c    c    c
Retry-After    404,413,480,486        -    o    o    o    o    o
Retry-After    500,503600,603        -    o    o    o    o    o
Route    R    adr    c    c    c    c    c    c
Server    r        -    o    o    o    o    o
Subject    R        -    -    -    o    -    -
Supported    R        -    o    o    m*    o    o
Supported    2xx        -    o    o    m*    m*    o
Timestamp            o    o    o    o    o    o
To    c(1)    r    m    m    m    m    m    m
Unsupported    420        -    m    -    m    m    m
User-Agent            o    o    o    o    o    o
Via    R    amr    m    m    m    m    m    m
Via    rc    dr    m    m    m    m    m    m
Warning    r        -    o    o    o    o    o
WWW-Authenticate    401    ar    -    m    -    m    m    m
WWW-Authenticate    407    ar    -    o    -    o    o    o
表3:頭域概覽,P-Z (1)和可能的附加tag一起拷貝。

例子:
Accept: application/sdp;level=1,application/x-private,text/html

20.2 Accept-Encoding
Accept-Encoding頭域類似Accept,但是限定了接收應答中的內容的編碼[H3.5]。參見[H14.3]。在SIP中的語義和在[H14.3]中的定義是一致的。

一個空的Accept-Encoding頭域是允許的。他等同於Accept-Encoding:identity,這就是說,只有identity編碼,也就是說沒有編碼的情況,是允許的。

如果沒有Accept-Encoding頭域存在,那麼服務端應當使用缺省值:identity。

這個和HTTP的定義略有不同,HTTP指出如果本頭域不存在,那麼任何編碼形式都可以使用,只是推薦identity編碼而已。

例如:
Accept-Encoding:gzip

20.3 Accept-Language
Accept-Language頭域用來在請求中指定首選的的語言的,這個首選的語言是在應答中的消息體中的的原因分析,會話描述,或者狀態報告的。如果沒有Accept-Language存在,那麼服務端應當假設所有的語言客戶端都可以接受。

Accept-Language頭域遵從[H14.4]節定義的語法。對於SIP來說,也同樣支持對語言通過”q”參數來進行排序。

例如:

Accept-Language: da, en-gb; q= 0.8, en;q=0.7

20.4 Alert-Info
當INVITE請求有一個Alert-Info頭域的時候,Alert-Info頭域就包含的是給UAS的一個額外的信息。當在180(Ringing)應答中出現的時候,Alter-Info頭域給出了UAC一個額外的回鈴信息。這個頭域的一個典型用法就是讓proxy增加這個頭域用來體哦你嘎一個與衆不同的振鈴效果。

Alter-Info頭域可能會帶來潛在的安全隱患。這個隱患以及相應的處理在20.9節有講述,這個隱患和Call-Info頭域的隱患是相同的。

另外,用戶應當可以有選擇的屏蔽這個特定。

這個可以保護用戶不因爲使用了未受信任節點發送過來的這個頭域而導致的破壞。
例如:
Alter-Info: <http://www.example.com/sounds/moo.wav>
20.5 Allow
Allow頭域列出了UA支持的方法列表。

如果要提供UA頭域,那麼所有只要是UA支持的方法,包括ACK和CANCEL都必須列在這個Allow頭域中。如果沒有Allow頭域出現,一定不能以爲UA什麼方法都不支持。應當解釋成爲發送這個消息的UA並沒有告訴大家它支持什麼方法。

在應答中提供Allow頭域比在OPTIONS請求/應答中會減小所需要的消息數量。

例如:
Allow: INVITE,ACK,OPTIONS,CANCEL,BYE

20.6 Authentication-Info
Authentication-Info 頭域提供了和HTTP類別相同的認證方法。UAS可以在給一個順利通過認證的請求的2xx應答中包含這個頭域,並且是使用基於Authorization頭域的分類。

這個頭域的語法和語義遵循RFC2617[17]的規範。

例如:

Authentication-Info: nextnonce=”47364c23432d2e131a5fb210812c”

20.7 Authorization
Authorization頭域包含了了UA進行認證的信任書。22.2節概述了對Authorization頭域的用法,22.4節講述了和HTTP 認證一起使用的時候的語法和語義。

這個頭域,和Proxy-Authorization,並不遵循通常的多頭域值的規則。雖然它不是由逗號分割的列表,這個頭域名可以出現多次,並且不能應用7.3節的規則合併成爲單個頭域。

在下邊的例子中,在分類參數兩邊沒有引號括起來。

Authorization:Digest username=”Alice”, realm=”atlanta.com”,
nonce = ”84a4cc6f3082121f32b42a2187831a94”,
response=”7587245234b3434cc3412213e5f113a5432”

20.8 Call-ID
Call-ID頭域用來唯一區別一個特定的邀請或者一個特定客戶端的所有註冊項。單個多媒體會議可以分解成爲多個不同Call-ID的呼叫,例如,當一個用戶數次邀請單個個體加入同一個會議的時候。Call-ID是大小寫敏感的並且是字節/字節比較的。

Call-ID頭域的簡寫就是i

例子:
Call-ID: [email protected]
i:[email protected]

20.9 Call-Info
Call-Info頭域提供了對呼叫方或者被叫方的附加信息,如果出現在請求中則是呼叫方的信息,如果出現在應答中則是被叫方的。”purpose”參數中存放了效果圖URI。”icon”參數包含了一個呼叫方或者被叫方的圖標。”info”參數描述了簡要的呼叫方或者被叫方的信息,例如,通過放置一個網頁進行介紹等。”card”參數提供了一個名片,比如,基於vCard[36]或者LDIF[37]格式。如果附加新的標記,那麼可以通過27節描述的步驟通過在IANA註冊來附加。

對Call-Info的使用可能會帶來一些安全隱患。如果一個被叫方接到一個惡意呼叫方提供的URI,被叫方可能會由顯示一個不合適的內容,或者危險的或者非法的內容,等等。因此,我們建議UA只顯示那些它能夠檢驗並且信任發送方身份的Call-Info頭域中的內容。這個對於對方UA來說不需要。proxy可以在請求中加入這個頭域。

例如:
Call-Info: ;purpose=icon,
http://www.example.com/alice/;purpose=info

20.10 Contact
Contact頭域提供了一個URI,這個URI的含義取決於是在請求還是在應答中。

Contact頭域包含了一個顯示的名字,一個包含參數的URI,還有header參數組成。

本文檔定義了一個Contact參數”q”和”expires”。這些參數只有當Contact頭域在REGISTER的請求或者應答,或者3xx的應答中才有效。在其他規範中可能會定義一個附加的參數。當頭域值包含一個顯示的名字,那麼帶參數的URI應當用”<”和”>”括起來。如果沒有”<”,”>”括起來,所有URI後邊的參數都將視爲header參數,而不是URI參數。顯示姓名可以是符號,或者引號引起來的字符串(如果很長的話)。

即使”display-name”是空的,如果”addr-spec”包含一個逗號或者分號,或者?的話,也必須使用”name-addr”的格式。這在display-name和”<”之間可以有也可以沒有LWS(線性空白)

這些關於顯示名字,URI和URI的參數,header參數的規則同樣對To和From頭域適用。Contact頭域的的角色很像HTTP中的Location頭域的角色。但是HTTP頭域只允許1個地址,沒有其他說明。由於URI中可以包含逗號和分號,所以他們在header或者參數分隔符上是錯誤的。

Contact頭域的縮寫是m(“moved”)。
例子:

Contact: “Mr.Watson” <sip:[email protected]>;q=0.7;
expires=3600,
“Mr. Watson” mailto:[email protected] ;q=0.1

m: <sips:[email protected]>;expires=60

20.11 Content-Disposition
Content-Disposition頭域描述了消息體,或者消息的多個部分,或者消息體的一個部分應被UAC或者UAS怎樣解釋。這個SIP頭域擴展了MIME Content-Type(RFC 2183[18])。

SIP定義了Content-Disposition幾個新的”disposition-types”。如果取值”session”意味着消息體位呼叫(calls)或者早期(pre-call)媒體,描述了一個會話。取值”render”表示了消息體可是被顯示或者展示給用戶。注意”render”比”inline”更適合避免MIME消息體作爲一個大的消息的一部分做展示(由於SIP消息的MIME消息體經常不被展示給用戶)。出於向後兼容的考慮,如果Content-Disposition頭域不存在,服務器應當假設Content-Type爲application/sdp的部屬方式是”session”,爲其他方式的時候是”render”。

部屬方式“icon”表示消息體部分包含了一個用於表示呼叫者或者被叫者的icon圖像,當UA收到這個消息,就可以展示一下,或者在對話過程中一致展示。”alert”意味着消息體部分包含了信息,比如是一段聲音,應當由UA展示給用戶提示用戶這個請求,通常是初始化對話的請求;這個altering消息體可以是一個在180Ringing臨時應答發出後的一個鈴聲。

所有需要展示給客戶的具有”disposition-type”的MIME消息體,都應當只在這個消息有適當的安全認證的時候展示。

處理參數,handling-param,描述了UAS在接收到這個內容類型或者部屬類型是它所不支持的消息體的時候,應當如何操作。這個參數定了了”optional”和”required”兩個值。如果處理參數沒有,那麼這個處理參數缺省值就是”required”。處理參數在RFC3204[19]中定義和描述的。

如果這個頭域不存在,那麼MIME類型決定了缺省的內容部屬。如果沒有MIME類型,那麼缺省值就是”render”
例如:

Content-Disposition: session

20.12 Content-Encoding
Content-Encoding頭域是對”media-type”(媒體類型)的一個修正。當存在這個頭域的時候,它的值就是對包體內容編碼的附加說明,並且因此必須根據本字段應用正確的解碼機制,這樣才能得到正確的Content-Type頭域指出的媒體類型的解碼。Content-Encoding首要應用於在不丟失媒體類型標記的情況下對消息體進行壓縮處理。

如果包體應用了多個編碼,那麼包體編碼必須按順序在這個字段中進行列出。

所有的Content-Encoding的值都是大小寫不敏感的。IANA是這個編碼方式的註冊機構。參見[H3.5]獲得Content-coding的語法定義。

客戶端可以在請求中進行包體的內容編碼。服務端也可以在應答中進行內容編碼。服務端必須只能應用客戶端在請求中的Accept-Encoding頭域中列出的編碼類型。

Content-Encoding簡寫是e。
例如:
Content-Encoding:gzip
e: tar

20.13 Content-Language
參見[H14.12].例如:
Content-Language: fr

20.14 Content-Length
Content-Length頭域標誌了消息體的大小,給消息的接受者,以10進製表示的數字。應用程序應當使用這個字段標誌的大小來傳送消息體,而不關心消息體的媒體類型是什麼。如果是基於流的通訊協議(比如TCP),那麼本頭域必須提供。

消息的大小並不包含CRLF分開的頭域和包體。任何大於或者等於0 的Content-Length都是合法的長度。如果消息中不包含包體,那麼Content-Length必須設置成爲0

對Content-Length的忽略能夠簡化創建一個類似cgi一樣動態生成應答的腳本。(???)

這個頭域的簡寫是l

例如:
Content-Length:349
l:173

20.15 Content-Type
Content-Type頭域標誌了發給對方的消息體的媒體類型。”media-type”是在[H3.7]中定義的。如果消息體不爲空,那麼Content-Type頭域就必須存在。如果消息體是空的,並且笨頭域存在,那麼就表示了特定類型的媒體的包體是0長度(比如空的音頻文件)。

本頭域的簡寫是c
例如:
Content-Type: application/sdp
c: text/html;charset=ISO-8859-4

20.16 Cseq
請求中的Cseq頭域包含了一個單個的數字序列號和請求的方法。這個序列號必須是表示成爲一個32位的無符號整數。在Cseq的請求方法部分是大小寫敏感的。Cseq頭域是爲了在會話中對事務進行排序的,提供事務的唯一標誌,並且區分請求和請求的重發。如果序列號相等,並且請求的方法相等,那麼兩個Cseq頭域就是相等的。
例如:
Cseq:4711 INVITE

20.17 Date
Date頭域包含了日期和時間。和HTTP/1.1不同,SIP只支持最近的RFC1123[20]格式的日期。如同在[H3.3]中,SIP限制了在SIP-date中的時區是”GMT”,但是在RFC1123中支持任意的市區。RFC1123的日期是大小寫敏感的。Date頭域反應的時間是請求或者應答被髮送的那一刻的時間。

Date頭域可以用來簡化沒有後備電池的終端系統,讓他們能夠獲得當前的時間。但是由於是GMT格式的,所以,它要求客戶端知道和GMT的時差。

例如:
Date:Sate,13 Nov 2010 23:29:00 GMT

20.18 Error-Info
Error-Info頭域提供了對有錯誤應答碼的應答的附加信息。

SIP UAC具有從彈出的窗口PC界面,到只有聲音的電話或者網關過來的終端界面。與其強制服務器產生一個錯誤來選擇是發送一個帶有詳細原因說明的錯誤代碼應答,還是播放一段聲音,不如使用Error-Info頭域把兩個都發送。讓UAC來決定用什麼來展示給呼叫方。

UAC可以把在Error-Info中的一個SIP或者SIPS URI當作是轉發的一個Contact地址,並且據此產生一個新的INVITE,這樣可以建立預先錄製的聲明會話。如果是非SIP URI,那麼可以展示給用戶。

例如:

SIP/2.0 404 The Number you have dialed is not in service
Error-Info: <sip:[email protected]>

20.19 Expires
Expires頭域給定了消息(或者內容)過期的相關時間。這個字段的精確定義是方法相關的。對於一個INVITE的超時時間並不影響這個INVITE請求建立的實際的會話。不過,會話描述協議可以描述在一個會話上的的時間限制。

這個頭域的值是一個以秒計數的整數,從0到(2**32)-1,從收到請求開始計數。

例如:
Expires:5

20.20 From
From頭域表示了請求的來源地。這個可能和對話的來源的不同,被叫方到呼叫方的請求會在From頭域使用被叫方的地址。

選項”display-name”是展示給界面的。如果客戶標誌停留在隱藏狀態,那麼系統應當使用”Anonymous”作爲顯示名字。即使是”displayname”是空的,如果”addr-spec” 包含一個逗號,?,或者分毫,那麼就必須使用”name-addr”格式。相關的格式在7.3.1節描述。

如果From的URI相等,並且參數也相等,那麼這兩個頭域就是相等的。如果擴展參數在一個頭域中存在,但是在另外一個頭域中不存在,那麼當這兩個頭域做比較的時候,這個參數將被忽略。這意味着顯示名字的存在與否不影響比較的結果。

參見20.10處理顯示名字,URI和URI參數,以及頭域參數的規則。

From頭域的簡寫是f
例子:
From: “A. G. Bell” <sip:[email protected]> ; tag=a48s
From: sip:+[email protected];tag=887s
f: Anonymous <sip:[email protected]>;tag=hyh8

20.21 In-Reply-To
In-Reply-To頭域列舉了本次呼叫相關的或者返回的Call-ID。這些Call-ID可以備客戶端cache起來,這樣可以在這個頭域中返回。

這允許自動呼叫奮發系統來路由這些返回的呼叫到第一個呼叫的原始請求地點。這也允許被叫方過濾呼叫,這樣只有在呼叫中原始請求建立的呼叫纔會被接受。這個字段不是對請求驗證的一個替代。
例如:

In-Reply-To: [email protected],[email protected]

20.22 Max-Forwards
Max-Forwards頭域必須在任何一個SIP請求中使用,來限制中間轉發請求到下一個節點的proxy或者gateway的個數。這個在客戶端trace一個請求,如果路由失敗或者在中間出現循環的時候特別有用。

Max-Forwards是一個0-255的整數,表明了在這個請求消息中允許被轉發的剩餘次數。每當服務器轉發這個請求一次,這個數字就減一。建議的初始值是70。當不能確定有無循環路由的時候,必須在頭域中增加本頭域。比如,一個B2BUA應當增加這個頭域。

例如:
Max-Forwards:6

20.23 Min-Expires
Min-Expires頭域包含了一個服務器所支持的內部狀態(soft-state)的最小的刷新時間間隔。這個包括被登記服務器所登記的Contact頭域。這個頭域包含了一個以秒計數的整數,從0到(2**32)-1。在423(Interval Too Brief)應答中,本頭域的用法在10.28,10.3,和21.4.17中有描述。
例如:
Min-Expires:60

20.24 MIME-Version
參見[H19.4.1]
例如:
MIME-Version: 1.0

20.25 Organization
Organization頭域包含了發出請求或者應答的SIP節點所屬的組織名字。這個字段可以用來讓客戶端軟件過濾呼叫。
例如:

Organization: Boxes by Bob

20.26 Priority
Priority頭域標誌了客戶端評價的請求緊急程度。Priority頭域描述了SIP應當處理人工或者UA發過來的請求的優先級。舉例來說,這可能是決定呼叫轉發和處理的優先要素。對於判定優先級來說,如果消息沒有包含Priority字段,那麼處理的時候應當當作”normal”優先級處理。Priority頭域不影響通訊資源的優先順序,比如路由上的包轉發的優先級或者訪問PSTN網關的優先級。本頭域有”non-urgent”,”normal”,”urgent”,和”emergency”取值,另外的取值可以在別處定義。我們強烈建議”emergency”只用於影響到生命、身體、或者財產危急時候才使用。其他情況下, 本頭域沒有額外的語義。在RFC2076[38]中,定義了”emergency”。

例如:
Subject: A tornado is heading our way!
Priority: emergency。

或者
Subject: Weekend plans
Priority: non-urgent.

20.27 Proxy-Authenticate
Proxy-Authenticate頭域用來進行認證使用的。這個頭域的用法在[H14.33]中定義。參見22.3節關於本字段的細節討論。

例如:
Proxy-Authenticate: Digest realm=”atlanta.com”,
domain=”sip:ss1.carrier.com”,qop=”auth”,
nonce=”f84f1cec41e6cbe5aea9c8e88d359”,
opaque=””,stale=FALSE,algorithm=MD5

20.28 Proxy-Authorization
Proxy-Authorization頭域允許客戶端向一個要求認證的proxy證明自己(或者證明它的使用者)的身份。一個Proxy-Authorization頭域包含了與UA認證信息相關的信任書,這個信任書是給proxy和/或者本請求相關的域的。

參見22.3節關於這個頭域的定義。

本頭域,連通Authorization頭域,並不遵循常用的多頭域名(多個相同頭域名的合併)的規則。雖然不是用逗號分割的列表,這個頭域名可以出現多次,並且不能用7.3.1描述的通常規則合併成爲一個頭域。

例如:
Proxy-Authorization: Digest username=”Alice”,realm=”atlanta.com”,
nonce=”c60f3082ee1212b402a21831ae”,
response=”245f23415f11432b3434341c022”

20.29 Proxy-Require
Proxy-Require頭域用來表示請求中一定要求proxy支持的相關的特性。參見20.32關於這個頭域的使用。

例子:
Proxy-Require:foo

20.30 Record-Route
Record-Route頭域是proxy在請求中增加的,用來強制會話中的後續請求經過本proxy的。本頭域的用法在16.12.1節有描述。

例子:
Record-Route: <sip:server10.biloxi.com;lr>,
<sip:bigbox3.site3.atlanta.com;lr>

20.31 Reply-To
Reply-To頭域包含了邏輯上返回目的地URI,這個可以和From頭域不同。比如,URI可以用來返回未接電話或者未建立的會話。如果用戶希望保留匿名,那麼這個頭域應當從請求中去除或者改變,這樣可以避免透露個人隱私信息。

即使”display-name”是空的如果”addr-spec”包含了逗號、問號、或者分號,那麼就需要使用”name-addr”的格式來填寫。這個語法在7.3.1中定義。

例如:
Replay-To: Bob <sip:[email protected]>

20.32 Require
Require頭域用於UAC告訴UAS關於要求UAS支持那些特性。雖然這是一個可選的頭域,但是如果Require頭域存在,那就一定不能掠過不處理。

頭域包含一個option tag的列表,這個列表在19.2節中描述。每一個option tag定了一個要處理請求要求UAS必須支持的SIP擴展。通常,這用於定義一個需要支持的擴展頭域的集合。複覈本規範的UAC應當值包含規範的RFC擴展。
例如:
Require:100rel

20.33 Retry-After
Retry-After頭域可以用於500(Server Internal Error)或者503(Service Unavailable)應答,用來標誌大約本服務還會處於不可用狀態多久。在404(Not Found),413(Request Entity Too Large), 480(Temporarily Unavailable),486(Busy Here), 600 (Busy), 或者603(Decline)應答中用於標誌何時被叫方會恢復正常。這個字段的值是一個秒爲單位的正整數(十進制),從應答生成開始的一個正整數。

對於回叫的時間,可以有一個附加的說明。”duration”參數標誌了被叫方變成正常狀態的時間長度。如果沒有定義,那麼服務可以被看作是永遠有效。

例如:
Retry-After: 18000;duration=3600
Retry-After:120 (I’m in a meeting)

20.34 Route
Route頭域用於強制一個請求經過一個proxy路由列表。Route頭域的使用在16.12.1節定義:
例如:
Route: <sip:bigbox3.site3.atlanta.com;lr>,
<sip:server10.biloxi.com;lr>

20.35 Server
Server頭域包含了關於UAS處理請求所使用的軟件信息。

服務器的特定軟件版本可能會使服務器由於特定軟件安全漏洞導致服務器收到攻擊。實現上應當使得Server頭域是一個可以配置的選項。

例如:

Server:HomeServer v2

20.36 Subject
Subject頭域提供了呼叫的一個概覽,允許呼叫不用分析會話描述就可以大致過濾。會話描述並不需要和INVITE邀請使用相同的主題標誌。

Subject的縮寫是s
例如:
Subject: Need more boxes
s: Tech Support

20.37 Supported
Supported頭域列舉了UAC或者UAS支持的擴展。

Supported頭域包含了一個option tag的列表,在19.2節描述的option tag,他們是這個UAS或者UAC所支持的。遵循本規範的UA必須只包含遵循標準RFC擴展的option tag。如果本字段是空的,意味着不支持任何擴展。

Supported頭域的縮寫是k
例如:

Supported: 100rel

20.38 Timestamp
Timestamp頭域描述了當UAC發送請求到UAS的時間戳。

參見8.2.6節關於如何給請求產生一個包含這個頭域的應答。雖然沒有定義本字段的標準行爲,我們允許對擴展應用或者SIP應用獲得RTT預計時間。
例如:
Timestamp:54

20.39 To
To頭域定義了邏輯上請求的接收者。選項”display-name”意味着展示給客戶的界面。”tag”參數提供了對話識別機制。

參見19.3節關於”tag”參數的些界描述。

對於To頭域的比較是和對From頭域的比較相同的。參見20.10節的比較規則來比較display name,URI和URI參數,以及頭域的參數。

To頭域的縮寫是t。
下邊是一個To頭域的例子:
To: The Operator <sip:[email protected]>;tag=287447
t: sip:+[email protected]

20.40 Unsupported
Unsupported頭域列出了不被UAS支持的特性列表。參見20.32。
例如:
Unsupported:foo

20.41 User-Agent
User-Agent頭域包含了發起請求的UAC信息。本頭域的語義在[H14.43]定義。

UA所使用的版本號情況可能會導致由於這個版本的安全漏洞二遭受攻擊。所以在實現上應當使得User-Agent頭域是可以配置的。
例如:
User-Agent:Softphone Beta1.5

20.42 Via
Via頭域是用來描述請求當前經歷的路徑的,並且標誌了應答所應當經過的路徑。Via頭域的branch ID參數提供了事務的標誌,並且用於proxy來檢查循環路由。

Via頭域包含了用於發送消息的通訊協議,客戶端主機名或者網絡地址,可能還有接收應答所用的端口號碼。Via頭域還可以包含參數”maddr”,”ttl”,”received”和”branch”,這些定義在其他節中描述。對於遵循本規範的實現,這個branch參數的值必須用magic cookie”z9hG4bK”打頭(8.1.1.7節)。

這裏定義的通訊協議是”UDP”,”TCP”,”TLS”,和”SCTP”,”TLS”意思是基於TCP的TLS。當請求發送到一個SIPS URI上時,協議依舊標記着時”SIP”,但是通訊協議是TLS。

Via: SIP/2.0/UDP erlang.bell-telephone.com:5060;branch=z9hG4bK87asdks7
Via: SIP/2.0/UDP 192.0.2.1:5060 ;received=192.0.2.207
;branch=z9hG4bK77asjd

Via頭域的縮寫是v

在這個例子中,從多源(multi-homed)主機的消息有兩個地址,192.0.2.1和192.0.2.207。發送者猜錯了發送的網絡界面(以爲是在192.0.2.1上發送的)。Erlang.belltelephone.com發現了這個不匹配,並且給這個節點的Via增加了一個參數,包含了實際包接收到的地址。

在SIP URI語法下,並不要求填寫主機名或者網絡地址和端口號。特別是,允許在”:”或者”/”兩遍的LWS(線形空白)。例如:

Via: SIP / 2.0 / UDP first.example.com: 4000;ttl=16
;maddr=224.2.0.1 ;branch=z9hG4bKa7c6a8dlze.1

即使本規範要求所有的請求中都包含branch參數,本頭域的BNF描述中,branch參數是可選的。這就和RFC2543元素可以進行互操作,因爲RFC2543沒有添加branch參數。

如果他們的發送協議和sent-by域相等,都有相同的參數集合,並且參數都相等,那麼兩個Via頭域就是相同的。

20.43 警告
Warning頭域用來給應答的狀態添加附加說明使用的。Warning頭域值是在應答中包含的,並且包括了一個3位的警告代碼,主機名,和警告正文。

“warn-text”應當是一個自然語言,給個人用戶接收應答時候來響應的。這可以通過現有的各種信息來決定這個warn-text,比如用戶的位置,Accept-Language域,或者應答重的Content-Language等等。缺省語言是idefault[21]。

下邊列出了當前定義的”warn-code”,並且有英文描述的推薦的warn-text。這些井蓋描述了會話描述中的各種可能的失敗情況。第一個warn-code的數字是”3”表示這是一個SIP規範的警告信息。警告信息300到329是保留用於標誌在會話描述中的保留字錯誤的,330到339是會話描述中基本網絡服務相關警告,370到379是關於會話描述重的QoS參數數量相關的警告,390到399是上邊未列除的雜項警告信息。

300 Incompatible network protocol:(不兼容的網絡協議),One or more network protocols contained in the session description are not available.(在會話描述中的一個或者多個網絡協議不適用)

301 Incompatible network address formats(不兼容的網絡地址格式):One or more network address formats contained in the session description are not available. (會話描述中的一個或者多個網絡地址格式不合法)

302 Incompatible transport portocol(不兼容的通訊協議):One or more transport protocols described in the session description are not available. (會話描述中的一個或者多個通訊協議不存在)。

303:Incompatible bandwidth units(不兼容的帶寬單位): One or more bandwidth measurement units contained in the session description were not understood.(會話描述中的一個或者多個帶寬單位不支持)。

304 Media type not available(媒體類型不存在): One or more media types contained in the session description are not available. (會話描述中的一個或者多個媒體類型不存在)。

305 Incompatible media format(媒體格式不兼容): One or more media formats contained in the session description are not available.(會話描述中的一個或者多個媒體格式不兼容)。

306 Attribute not understood(媒體屬性不支持): One or more of the media attributes in the session description are not supported.(會話描述中的一個或者多個媒體屬性不支持)。

307 Session description parameter not understood(會話描述參數不支持): A parameter other than those listed above was not understood.(列出的會話描述參數不支持)。

330 Multicast not available(多點傳輸不允許): The site where the user is located does not support multicast.(用戶定位的這個服務器不支持多點傳送)。

331 Unicast not available(Unicast不支持): The site where the user is located does not support unicast communication (usually due to the presence of a firewall)。(用戶定位的節點不支持unicast通訊(通常由於在防火牆之後))。

370 Insufficient bandwidth(帶寬不足): The bandwidth specified in the session description or defined by the media exceeds that known to be available.(會話描述的帶寬要求或者媒體要求的帶寬超過限制)。

399 Miscellaneous warning(雜項警告): The warning text can include arbitrary information to be presented to a human user or logged. A system receiving this warning MUST NOT take any automated action.(這個警告信息可以包含給用戶的任意信息或者做日誌記錄。接收到這個警告的系統禁止做任何自動操作)。

1xx和2xx消息是HTTP/1.1使用的。
附加的”warn-code”是IANA定義的,在27.2節有附加說明。
例如:
Warning: 307 isi.edu "Session parameter ’foo’ not understood"
Warning: 301 isi.edu "Incompatible network address type ’E.164’"

20.44 WWW-Authenticate
WWW-Authenticate頭域包含了認證信息,參見22.2節有關的詳細說明。
例如:
WWW-Authenticate:Digest realm=”atlanta.com”,
domain=”sip:boxesbybob.com”,qop=”auth”,
nonce="f84f1cec41e6cbe5aea9c8e88d359",
opaque="", stale=FALSE, algorithm=MD5

21 應答代碼
應答碼是包含了,並且擴展了HTTP/1.1應答碼。並不是所有的HTTP/1.1應答碼都適當應用,只有在這裏指出的是適當的。其他HTTP/1.1應答碼不應當使用。並且,SIP也定義了新的應答碼系列,6xx。

21.1 臨時應答1xx
臨時應答,也就是消息性質的應答,標誌了對方服務器正在處理請求,並且還沒有決定最後的應答。如果服務器處理請求需要花200ms以上才能產生終結應答的時候,它應當發送一個1xx應答。

注意1xx應答並不是可靠傳輸的。他們不會導致客戶端傳送一個ACK應答。臨時性質的(1xx)應答可以包含消息體,包含會話描述。

21.1.1 100 Trying
這個應答表示下一個節點的服務器已經接收到了這個請求並且還沒有執行這個請求的特定動作(比如,正在打開數據庫的時候)。這個應答,就像其他臨時應答一樣,種植了UAC重新傳送INVITE請求。100(Trying)應答和其他臨時應答不同的是,在這裏,它永遠不會被有狀態proxy轉發到上行流中。

21.1.2 180 Ringing
UA收到INVITE請求並且試圖提示給用戶。這個應答應當出世化一個本地回鈴。

21.1.3 818 Call is Being Forwarded(呼叫被轉發)
服務器可以用這個應答代碼來表示呼叫正在轉發到另一個目的地集合。

21.1.4 182 Queued
當呼叫的對方暫時不能接收呼叫的時候,並且服務器決定將呼叫排隊等候,而不是拒絕呼叫的時候,那麼就應當發出這個應答。當被叫方一旦恢復接收呼叫,他會返回合適的終結應答。對於這個呼叫狀態,可以有一個表示原因的短語,比如:”5 calls queued;expected waiting time is 15minutes”。服務器可以給出好幾個182(Queued)應答告訴呼叫方排隊的情況(比如排隊靠前了等等)。

21.1.5 183 會話進度
183(Session Progress)應答用於提示建立對話的進度信息。Reason-Phrase(表達原因的句子)、頭域或者消息體可以用於提示呼叫進度的更消息的信息。

21.2 成功信息2xx
這個應答表示請求是成功的。

21.2.1 200 OK
請求已經處理成功。這個信息取決於不同方法的請求的應答。

21.3 轉發請求3XX
3xx系列的應答是用於提示用戶的新位置信息的,或者爲了滿足呼叫而轉發的額外服務地點。

21.3.1 300 Multiple Choices
請求的地址有多個選擇,每個選擇都有自己的地址,用戶或者(UA)可以選擇合適的通訊終端,並且轉發這個請求到這個地址。

應答可以包含一個具有每一個地點的在Accept請求頭域中允許的資源特性,這樣用戶或者UA可以選擇一個最合適的地址來轉發請求。沒有未這個應答的消息體定義MIME類型。

這些地址選擇也應當在Contact頭域中列出(20.10節)。不同於HTTP,SIP應答可以包含多個Contact頭域或者一個Contact頭域中具有一個地址列表。UA可以使用Contact頭域來自動轉發或者要求用戶確認轉發。不過,本規範沒有定義自動轉發的標準。

如果被叫方可以在多個地址被找到,並且服務器不能或者不願意轉發請求的時候,可以使用這個應答來給呼叫方。

21.3.2 301 Moved Permently
當不能在Request-URI指定的地址找到用戶的時候,請求的客戶端應當使用Contact頭域(20.10)所指出的新的地址重新嘗試。請求者應當用這個新的值來更新本地的目錄,地址本,和用戶地址cache,並且在後續請求中,發送到這個/這些列出的地址。

21.3.3 302 Moved Temporarily
請求方應當把請求重新發到這個Contact頭域所指出的新地址(20.10)。新請求的Request-URI應當用這個應答的Contact頭域所指出的值。

在應答中的Expires(20.19節)或者Contact頭域的expires參數定義了這個Contact URI的生存週期。UA或者proxy在這個生存週期內cache這個URI。如果沒有嚴格的有效時見,那麼這個地址僅僅本次有效,並且不能在以後的事務中保存。

如果cache的Contact頭域的值失敗了,那麼被轉發請求的Request-URI應當再次嘗試一次。臨時URI可以比超時時間更快的失效,並且可以有一個新的臨時URI。

21.3.4 305 Use Proxy
請求的資源必須通過Contact頭域中指出的proxy來訪問。Contact頭域指定了一個proxy的URI。接收到這個應答的對象應當通過這個proxy重新發送這個單個請求。305(UseProxy)必須是UAS產生的。

21.3.5 380 Alternative Service
呼叫不成工,但是可以嘗試另外的服務。另外的服務在應答的消息體中定義。消息體的格式在這裏沒有定義,可能在以後的規範中定義。

21.4 請求失敗4xx
4xx應答定義了特定服務器響應的請求失敗的情況。客戶端不應當在不更改請求的情況下重新嘗試同一個請求。(例如,增加合適的認證信息)。不過,同一個請求交給不同服務器也許就會成功。

21.4.1 400 Bad Request
請求中的語法錯誤。Reason-Phrase應當標誌這個詳細的語法錯誤,比如”Missing Call-ID header field”。

21.4.2 401 Unauthorized
請求需要用戶認證。這個應答是由UAS和註冊服務器產生的,當407(Proxy Authentication Required)是proxy服務器產生的。

21.4.3 402 Payment Required
保留/以後使用
21.4.4 403 Forbidden
服務端支持這個請求,但是拒絕執行請求。增加驗證信息是沒有必要的,並且請求應當不被重試。

21.4.5 404 Not Found
服務器返回最終信息:用戶在Request-URI指定的域上不存在。當Request-URI的domain和接收這個請求的domain不匹配的情況下, 也會產生這個應答。

21.4.6 405 Method Not Allowed
服務器支持Request-Line中的方法,但是對於這個Request-URI中的地址來說,是不允許應用這個方法的。

應答必須包括一個Allow頭域,這個頭域包含了指定地址允許的方法列表。

21.4.7 Not Acceptable
請求中的資源只會導致產生一個在請求中的Accept頭域外的,內容無法接收的錯誤。

21.4.8 407 Proxy Authentication Required
這個返回碼和401(Unauthorized)很類四,但是標誌了客戶端應當首先在proxy上通過認證。SIP對認證的訪問請參見26節和22.3節。

這個返回碼用於應用程序訪問通訊網關(比如,電話網關),而很少用於被叫方要求認證。

21.4.9 408 Request Timeout
在一段時間內,服務器不能產生一個終結應答,例如,如果它無法及時決定用戶的位置。客戶端可以在稍後不更改請求的內容然後重新嘗試請求。


21.4.10 410 Gone
請求的資源在本服務器上已經不存在了,並且不知道應當把請求轉發到哪裏。這個問題將會使永久性的。如果服務器不知道,或者不容易檢測,這個資源消失是臨時性質的還是永久性質的,那麼應當返回一個404(Not Found)。

21.4.11 413請求實體過大。
服務器拒絕處理請求,因爲這個請求的實體超過了服務器希望或者能夠處理的大小。這個服務器應當關閉連接避免客戶端重發這個請求。

如果這個情況是暫時的,那麼服務端應當包含一個Retry-After頭域來表明這是一個暫時的故障,並且客戶端可以過一段時間再次嘗試。

21.4.12 414 Request-URI Too Long
服務器拒絕這個請求,因爲Request-URI超過了服務器能夠處理的長度。

21.4.13 415 Unsupported Media Type
服務器由於請求的消息體的格式本服務器不支持,所以拒絕處理這個請求。這個服務器必須根據內容的故障類型,返回一個Accept,Accpet-Encoding,或者Accept-Language頭域列表。UAC根據8.1.3.5節定義的方法處理這個應答。

21.4.14 416 Unsupported URI Scheme
服務器由於不支持Request-URI中的URI方案而終止處理這個請求。客戶端處理這個應答參照8.1.3.5。

21.4.15 Bad Extension
服務器不知道在請求中的Proxy-Require(20.29)或者Require(20.32)頭域所指出的協議擴展。服務器必須在Unsupported頭域中列出不支持的擴展。UAC處理這個應答請參見8.1.3.5

21.4.16 421Extension Required
UAS需要特定的擴展來處理這個請求,但是這個擴展並沒有在請求的Supported頭域中列出。具有這個應答碼的應答必須包含一個Require頭域列出所需要的擴展。

UAS不應當使用這個應答除非它真的不能給客戶端提供有效的服務。相反,如果在Support頭域中沒有列出需要的擴展,服務器應當根據基準的SIP兼容的方法和客戶端支持的擴展來進行處理。

21.4.17 423 Interval Too Brief
服務器因爲在請求中設置的資源刷新時間(或者有效時間)過短而拒絕請求。這個應答可以用於註冊服務器來拒絕那些Contact頭域有效期過短的註冊請求。這個應答的用法和相關的Min-Expires頭域在10.2.8,10.3,20.23節中介紹和說明。

21.4.18 480 Temporarily Unavailable
請求成功到達被叫方的終端系統,但是被叫方當前不可用(例如,沒有登陸,或者登陸了但是狀態是不能通訊,或者有”請勿打擾”的標記)。應答應當在Retry-After中標誌一個合適的重發時間。這個用戶也有可能在其他地方是有效的(在本服務器中不知道)。Reason-Phrase(原因短句)應當提示更詳細的原因,爲什麼被叫方暫時不可用。這個值應當是可以被UA設置的。狀態碼486(Busy Here)可以用來更精確的表示本請求失敗的特定原因。

這個狀態碼也可以是轉發服務或者proxy服務器返回的,因爲他們發現Request-URI指定的用戶存在,但是沒有一個給這個用戶的合適的當前轉發的地址。


21.4.19 481 Call/Transaction Does Not Exist
這個狀態表示了UAS接收到請求,但是沒有和現存的對話或者事務匹配。

21.4.20 482 Loop Detected
服務器檢測到了一個循環(16.3/4)

21.4.21 483 Too Many Hops
服務器接收到了一個請求包含的Max-Forwards(20.22)頭域是0

21.4.22 484 Address InComplete
服務器接收到了一個請求,它的Request-URI是不完整的。在原因短語中應當有附加的信息說明。這個狀態碼可以和撥號交疊。在和撥號交疊中,客戶端不知道撥號串的長度。它發送增加長度的字串,並且提示用戶輸入更多的字串,直到不在出現484(Address Incomplete)應答爲止。

21.4.23 485 Ambiguous
Request-URI是不明確的。應答可以在Contact頭域中包含一個可能的明確的地址列表。這個提示列表肯囊個在安全性和隱私性對用戶或者組織造成破壞。必須能夠由配置決定是否以404(NotFound)代替這個應答,又或者禁止對不明確的地址使用可能的選擇列表。
給帶有Request-URI的請求的一個應答例子:
sip: [email protected]:
SIP/2.0 485 Ambiguous
Contact: Carol Lee <sip:[email protected]>
Contact: Ping Lee <sip:[email protected]>
Contact: Lee M.Foote <sips:[email protected]>

部分email和語音郵箱系統提供了這個功能。這個狀態碼和3xx狀態碼不同:對於300來說,它是假定同一個人或者服務有不同的地址選擇。所以對3xx來說,自動選擇系統或者連續查找就有效,但是對485(Ambiguous)應答來說,一定要用戶的干預。

21.4.24 486 Busy Here
當成功聯繫到被叫方的終端系統,但是被叫方當前在這個終端系統上不能接聽這個電話,那麼應答應當回給呼叫方一個更合適的時間在Retry-After頭域重試。這個用戶也許在其他地方有效,比如電話郵箱系統等等。如果我們知道沒有其他終端系統能夠接聽這個呼叫,那麼應當返回一個狀態碼600(Busy Everywhere)。

21.4.25 487 Request Terminated
請求被BYE或者CANCEL所終止。這個應答永遠不會給CANCEL請求本身回覆。

21.4.26 488 Not Acceptable Here
這個應答和606(Not Acceptable)有相同的含義,但是隻是應用於Request-URI所指出的特定資源不能接受,在其他地方請求可能可以接受。

包含了媒體兼容性描述的消息體可以出現在應答中,並且根據INVITE請求中的Accept頭域進行規格化(如果沒有Accept頭域,那麼就是application/sdp)。這個應答就像給OPTIONS請求的200(OK)應答的消息體一樣。

21.4.27 491 Request Pending
在同一個對話中,UAS接收到的請求有一個依賴的請求正在處理。14.2描述了這種情況應當怎樣解決。

21.4.28 493 Undecipherable
UAS接收到了一個請求,包含了一個加密的MIME,並且不知道或者沒有提供合適的解密密鑰。這個應答可以包含單個包體,這個包體包含了合適的公鑰,這個公鑰用於給這個UAS通訊中加密包體使用的。細節描述在23.2節。

21.5 Server Failure 5xx
5xx應答是當服務器本身故障的時候給出的失敗應答。

21.5.1 500 Server Internal Error
服務器遇到了未知的情況,並且不能繼續處理請求。客戶端可以顯示特定的錯誤情況,並且可以在幾秒種以後重新嘗試這個請求。

如果這個情況是臨時的,服務器應當在Retry-After頭域標誌客戶端過多少秒鐘之後重新嘗試這個請求。

21.5.2 501 Not Implemented
服務器沒有實現相關的請求功能。當UAS不認識請求的方法的時候,並且對每一個用戶都無法支持這個方法的時候,應當返回這個應答。(proxy不考慮請求的方法而轉發請求)。

注意405(Method Not Allowed)是因爲服務器實現了這個請求方法,但是這個請求方法在特定請求中不被支持。

21.5.3 502 Bad Gateway
如果服務器,作爲gateway或者proxy存在,從下行服務器上接收到了一個非法的應答(這個應答對應的請求是本服務器爲了完成請求而轉發給下行服務器的)。

21.5.4 503 Service Unavailable
由於臨時的過載或者服務器管理導致的服務器暫時不可用。這個服務器可以在應答中增加一個Retry-After來讓客戶端重試這個請求。如果沒有Retry-After指出,客戶端必須就像收到了一個500(Server Internal Error)應答一樣處理。

客戶端(proxy或者UAC)收到503(Service Unavailable)應當嘗試轉發這個請求到另外一個服務器處理。並且在Retry-After頭域中指定的時間內,不應當轉發其他請求到這個服務器。

作爲503(Service Unavaliable)的替代,服務器可以拒絕連接或者把請求扔掉。

21.5.5 504 Server Time-out
服務器在一個外部服務器上沒有收到一個及時的應答。這個外部服務器是本服務器用來訪問處理這個請求所需要的。如果從上行服務器上收到的請求中的Expires頭域超時,那麼應當返回一個408(Request TimeOut)錯誤。

21.5.6 505 Version Not Supported
服務器不支持對應的SIP版本。服務器是無法處理具有客戶端提供的相同主版本號的請求,就會導致這樣的錯誤信息。

21.5.7 Message To Large
服務器無法處理請求,因爲消息長度超過了處理的長度。

21.6 Global Failures 6xx
6xx應答意味這服務器給特定用戶有一個最終的信息,並不只是在Request-URI的特定實例有最終信息。

21.6.1 600 Busy Everywhere
成功聯繫到被叫方的終端系統,但是被叫方處於忙的狀態,並不打算接聽電話。這個應答可以通過增加一個Retry-After頭域更明確的告訴呼叫方多久以後可以繼續呼叫。如果被叫方不希望提示拒絕的原因,被叫方應當使用603(Decline)。只有當終端系統知道沒有其他終端節點(比如語音郵箱系統)能夠訪問到這個用戶的時候才能使用這個應答。否則應當返回一個486(Busy Here)的應答。

21.6.2 603 Decline
當成功訪問到被叫方的設備,但是用戶明確的不想應答。這個應答可以通過增加一個Retry-After頭域更明確的告訴呼叫方多久以後可以繼續呼叫。只有當終端知道沒有其他任何終端設備能夠響應這個呼叫的勢能才能給出這個應答。

21.6.3 604 Does Not Exists Anywhere
服務器驗證了在請求中Request-URI的用戶信息,哪裏都不存在

21.6.4 606 Not Acceptable
當成功聯繫到一個UA,但是會話描述的一些部分比如請求的媒體,帶寬,或者地址類型不被接收。

606(NotAcceptable)應答意味着用戶希望通訊,但是不能充分支持會話描述。606(Not Acceptable)應答可以在Warning頭域中包含一個原因列表,用於解釋爲何會話描述不能被支持。警告原因代碼在20.43節中列出。

在應答中,可以出現一個包含媒體兼容性描述的消息體,這個消息體的格式根據INVITE請求中的Accept頭域指出的格式進行規格化(如果沒有Accept頭域,那麼就是application/sdp),就像給OPTIONS親求的200(OK)應答中的消息一樣。

我們希望這些媒體協商不要經常需要,並且當一個新用戶被邀請加入已經存在的會話的時候,這個媒體協商可能不需要。這取決於邀請的初始化者是否需要對606(Not Acceptable)進行處理。

這個應答只有當客戶端知道沒有其他終端能夠處理這個請求的時候才能發出。


22 使用HTTP認證
SIP爲認證系統提供了一個無狀態的,試錯機制,這個認證機制式基於HTTP的認證機制的。任何時候proxy服務器或者UA接收到一個請求(22.1節例外),它嘗試檢查請求發起者提供的身份確認。當發起方身份確認了,請求的接受方應當確認這個用戶是否式通過認證的。在本文檔中,沒有建議或者討論認證系統。

本節描述的“Digest”認證機制,只提供了消息認證和複查保護,沒有提供消息完整性或者機密性的保證。上述的保護級別和基於這些Digest提供的保護,可以防止SIP攻擊者改變SIP請求和應答。

注意由於這個脆弱的安全性,我們不贊成”Basic”(基本的)認證方法。服務器必須不能接收驗證方法式”Basic”類型的信任書,並且服務器必須拒絕”Basic”。這是和RFC2543的改變。


22.1 框架
SIP認證的框架和HTTP非常接近(RFC2617[17])。特別式,auth-scheme的BNF範式,auth-param,challenge,realm,realm-value,以及信任書都是一樣的(雖然對”Basic”認證方案是不允許的)。在SIP,UAS使用401(Unauthorized)應答來拒絕UAC的身份(或者講是考驗UAC的身份,如果不通過,就是401)。另外,註冊服務器,轉發服務器可以使用401(Unauthorized)來應答身份認證,但是proxy必須不能用401,只能用407(Proxy Authentication Required)應答。對於Proxy-Authenticate的包含要求,Proxy-Authroization,WWW-Authenticate,Authorization在不同的消息中是相同的,如同在RFC2617[17]中講述的一樣。

由於SIP並沒有一個規範的root URL的概念,所以,需要保護的空間的概念在SIP中的解釋也不一樣。realm字串單獨定義被保護的區域。這個是和RFC2543的改變,在2543中Request-URI和realm一起定義了被保護的區域。

這個先前定義的被保護的區域回導致一定程度的混亂,因爲Request-URI是UAC發送的,並且接收到Request-URI的認證服務器可能是不同的,並且真正的最終的Request-URI的格式可能對UAC並不知道。同樣,早先的定義依賴於一個Request-URI中的SIP URI,並且看起來不允許其他的URI 方案(比如tel URL)

需要鑑別接收到的請求的UA使用者或者proxy服務器,必須根據下邊的指導來爲他們的服務器創建一個realm字串。

o Realm字串必須是全局唯一的。我們強調這個realm字串必須包含一個主機名或者域名,遵循3.2.1節或者RFC2617[17]的推薦

o Realm字串應當是一個可讀的能夠展示給用戶的字串。
例如:
INVITE sip:[email protected] SIP/2.0
Authorization: Digest realm=”biloxi.com”,<…>
通常,SIP認證對於特定realm(一個保護區域)是有意義的。因此,對於Digest認證來說,每一個類似的保護區域都有自己的用戶名和密碼集合。如果服務器對特定請求沒有要求認證,那麼它可以接收缺省的用戶名,”anonymous”,並且這個用戶名沒有密碼(密碼是””)。類似的,代表多個用戶的UAC,比如PSTN網關,可以有他們自己的設備相關的用戶名和密碼,而不是每一個用戶名一個用戶名密碼(這就是說,比如網關,有一個網關的用戶和密碼,而不是說通過網關的每一個實際用戶和密碼)。

當服務器可以正確處理絕大部分SIP請求,有本文檔約定了兩類請求要求特別的認證處理:ACK和CANCEL。在某一個認證方案下,並且這個認證方案是使用應答來放置計算nonces(比如Digest),那麼對於某些沒有應答的情況,就會出現問題,比如ACK。所以,基於這個原因,一個服務器接受在INVITE請求中的信任書,也必須同樣接收對應ACK的信任書。UAC通過賦值所有的INVITE請求中的Authorization和Proxy-Authorization頭域值來創建一個相關的ACK消息。服務器必須接收這個ACK請求。

雖然CANCEL方法具有應答(2xx),服務器必須不能拒絕CANCEL請求,因爲這些請求不能被重新提交。通常,如果CANCEL請求和被CANCEL的請求來自同一個節點(假設某種通訊協議,或者網絡層有安全關係26.2.1節描述),服務器應當接收CANCEL請求。

當UAC接收到驗證拒絕,並且UAC設備並不知道realm驗證失敗的具體原因,它必須展示給用戶,驗證失敗的”realm”參數內容(既可以在WWW-Authenticate頭域或者Proxy-Authenticate頭域)。對於給自己的realm預先配置信任狀的UA服務提供商來說,應當注意到這樣一點:當被一個預先配置信任狀的設備拒絕的時候,用戶不會有機會在這個realm中展示他們自己的信任狀。

最後,注意即使一個UAC能夠定位與相關realm匹配的信任書,也有可能存在這個信任書可能不在有效,或者某個服務器會用什麼原因不接受這個信任書(特別是當提供的是沒有口令的”anonymous”用戶時)。在這種情況下,服務器可能會繼續拒絕,或者返回一個403 Forbidden。UAC必須不能再次使用剛纔被拒絕的信任書進行嘗試(如果當前環境沒有改變,那麼請求可以再次嘗試)。

22.2 用戶到用戶的認證。
當UAS收到一個UAC發起的請求,UAS在請求被處理之前進行身份認證。如果請求中沒有信任書(在Authorization頭域),UAS可以使用401(Unauthorized)拒絕認證,並且讓客戶端提供一個認證書。

WWW-Authenticate應答頭域必須在401(Unauthorized)應答消息中出現。這個頭域值包含了至少一個表明認證方式和適用realm的參數的拒絕原因。

在401中的WWW-Authenticate頭域例子:
WWW-Authenticate:Digest,
realm=”biloxi.com”,
qop=”auth,auth-int”,
nonce=”dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"

當原始請求的UAC接收到這個401(Unauthorized)應答的時候,如果可能的話,他應當重新組織這個請求,並且填寫正確的信任書。在繼續處理之前,UAC可以要求原始用戶輸入信任書。一旦信任書(不管是用戶輸入的,還是內部密鑰)提供了,UA應當把這個給特定To頭域和”realm”字段的信任書cache起來,以備給這個地址下一個請求時候使用。UA可以用任何方式來cache這個信任書。

如果沒有找到對應realm的信任書,UAC應當嘗試用用戶”anonymous”和空口令來重新嘗試這個請求。

一旦找到了一個信任書,那麼UA應當要求在UAS或者註冊服務器上認證自己,這是通常的情況,但是並非一定要求的,在接收到一個401(Unauthorized)應答後-可以在請求中增加一個Authorization頭域然後再認證。Authorization頭域包含了具有這個UA到請求的資源所在的realm(區域)的信任書和所需要的認證支持的參數和重現保護的參數。

Authorization頭域例子:
Authorization: Digest username=”bob”,
   realm=”biloxi.com”,
   nonce=”dcd98b7102dd2f0e8b11d0f600bfb0c093",
   uri=”sip:[email protected]”,
qop=auth,
nc=00000001,
   cnonce=”0a4f113b”,
   response=”6629fae49393a05397450978507c4ef1",
   opaque=”5ccc069c403ebaf9f0171e9517f40e41"

當UAC在接收到401(Unauthorized)或者407(ProxyAuthenticationRequired)應答之後,重新用它的信任書來提交請求,它必須增加Cseq頭域的值,就像發送一個正常的新請求一樣。

22.3 Proxy到用戶的認證
類似的,當UAC發送一個請求到proxy服務器,proxy服務器可以在處理請求之前,驗證原始請求的認證。如果請求中沒有信任書(在Proxy-Authorization頭域),proxy可以用407(Proxy Authentication Required)拒絕這個原始請求,並且要求客戶端提供適當的信任書。proxy必須在407(ProxyAuthenticationRequired)應答中增加一個Proxy-Authenticate頭域,並且在這個頭域中給出適用於本proxy的認證資源。

對於Proxy-Authenticate和Proxy-Authorization一起在[17]中描述,兩者有一個不同。Proxy不能在Proxy-Authorization頭域中增加值。所有的407(ProxyAuthenticationRequired)應答必須轉發到上行隊列,遵循發送應答的步驟發送到UAC。UAC負責在Proxy-Authorization頭域值增加適用於這個proxy要求認證的這個proxy的realm的信任書。

如果proxy要求UAC在請求中增加Proxy-Authorization頭域並且重新提交請求,那麼UAC應當增加Cseq頭域的值,就像一個新請求一樣。不過,這樣就導致提交原始請求的UAC需要忽略UAS的應答,因爲Cseq的值可能是不一樣的。

當原始請求的UAC接收到一個407(Proxy Authentication Required)的時候,如果可能,它應當使用正確的信任書重新組織請求。它應當和對前邊講述的401應答的處理步驟一樣顯示和處理”realm”參數。

如果沒有找到對應realm的信任書,那麼UAC應當嘗試用用戶”anonymous”和空口令重新嘗試請求。

UAC也應當cache這個在重新發送請求中的信任書。

我們建議使用下列步驟來cache一個proxy的信任書:

如果UA在給特定Call-ID的請求的401/407應答中,接收到一個Proxy-Authenticate頭域,它應當合併對這個realm的信任書,並且爲以後具有相同Call-ID的請求發送這個信任書。這些信任書必須在對話中被cache住;不過如果UA配置的是它自己的本地外發proxy,那麼如果出現要求認證的情況,那麼UA應當cache住跨對話的信任書。注意,這個意味着在一個對話中的請求可以包含在Route頭域中所經過proxy都不需要的信任書。

任何希望在proxy服務器上認證的UA――通常,但是並非必須,在接收到407(Proxy Authentication Required)應答之後――可以在請求中增加一個Proxy-Authorization頭域然後再次嘗試。Proxy-Authorization請求頭域允許客戶端像proxy來證明自己(或者使用者)的身份。Proxy-Authorization頭域包含了UA提供給proxy和/或者請求資源所在的realm的身份認證信息的信任書。

一個Proxy-Authorization頭域值只提供給指定proxy驗證的,這個proxy的realm是在”realm”參數中指明的(這個proxy可以事先通過Proxy-Authenticat頭域提出認證要求)。當多個proxy組成一個鏈路的時候,如果proxy的realm和請求中的Proxy-Authorization頭域的”realm”參數不匹配,那麼這個proxy就不能使用本Proxy-Authorization頭域值來驗證。

注意,如果一個認證機制不支持Proxy-Authorization頭域的realm,porxy服務器必須嘗試分析所有的Proxy-Authorization頭域值來決定是否其中之一有這個proxy認爲合適的信任書。因爲這個方法在大型網絡上很耗時間,proxy服務器應當使用一個一個支持Proxy-Authorization頭域的realm的認證方案。

如果一個請求被分支(參見16.7節),可能對同一個UAC有不同的proxy服務器和/或者UA希望要求認證。在這種情況下,分支的proxy服務器有責任把這些被拒絕的認證合併成爲一個應答。每一個分支請求的應答中接收到WWW-Authenticate和Proxy-Authenticate頭域值必須由這個分支proxy放置在同一個應答中發送給UA;這些頭域值的順序並沒有影響。

當proxy服務器給一個請求發出拒絕認證的應答,在UAC用正確的信任書重新發請求過來之前,不會轉發這個請求。分支proxy可以同時向多個要求認證的proxy服務器轉發請求。每一個proxy在沒有接收到UAC在他們各自的realm的認證之前,都不會轉發這個請求。如果UAC沒有給這些失敗的驗證提供信任書,那些發出拒絕通過認證的proxy是不會把請求轉發給UA的目標用戶的,因此,分支的優點就少了很多。

當針對包含多個拒絕認證的401(Unauthorized)或者407(Proxy Authentication Required)應答重新提交請求時,UAC應當對每一個WWW-Authenticate和Proxy-Authorization頭域值提供一個信任書。根據上邊的說明,一個請求的多個認證書應當用”realm”參數分開。

不過,在同一個401(Unauthorized)或者407(Proxy Authentication Required)應答中,可能包含對同一個realm的多個驗證拒絕。例如,當在相同域的多個proxy,使用共同的realm,接收到了一個分支請求,並且認證拒絕了的時候,就會有這樣的情況。當UAC重新嘗試這個請求的時候,UAC因此會提供多個Authorization或者Proxy-Authorization頭域,包含相同的”realm”參數。並且對於同一個realm,應當有相同的信任書。

22.4 Digest 認證方案
奔進誒描述了對HTTP Digest 認證方案的SIP修改和簡化。SIP使用了和HTTP[17]幾乎完全一樣的方案。

由於RFC 2543是基於RFC2069[39]定義的HTTP Digest的,支持RFC2617的SIP服務器也必須確保他們和RFC2069兼容。RFC2617定義了保證兼容性的步驟。注意,SIP服務器必須不能接收或者發出Basic認證請求。

Digest認證的規則在[17]中定義,只是使用”SIP/2.0”替換”HTTP/1.1”,並且有如下的不同:

1、    URI有着如下的BNF:
URI=SIP-URI/SIPS-URI
2、    在RFC 2617定義中,有一個HTTP Digest認證的Authorization頭域”uri”參數的錯誤,是沒有括號配對的錯誤。(在RFC2617的3.5節的例子是正確的)。對於SIP來說,’uri’參數必須在引號中引起來。
3、    digest-uri-value的BNF是:
digest-uri-value=Request-URI; 在25節定義。
4、    對SIP來說,產生基於Etag的nonce的步驟例子不適用。
5、    對SIP來說,RFC2617[17]關於chache操作不適用。
6、    RFC2617[17]要求服務器檢查請求行的URI,並且在Authorization頭域的URI要指向相同的資源。在SIP中,這兩個URI可以指向不同的用戶,因爲是同一個proxy轉發的。因此,在SIP,一個服務器應當檢查在Authorization頭域值的Request-URI和服務器希望接收請求的用戶是否一致,但是如果兩者不一致,並無必要展示成爲錯誤。
7、    在Digest認證方案中,關於計算消息完整性保證的A2值的一個澄清,實現着應當假定,當包體是空的(也就是說,當SIP消息沒有包體)應當對包體的hash值產生一個M5hash空串,或者:
H(entity-body)=MD5(“”)=
"d41d8cd98f00b204e9800998ecf8427e"
8、    RFC2617指出了在Authorization(以及擴展的Proxy-Authorization)頭域中,如果沒有qop指示參數,就不能出現cnonce值。因此,任何基於cnonce(包括”MD5-Sess”)的運算都要求qop指數先發送。在RFC2617中的”qop”參數是可選的,這是爲了向後兼容RFC2069;由於RFC2543是基於RFC2069的,”qop”參數必須被客戶和服務器依舊是當作可選參數存在。不過,服務器必須始終在WWW-Authentication和Proxy-Authenticate頭域值中傳送”qop”參數。如果一個客戶端在一個拒絕認證的應答中收到一個”qop”參數,他必須把這個”qop”參數放在後續的認證頭域中。

RFC 2543不允許使用Authentication-Info頭域(在RFC2069中使用)。不過我們現在允許使用這個頭域,因爲他提供了對包體的完整性檢測以及提供了相互認證。RFC2617[17]定義了在請求中使用qop屬性的向後兼容機制。這些機制必須在服務器使用,用來檢測是否客戶支持RFC2617的,沒有在RFC2069中定義的新機制,

23 S/MIME
SIP消息可以加載一個MIME 消息體,並且MIME標準包括了MIME內容的保密機制,確保完整性和機密性(包括”multipart/signed”和”application/pkcs7-mime”的MIME類別,參見RFC 1847[22],RFC 2630[23],RFC2633[24])。實現中應當注意,不管怎樣,也會有很少的網絡節點(不是典型的proxy服務器),會依賴於查看修改SIP消息(特別是SDP),採用加密的MIME可以防止這類網絡節點操作。

這個實現特別對某些類型防火牆有效。

在RFC2543描述的對於SIP頭域和包體的PGP加密機制,已經不建議使用了。

23.1 S/MIME 認證
用於區別服務器使用的S/MIME而進行的最終用戶的鑑定,有一種重要的特點-這些信任狀的持有者是被最終用戶地址鑑定的,而不是由一個特定的hostname所鑑定的。這個地址是由SIP或者SIPS URI的”userinfo””@”和”domainname”組成的(換句話說,就是用的email格式,類似[email protected]),最常見的就是和用戶的address-of-record對應的地址。

這些認證也同樣和用於標記或者加密SIP消息包體的密鑰相關聯。包體由發送方的私鑰所標記(這個發送方在適當情況下,可以包含他們的公鑰),並且包體是由被接受方的公鑰所加密。顯然,發送方必須事先知道接受方的公鑰,這樣才能加密包體。公鑰可以在UA的一個虛擬的鑰匙環上保存。

每一個支持S/MIME的UA都必須包含用於終端用戶驗證的一個特定密鑰組。這個密鑰組應當由address-of-record和相應的認證信息的映射組成。在時間上,當用戶產生具有相同address-of-record的原始的信號URI(From頭域)時,用戶應當使用相同的認證信息。

任何依賴於現存的終端用戶認證的機制都是嚴格受限於:事實上,目前沒有一個統一的權威認證機構爲終端用戶應用提供認證。不過,用戶應當從已知的公共認證機構獲得認證。作爲替代,用戶可以創建自標記(self-signed)的信任書。self-signed信任書在26.4.2節中有介紹。在實現中,也可以採用在配置中存放預先配置的信任書,這個配置中存放的時上次SIP實體之間的信任關係。

在獲得終端用戶的認證問題上,很少有廣爲人知的集中發佈終端用戶認證的目錄機構。信任書的擁有者應當在一些公共的目錄機構中,適當的發佈自己的信任書。類似的,UAC應當支持從與SIP請求的目標URI有關的公共目錄機構導入信任書(手工或者自動的)。

23.2 S/MIME 密鑰交換
SIP自身可以根據下列的方法發佈公鑰。

無論何時SIP的S/MIME使用了CMS SignedData消息,他必須包含由公鑰所加密的信任書,用於檢查簽名。

當UAC發送一個創建對話的請求,包含了一個S/MIME包體,或者在對話外發送一個非INVITE請求,UAC應當創建一個S/MIME ‘multipart/signed’ CMS SignedData包體結構的包體。

如果特定的CMS服務時EnvelopedData(並且知道目標用戶的公鑰),UAC應當在一個SignedData消息中發送EnvelopedData消息。

當UAS接收到一個包含S/MIME CMS包體的請求,並且這個包體包含一個信任書,UAS應當首先檢查這個信任書,如果可能,使用以後的root信任書來進行信任書檢查。UAS也應當檢查信任書的主題(subject)(對於S/MIME,SubjectAltName應當包含了適當的標記)並且,把這個值和請求From頭域進行比較。如果信任書不被通過,因爲它是self-signed(自簽發),或者被位置的信任機構所頒發的,或者它是可信任的,但是他的主題和請求的From頭域不匹配,UAS必須把這個通知用戶(包括信任書的主題,簽發者,和密鑰指紋信息),並且在繼續處理之前,要求用戶確認。如果信任書成功通過認證,並且信任書的主題(subject)和SIP請求的From頭域相同,或者如果用戶(在知會之後)批准了這個信任書的使用,那麼UAS應當增加這個信任書到本地密鑰組中(keyring),並且用信任書擁有者的address-of-record作爲索引。

當UAS要發送一個包含S/MIME消息體的應答,這個應答迴應了在對話中的前一個請求,或者是給對話外的一個非INVITE請求的應答,UAS應當構造一個S/MIME ‘multipart/signed’ CMS SignedData包體。如果給定的CMS服務要求EnvelopedData,UAS應當發送一個EnvelopedData的SignedData消息

當UAC收到一個包含S/MIME CMS包體的應答,這個應答中包含了一個信任書,UAC應當首先檢查這個信任書,如果可能,使用任何適當的root信任書來進行檢查。UAC應當同樣檢查信任書的主題(subject),並且和應答的To頭域進行比較;雖然兩個可能完全不同,這個也沒有必要當作是不安全的。如果因爲self-signed,或者由未知認證機關頒發而導致信任書不能通過認證,那麼UAC應當通知它的使用者這個狀態(包含信任書的主題,它的簽發者,以及密鑰的指紋信息),並且在繼續操作之前,要求使用者確認。如果信任書通過了認證,並且信任書的主題和應答的To頭域相同,或者用戶(在提示確認後)明確的確認這個信任書以後,UAC應當把這個信任書放在本地密鑰組中,用這個信任書的擁有者的address-of-record作爲索引。如果UAC沒有把自己的信任書事先傳送給UAS,它在下一個請求或者應答時應當使用一個CMS SignedData包體。

在以後,當UA接收到包伙那一個From頭域的請求或者應答,並且這個From頭域和本地的一個密鑰組的索引匹配,那麼UA應當比較消息中的信任書和這個密鑰組對應索引的信任書。如果他們不匹配,那麼UA必須通知用戶信任書改變了(更合適的是提示這個可能是一個潛在的安全衝突),並且在繼續處理前要求用戶的確認。如果用戶確認了這個信任書,它應當在本地密鑰組的這個address-of-record項的前一個值旁邊附加這個信任書。

注意,這個值的改變機制,在self-signed信任書的情況或者未知機關頒發的信任書情況下,並不保證密鑰變更的安全性,並且這個缺陷被廣爲人知的攻擊。在本文的作者看來,它提供的安全性當然比什麼也沒有要強;實際上可以和廣泛應用的SSH應用相比。這些限制在26.4.2節中有詳細描述。

如果UA接收到了一個S/MIME包體,並且是由本接受方所不知道的公鑰加密的,它必須用493(Undecipherable)拒絕這個請求。這個應答應當回答一個合法的信任書(相應的,如果可能,給被拒絕請求的To頭域指出的全部地址),這個信任書包含一個’certs-only’ “smime-type”參數的MIME包體。。

一個沒有任何信任書信息的493(Undecipherable)應答表示回答者不能或者不會利用S/MIME加密信息,雖然他們可以依舊支持S/MIME標記。

注意UA接收到一個包含一個S/MIME包體的請求(這個請求包含了Content-Disposition頭域和”required”的”handling”參數),如果這個MIME類型是不被支持的,那麼就必須用415 Unsupported MediaType來拒絕這個請求。當UA接收到這個應答,並且這個應答表示的是對方不支持剛纔發送的S/MIME類型的請求,那麼UA應當通知它的使用者對方不支持這個S/MIME類型,並且如果可以,他可以在隨後的請求中不包含S/MIME部分;另外,這個415應答可以製造一個下級的攻擊。

如果一個UA在請求中發送了一個S/MIME包體,但是接收到的應答包含了一個未加密的MIME包體,UAC應當提示用戶,這個會話可能是不安全的。可是,如果一個支持S/MIME的UA接收到一個包含未加密的包體的請求,它不應當給出一個包含加密包體的應答,但是如果它希望從發送方獲得一個S/MIME(比如,因爲發送方的From頭域值在它的密鑰組中存在關聯),UAS應當通知它的使用者這個會話可能是不安全的。

當信任書管理不正常的情況下,許多條件都可以導致前邊講的要給用戶提示以及確認的情況。使用者可能會問在這個情況下應當怎樣做。首先,一個信任書的異常改變,或者在需要安全保護的時候不安全,是導致這個警告出現的原因,但是並非表示正在遭受攻擊。使用者可以中斷現有的連接或者拒絕連接請求;在電話談話中,他們可以掛機並且回叫。使用者可能會使用另外的方式來聯繫對方並且確認他們的密鑰是否合法的更改了。注意用戶有時候需要強制更改他們的信任書,例如當他們懷疑他們的私鑰不夠安全的情況。當他們的私鑰不再私鑰,用戶必須合法的產生一個新的密鑰並且重新和其他持有舊密鑰的用戶建立信任關係。

最後,如果在對話中UA收到了在一個CMS SignedData Message中的信任書,並且和早先對話中交換的信任書不一致,那麼UA必須提示它的使用者這個變化,更好的方法是展示成爲一個安全隱患。

23.3 加密MIME 包體
SIP中,總共由兩種類型的加密MIME包體:對他們的使用應當遵循S/MIME規範[24],並且有幾點不同:

l    multipart/signed”只在CMS 分離簽名的時候有用。這是爲了和非S/MIME規範接受者兼容。
l    S/MIME包體應當包含一個Content-Disposition頭域,並且他的”handling”參數的值應當是”required”
l    如果UAC在它的密鑰組中沒有對應要發送請求的接受者的address-of-record的信任書,它不能發送加密的”application/pkcs7-mime” MIME消息。UAC可以發送一個初始化的請求(比如OPTIONS消息),包含一個爲了方便對方處理的CMS分離的簽名(簽名應當基於一個”message/sip”包體,類型描述在23.4節)。
注意以後的S/MIME標準工作可以定義基於非信任書的密鑰。
l    S/MIME的發送方應當使用”SMIMECapabilities”(參見2.5.2 [24])屬性來爲以後的通訊介紹他們自己的能力和參數。注意,特別是那些可能用”preferSignedData”的發送方希望接受方應答一個CMS SignedData消息(例如,當發送一個OPTIONS請求的時候)。
l    S/MIME實現必須至少支持SHA1作爲數字簽名算法,並且3DES作爲加密算法。其他的簽名和加密算法也可以支持,實現上應當可以用”SMIMECapabilities”屬性進行這些算法的協商。
l    在SIP中的每一個S/MIME包體應當只有一個信任書的簽名。如果UA接收到的消息有多個信任書,最外邊的信任書應當當作這個包體的信任書。並行的簽名應當不能使用。
下邊是一個SIP中的加密的S/MIME SDP包體的例子:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Max-Forwards: 70
Contact: <sip:[email protected]>
Content-Type: application/pkcs7-mime; smime-type=enveloped-data;
name=smime.p7m
Content-Disposition: attachment; filename=smime.p7m
handling=required
********************************************************************
* Content-Type: application/sdp                        *
*                                                    *
* v=0                                                *
* o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com    *
* s=-                                                *
* t=0 0                                                *
* c=IN IP4 pc33.atlanta.com                            *
* m=audio 3456 RTP/AVP 0 1 3 99                        *
* a=rtpmap:0 PCMU/8000                                *
********************************************************************


23.4 SIP頭隱私和用S/MIME的完整性:SIP地道
作爲提供端到端的某種程度認證來說,SIP頭域的完整性或者機密性,SI/MIME可以把SIP消息通過”message/sip”的包體類型,整個裝入一個MIME包體,並且接着就像處理普通SIP包體一樣,對這個大的包體用MIME安全性來保護。這些被封裝的SIP請求和應答並不產生另外的對話或者事務,他們只是一個用來檢驗完整性的或者提供附加信息的”outer”外部包裝消息。

如果UAS接收到一個請求,包含一個”message/sip”隧道的S/MIME包體,它應當把應答用同樣的SMIME-TYPE封裝成一個”message/sip”隧道包體。

任何傳統的MIME包體(比如SDP),應當附加爲”inner”內部消息,這樣他們可以使用到S/MIME安全性。注意,如果在請求中需要傳送未加密的MIME類型的內容,那麼”message/sip”包體可以作爲MIME “multipart/mixed”包體的一部分存在,

23.4.1 SIP頭的完整性和機密屬性
當應用了S/MIME完整性或者機密性機制,那麼在”inner”消息和”outer”消息中的值可能會有差異。對於所有頭域來說,處理這些差異的規則在本節指出。

注意,由於鬆散的時間戳,所有的在”message/sip”隧道中的SIP消息應當在”inner”和”outer”消息中都包含一個Date頭域。

23.4.1.1 完整性
無論何時,當完整性被檢查,頭域的完整性應當通過檢查被封裝包體中的頭域值和”outer”消息的頭域值,使用20節描述的SIP比較規則。

頭域可以被proxy服務器合法修改的是:Request-URI, Via, Record-Route, Route, Max-Forwards, 和Proxy-Authorization。如果這些頭域不完全相等,實現中不應當認爲是一個安全錯誤。對於其他頭域的修改就是破壞了完整性,必須通知使用者關於這個差異。

23.4.1.2 機密性
當消息加密以後,頭域可以在加密的包體中存在,而不用在”outer”消息中存在。

有一些頭域必須有一個明碼格式的版本,因爲他們是請求和應答中必須要求的頭域-他們是:To, From, Call-ID, Cseq, Contact。 雖然提供一個額外的Call-ID,Cseq,或者Contact的加密版本沒有什麼用處,我們允許把To/From 放一份在”outer”消息的To或者From頭域中。注意這些加密包體中的值並不用作鑑別事務或者對話――加密包體中的這些值僅僅作爲提示信息使用。如果在加密包體中的From頭域和在”outer”消息中的值不一樣,那麼這個加密包體中的值應當顯示給用戶,但是不能用於後續”outer”消息的頭域中。

首先,UA應當希望加密有着端到端語義的頭域,包括: Subject,Replay-To,Organization, Accept,Accept-Encoding,Accept-Language,Alter-Info,Error-Info, Authentication-Info , Expires, In-Replay-To, Require, Supported, Unsupported, Retry-After, User-Agent, Server, 和Warning。 如果這些頭域在加密包體中出現,那麼就應當替換在”outer”消息中的頭域,而不管這個頭域是顯示給用戶的還是設置UA內部狀態的。他們應當在後續消息中不在在”outer”消息的頭域中使用。

如果存在Date頭域,那麼Date頭域必須在”inner”和”outer”頭域中的值一樣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章