SIP協議詳解(中文)-3

 
7.3.2 頭域分類。
有一些頭域是僅僅在請求(或者應答)中有效的。這些頭域叫做請求頭域或者應答頭域。如果消息中的頭域與這個消息的類型不匹配(比如在應答消息中出現的請求頭域),這個頭域必須被忽略。20節定義了每一個頭域的分類。
7.3.3 縮寫格式
SIP提供了一個用縮寫格式來表達通用頭域名字的機制。這個有助於避免消息過大而導致通訊層無法傳輸(比如在UDP傳輸的時候超過了最大傳輸單元(MTU))。這個縮寫格式在20節定義。
縮寫格式的消息頭域名字可以在不改變消息語義的情況下替代較大的消息頭域名字。在單個消息中,頭域名字既可以用長的格式,也可以用縮寫格式。在實現中,必須同時支持對長名字和縮寫名字的處理。
7.4包體
請求信息,包括這個規範以後的擴展的新請求,都可以包含一個消息正文體。對消息正文體的解釋依賴域請求的方法(請求類型)。對於應答消息來說,請求方法和應答狀態(response status code)決定了消息正文體的格式。所有的應答消息都可以有一個消息正文體(body)。
7.4.1 消息正文類型(MessageBodyType)
消息中的internet媒體類別必須在Content-Type頭域中指明。如果消息正文(body)通過某種形式的編碼(encoding),比如壓縮等等,都必須在Content-Encoding 頭域中指明,否則Content-Encoding域必須忽略。如果可行,消息體的字符集作爲Content-type頭域的值的一部分表達。

在RFC2046[11]中定義的多部分”multipart” MIME類型可以在消息體中應用。在由多部分組成的消息體發送的時候,如果接受方的實現中,包頭域的Accept域中,不包含多部分的標記,那麼發送方必須發送一個非多部分的session description。
SIP消息可以包含二進制的包體或者部分包體。如果發送方沒有其他顯示的字符集參數指出,媒體的文本”text”子類型會是缺省的字符集”UTF-8”。
7.4.2 消息體長度
在Content-Length頭域中存放了包體的字節長度。第20.14節講述了本域的詳細解釋。
HTTP/1.1的“chunked”傳輸編碼方式並不適用於SIP。(備註:chuncked編碼傳輸方式是通過把消息正文體分爲一系列的塊來傳輸的,每一塊有它自己的大小標記)

7.5 分幀的SIP消息(Framing SIP Messages)
不同於HTTP的是,SIP實現可以使用UDP或者其他非可靠傳輸協議。每一幀包括一個請求或者應答。第18節講述了非可靠傳輸的應用。
在處理以面向流的通訊爲基礎的SIP消息的時候,必須忽略在開始行之前的CRLF[H4.1]。
Content-Length頭域用來確定每一個SIP消息在通訊流中的結束位置的。在基於面向流通訊基礎上的SIP消息一定要使用這個頭域。

8 一般用戶代理行爲
一個用戶代理代表了一個終端系統。它包含一個用戶代理客戶端(UAC),用來產生請求的,它包含一個用戶代理服務端(UAS),用來響應請求的。UAC可以由一些外部的東西來發出請求和處理應答(比如用戶按了一個按鈕,或者按下了一個電話鍵產生了一個音頻信號等等)。UAS是一個能夠接收請求,並且產生應答的東西,它可以根據用戶輸入,外部輸入,程序執行結果或者其他什麼機制來產生應答。

當一個UAC發送一個請求,這些請求可能通過一些PROXY(代理服務器)傳遞到UAS上。當UAS產生一個應答,那麼這個應答就會同樣的被傳送到UAC。UAC和UAS的處理由兩個特點。第一,基於請求或者應答是否在一個對話裏,第二,基於請求的方法(method)。會話的徹底描述在第12節;哪裏描述了點對點的用戶代理之間的關係,並且通過一些SIP方法建立了會話,比如INVITE方法等。

在本節,我們將討論在處理對話外的請求時,UAC和UAS的方法無關的規則。這些當然也包括用於建立會話的請求。在26節講述了對在對話外的請求和應答的安全處理。特別時,UAS和UAC之間的互相認證的機制。通過用S/MIME加密的消息體可以提供有限的隱私保證。
8.1 UAC特性
本節講述UAC在會話外的特性。
8.1.1 產生一個請求
一個合法的SIP請求必須至少包含如下頭域:TO,FROM,Cseq,Call-ID,Max-Forwards, Via;這些字段在所有SIP請求中必須包含。這6個字段是SIP消息的基本組成部分,他們提供了用於路由用的核心信息,包含了消息的地址,響應的路由,消息傳遞次數,詳細的順序,事務的唯一標誌。
這些頭域字段是必須包含在請求行之後的,請求行包含了請求的方法,Request-URI,SIP的版本號碼。
有兩個在對話外的發送請求的示例(通過INVITE請求建立連接,第13節),(通過OPTIONS請求查詢負載,第11節)。
8.1.1.1 Request-URI
最開始的Request-URI頭域應該是TO頭域的的值。但是在REGISTER方法中,有一個值得注意的不同;REGISTER方法的Request-URI頭域在第10節中指出。出於隱私的原因而把這些字段的值設置成爲同一個值並不太合適(尤其是如果初始的UA期望Request-URI會在傳輸中改變的話)。
在一些特定的情況下,預先設置的路由表(route-set)會影響消息中的Request-URI。一個預置路由表是由一串server的URI組成,這些服務器是UAC往外發送會話外請求所需要經過的。通常,他們是由用戶或者服務提供商手工在UA上設置的,或者通過一些非SIP的方法自動設置。當一個提供商希望配置一個出口proxy給一個UA,我們強烈建議通過一個預置一個單個URI路由表的方式來實現,這個單個路由就是出口proxy。
當要使用預置路由表(route set),必須提供Request-URI和Route頭域(在12.2.1.1節中有詳細描述)(甚至在沒有對話存在的時候也必須提供),並且把Request-URI當作遠端目標URI。
8.1.1.2 TO
To頭域是第一個並且也是最先指定請求的”邏輯”接收地,或者是這個請求的用戶或者資源的address-of-record。這個域內的地址可以是也可以不是請求的最終接收者。TO頭域可以用SIP或者SIPS URI,也可以用其他方式的URI(比如電話URL (RFC2806[9]))。所有的SIP實現必須支持SIP URI的實現。任何支持TLS的實現必須支持SIPS URI的實現。
To頭域允許有一個顯示用的姓名。
UAC可以通過無數的方法來知道在一個給定請求的時候該如何填寫TO頭域。通常用戶會建議採用人工界面中輸入的To頭域,可能手工輸入這個URI或者從地址本中選擇(就好像outlook郵件中的to一樣)。用戶通常不會輸入完整的URI,可能只是一個簡單的字串(比如”bob”)。這就要求UA能夠判斷用戶輸入的這個到底是那個URI。一般使用用戶輸入的字串加上”@”標誌和主機的名字組合成爲SIP URI(比如sip:[email protected])。如果希望通訊在保密機制下進行,那麼就用用戶輸入的字串組成SIPS URI的部分,用戶輸入的將加上”@”和主機的名字作爲整個SIPS URI。這個主機的名字通常是請求方的主機名字,這個主機允許處理外發請求。這個很像”縮位撥號”的機制,這個機制要求請求者自身的主機能夠解釋這個縮位撥號一樣。
如果UA不希望指定主機,那麼就需要將用戶輸入的電話號碼解釋成爲一個電話的URL。相當於,每一個請求經過的主機都會有機會來處理這個請求。比如,一個用戶在機場可能登陸機場的代理服務器,並且通過機場的代理服務器發出一個請求。如果他輸入”411”(美國本地電話本查詢服務號碼),這個就需要機場的外發的代理服務器進行解釋和處理,而不是解釋成有主機的用戶。在這裏,tel:411是一個正確的解釋。
在會話外的請求中,不能包含To tag字段,在to頭域中的tag是用來在對話中做標誌的。既然對話還沒有建立,那麼tag就不能存在。
20.39節有進一步的描述。
下邊這個例子是一個To頭域的例子:
To: Carol <sip:[email protected]>
8.1.1.3 From
From頭域包含了請求發起者的邏輯標誌,可能是用戶的address-of-record。就像To頭域一樣,From頭域也包含一個URI並且可以包含一個顯示的姓名。SIP可以用這個頭域來實現對請求的檢查和選擇一個規則進行對請求的處理(比如,自動的呼叫拒絕,凡是x人發過來的東西,一律無視)。同樣的,因爲From頭域包含的是邏輯名字,所以From URI也可以不包含IP地址或者UA對應的主機名字FQDN。
From頭域可以包含一個顯示姓名。在客戶身份隱藏的情況下,一個UAC應該使用顯示名字”Anonymous”,連通一個語法正確,但是沒有意義的URI(比如:sip:[email protected])。通常,用戶或者用戶的本地主機的管理人員會事先規定請求頭域中的From頭域的值。如果給定的UA是多個用戶共同使用的,那麼必須有一個URI對應身份的profile,這樣才能夠切用戶的profile。收到請求的服務方可以根據這個用於分辯身份的URI來區分同一個UA上的不同的用戶,並且根據他們的From頭域來判定他們的身份。(22節有更多的驗證說明)。
From域必須包含一個由UAC產生的新的”tag”參數。19.3節有tag的詳細描述。20.20節有更深入的資料。
例子:
From: “Bob” <sips:[email protected]> ; tag=a48s
From: sip:+[email protected];tag=887s
From: Anonymous <sip:[email protected]>;tag=hyh8
8.1.1.4 Call-ID
Call-ID是一個在一系列消息中,區分一組消息的唯一標誌。在對話中的任一UA的所有請求和所有應答的Call-ID必須一致。在UA的每次註冊中,都應該是一樣的。在會話外的時候,UAC發起一個新的請求,這個Call-ID頭域必須由UAC產生一個全局(在時間和空間上都是)唯一的Call-ID, 除非是請求頭的方法(method)指明瞭別的產生方式。所有的SIP UA都必須保證自己產生的Call-ID不會和其他UA產生的Call-ID重複。注意,如果是請求的重新嘗試,則重新嘗試的請求不被當作一個新的請求,所以不需要新的Call-ID(重新嘗試的請求例如:認證衝突等等)。(見8.1.3.5)
我們強烈建議用密碼亂序隨機串(RFC 1750[12])來產生Call-ID。實現中,可以用類似”localid@host”這樣的格式產生。Call-ID是大小寫敏感的,並且通過簡單字節/字節的來進行比較。
採用密碼亂序隨機串可以降低會話被竊聽的機會,並且降低Call-ID重複的衝突。不規定或者要求使用用戶界面來選擇輸入Call-ID頭域的值。參見20.8節。
例子:
Call-ID: [email protected]
8.1.1.5 Cseq
Cseq 頭域是用來區分和做位事務的順序使用的。他由一個方法(method)和一系列的順序號碼組成。方法(method)必須和請求的方法一致。對於對話外的非REGISTER請求來說,順序號碼可以是任意的。這個順序號碼必須可以由32位的無符號整數表達,必須小於2^31。只要遵循了上述指導方針,客戶端可以用任意的方法來產生這個Cseq頭域。12.2.1.1節講述了在對話中如何創建Cseq
例子:
Cseq: 4711 INVITE
8.1.1.6 Max-Forwards
Max-Forwards頭域用來限制請求到他的目的地中間的跳轉。它包含一個每隔一個跳轉就自動減一的數字。如果Max-Forwards在到達目的之前就減到0,他會報告一個483(太多的路由)錯誤迴應。
一個UAC必須爲每一個請求填寫一個Max-Forwards頭域,這個字段的缺省值應該是70。這個數字是保證了請求在沒有環路的SIP網絡中都能夠送達,也保證了在有環路的時候,儘量少消耗proxy的資源。如果這個數字要變小,則必須保證UA知道整個網絡的拓撲結構。
8.1.1.7 Via
Via頭域是標誌了用於事務傳輸的傳輸設備,並且也標誌了應答送回的地址。只有當需要通過選擇傳輸設備到達下一個節點(hop)的時候,才需要在頭域中包含Via域。當UAC創建一個請求,它必須在頭域中添加一個Via域。protocol 名字和protocol版本必須分別是SIP和2.0。Via頭域必須包含一個分支(branch)參數。這個參數用於區分請求創建的事務。這個參數客戶端和服務器都會使用。除了CANCEL和給非2xx應答的ACK以外,branch參數對UA發出的所有的請求來說,在時間和空間上必須唯一。在下邊的講解中,CANCEL請求的branch參數必須和他所取消的請求的branch參數一致。在17.1.1.3節中講述了給非2xxx(non-2xx)應答的ACK必須和其對應的的INVITE請求有相同的branch ID。
利用branch ID參數的唯一性來作爲事務的ID(transaction ID),並非RFC 2543的一部分。根據本標準產生的branch ID必須用”z9h64bK”開頭。這7個字母是一個亂數cookie(定義成爲7位的是爲了保證舊版本的RFC2543實現不會產生這樣的值),這樣服務器收到請求之後,可以很方便的知道這個branch ID是否由本規範所產生的(就是說,全局唯一的)。在這樣的要求下,精確的branch ID的格式必須事先有實現的定義。
Via頭域中,maddr,ttl,和sent-by字段會在transport層處理請求的時候設置(18節)。Via在proxy的處理在16.6節8段和16.7節3段描述。
8.1.1.8 Contact
Contact頭域提供了訪問後續請求的特定UA實例的聯繫方法:SIP或者SIPS URI。在任何會建立一個對話的請求中,Contact頭域必須提供和包含一個SIP或者SIPS URI。在這個規範中定義的方法中,只有INVITE請求會建立一個會話。對這些請求來說,Contact的作用域是全局性的。這就是說,Contact頭域中包含的URI是UA能夠接收請求的,這個URI必須是有效的,甚至在對話外的請求中的Contact頭域中的URI也必須是有效的。
如果Request-URI或者頭上的Route頭域包含了SIPS URI,Contact頭域也必須是一個SIPS URI。在20.10節有更進一步的說明。
8.1.1.9 Supported 和 Require
如果UAC支持服務端響應請求的SIP擴展,UAC應該在請求的時候包含一個Supported頭域說明options tags(19.2節)描述那些SIP擴展。option tags中出現的擴展說明必須是遵循RFCs的標準擴展說明。這樣可以防止服務端支持非標準的客戶端擴展實現。在Support頭域中的對於SIP擴展定義中,嚴格遵守不支持試驗性質的或者說明性質的RFCs擴展,這個也是由於這些擴展是描述提供商定義的擴展說明。如果UAC要求UAS能夠支持擴展,以便UAS能夠處理UAC的特定請求,那麼它必須在請求頭中增加一個Require頭域來說明處理本特定請求需要什麼樣的一個擴展option tags。如果UAC需要請求經過的所有proxy都支持它發出的某個請求的擴展部分,它必須增加一個Proxy-Require頭域來說明需要Proxy支持何種option tag擴展。
如同在Supported頭域指出的,Require和Proxy-Require頭域中的option字段必須限定於RFCs的標準擴展。
8.1.1.10 附加信息部分
在一個新請求創建以後,以上的頭域都被正確初始化了以後,就可以位這個請求增加它所需要的附加頭域了。SIP請求允許包含一個MIME-encoded消息正文。無論請求包含哪種消息正文,都必須引入頭域來指出這個正文的類型,以及這個正文的一些其他說明。關於這些頭域的詳細說明,請參見20.11節到20.15節。
8.1.2 發送一個請求
於是,我們就開始查找請求發送的目標。除非有其他的特定說明,目標必須是通過DNS來查找的(參見[4]說明)。如果路由表(route set)中的第一個元素表明這是一個嚴格路由(strict router,在12.2.1.1節中講述),那麼這些過程必須在請求的Request-URI中說明。否則,這些過程在請求中被應用於第一個Route頭域中(如果存在),或者在請求的Request-URI中(如果Route頭域不存在)。這樣一些過程產生了一系列的地址,端口,和用於傳輸的傳輸器。無論那個URI用在這個[4]中描述的過程的輸入,如果Request-URI指明瞭SIPS,那麼UAC必須按照[4]中描述的說明來認爲輸入的URI是SIPS的URI。
本地策略可以指定一套額外的目的地用於發送。如果Request-URI包含一個SIPS URI,任何額外的目的地都必須用TLS來表達。除此之外,如果請求沒有包含Route頭域,那麼就沒有對額外的目的地有什麼其他的限制了。這個就提供了一個簡單的外發(outbound)proxy的事前路由的選擇。但是,用這樣的方法配置一個外發proxy是不推薦的;應該由單個UPI規定的預先設定的路由集來指定外發proxy。如果請求包含了Route頭域,請求應該發送到Route頭域最上邊的一個位置,但是請求也可能被髮給由本文檔約定的Route或者Request-URI所指定的服務器(同RFC2543定義的相反)。特別的,一個配置了外發proxy的UAC應該首先嚐試把請求發送給由第一個Route頭域值指定的位置,而不是採用把所有消息都發給外發proxy的策略。這就保證了外發的proxy通過不增加Record-Route頭域而不參與後續請求的路徑。這個也允許讓不能分析第一個Route URI的終端,把請求交給外發proxy來發送。UAC應該遵循[4]中定義的過程來實現有狀態的元素,嘗試每一個地址直到連接到一個服務器。每一個嘗試都是一個事務,因此,每一個都有一個不同的Via頭域值和一個新的branch參數值。
此外,在Via頭域中的transport的值被設置成爲要到目標服務器所必須的transport。
8.1.3 處理應答
應答首先是被transport層處理,並且被transport層發送給上一層transaction層處理。transaction層處理完成之後將應答發送給更上一層TU處理。在TU層進行的對應答的主要處理是方法相關的。但是也有集中通用的處理原則:
8.1.3.1: transaction 層的錯誤
在某些情況下,從transaction層返回的應答不一定是一個SIP消息,而是一個transaction層的錯誤。當從transaction層收到一個timeout錯誤的時候,必須將這個timeout錯誤當作是收到了一個狀態碼是408(請求timeout)的應答。如果transport層報告了一個嚴重錯誤(通常取決於UDP傳輸中的嚴重的ICMP錯誤,或者是TCP連接中的錯誤),必須把這個錯誤當作是狀態碼503(服務未提供)的錯誤。
8.1.3.2 未知的應答
UAC必須把自己不認識的所有最終應答當作是x00的那類應答,當然UAC也必須能夠處理所有的類別應答的x00的應答。比如,如果UAC收到了不認識的應答代碼431,他可以很安全的假設在他發出的請求中有什麼地方弄錯了,並且可以很簡單的把這個應答錯誤當作是接收到了一個應答代碼是400(非法請求)的錯誤應答。並且,UAC必須能夠處理所有的不認識的非終結應答響應當作是183(session progress)。一個UAC必須能夠處理100和183應答。
8.1.3.3 Vias
如果在應答中,有不只一個Via頭域值存在,那麼UAC應該丟棄這個消息。包含超過一個Via頭域值的消息是因爲被錯誤的路由或者消息被破壞。
8.1.3.4 處理3xx應答
由於接收到一個重定向的應答(比如,狀態碼是301的應答),客戶端應該用在Contact頭域中的URI(s)來組織一個或者多個基於重定向以後的新請求,這個處理過程同proxy處理一個3xx類別的應答很類似,相關資料在16.5節和16.6節中有描述。客戶發起請求的時候只有一個目標URI,就是原始請求中的Request-URI。如果客戶端想在這個請求基礎上重構一個基於3xx類別應答的新請求,那麼就需要把這個需要嘗試的URIs放到目標集合中去。基於本規範的規定,一個客戶端可以選擇放置那個Contact URIs到目標集合中(target set)。同proxy會遞歸一樣,客戶端處理3xx應答的時候必須不能重複添加任何URI到target set。如果原始請求的Request-URI頭域中包含了一個SIPS URI,那麼客戶端可以選擇改乘一個非SIPS URI,但是需要知會客戶轉發到一個非安全的URI去。任何新的請求都可能導致接收到這些請求的3xx應答,並且在Contact中包含原始的URI。可以通過對兩個位置的配置來形成互相重定向。只要保證在target set中任何URI都只出現1次就能避免無窮的重定向循環。當target set增長了,客戶端可
以對這個URIs,用任意順序來產生新的請求。常見機制是通過在Contact頭域的值中設置”q”參數來指定這個順序。對這些URIs的請求可以是並行產生的也可以是串行產生的。有一個實現是按照q參數值遞減的方法順序處理URIs,並且對相同q參數值的URIs進行並行處理。還有一種就是直接按照順序的方法處理URIs,對於q參數值不同的按照遞減的順序處理,對於q參數值相同的按照隨機順序處理。
如果發送給連接表上的地址失敗了,(在下一段我們有定義),那麼就選擇列表中的下一個地址進行發送,直到列表全部遍歷一遍。如果列表遍歷完了還沒有,那麼請求就失敗了。
通過響應碼(大於399)我們可以知道請求的失敗;對於網絡錯誤來說,客戶transaction會給transaciton user報告transport層的通訊錯誤錯誤。注意有一部分響應碼(8.1.3.5)表示請求可以被重試;這個時候,請求可以重發而不是簡單的當作一個錯誤。如果某個contact地址發送失敗,那麼client應該嘗試下一個contact地址。這個會導致創建一個新的客戶事務來處理這個新的請求。
爲了在處理3xx應答中創建一個基於一個contact地址的請求,UAC必須首先從target set中拷貝除了”method-param”和”header”URI參數之外的整個URI到Request-URI(見參數的定義見19.1.1)。通過使用”header”參數來創建新請求的頭域值,按照19.1.5節的指引,根據重定向的請求來重寫頭域的值。
注意在某些情況下,在contact地址中進行通訊所需要的頭域,可能代替添加到現有的在原始轉發的請求的請求頭域中。作爲通用的規則,如果頭域可以接受用逗號分割的值列表,那麼新的頭域值可以添加到原始轉發的請求的任何值後邊。如果請求頭域不接收多值列表,那麼原始轉發請求中的頭域值可以由contact地址中進行通訊所需要的頭域的值所替換。比如,如果contract地址返回瞭如下的值:
sip:user@host?Subject=foo&Call-Info=Http://www.foo.com
那麼在原始轉發請求中的任何Subject頭域都被重寫,但是HTTP URL僅僅添加到現存的Call-info 頭域值中。
我們推薦UAC重用與原始轉發請求相同的To,From,和Call-ID域值,但是也允許UAC爲新的請求改變Call-ID頭域。
最後,當一個新的請求構造好以後,這個請求將通過一個新的客戶transaction發送,應此在最開始的Via頭域中必須有一個新的branch ID (8.1.1.7節說明)
在其他的方面,轉發的請求應該重用原始請求的頭域和消息體。
在某些情況下,Contact頭域的值可能在UAC中暫時或者永久保存,這個依賴於接收到的請求碼和過期的時間;參見21.3.2和21.3.3節。
8.1.3.5 處理4xx應答
某個4xx應答碼要求特定的UA處理,和請求的方法無關。
當接收到401(未授權)或者407(Proxy認證需要)應答的時候,UAC應該遵循在22.2和22.3中規定的認證步驟,重新發送帶認證信息的請求。
當收到413(請求過大)應答的時候(21.4.11節),這說明請求包含了一個UAS所不能接收長度的消息體。如果可能,UAC應該嘗試重新retry這個請求,或者去掉包體或者換一個小一點的長度。
如果收到了一個415(不支持的媒體類型)應答(21.4.13節),那麼請求中包含的媒體類別是UAS所不支持的。UAC應該重發這個請求,並且這次發出的請求只包含應答中的Accept頭域所指明的媒體類別,並且採用Accept-Encoding頭域中指明的encoding方法,還有Accept-Language指明的語言。
如果收到了一個416(不支持的URI Scheme)應答(21.4.14節),Request-URI使用的URI Scheme(方案)是服務端所不支持的。客戶端應該重新嘗試這個請求,並且換用SIP URI。
如果收到了一個420(非法擴展)應答(21.4.15節),請求的Require或者Proxy-Require頭域包含的option-tag中包含了UAS或者proxy不支持的特性。UAC應該嘗試去掉應答中的Unsupported頭域中列出的擴展以後然後再嘗試。
在上述所有的情況中,所有需要重試的請求,都需要經過適當修正成爲一個新的請求。這個新請求採用一個新的transaction並且應該有和上次請求相同的Call-ID,TO,From頭域,Cseq應該有一個新的順序號碼(比原有順序號碼更大)。
其他的4xx應答,包括尚未制定的,是否允許請求重試,依賴於具體的方法和應用。
8.2 UAS特性
UAS在處理對話外的請求的時候,有一組規則需要遵守,這組規則與方法無關。12節指明瞭一個方法來判定一個請求是否在一個對話裏。
注意,請求的處理是原子級別的。如果請求被處理,那麼這個請求的相關狀態一定是一起更新的。如果它被拒絕了,那麼這個請求的所有相關狀態一定是沒有改變的。
UASs應當遵循本節所規定的順序來處理請求。(就是說,首先是身份認證,然後是方法判定,然後是頭域,然後按照本文規定處理剩餘部分)
8.2.1 方法判定
當請求被認證(或者身份認證被忽略),UAS必須首先判定這個請求的方法。如果UAS發現自己不能處理這個請求的方法的時候,它必須給出一個405(方法不支持)的應答。產生應答的步驟在8.2.6節規定,並且UAS必須在給出的405(方法不支持)應答中增加一個Allow頭域。這個Allow頭域必須列明哪些方法UAS支持。Allow頭域的說明在20.5節。
如果請求中的方法是服務器所支持的,那麼處理將繼續。
8.2.2 包頭判斷
如果UAS不認識請求中的包頭域(就是說,包頭域不在本規範中定義或者不在任何擴展中定義),那麼服務器必須忽略掉這個包頭域並且繼續處理本請求。UAS必須忽略任何處理本請求所不需要的長得畸形的包頭域。
8.2.2.1 TO 和Request-URI
To頭域包含了由From域描述的發送者發出的請求的原始接受者。原始接受者可能是也可能不是正在處理這個請求的UAS,取決於呼叫轉移或者其他的proxy操作。當TO域值和自身不相符的情況下,UAS可以自行決定是否接收這個請求。但是,我們依舊是建議UAS處理這個請求,甚至TO這個頭域是以他們不認識的URI方案表達的(比如一個tel:URI),或者To頭域並非指向這個自身處理的UAS。當然,另外一方面來說,如果UAS決定拒絕這個請求,它應該產生一個403(禁止訪問)的狀態碼,並且交給服務器的transaction層來發送。
但是,Request-URI確定UAS來處理這個請求。如果Request-URI使用了一個UAS所不支持的方案(比如tel:URI),那麼UAS應當拒絕這個請求,並且給出拒絕代碼416(不支持的URI方案)。如果Request-URI並沒有指明本UAS來處理這個請求,那麼UAS應當給出一個404(未找到)的應答。比如,一個UA使用REGISTER方法來綁定它的address-of-record到一個特定的聯繫地址,將會收到Request-URI等於那個特定聯繫地址的請求。
其他潛在的Request-URI資源包括建立和刷新對話的UA發出的請求和應答的Contact頭域。
8.2.2.2 合併的請求
如果請求的To頭域中沒有tag標誌,UAS的處理核心必須檢查基於正在進行的transactions上的請求。如果接收到的請求和正在處理的transaction的請求中的頭域From tag,Call-ID,CSeq精確匹配了,但是請求並不匹配那個事務(基於事務匹配機制17.2.3節),UAS核心應該產生一個482(檢測到循環)應答並且給服務器的transaction層發送。
這是由於相同的請求通過不同的路徑到達UAS,很多情況下是由於分支的原因。UAS處理了第一個請求並且給其他所有這個請求以482(檢測到循環)應答。
8.2.2.3 Require
如果請求的各項要素通過了UAS的判定,那麼如果存在Require頭域,接下來就是檢查Require頭域。Require頭域是UAC用來通知UAS應該用什麼樣的SIP擴展來處理本請求的。Require的格式在20.32節中有介紹。如果UAS不支持請求的Require頭域中的option-tag列表,那就必須產生一個420應答(錯誤的擴展)。並且UAS必須添上Unsupported頭域,裏邊填上剛纔接收到的請求的Require頭域中,哪些options是自己所不支持的。
需要注意的是,Require和Proxy-Require禁止出現在SIP CANCEL請求中,或者回應給非2xx應答的ACK請求中。就算出現了在處理的時候也必須被忽略。並且迴應給2xx應答的ACK請求必須只能包含在初始請求(在這個ACK請求之前的請求)中包含的Require和Proxy-Require所規定options,這樣才能保證服務端能夠正確處理。
例子:
UAC->UAS: INVITE sip:[email protected] SIP/2.0
Require: 100rel
UAS->UAC: SIP/2.0 420 Bad Extension
Unsupported: 100rel
這個特性(Unsupported)是爲了保證客戶-服務端都能夠無阻礙的交互,除非是options對方不支持(就像上邊的例子說明的一樣)。對於相互匹配的客戶-服務端(相互匹配的意思就是客戶端Require的正好是服務端支持的),那麼這些請求、應答將會處理的非常迅速,減少了一個請求的往返協商的浪費。另外,這個也避免了客戶端不知道服務端到底不支持那些特性擴展。
某些特性擴展只對終端(endsystem)有效例如呼叫處理域等等。

8.2.3 內容處理
當UAS支持客戶端請求中要求的擴展支持後,UAS要檢查消息頭域描述的消息體部分。如果UAS並不支持消息體部分的類型(Content-Type指明),語言(Content-Language指明),編碼(Content-Encoding指明),並且這個消息體部分並非可選的消息體(Content-Disposition頭域指明),UAS必須迴應一個415錯誤應答(不支持的媒體類型)應答。並且如果不支持請求中包含的消息體的正文類型,那麼在應答中必須包含UAS所支持的消息體的類型列表(在Accept頭域中指明)。如果不支持請求包含的消息體的encoding方式,那麼應答中必須包含Accept-Encoding頭域列明服務端支持的encoding方式。如果請求中的語言部分不支持,那麼就必須在應答中包含Accept-Language頭域列明支持的語言。在這些檢查之外,消息體正文的處理依賴於方法和類型(method and type)。關於處理內容相關的頭域的進一步的資料在7.4、20.11到20.15節。
8.2.4 應用擴展
如果UAS希望應用一部分SIP擴展,那麼不可以在產生應答的時候做SIP擴展,除非這個擴展是在請求中的Supported頭域中指明瞭的。如果這個擴展並沒有在本請求的Supported頭域中指明,那麼服務端必須基於基準SIP給出應答,或者給出已知客戶端支持的擴展應答。在極少數情況下,如果服務端不用擴展就無法處理請求,那麼服務端應該發送421(需要擴展支持)應答。這個應答說明如果沒有適當的擴展就無法給出正確的應答。在應答中需要的擴展必須在應答中的Require頭域中指出。我們並不推薦這個方法,因爲它會降低協同工作的能力。
除了421應答之外的其他應答中,如果需要應用擴展,那麼這些擴展需要在421的應答中的Require頭域中列明。當然,服務端不允許使用沒有在請求中的Supported頭域中列明的擴展。因此,應答中的Require頭域只會包含標準的RFCs的擴展option tags。
8.2.5 處理請求
當所有的檢查都通過了以後,UAS根據方法決定如何處理請求。第10節講述了REGISTER請求的處理,11節講述了OPTIONS請求的處理,13節講述了INVITE的處理,15節講述了BYE的處理。
8.2.6 產生應答
UAS產生應答,需要遵守接下來的幾個小節中講述的步驟產生一個應答。
在本節沒有描述的應答代碼的其他的行爲,也可能會跟據應答代碼的不同而要求。當創建應答的步驟完成之後,UAS將應答交給收到這個請求的服務端的transaction去處理。
8.2.6.1 發送一個臨時應答
很多情況下,在與方法無關的應答規範中,在非INVITE請求的情況下,我們都要求UAS不應該發送臨時應答給請求者。在這種情況下,UAS應該儘快發送一個終結應答給非INVITE請求。
當需要產生一個100(Trying)應答的時候,所有對應請求中包頭的Timestamp域必須也拷貝到這個應答包頭(就是說如果請求中有Timestamp,應答中也必須有timestamp)。而且如果應答有延時,那麼UAS應該在這個Timestamp上增加延時的值。這個數值必須包含了接收請求和發送應答的時間,用秒來計數。
8.2.6.2 包頭和Tags
應答中的From頭域必須和請求中的From頭域相等。應答中的Call-ID頭域必須和請求中的Call-ID頭域相等。應答中的Cseq頭域必須和請求中的Cseq頭域相等。應答中的Via頭域必須和請求中的Via頭域相等,而且順序也必須相等。如果請求中包含了To tag,那麼應答中的To頭域必須和請求中的To頭域相等。如果請求中的To頭域並不包含Tag,那麼應答中的To頭域的URI必須和請求中的TO頭域的URI相等;此外,UAS還必須增加一個Tag到To頭域上(100(trying)應答是一個例外,在100中可能已經存在了一個tag)。這就提供了一個UAS正在應答的標誌,也許就是對話ID的一部分。對同一個請求來說,它的應答必須有相同的tag標誌,包括終結應答和臨時應答(同樣100(trying)除外)。生成tag的步驟在19.3節。
8.2.7 無狀態UAS行爲
無狀態UAS就是說UAS本身不保持事務的狀態。但是它在發送對應請求的應答之後並不保存請求的狀態。如果無狀態UAS接收到了一個重新發送的請求,它會重新產生一個應答並且重新發送應答,就像它接收到的是一個第一個請求一樣(就像是新請求而不是重發的請求一樣)。只有當相同請求的處理會導致相同的應答的時候,這個UAS纔會是無狀態的。例如:這條規則排除了無狀態的登記服務。無狀態的UAS並不包含一個transaction層;他們直接從通訊層接收請求和發送應答。
無狀態的UAS通常用於處理不需要身份認證的請求,而且這些請求的應答是可以預期的。如果當不需要身份認證的請求被作爲有狀態的UAS來處理,那麼大量的不需要身份認證的請求會造成服務器大量的事務狀態,可能會導致UAS的處理非常慢,甚至中斷處理,這樣就導致了DoS(denial of service)狀態。在26.1.5節中有進一步的描述。
無狀態的UAS有下列重要的特性:
o 無狀態的UAS不許發送臨時應答(1xx)
o 無狀態的UAS必須忽略ACK請求
o 無狀態的UAS必須忽略CANCEL請求
o To頭域必須依據無狀態的規則來產生-就是說對於相同的請求,產生相同的tag標記。19.3節有講tag標記。
對於其他情況而言,無狀態的UAS遵循有狀態的UAS的規則。對於一個新請求來說,同一個UAS可以是有狀態的,也可以是無狀態的。
8.3 重定向服務器
在某些架構下,可以透過重定向機制,來降低proxy服務器上的路由請求的壓力,從而提高消息轉發的效率。重定向允許服務器在一個請求的應答中,推送路由信息到客戶端,這樣就可以做到把自己從後續的消息流中脫離出來,但是同時又能提供準確的請求定位服務。當請求的發起者接收到轉發的應答之後,他會重新產生一個基於接收到的URI(s)的請求。從network的中央轉發到最邊緣,轉發機制可以適用於跨度很大的網絡。
轉發服務器在邏輯上是通過一個服務器的transaction層建立的,他作爲transaction user可以訪問某些類型的位置服務(參見第10節有關注冊服務器和位置服務的說明)。這個位置服務可以很方便的用數據庫裏邊的一個URI對應多個地址URI(可能在這個地址找到對應的客戶)來實現。
一個重定向服務器並不發出任何指向它自己的請求。接收到任何一個非CANCEL的請求之後,服務器要麼拒絕這個請求,要麼從位置服務器上找到這個請求應該去的其他位置然後返回一個3xx的終結應答。對於合法的CANCEL請求,它應該返回一個2xx的應答。這個應答將會結束掉SIP事務。重定向服務器在整個SIP事務中位置事務的狀態。在重定向服務器之間檢測循環死鎖應該是客戶端的責任。
當重定向服務器給請求方返回一個3xx應答的時候,它會在Contact頭域填寫一組(一個或者多個)其他位置信息。如果需要指明這個Contact數據的生存週期,可以在Contact頭域添加一個”expires”參數。Contact頭域包含指向新位置的URI或者可以試試看的用戶名,或者就是簡單的附加通訊參數等等。301(永久去除)或者302(臨時去除)應答同樣可以指定和原始請求一樣的目的位置和用戶名,但是會附加像不同的服務器或者多點傳送地址、或者SIP由UDP到TCP傳輸等等這樣的通訊參數。
重定向服務器必須不能重定向一個請求到它自己的Request-URI列表中的地址;但是倘若那個URI並沒有指向自己,重定向服務器可以路由這個請求到目的URI,或者可以返回一個404拒絕。

如果一個客戶端正在使用外出的proxy,並且這個proxy實際上是重定向請求,那麼就可能出現無限重定向循環。

注意,Contact頭域的值可能指向一個與原始呼叫者無關的資源。比如,一個SIP對PSTN(本地電話網)網關的呼叫可能被轉遞給一個特別的說明,比如”你所呼叫的電話號碼已經改爲….”。Contact應答頭域可以包含任何合適的能處理這個呼叫對方的URI,並不限於SIP URI。比如,它可以是電話,傳真,或者IRC(如果有支持和定義的話)或者一個mailto:(RFC 2368[32]) URL。在26.4.4節講述了對SIPS URI到非SIPS URI的實現和限制。

在Contact頭域中的”expires”參數指明瞭這個URI的生存週期。這個參數的值是以秒作爲單位的。如果這個參數沒有提供,那麼這個”expires”的缺省是有Expires頭域所指定的。這個參數中如果設置了非法的值,那麼都應改更改成爲缺省的3600。這提供了對RFC2543的向後兼容,RFC2543允許在這個頭域中填寫絕對時間。在本協議中,如果這個expires填寫了絕對時間,那麼就會當作是非法的值,就會被當作是3600。

重定向服務器必須忽略自己所不能理解的特性(包括不認識的頭域,不認識的Require中的option tag,甚至是不認識的方法名),並且帶着問題處理這個請求的重定向。

9 取消一個請求(Cancel)
前邊幾節講述了對所有方法的處理請求和處理應答的UA的通用處理過程。在本節中,我們討論一個通用的方法,CANCEL。CANCEL請求,就像名字所說的,是用來取消客戶端發起的上一個請求的。特別是,它請求UAS去終止上一個請求並且對上一個請求產生一個錯誤的應答。CANCEL對UAS已經給出終結應答的請求無效。所以,CANCEL請求的最大用處是取消需要服務器長時間處理的請求。也就是說,CANCEL最常用來處理取消INVITE請求,因爲INVITE通常需要花費很長時間來產生一個終結應答。在這種使用中,UAS接收到對一個INVITE請求的CANCEL請求,當這個INVITE還沒有得到終結應答的時候,UAS會”停止振鈴”,並且給INVITE請求一個錯誤的應答(487)。
CANCEL可以由proxy或者UAC發起。15節講述了在何種情況下,UAC會CANCEL
一個INVITE請求,在16.10節講述了proxy對CANCEL的使用。
一個有狀態的proxy需要對CANCEL進行響應,而不是簡單的轉發從下行流中接收到的一個應答。基於這個原因,CANCEL是一個”點對點”(hop-by-hop)的請求,也就是說,CANCEL需要每一個有狀態的proxy節點進行處理和應答。
9.1 客戶行爲(Client Behavior)
CANCEL請求不應該取消除了INVITE之外的請求。因爲除了INVITE之外的請求的響應都是立即響應的,所以,發送CANCEL來取消一個非INVITE請求總是形成一種賽跑的局面(就是說,cancel先到還是被取消的請求先到)。
下列步驟用於創建一個CANCEL請求。在CANCEL請求中的Request-URI , Call-ID , To , Cseq的數字部分,From這些頭域都必須和被取消的請求頭域一樣,包含這些頭域的tags. 客戶端創建的CANCEL必須只有一個Via頭域值,這個頭域值和被取消的請求的最上一個Via頭域值相同。這些頭域的值和請求的值相同可以讓CANCEL請求和被取消的請求相匹配(9.2節描述瞭如何匹配)。在Cseq請求頭域的method部分必須是一個CANCEL方法。這個讓這個CANCEL請求被當作自己的事務而被正確的鑑別和處理(參見17節)。
如果被取消的請求包含一個Route頭域,CANCEL請求也必須包含這個Route頭域的值。這個是讓無狀態的proxy能夠正確路由CANCEL請求。
CANCEL頭域必須不能包含任何Require或者Proxy-Require頭域。
一旦CANCEL請求被創建了,客戶端應當檢查是否收到了這個CANCEL請求取消的原始請求的任何應答(臨時的或者終結的應答)。如果沒有任何臨時應答收到,這個CANCEL請求一定不能發送,直到客戶端等到了第一個臨時應答。如果原始請求已經收到一個終結應答,這個CANCEL也不應當發送,因爲CANCEL請求對已經產生了終結應答的請求沒有任何作用。當客戶端決定發送一個CANCEL,它會爲這個CANCEL創建一個客戶transaction,並且通過目的地址、端口、傳輸層來發送CANCEL請求。這個CANCEL中的目標地址、端口和傳輸層必須和原始請求一樣。
如果允許在接收應答之前發送CANCEL請求,那麼服務端必須支持在接收原始請求之前接收到CANCEL請求。
注意,原始請求的事務和CANCEL請求的事務都是互相獨立的。也就是說,UAC判定一個請求的取消不能依賴原始請求的一個487(請求終止)應答,遵循RFC2543協議,UAS不會產生這樣一個應答。如果原始請求經過了64*T1(T1在17.1.1.1節定義)秒還沒有應答,客戶端應當認爲原始請求已經取消,並且應當銷燬對應原始請求的客戶端事務。
9.2 服務端行爲(Server Behavior)
CANCEL請求要求服務端的TU取消相關的事務(transaction)。TU根據接收到的CANCEL請求,並且假定請求的方法不是CANCEL或者ACK,並且用17.2.3節描述的事務匹配方法來匹配事務,這樣TU就可以決定那個事務需要被取消了,被匹配的事務就是需要被取消的事務。
服務端對CANCEL請求的處理依賴於服務器的類型。一個無狀態的proxy會轉發這個請求,一個有狀態的proxy可能會響應這個請求,並且自己再產生一些CANCEL請求,UAS會響應這個CANCEL請求。16.10節講述了proxy怎樣處理CANCEL請求。
當UAS收到CANCEL請求,首先按照8.2節的UAS通用處理方法進行處理。不過,既然CANCEL請求是基於”點對點”(hop-by-hop)的,也是不能再提交的,他們不能由服務器爲了獲得Authorization頭域中正確的認證而反覆嘗試。注意,因此CANCEL請求也不能包含Require頭域。
如果根據上邊的步驟,UAS不能找到與CANCEL請求相匹配的事務,它應該給CANCEL一個481應答(調用的Leg/Transaction不存在 會話/事務不存在)。如果對應原始請求的事務存在,那麼UAS在接收到CANCEL請求的處理就依賴於是否已經給這個原始請求發出了終結應答。如果已經發出了,不會對CANCEL請求對應的原始請求做任何處理,不會更改任何會話狀態,不會對原始請求的應答做任何處理。如果UAS沒有發出對原始請求的終結應答,它會依賴於CANCEL所取消的原始請求方法。如果原始請求方法是INVITE,UAS應當立刻響應INVITE一個487(請求終止)。本協議中,對CANCEL取消的其他本協議中定義的方法沒有約定。
不管原先請求的方法是什麼,只要CANCEL匹配一個事務,UAS就響應CANCEL請求一個200(OK)應答。這個應答根據8.2.6節約定構造。注意,給CANCEL應答的To tag和給原始請求的應答的To tag應該是一樣的。對CANCEL的應答會通過服務端transaction來傳送。
10 註冊(Registrations)
10.1 概覽
SIP提供了一個搜索機制,如果一個用戶希望建立和其他用戶的會話,SIP必須查找能夠找到對方用戶正在使用的當前主機(hosts)。這個搜索機制經常被SIP網絡基本元素使用,比如proxy服務器,重定向服務器等等。他們在接收、以及響應一個請求的時候,會基於這個用戶的位置信息來判定這個消息應該發送到哪裏。要實現這個,SIP網絡部件考慮了一個抽象的服務:位置服務;位置服務是通過對特定地區提供地址綁定來實現的。這些地址綁定轉換輸入的SIP或者SIPS URI,比如sip:[email protected],轉換到一個或者一組更加”接近”目標用戶的URI,比如sip:[email protected]。基本上,一個proxy會從把輸入的URI轉換到用戶實際位置的位置服務中得到最終用戶的位置。
註冊服務爲特定地區的位置服務創建綁定關係,這個綁定關係是用來建立包含一個或者多個聯繫地址的address-of-record URI。因而,當那個地區的proxy接收到一個請求,這個請求的Request-URI和address-of-record的記錄匹配,那麼這個proxy會轉發請求到這個address-of-record中登記的聯繫地址中去。通常,只有當對那個address-of-record的請求會被路由到這個區域的時候,登記這個address-of-record 到這個這個區域的位置服務纔是有意義的。在大多數情況下,這個就要求登記服務所覆蓋的區域和URI中的address-of-record所覆蓋的區域相同。有很多種方法來建立位置服務。一個方法是administratively(管理)。在上述的例子種,Bob我們通過查詢公司數據庫知道他是一個工程部職員。不過,SIP提供了一個讓UA能夠創建精確綁定的機制。這個機制就是登記服務。
登記服務需要向一個特殊的UAS服務器(註冊服務器registrar)發出REGISTER請求。註冊服務器(registrar)爲一個區域的位置服務作爲前端接入,根據REGISTER請求的內容讀寫位置對照表。這個位置服務通常爲處理這個區域的proxy服務器提供位置服務。
總的登記服務處理流程在圖2中說明。需要注意的是,登記服務器(registrar)和proxy服務器都是邏輯上的角色,可以在網絡中用一個設備來部屬;在例子圖中是爲了能夠清楚的表示所以分開描述。還需要注意的是如果他們(登記服務器和proxy)本身是分開的,那麼UA可以通過proxy服務器發送註冊請求。
SIP本身對實現位置服務器(location service)沒有特別的要求。唯一的要求是某些區域的註冊服務器(registrar)必須能夠對位置服務的數據進行讀寫,並且這個區域的proxy或者重定向服務器必須能夠兼容讀取相同的數據。註冊服務器(registrar)可能和某一個區域的proxy服務器部署在一起。
10.2 構造一個REGISTER請求
REGISTER請求用來增加、刪除、查詢綁定資料。一個REGISTER請求可以增加一個address-of-record和一個或者多個聯繫地址之間的綁定。在合適的第三方認證的情況下,可以做address-of-record的登記。客戶端同樣可以刪除前邊綁定的內容也可以查詢address-of-record的當前綁定地址。除了特別說明以外,REGISTER請求的構造以及客戶端如何發送REGISTER請求和通常的8.1節描述的和17.1節描述的UAC發出請求是一致的。
一個REGISTER請求並不建立一個對話。當基於事先給定路由集(8.1節)的情況下,一個UAC可以在REGISTER請求中包含一個Route頭域。在REGISTER請求和應答包中,Record-Route頭域並沒有任何意義,如果這個頭域存在,必須被忽略。另外,UAC一定不能基於REGISTER請求的應答包中的任何Record-Route頭域來創建新的路由集合。
下面這些頭域,除了Contact,必須在REGISTER頭域中包含。Contact頭域可選。
Request-URI:    這個頭域指明瞭登記服務所指明的位置服務所在的區域(比如sip:chicago.com)。”userinfo”和”@”元素在SIP URI中不能出現。
To:            這個頭域包含了被查詢、增加、修改的address-of-record。to頭域和Request-URI頭域通常是不同的,因爲這個由用戶名組成。這個address-of-record必須是一個SIP URI或者SIPS URI.
From:            這個頭域包含了提交這個註冊信息的用戶的address-of-record資料。這個值和To頭域的值相同,除非這個請求是第三方發起的註冊請求。
Call-ID:            UAC發出的給某個註冊服務器(registrar)的所有註冊請求都應該有相同的Call-ID頭域值。如果相同的客戶端用了不同的Call-ID值,註冊服務器(registrar)就不能檢測是否一個REGISTER請求由於延時的關係導致了故障。
Cseq:            Cseq值保證了REGISTER請求的正確順序。一個UA爲每一個具備相同的Call-ID的REGISTER請求順序遞增這個Cseq字段。
Contact:            REGISTER請求可以有一個Contact頭域。這個頭域可以有0個或者多個包含綁定地址信息的值。
UA在沒有收到上一個註冊請求的應答或者上一個REGISTER請求超時之前,禁止發送新的註冊請求(就是說,包含一個新的Contact頭域值,而不是重發)。


bob
+----+
| UA    |
|      |
+----+
|
|3)INVITE
|    [email protected]
chicago.com            +--------+            V
+---------+ 2)Store    |Location|4)Query +-----+
|Registrar|=======>    | Service|<======= |Proxy|sip.chicago.com
+---------+            +--------+=======> +-----+
A                                5)Resp        |
|                                            |
|                                            |
1)REGISTER|                                        |
|                                            |
+----+                                            |
| UA |       <-------------------------------+
cube2214a| |                                    6)INVITE
+----+                                [email protected]
carol
               圖2:REGISTER例子
下邊的Contact頭域參數在REGISTER請求中有特別的意義:
action: 在RFC2543中的“action”參數已經廢棄了,UAC不能使用”action”參數。
expires: “expires”參數表明UA的綁定的有效時間。以秒爲單位的整數。如果本參數沒有制定,那麼這個參數的值就是Expires頭域的值。實現中,可以把超過2**32-1的值(4294967295秒或者136年)認爲是2**32-1。非法的值應當視同3600。

10.2.1 增加綁定
REGISTER請求是向註冊服務器(registrar)發送一個包含對某一個address-of-record的地址的SIP請求應當發送的實際聯繫地址。address-of-record包含在REGISTER請求的To頭域中。
請求中的Contact頭域通常包含了SIP或者SIPS的URI,這些URI表明了特定的SIP端點(比如sip:[email protected]),他們也可以使用其他的URI表示方法。一個SIP UA可以選擇註冊一個電話號碼(比如使用tel URL, RFC 2806[9])或者一個email地址(比如用mailto URL, RFC2368[32])來作爲address-of-record的聯繫地址Contact域。
例如,Carol,有一個address-of-record”sip:[email protected]”,將會在區域chicago.com的註冊服務器上註冊。她的註冊服務信息將會被chicago.com區域的proxy服務器使用,用來路由和轉發到Carol的address-of-record請求到她的SIP終端。
當客戶端在註冊服務器(registrar)上建立好了綁定以後,它可以根據需要發送後續的註冊請求,包含新的綁定信息或者修改以前的綁定信息。給REGISTER請求的2xx應答中,在Contact頭域中是在這個註冊服務器(registrar)上登記的完整的這個address-of-record的綁定列表。
如果REGISTER請求中的To頭域中的address-of-record是一個SIPS URI,那麼任何在REGISTER請求中的Contact頭域都應當是SIPS URI。客戶端只有在有其他手段保證非SIPS URI的安全性的情況下,才能在SIPS 的address-of-record的地址上註冊非SIPS URI。這個也可以適用域使用非SIP協議的URI,或者用非TLS來加密的SIP設備。
註冊並不需要更新所有的綁定。一般情況下,UA只更新它現在的聯繫地址。
10.2.1.1 設置Contact地址的過期參數
當一個客戶端發出一個REGISTER請求,它可能包含一個過期參數用來表示這個註冊的地址的有效期。(就像在10.3節講述的那樣,註冊服務器(registrar)根據自己的策略選取實際的時間間隔來計算有效期)。
客戶端設置有效期的方法有兩種:一個是通過設置Expires頭域,一個是通過設置”expires”contact頭域的參數來設置。 後一種允許針對同一個REGISTER請求中的多個綁定聯繫地址中的每一個聯繫地址單獨設定有效期,然後所有沒有帶”expires”參數的Contact頭域的值都使用Expires的設置。
如果REGISTER中沒有兩種有效期都沒有設置,這就表明這個有效期由服務器來決定。
10.2.1.2 Contact Adress的參數選擇
如果在一個REGISTER請求中包含多個Contact,着說明UA想要把這些Contact頭域的內容都和To頭域中制定的address-of-record地址綁定起來。這個列表可以用”q”參數來區分Contact頭域的優先級。”q”參數用來標誌特定Contact頭域值和其他綁定的address-of-record的聯繫地址之間的優先級。16.6節講述了一個proxy服務器如何使用優先級。
10.2.2 刪除綁定
註冊信息是一個純粹軟件的狀態,並且如果不刷新會過期。如果需要,也可以被刪除。一個客戶端可以設置註冊服務器(registar)的有效期(10.2.1)。一個UA可以通過發出有效期爲”0”的REGISTER請求,使某一個聯繫地址立刻失效。UAS都需要實現這個機制使得在聯繫地址過期前能夠被刪除。
REGISTER規範中的Contact頭域如果設置成爲”*”則表示需要操作所有的註冊項。但是也只能在具有一個Expires頭域並且這個頭域爲’0’的情況下能夠使用。(這就是說,只能夠在要刪除所有的註冊項的時候使用”*”)。
用”*”來刪除所有的註冊項有一個好處,就是使得UA不需要知道每一個註冊項的精確值。
10.2.3 訪問綁定
無論請求是否包含了Contact頭域,給任何REGISTER請求的成功應答都包含了一個完整的綁定列表。如果REGISTER請求頭域中不包含Contact頭域,那麼註冊服務器的綁定列表將不會改變。
10.2.4 刷新綁定
每一個UA都對先前它建立的綁定信息由刷新的義務。禁止對其他UA建立的綁定信息進行刷新。在註冊服務器(registrar)給出的200(OK)應答中,包含了的Contact頭域中列明瞭所有的當前綁定信息。UA需要挨個比較這些聯繫地址,看看是否這個地址是可以建立聯繫的,這個比較是通過19.1.4節中的比較規則來進行的。如果是,它通過更新expires參數來更新過期時間(或者Expires頭域)。於是在這些綁定信息過期前,UA爲每個綁定發出REGISTER請求來刷新綁定。也可以通過一個REGISTER請求來刷新數個綁定請求。
UA在一個刷新週期中,應該使用相同的Call-ID來進行註冊調用。刷新的註冊信息應該是和原來登記的信息一致。
10.2.5 設置內部時鐘
如果REGISTER請求的應答中包含一個Date頭域,客戶端可以用這個頭域來校正當前內部的時鐘。
10.2.6 尋找註冊服務器
UA有3種方法來決定向哪裏發出註冊請求:通過配置,使用address-of-record,廣播方式。一個UA可以用非本文檔規定的方式,配置一個註冊服務器的地址。如果UA沒有配置任何註冊服務器的地址,UA應該用請求的Request-URI部分種的address-of-record的服務器部分(host part),用普通的SIP服務器定位機制[4]。比如,用戶”sip:[email protected]”地址的註冊服務應該是”sip:chicago.com”。
最後,UA可以通過監聽廣播的形式來獲得註冊服務器地址。監聽廣播的註冊服務器是通過監聽著名的”全部SIP 服務器”廣播地址”sip.mcast.net”(224.0.1.74)。沒有Ipv6的廣播地址。SIP 的UA可以監聽這個地址,並且用這個來知道其他本地用戶的地址(見附件[33]);不過他們並不對請求做響應。通過監聽廣播的登記服務可能在某些環境下不能用,比如,基於同一個本地網絡的多個商業應用的情況。
10.2.7 傳送一個請求
當REGISTER請求被構造好以後,並且也有了登記服務起地址,UAC遵循8.1.2節的說明來提交transaction層來發送REGISTER請求。如果transaction層返回一個由於REGISTER請求沒有應答的超時錯誤,UAC不應該立刻重新嘗試對同一個註冊服務器的註冊請求。
立刻重新嘗試很有可能導致再次超時。等待一個合理的時間在嘗試可以降低網絡的負載,在這裏並沒有一個約定的等待時間間隔。
10.2.8 錯誤響應
如果UA接收到一個423(間隔太簡略)應答,它可能需要更改REGISTER請求中的所有有效期,使得這些有效期必須大於等於423應答頭中的Min-Expires頭域中的有效期,並且重新嘗試發送這個REGISTER請求。
10.3 處理REGISTER請求
一個註冊服務器(registrar)就是一個UAS,這個UAS用來響應REGISTER的請求,並且維持一個綁定表,這個綁定表用來提供給它所管理的區域中的proxy服務器和重定向服務器的。一個註冊服務器根據8.2和17.2中的規定來處理請求,但是它僅僅處理REGISTER請求。一個註冊服務器禁止產生6xx應答。一個註冊服務器可以適當的轉發REGISTER請求。通常用於一個註冊服務器(registar)監聽一個多點廣播,並且通過302應答(臨時轉移)轉發這個多點廣播的REGISTER請求到它正確的處理位置。
註冊服務器必須忽略在REGISTER請求中的Record-Route頭域,並且也不能在REGISTER請求的應答中包含任何Record-Route頭域。註冊服務器可能收到一個有proxy轉發過來的REGISTER請求,這個請求中由於proxy處理這個請求當作未知請求所以添加了Record-Route頭域。
一個註冊服務器必須知道(例如,通過配置)它所管理的區域。註冊服務器一定需要按照接收到的REGISTER請求順序進行處理。
REGISTER請求必須當作原子請求來處理,意味着給定的REGISTER請求要麼就完整處理,要麼就完全拒絕。每一個REGISTER信息的處理都和其他的註冊和綁定信息的處理無關。
當接收到一個REGISTER請求,註冊服務器(registrar)按照如下步驟處理:
1、    註冊服務器(registrar)檢查Request-URI來決定是否它屬於本註冊服務器所管理的區域的Request-URI。如果不是,並且如果這個服務器同時也作爲一個proxy服務器,那麼這個服務器應當轉發這個請求到指定的區域。這個轉發是根據16節所規定的proxy通用信息處理規則來進行的。
2、    爲了保證註冊服務器能夠支持所需要的擴展,註冊服務器必須遵循8.2.2節描述的情況來處理Require頭域。
3、    一個註冊服務器應當對UAC進行身份認證。SIP UA的身份認證機制在22節描述。註冊這個動作需要遵循SIP的通用的身份認證框架。如果沒有任何認證機制,註冊服務器可以使用From地址來作爲原始請求的信任依據。
4、    註冊服務器應當檢查認證的用戶是否通過認證來更改這個address-of-record的登記權限。比如,一個登記服務起(registrar)可以通過訪問一個認證數據庫,這個認證數據庫映射了用戶名和一個address-of-record列表,這些列表是用戶可以更改綁定信息的列表。如果認證用戶並沒有權利修改綁定信息,註冊服務器應當返回一個403(禁止訪問)並且跳過後續步驟。在支持第三方認證和註冊的架構下,一個實體可以被授權來更新多個address-of-record的註冊信息。
5、    註冊服務器(registrar)從REGISTER請求的To頭域中解出address-of-record。如果這個address-of-record並非在這個Request-URI指明的區域中合法,那麼註冊服務器必須發出一個404(沒有找到)的應答,並且跳過後續步驟。接着URI必須轉換成爲標準的格式。所有的URI參數都必須刪去(包括用戶參數user-param),並且任何非法(escaped)字符必須轉換成爲合法字符(unescaped)格式。最後形成一個可以用於綁定的列表。
6、    註冊服務器(registrar)檢查是否請求包含了一個Contact頭域。如果沒有包含,它跳過到最後一步。如果Contact頭域包含了,註冊服務器檢查是否有一個Contact頭域值是”*”,並且包含了一個Expires頭域。如果請求有其他的Contact頭域或者任何有效期的值是非0的,這個請求就是非法請求,並且服務器必須送回一個400(非法請求)的應答,跳過後續步驟。如果沒有,那麼註冊服務器檢查是否Call-ID複覈每一個綁定的值。如果不符合,它必須刪除綁定。如果複覈,它必須僅僅刪除保存的綁定表中CSeq值小於請求中的Cseq值的記錄。否則,更新必須終止,請求失敗。
7、    現在註冊服務器(registrar)可以依次處理Contact頭域中的聯繫地址了。對於每一個地址,它根據下邊的規則進行有效期檢查。
- 如果含有”expires”參數,這個參數值就是最終的有效期。
- 如果沒有這個參數,並且請求有一個Expires頭域,那麼這個值就是有效期。
- 如果沒有Expire頭域也沒有參數,那麼本地的缺省配置應當作爲有效期。
註冊服務器可以選擇一個小於請求中的有效期值作爲最後的有效期。當且僅當請求的有效期大於0 並且小於1個小時並且小於一個註冊服務器配置的最小有效期的時候,註冊服務器可以響應一個423(有效期過小)的錯誤來拒絕。這個應答必須包括了一個Min-Expires頭域來表明本註冊服務器所接收的最小有效期,然後跳過所有後續步驟。
允許註冊服務器設置註冊服務器自己的有效期防止了過分頻繁的刷新註冊信息,並且也降低了維持和管理註冊信息的工作量。在服務的創建的時候,註冊信息中的有效期會經常用到。一個例子是follow-me(跟隨我)服務,在這個服務中,一個用戶可能在一個終端上只停留一小會兒。因此,註冊服務器應當接收簡略的註冊;一個請求只有當它的有效期過短的時候(短到可能降低註冊服務器性能的時候)才應當被拒絕。
對於每一個地址,註冊服務器在當前綁定列表中用URI比較規則進行搜索。如果綁定不存在,它會暫時性的添加進去。如果綁定存在,註冊服務器檢查Call-ID值。如果Call-ID值在這個已經存在的綁定中和本次請求的Call-ID值不一樣,那麼如果綁定的有效期爲0就刪除這個綁定,否則就刷新這個綁定。如果Call-ID值一樣,那麼註冊服務器比較Cseq值,如果請求中的這個值比現存的綁定值中的Cseq高,那麼必須更新或者刪除這個綁定(如果有效期爲0 就刪除,否則就刷新)。如果這個Cseq值比現存的Cseq值小,那麼必須終止更新並且請求失敗。
這個規則確保了從同一個UA過來的請求順序處理,對於非順序的請求跳過處理。
每一個綁定記錄都包含了當時請求的Call-ID和Cseq的值。
只有當且僅當所有的綁定更新和綁定添加都完成的時候,綁定纔可以做COMMIT處理(就是說,這次修改對proxy和重定向服務器可見)。如果任何更新或者添加失敗了(比如,由於後臺的數據庫commit失敗),必須給出一個500(服務器錯誤)的應答,並且中間進行的臨時更新都必須刪除。
8、    註冊服務器(registrar)返回一個200(OK)應答。這個應答必須包含Contact頭域,並且這個頭域的值中列舉了所有當前綁定的註冊信息。每一個Contact值都必須包含一個”expires”參數,用來標誌還有多久這個綁定信息就過期了。應答也必須包含一個Date頭域。

11 查詢能力
SIP方法OPTIONS允許一個UA來查詢另外一個UA或者proxy服務器的能力。這個提供個客戶端一個手段來查詢服務端支持的方法,內容類型,擴展,codecs等等。這些都不用”ringing”對方。比如,在客戶端試圖在INVITE請求頭中增加一個請求字段選項的時候,它並不知道對方UAS能否支持這個選項,它就可以用OPTIONS來查詢一下UAS,通過檢查OPTIONS返回的Supported頭域,就可以知道是否支持這個選項。所有的UA都必須支持OPTIONS方法。
OPTIONS請求的目標是用Request-URI指明的,這個既可以是一個UA也可以是一個SIP服務器。如果OPTIONS指向一個proxy服務器,Request-URI設置成爲一個沒有用戶部分(user part)的,類似REGISTER請求中的Request-URI一樣。或者,一臺服務器收到一個OPTIONS請求並且Max-Forwards頭域值是0的時候,它就需要響應這個請求而不需要關心Request-URI的內容。
這個機制就像HTTP/1.1一樣。這個機制可以用來實現類似”traceroute”功能來通過發出一系列的有着增量Max-Forwards頭域的OPTIONS請求來檢查每一個途徑節點的能力。
就像對一般UA機制來說,如果OPTIONS沒有應答,transaction層能夠返回一個超時錯誤。這個可能標誌着對方無法到達因此無響應。OPTIONS請求可以作爲建立會話的一部分,用來查詢對方的能力使用,這樣在後續對話中可以使用雙方兼容的方式。
11.1 構造OPTIONS請求
一個OPTIONS請求可以根據8.1.1節中的標準構造方法來進行構造。
Contact頭域在OPTIONS請求中可以存在,也可以不存在。
Accept頭域應當包含在請求中,用來標誌UAC希望接收應答中的消息體的類型。通常情況下,這個設置成爲UA的多媒體兼容能力,比如SDP(應用/SDP)格式。
對於一個OPTIONS請求的應答是假定是在原請求中的Request-URI範圍內的。但是,僅當一個OPTIONS請求作爲建立對話的一部分而發送的時候,後續的請求應當由收到並且響應這個OPTIONS請求的服務器進行處理。(就是說如果在建立會話的時候使用OPTIONS請求,那麼OPTIONS之後的這些請求都應該由這個OPTIONS查詢的服務器處理,這樣才能保證使用的特性和OPTIONS查詢出來的能力是一樣的)

OPTIONS請求的例子:
OPTIONS sip: [email protected]
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9Hg4bKhjhs8ass877
Max-Forwards: 70
To: <sip:[email protected]>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章