1、SIP協議介紹css
Internet的許多應用都須要創建和管理一個會話,會話在這裏的含義是在參與者之間的數據的交換。因爲考慮到參與者的實際狀況,這些應用的實現每每是很複雜的:參與者多是在代理間移動,他們可能能夠有多個名字,他們中間的通信多是基於不一樣的媒介(好比文本,多媒體,視頻,音頻等)-有時候是多種媒介一塊兒交互。人們創造了無數種通信協議應用於實時的多媒體會話數據好比聲音,影像,或者文本。本SIP(會話初始協議)和這些協議同樣,一樣容許使用Internet端點(用戶代理)來尋找參與者而且容許創建一個可共享的會話描述。爲了可以定位精確的會話參與者,而且也爲了其餘的目的,SIP容許建立基礎的network hosts(叫作代理服務器),而且容許終端用戶註冊上去,發出會話邀請,或者發出其餘請求。SIP是一個輕形的,多用途的工具,能夠用來建立,修改和終止會話,它獨立運做於通信協議之下,而且不依賴創建的會話類型。html
2、SIP協議功能概況前端
SIP是一個應用層的控制協議,能夠用來創建、修改、和終止多媒體會話(或者會議)例如Internet 電話。SIP也能夠邀請參與者參加已經存在的會話,好比多方會議。媒體能夠在一個已經存在的會話中方便的增長(或者刪除)。SIP顯示的支持名字映射和重定向服務,這個用於支持我的移動業務-用戶能夠使用一個惟一的外部標誌而不用關係他們的實際網絡地點。SIP在創建和維持終止多媒體會話協議上,支持5個方面:web
1. 用戶定位: 檢查終端用戶的位置,用於通信。算法
2. 用戶有效性:檢查用戶參與會話的意願程度。數據庫
3. 用戶能力:檢查媒體和媒體的參數。api
4. 創建會話:」ringing」,創建會話參數在呼叫方和被叫方。數組
5. 會話管理:包括髮送和終止會話,修改會話參數,激活服務等等。瀏覽器
SIP不是一個垂直集成的通信系統。SIP可能叫作是一個部件更合適,它能夠用做其餘IETF協議的一個部分,用來構造完整的多媒體架構。好比,這些架構將會包含實時數據傳輸協議(RTP)(RFC 1889)用來傳輸實時的數據而且提供QoS反饋,實時流協議(RSTP)(RFC 2326)用於控制流媒體的的傳輸,媒體網關控制協議(MEGACO)(RFC 3015)用來控制到公共電話交換網(PSTN)的網關,還有會話描述協議(SDP)(RFC 2327)用於描述多媒體會話。所以,SIP應該和其餘的協議一塊兒工做,才能提供完整的對終端用戶的服務。雖然基本的SIP協議的功能組件並不依賴於這些協議。安全
SIP自己並不提供服務。可是,SIP提供了一個基礎,能夠用來實現不一樣的服務。好比,SIP能夠定位用戶和傳輸一個封裝好的對象到對方的當前位置。而且若是咱們利用這點來經過SDP傳輸會話的描述,馬上,對方的用戶代理能夠獲得這個會話的參數。若是咱們用這個像傳輸會話描述(SESSION DESCRIPTION SD)同樣呼叫方的照片,一個」呼叫ID」服務很容易就創建了。這個簡單的例子說明了,SIP做爲一個基礎,能夠在其上提供不少不一樣的服務。
SIP並不提供會議控制服務(好比議席控制或者投票系統),而且並無建議會議應該則那樣管理。能夠經過在SIP上創建其餘的會議控制協議來發起一個會議。因爲SIP能夠管理參與會議的各方的會話,因此會議能夠跨異構的網絡,SIP 並不能,也不打算提供任何形式的網絡資源預留管理。
安全對於提供的服務來講特別重要。要達到理想的安全程度,SIP提供了一套安全服務,包括防止拒絕服務,認證服務(用戶到用戶,代理到用戶),完整性保證,加密和隱私服務。
SIP能夠基於IPV4也能夠基於IPV6
3、術語
在這個文檔中,關鍵詞」必須」,」不容許」,」要求」,」能夠」,」不能夠」,」應該」,」不該該」,」建議」,」不建議」,」可能」,」可選」 是根據BCP14,RFC 2119[2]的規範描述SIP實現須要的不一樣層次
4、實施概覽
這節經過簡單的示例介紹了SIP的基本實現。本節是經過天然的而非正則的示例來介紹的。
第一個例子說明了SIP的基本功能:定位一個斷點,發出通信請求,經過協商會話參數創建會話,拆卸剛纔創建的會話。
圖一表示一個典型的Alice和Bob兩個用戶間的SIP消息交易交換例子.(每個消息採用字母」F」和一個用來指向正文的一個數字作標記)在這個例子裏,Alice在她的PC上使用一個SIP的應用程序(好比說一個軟的電話),呼叫Bob在Internet上的一個SIP電話。這個例子也掩飾了兩個SIP代理之間,怎樣爲Alice和Bob創建會話鏈接。This typical arrangement is often referred to as the "SIP trapezoid" as shown by the geometric shape of the dotted lines in Figure 1.
Alice 經過Bob的SIP標誌 「呼叫」 Bob,這個SIP標誌是統一分配的資源(Uniform Resource Identifier URI)稱做SIP URI。SIP URI在19.1節中定義。它很像一個email地址,典型的SIP URI包括一個用戶名和一個主機名。在這個範例中,SIP URI是sip:bob@biloxi.com,biloxi.com是Bob的SIP服務提供商。Alice有一個SIP URI: sip:alice@atlanta.com。 Alice能夠輸入Bob的URI,也能夠直接在地址本的一個超級連接上點擊一下Bob的URI。SIP也提供保密URI,稱做SIPS URI。例如:sips: bob@biloxi.com。 一個基於SIPS URI的通話保證這個通話是安全的,而且對呼叫者和被叫的全部的SIP消息是加密傳輸的(叫作TLS)。在TLS中,請求是經過加密方式傳輸給被叫方,可是這個加密機制是基於被叫方宿主服務器的實現的。
SIP是基於一個相似HTTP協議的請求應答的通信模式。每個通信都包含對某個功能的請求,而且起碼須要一個應答。在這個應答中,Alice的軟電話發送一個含有Bbo的SIP URI抵制的INVITE通信請求。INVITE是一個SIP請求的例子,表示請求方(Alice)但願服務方(Bob)應答。INVTE請求包含一系列的包頭域(Header fields)。包頭中包含不少屬性而且包含了傳輸消息的附加信息。在INVITE中有以下的字段:呼叫的惟一標誌,目的抵制,Alice的地址,Alice和Bob創建會話的類型。INVITE請求(圖1中的F1)可能看起來像這樣的:
INVITE sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds
Max-Forwards: 70
To: Bob <sip:bob@biloxi.com>
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Contact: <sip:alice@pc33.atlanta.com>
Content-Type: application/sdp
Content-Length: 142
(Alice’s SDP not shown)
atlanta.com . . . biloxi.com
. proxy proxy .
. .
Alice’s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . Bob’s
softphone SIP Phone
| | | |
| INVITE F1 | | |
|---------------> | INVITE F2 | |
| 100 Trying F3 |---------------> | INVITE F4 |
|<--------------- | 100 Trying F5 |---------------> |
| |<-------------- | 180 Ringing F6 |
| | 180 Ringing F7 |<--------------- |
| 180 Ringing F8 |<--------------- | 200 OK F9 |
|<--------------- | 200 OK F10 |<--------------- |
| 200 OK F11 |<--------------- | |
|<--------------- | | |
| ACK F12 |
| -------------------------------------------------> |
| Media Session |
|<================================================> |
| BYE F13 |
| <------------------------------------------------- |
| 200 OK F14 |
| -------------------------------------------------> |
| |
圖一:SIP矩形表達的SIP會話創建例子。
在文本消息的第一行,包含了請求的類型(INVITE)。在這行以後的是這個請求的頭域。這個例子中包含了最少須要的頭域集合。簡單介紹一下:
VIA域包含了Alice接收發送請求的服務器地址(pc33.atlanta.com)。一樣這個包含了一個分支參數來標誌Alice和這個服務器的會話事務。
TO域包含了顯示姓名(Bob)和一個SIP或者SIPS URI(sip:bob@biloxi.com)請求將首先傳輸到這個URI中。顯示姓名(Display names)在RFC 2822中描述。
From域也一樣包含一個顯示姓名(Alice)和一個SIP或者SIPS URI(sip:alice@atlanta.com)這個URI用來標誌請求的原始發起者。
這個域也包含了一個TAG參數,這個TAG參數是一個隨機字串(1928301774),是軟電話(softphone)在URI上增長的一個隨機串。用來作標誌用途的。
Call_ID包含一個全局的惟一標誌,用來惟一標誌這個呼叫,經過隨機字串和softphone的本身名字或者IP抵制混和產生的。經過TO TAG, FROM TAG和CALL-ID完整定義了Alice和Bob之間的端到端的SIP關係,而且表示這個是一個對話性質的關係。
CSEQ或者Command Sequence包含了一個整數和一個請求名字。這個Cseq數字是順序遞增的。每當對話中發起一個新的請求都會引發這個數字的順序遞增。
Contact域包含一個SIP或者SIPS URI用來表示訪問Alice的直接方式,一般由用戶名和一個主機的全名(Fully Qualified Domain Name FQDN)組成。當FQDN做爲首選的時候,許多終端用戶因爲不會由名字登記(而致使不能訪問Alice的主機),因此IP地址是可選的。
VIA域告訴你們本請求發送到哪裏而且應答到哪裏,Contract域告訴你們未來的請求將發送到哪裏(奇怪…不是Alice發起的麼,未來的請求應該是Bob纔對啊)。
Max-Forwards:最大轉發數量限制了通信中轉發的數量。它是由一個整數組成,每轉發一次,整數減一。
Content-type包含了消息正文的描述(消息正文在本範例中沒有列出)
Content-length:包含消息正文的長度(字節數)
完整的SIP包頭域的定義在20節。會話的細節,好比媒體的類型,codec,或者採樣速率,沒有經過SIP來描述。這個能夠經過SIP的消息正文來描述,能夠經過其餘定義的協議在正文中進行描述。有一種是會話描述協議(Session Descripotion Protocol SDP)(RFC2327[1])。這個SDP消息(沒有在例子中列出)經過SIP的消息中傳送,就像經過附件發送EMAIL同樣,或者說經過HTTP傳輸的網頁同樣。
因爲softphone並不知道bob或者bob的sip服務器biloxi.com在哪裏,因此softphone發送INVITE請求到Alice的sip服務器,atlanta.com。這個atlanta.com SIP服務器應該已經在Alice的softphone中配置了,或者能夠經過DHCP得到。atlanta.com SIP服務器是一臺代理服務器。代理服務器接收SIP請求而且根據請求轉發。在這個例子中,代理服務器接收到INVITE請求,而且回送一個100(Trying)應答給Alice的softphone。100(Trying)應答表示INVITE請求已經收到,而且代理服務器正在轉發INVITE請求。SIP的應答是經過一個三位數的數字表示的。SIP應答一樣包含TO、FROM、Call-ID,CSEQ和在VIA中的分支參數,這個參數使得Alice的softphone能夠把請求和應答關聯起來。atlanta.com代理服務器收到INVITE請求以後,就去找biloxi.com可能經過DNS服務來找提供這個biloxi.com的SIP服務器。這在[4]中有描述。最後,轉發INVITE請求到biloxi.com或者能到達biloxi.com的代理服務器。在轉發請求以前,atlanta.com代理服務器會在via頭上增長一個一段包含本身抵制的值(INVITE已經包含了Alice的的地址VIA域)。biloxi.com代理服務器收到這個INVITE請求而且返回一個100(Trying)應答給atlanta.com代理服務器標誌這它已經收到這個請求而且正在處理這個請求。這個代理服務器經過查詢數據庫,一般叫作地址服務,這個服務中包含了bob的當前ip地址。(咱們在下一節能夠看到這個數據庫是怎麼回事)biloxi.com代理服務增長另外一段包含本身地址的VIA頭域而且發送它到bob的sip 電話。
Bob的SIP電話接收到INVITE請求而且提醒bob有一個從Alice的呼入,這樣bob能夠決定是否響應這個呼入。這個意思就是:bob的電話響了。bob的sip電話發送一個180(Ringing)迴應,這個迴應將經過兩個代理服務器原路返回給Alice。每個代理服務器經過via頭域決定該把這個應答發送給哪裏,而且在發送以前把本身的地址從頭上拿走。雖然DNS和定位服務在路由最初的INVITE請求,180(ringing)響應能夠簡單返回給發起者而不須要查找發起者在哪裏,而且不須要在代理服務器保留狀態,同時,每個轉發INVITE的代理也能夠獲得INVITE的每個應答,這樣的特性也很是有用。
當Alice的softphone收到180(Ringing)應答的時候,它提示Alice,多是經過一個回鈴音,或者屏幕上的一個消息提示。
在這個例子中,Bob決定響應這個呼叫。當他拿起電話,他的SIP電話發送200(OK)迴應給發送者,表示這個電話已經接起來了。這個200(OK)包含了一個消息體,這個消息體包含SDP媒體描述,這個媒體描述包含Bob但願和Alice創建何種媒體鏈接。一樣,SDP消息也是兩段交換:Alice發送一個給Bob,Bob發送一個回給Alice。這個兩段的交換提供基本的兼容性協商,而且基於簡單的SDP提出/應答交換模型。若是Bob不想響應這個呼叫或者正在響應別的呼叫,一個錯誤的響應會代替正常的200(OK)回送出去,這樣,就不會有鏈接創建。SIP完整的返回代碼在21節有介紹。Bob發出的200(OK)(圖一的F9消息)可能長得像這樣的:
SIP/2.0 200 OK
Via: SIP/2.0/UDP server10.biloxi.com
;branch=z9hG4bKnashds8;received=192.0.2.3
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com
;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com
;branch=z9hG4bK776asdhds ;received=192.0.2.1
To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Contact: <sip:bob@192.0.2.4>
Content-Type: application/sdp
Content-Length: 131
(Bob’s SDP not shown)
應答的第一行包含了應答代碼(200)和緣由(ok)。剩下的行包含了包頭域。VIA,TO,FROM,CALL-ID,Cseq包頭域是從INVITE請求包中直接拷貝過來的。(有三個VIA域值-一個是Alice SIP電話增長的,一個是atlanta.com代理加的,一個是biloxi.com代理加的)。Bob的SIP電話增長了一個TAG參數。這個TAG參數會被參與對話的各方所使用,而且在之後的對話中被使用。Contract域包含了一個能直接聯繫到Bob的URI。Content-type和Content_Length域包含了消息體(沒有在例子中體現),這個消息體裏邊是Bob的SDP媒體信息。
除了DNS和位置服務以外,代理服務器能夠自主決定路由,也就是說本身決定應該向哪裏轉發請求。好比,若是Bob的SIP電話返回一個486(電話正忙)信號,biloxi.com這個代理服務器能夠轉發這個INVITE請求到Bob的語音郵箱服務器。一個代理服務器能夠同時向N個地方發送INVITE請求。這種併發尋找就是傳說中的分流(forking)。
在這個例子中,200(OK)應答經過兩個代理而且發送到Alice的softphone上,Alice的softphone收到這個應答,中止振鈴,而且標誌電話Bob已經接聽。最後,Alice的電話發送一個確認消息,ACK,到Bob的SIP電話來確認接收到了這個最後的200(o’k)應答。在這個例子中,ACK信號是直接由Alice的softphone發送到Bob的SIP phone上,跨過了兩個代理服務器。這是由於兩個端點(Alice和Bob)經過INVITE/200(OK)的請求應答包中的Contact包頭域都知道互相之間的地址了,這個地址是最開始發起INVITE請求的時候所不知道的。因此,不須要兩個代理服務器再查找對方的地址了,因此代理服務器不參與接下來的通話流了。這就完成了一個完整的使用INVITE/200/ACK 三方握手來創建SIP會話的過程。會話創建過程當中的細節描述再13節由描述。
如今,Alice和Bob的媒體會話開始了,他們經過發送剛纔創建會話所交換的SDP包中約定的互相明白的媒體包來進行會話。通常狀況下,端到端的媒體包和SIP信號控制包經過不一樣的通信路徑來發送。
在會話中,Alice或者Bob均可以改變他們本身的媒體會話屬性。這個能夠經過發送一個包含新媒體屬性描述的re-INVITE請求來完成。這個re-INVITE是捆綁在一個現有的會話的,這樣參與會話的對方能夠明白這是要改變現有的會話屬性而不是新創建一個會話。對方收到這個re-INVITE請求後,會發送一個200(OK)應答表示接受這個改變。請求方經過一個ACK來表示接受了對方的這個200(OK)應答。若是對方不一樣意這個媒體屬性變化,他會發送一個錯誤的應答好比488(暫時不能進行),這個也會收到發起者的一個ACK響應。無論怎樣,就是是re-INVITE的失敗也不會影響到現有的會話-原有的會話還能夠用上次的媒體會話屬性繼續。能夠在14節找到會話屬性更改的細節說明。
在通話結束的時候,Bob首先斷開(掛機hangs up),而且發送一個BYE的消息。這個BYE的消息將直接送到Alice的softphone,一樣是跳過代理的。Alice經過發送200(OK)應答來確認收到了這個BYE消息,這個消息終止了會話而且應答了BYE的請求。ACK在這裏不須要發送-一個ACK信號只在響應一個INVITE的響應的時候被髮送。咱們稍晚一點會討論這個INVITE的特別處理,可是基於SIP的可靠性的機制,一個通話的時間能夠認爲包含電話振鈴和掛機的時間(but relate to the reliability mechanisms in SIP, the length of time it can take for a ringing phone to be answered, and forking.)基於這樣的緣由,SIP請求的處理一般根據是否INVITE請求進行分類,INVITE類和非INVITE類請求分開處理。結束會話的細節能夠在15節查到。
24.2節描述了圖1中使用的所有消息詳細解釋。在某些狀況下,全部會話中的包都繼續經過代理轉發會頗有用。好比,若是biloxi.com代理服務器但願在INVITE以後繼續保持SIP消息流,他會在INVITE中增長一個頭域(Record-Route)包含一個URI指向這個代理服務器的hostname或者IP地址。這個消息會被Bob的SIP電話和Alice的softphone所接到(由於Record-Route頭域將在200(OK)應答中被送回),而且在會話中一直保存。那麼biloxi.com代理服務器就能夠繼續接收和轉發ACK,BYE,給BYE的200(OK)應答。每個代理均可以單獨決定是否接收INVITE之後的後續消息,而且這些後續消息均可以被髮送到那些決定接收後續消息的代理服務器。這種狀況一般發生在提供mid-call業務的代理服務器上。
登記服務是另外一個經常使用的SIP操做。登記服務是biloxi.com代理服務器知道Bob當前地址的一個方法。在初始化的時候,或者每隔一段時間,Bob的SIP 電話發送REGISTER消息給biloxi.com的一個註冊服務器。REGISTER消息包含了Bob當前登錄服務器的SIP或者SIPS的URI(sip:bob@biloxi.com)(轉換成爲Contact域中的SIP或者SIPS URI)。登記服務器登記這個映射,這個叫作綁定(binding),寫到一個數據庫裏邊,叫作定位服務(location service),這個數據庫能夠被biloxi.com的代理服務器使用。一般登記服務器和代理服務器是作在一塊兒的。一個很重要的概念就是SIP服務器的差異在邏輯上,並不是在物理上的差異。
Bob並無限定非得在一個單個設備上發起註冊。好比,他家裏的SIP電話和公司的SIP電話均可以註冊。這些消息在定位服務(location service)中保存,而且容許代理服務器經過不一樣的手段查找Bob。一樣的,不一樣的用戶也能夠在同一個設備上同時註冊。
定位服務(location service)是一個邏輯概念。他是讓代理服務經過輸入一個URI來查詢到底應該向哪裏轉發請求。能夠簡單經過用戶註冊來創建這個定位服務所須要的資料,也能夠經過其餘方法。能夠經過其餘任意的地址映射方式來實現定位服務。
最後在SIP中須要注意的是,註冊服務只是用來提供路由收到的SIP請求的,它並不作請求的身份認證的斷定。在SIP中受權和認證能夠經過創建在基於請求/應答的模式上的上下文相關的請求來實現,也能夠使用更底層的方式來實現(具體在26節有描述)。
完整的註冊SIP消息描述例子在24.1節。
其餘SIP的操做,好比檢查SIP服務器的負載,或者使用客戶端使用可選項(OPTIONS),或者用CANCEL取消一個未決的請求,在後續的章節中會介紹。
5、協議的結構
SIP是一個分層的協議,意思是說SIP協議由一組至關無關的處理層次組成,這些層次之間只有鬆散的關係。協議分紅不一樣層次來描述是爲了可以更清晰的表達,在同一個小節裏有功能的公共要素的交叉描述。本協議並無規定一個具體的實現。當咱們說一個要素」包含」某一個層,咱們的意思是這個要素複覈這個層定義的規則。
不是SIP每個要素都必定包含每個層。此外,SIP定義的要素是邏輯上的要素,不是物理要素。一個物理的實現能夠實現不一樣的邏輯要素,或許甚至是基於串行事務處理原理。SIP最底層的是它的語法和編碼層。編碼方式是採用擴展的Backus-Naur Form grammar(BNF範式)。完整的BNF描述在25節;第7節有簡要的SIP消息結構描述。
第二層是傳輸層。它定義了一個客戶端如何發送請求和接收應答,以及一個服務器如何接收請求和發送應答。全部的SIP要素都包含一個通信層。第18節有通信層的描述。
第三層是事務層。事務是SIP的基本組成部分。一個事務是客戶發送的一個請求事務(經過通信層)發送到一個服務器事務,連同服務器事務的全部的該請求的應答發送回客戶端事務。事務層處理應用服務層的重發,匹配請求的應答,以及應用服務層的超時。任何一個用戶代理客戶端(user agent client UAC)完成的事情都是由一組事務構成的。有關事務的討論在第17節有描述。用戶代理包含一個事務層,來實現有狀態的代理服務器。無狀態的代理服務器並不包含事務層。事務層包含一個客戶元素(能夠認爲是一個客戶事務)和一個服務器元素(能夠認爲是一個服務器事務),他們均可以用一個有限狀態機來處理特定的請求。
在事務層之上是事務用戶(TU)。每個SIP實體,除了無狀態代理,都是一個事務用戶。當一個TU發出一個請求,它首先建立一個客戶事務實例(client transaction instance)而且和請求一塊兒發送,這包括了目標IP地址、端口號、以及發送請求的設備。TU能夠建立客戶事務,也能夠取消客戶事務。當客戶取消一個事務,它請求服務器終止正在處理的事務,而且回滾狀態到該事務開始前的狀態,而且產生指定的該事務的錯誤報告。這是由CANCEL請求完成的,這個請求有本身的事務,而且包含一個被取消的事務(第9節)。
SIP要素,包含,用戶代理客戶端和服務器,無狀態和有狀態代理服務器和註冊服務器,包含一個能夠互相區別的核心(Cores)。Cores,除了無狀態代理服務器,都是事務用戶。UAC(用戶代理客戶端)和UAS(用戶代理服務端)的cores的行爲依賴於實現,對全部的實現來講,有幾個公共的原則(第8節)。對UAC來講,這些規則約束請求的創建;對UAS來講,這些規則約束請求的處理和應答。因爲註冊服務在SIP中是一個重要的角色,因此UAS處理REGISTER請求有一個特別的名字:登記員(registrar,登記服務器)。第10節描述了UAC和UAS的對REGISTER實現的core(核心)行爲。第11節描述了OPTIONS的UAC和UAS的core實現,這個OPTIONS用來檢測UA的處理能力的(UA-user agent)。
小虎 2006-05-25 00:03
在對話中,有其餘的相關會被髮送。一個對話是一個持續必定時間的兩個用戶之間的端到端的SIP關係。對話過程要求兩個用戶代理之間的信息是有序的並且請求被正確路由傳輸的。在這個規範中,只有INVITE請求能夠用來創建會話。當一個UAC在一個對話中發出請求的時候,它不只遵循第8節描述的通常UAC規則並且也遵循對話中的請求規則。第12節講述了對話而且討論了對話的建立和維持,以及在對話中建立一個請求。
SIP中最重要的方法就是INVITE方法,它用來在不一樣的參與者中建立會話使用。一個會話由一組參與者,他們之間用於交流的媒體流組成。第13節講述了這些會話的建立初始化過程,以及建立一個或一組對話。第14節講述了在對話中使用INVITE請求來改變會話的屬性。最後,第15節,講述瞭如何終止會話。
第8、10、11、12、13、14、15節講述了完整的UA核心(第9節描述了取消,在UA核心和代理核心中使用)。第16節講數了代理服務器,代理服務器用於在兩個UA之間作消息路由使用。
6、協議的定義
如下講述的名次對SIP有着額外的意義:
Address-of-Record: 記錄地址。一個address-of-record(AOR)是一個SIP或者SIPS URI它指向了一個具備定位服務的主機,這個主機能夠把URI映射成爲用戶真正物理位置的URI。一般狀況下,定位服務器是經過登記服務來創建的。一個AOR常常被認爲是一個用戶的」公共地址」
Back-to-Back UserAgent:背對背的用戶代理(B2BUA)是一個邏輯實體,它就像用戶代理服務器(UAS)同樣接收和處理請求。爲了決定該如何應答一個請求,B2BUA就像UAC同樣工做,而且發出請求。可是它不像代理服務器(proxy),它維持對話狀態,而且參與已經創建的對話中的每個請求。因爲它是直接的UAC和UAS的串連,因此,不須要對他有額外的定義。
Call:呼叫,一個呼叫是一個非正式的術語,它是指在端點之間一個一些通信行爲,一般用於創建多媒體對話。
Call Leg: 對話的別名;在本規範中沒有使用。
Call Stateful: 若是一個代理服務器(proxy)保存一個對話的狀態(從最開始的INVITE到對話終結的BYE),那麼這個代理服務器就是請求有狀態的。一個請求有狀態(call stateful)的代理服務器也必定是事務有狀態的,可是事務有狀態的不必定是請求有狀態的。
Client:客戶端。一個客戶端是一個任意的網絡元素,它發出SIP請求和接收SIP應答。客戶端可能會也可能不會和人交互。用戶代理客戶端(UAC)和代理服務器都是客戶端。
Conference: 一個包含多個參與方的多媒體會話(見後)。
Core:核心。核心定義了SIP實體的特定類別。好比定義了一個有狀態和無狀態的代理服務器,一個用戶代理或者註冊服務器(registrar)。全部的核心,除了無狀態代理服務器,都是事務用戶。
Dialog:對話,一個對話是持續一段時間的兩個UA之間的端到端的SIP關係。一個對話由SIP消息創建,就像用2xx響應INVITE請求。咱們用Call identifier,local tag(本地tag),remote tag(對方tag)來標誌一個對話,一個對話在RFC 2543中被正式叫作CALL LEG.
Downstream: 它是事務中的消息傳遞方向。它特指從UAC到UAS的請求流的方向,
Final Response:終結響應。一個響應終端SIP事務的應答,和事務中間的臨時響應相反。全部的2xx,3xx,4xx,5xx,6xx響應都是終結響應。
Header:頭。頭域是在SIP消息頭部用來描述這個SIP消息信息的部分。它由一堆頭域字段組成。
Header Field:頭域字段。頭域字段是在SIP消息頭域的字段。一個頭域字段能夠由多個頭域字段行組成。一個頭域字段由一個頭域名和(零個或多個)頭域值組成。多個頭域值用’,’分割。某些頭域字段只能有單個值,好比結果域(result)就只能有一個值。
Header Field Value:頭域值。一個頭域值是一個單個的值,一個頭域字段能夠有0個或者多個頭域值。
Home Domain:宿主機。一個提供SIP服務的主機。通常指的是在登記服務中指明的記錄地址中的URI的主機。
Informational Response:提示應答。和臨時應答同樣。
Initiator, Calling Party, Caller: 用INVITE初始一個會話(和對話)的那方。一個caller從發出INVITE請求創建對話開始,到對話終止都一直是這個角色。
Invitation: 一個INVITE請求。
Invitee,Invited User,Called Party, Callee:被叫方。收到INVITE請求而且創建會話的那方。一個被叫方從收到INVITE請求起,到終止INVITE創建的對話結束,都稱做被叫方。
Location Service: 定位服務。定位服務是用來給SIP轉發或者代理服務器肯定被叫方可能的位置使用的。它包含一張綁定了address-of-record的表,被叫方可能有0到多個記錄。綁定的記錄能夠經過多種渠道添加和刪除;本規範定義了REGISTER方法來更新綁定表。
Loop:環路。當請求抵達一個代理服務器,代理服務器轉發這個請求,當這個請求再次來到同一個代理服務器,就稱之爲環路。當第二次抵達的時候,Request-URI中包含了上次抵達的資料,而且因爲並無什麼東西能夠改變轉發的策略,這樣就致使這個請求還會再次被轉發回來。環路請求是錯誤的,因此,處理程序須要檢測和防止協議中出現的環路請求。
Loose Routing:丟失路由。代理服務器在下述狀況下會丟失路由。
A proxy is said to be loose routing if it follows the procedures defined in this specification for processing of the Route header field. These procedures separate the destination of the request (present in the Request-URI) from the set of proxies that need to be visited along the way (present in the Route header field). A proxy compliant to these mechanisms is also known as a loose router.
Message:消息。SIP元素之間傳送的協議數據就是消息。SIP消息既能夠是請求也能夠是應答。
Method:方法。方法是在服務器請求處理的主要功能。方法是請求消息自身攜帶的。典型的方法就是INVITE和BYE。
Outbound Proxy:對外代理服務器。一個代理服務器接收到客戶的請求,即便它不是由Request_URI所決定的服務器。一般一個UA會手工配置一個對外的代理服務器,或者能夠經過一個自動配置的協議自動配置一個。
Parallel Search: 並行搜索。並行搜索狀況下,代理服務器會向多個用戶可能存在的地方發起請求,而且等待應答。同串行搜索不一樣的地方是,並行搜索不會等待上一個請求應答回來以後再發起下一個搜索,而是一個接一個的發起搜索請求。
Provisional Response: 臨時應答。服務器用來標誌本身正在處理的應答,可是本應答並不結束一個SIP事務。1xx應答就是臨時的,其餘應答標誌着事務的結束。
Proxy,Proxy Server:代理、代理服務器。一箇中間的實體。它自己即做爲客戶端也做爲服務端,爲其餘客戶端提供請求的轉發服務。一個代理服務器首先提供的是路由服務,也就是說保證請求被髮到更加」靠近」目標用戶的地方。代理服務器對某些強制政策有用(好比,確認一個用戶是否容許創建一個呼叫等)。一個代理服務器翻譯,而且,若是有須要的話,再轉發前會重寫請求消息。
Recursion:迴路、遞歸。一個客戶端,在響應請求的時候產生新的到Contract包頭域的URI請求的時候,會在3xx響應中陷入遞歸。A client recurses on a 3xx response when it generates a new request to one or more of the URIs in the Contact header field in the response.
Redirect Server:重定向服務器。一個重定向服務器是一個產生3xx應答的UAS服務器,指示客戶端鏈接別的URI。
Registrar: 登記員。一個登記員(登記服務器)是一個接收REGISTER請求得服務器。他把請求得信息放到定位服務器中,這樣可讓定位服務器很方便得查找位置信息。
Regular Transaction:常規事務。凡不包含INVITE,ACK,或者CANCEL方法得事務就是常規事務。
Request: 請求。 一個由客戶端發到服務端得SIP信息,用於執行特定得功能。
Response:應答。一個由服務端發到客戶端得SIP信息。用來標誌從客戶端發往服務端得請求處理得狀況得。
Ringback: 回鈴音。回鈴音是一個信號音。是給呼叫方得一個信號表示被叫方正在振鈴(Ringing)。
Route Set: 路由集。路由集合是一個順序得SIP或者SIPS URI。這些URI描述了傳遞一個請求所必須經歷得代理列表。一個路由集能夠是自適應得,由於包頭中包含了Record-Route(記錄路由),也能夠是依賴配置獲得得。
Server:服務器。一個server是一個網絡元素接收請求而且處理請求而且發送迴應給請求方。典型得服務器就是代理服務器(proxies),用戶代理服務器(user agent servers),重定向服務器,登記服務器。
Sequential Search:順序查找。在順序查找中,代理服務器順序嘗試聯繫地址,在處理下一個以前必須等待上一個請求已經有一個結束應答。一個2xx或者6xx系列得最終應答老是結束一個順序查找。
Session:會話。根據SDP得描述:」一個多媒體會話是一個由多媒體發送方和接受方組成得集合,而且包括在發送方和接受方之間得數據流。一個多媒體會議是一個典型得多媒體會話。」(RFC 2327[1])(一個session在SDP訂一下能夠是一個或者多個RTP sessino)。在定義中,一個被叫方能夠被屢次邀請,被不一樣得呼叫方邀請,到同一個會話。在SDP中,一個會話能夠被SDP用戶名,session id,網絡類型,地址類型,地址元素得一個集合串所規定。
SIP 事務:一個SIP事務是在客戶端和服務端得事件,包括了從第一個由客戶端發送到服務端得請求,到最後一個(非1xx)服務端向客戶端發出得終結應答。若是請求是一個INVITE請求,而且終結應答是一個非2xx得應答,那麼事務還包括一個ACK給服務器作應答。給INVITE請求的2xx應答的ACK迴應,是一個獨立的事務。
Spiral:回溯。一個回溯是指一個SIP請求,路由給一個proxy,而且轉發,可是又被路由回這個proxy,可是不一樣於迴路(遞歸)的是,此次路由回來的請求包的包頭中,包含了不一樣於原請求的請求包部分,使得本次proxy決定的路由轉發與上次不一樣。一般,這是說,請求的Request-URI不一樣於上次的Request_URI。一個回溯不是一個錯誤,不一樣於迴路(環路loop)。一般致使這樣的現象是呼叫轉發(call forwarding)。一個用戶呼叫joe@example.com。example.com代理服務器轉發請求到Joe的PC,而且Joe的pc呼叫轉移到bob@example.com。這個請求被轉發回example.com代理服務器。但是這個並非一個環路(loop)。由於請求的目的地址變成了另外一個用戶,這就是回溯,是一個合法的狀況。
Stateful Proxy:有狀態的代理服務器。在邏輯上,有狀態的代理服務器就是處理一個請求的過程當中,維持的一個本規範所定義的客戶端和服務端的事務狀態機。也是一個事務又狀態代理服務器(transaction stateful proxy)。具體的stateful proxy在第16節定義。一個(事務)有狀態代理服務器和一個call stateful proxy不是一回事。
Stateless Proxy:無狀態的代理服務器。在邏輯上,無狀態代理服務器在處理請求中,並不維持客戶和服務端的事務狀態機。一個無狀態的代理服務器直接轉發每個接收到的請求和每個接收到的響應。
Strict Routing:嚴格路由。路由處理規則若是複覈RFC2543協議(and many prior work in progress versions of this RFC) 就是一個嚴格路由。在這個規則下,若是在包頭中包含Route域,那麼代理服務器就會刪除Request_URI域內容。本文檔並不要求必定要有嚴格路由,本文檔只要求鬆散路由就能夠了。支持嚴格路由的代理服務器也叫嚴格路由器。
Target Refresh Request: 目標刷新請求。一個Target Refresh Request是一個在對話中發出的請求,用來更改對話目標的請求。
Transaction User(TU):事務用戶。在transaction 層之上的協議層。TU包括了UAC 核心,UAS core,和proxy core。
Upstream:上行流。一個在事務中的消息流向方向。它是指由用戶代理服務器(UAS)發出應答到用戶代理客戶端(UAC)的消息流向方向。
URL-encoded:一串根據RFC2396-2.4節編碼的字符。
User Agent Client(UAC):用戶代理客戶端。用戶代理客戶端是一個邏輯的概念,他建立一個新請求,而且用客戶事務狀態機發送這個請求。UAC角色只在事務中存在。換句話說,UAC就是一小段代碼初始化一個請求,而且在事務中遵循UAC的規則。若是它接下來收到一個請求,那麼在那個事務中,它就是做爲UAS來處理請求。
UAC Core:UAC核心。在transaction和transport層之上得UAC實現的功能集合。
User Agent Server(UAS): 用戶代理服務器.UAS是一個邏輯的實體,對SIP請求作響應的。應答接受、拒絕、或者轉發對應的請求。UAS角色在事務中存在。換句話說,是響應請求的一小段軟件,在事務中做爲UAS存在。若是他發出請求,那麼他就在事務中做爲UAC存在。
UAS Core:UAS核心。在transaction和transport層智商的UAS實現的功能集合。
User Agent(UA)。一個邏輯實體的概念,包含UAC和UAS。
UAC和UAS,就像代理服務器和轉發服務器,是在事務by事務的原理(串行事務處理)上定義的。例如,當發出一個初始化INVITE請求的時候,UA做爲UAC初始化一個呼叫動做,當從被叫方接收到一個BYE請求的時候,UA做爲UAS響應。相似的,一樣的代碼能夠對一個請求作爲proxy服務器處理,對另外一個請求做爲重定向服務器。
proxy,location,registrar服務器都是邏輯實體,在它們的實現中,多是做爲單個應用實現的。
7、SIP消息:
SIP協議是一個基於文本的協議,使用UTF-8字符集(RFC2279[7])。
一個SIP消息既能夠是一個從客戶端到服務器端的請求,也能夠是一個從服務器端到客戶端的一個應答。
即便在字符集上和語法細節上有所不一樣,請求(7.1)仍是應答(7.2)消息都基於RFC2822格式的。(SIP容許包頭域不是標準的RFC2822包頭域)。這兩種消息類型都由一個起始行,一個或者多個包頭域,一個可選的消息中文組成。
通常消息= 起始行
*消息包頭
CRLF
[消息正文]
起始行= 請求行/狀態行
起始行、每個包頭行,空行、都必須由回車換行組成(CRLF)。即便消息中文沒有,也必須有一個空行跟隨。
除了在字符集上的區別之外,不少SIP的消息和包頭域的格式都同HTTP/1.1同樣。咱們在這裏就不重複它的語法和語義了,咱們用[HX.Y]來標誌HTTP/1.1規範(RFC2616[8])的X.Y節的描述。
SIP並不是一個HTTP的超集或者擴展。
7.1 請求
SIP請求是根據起始行中的Request-Line來區分的。一個Request_line包含方法名字,Request-URI,用單個空格(SP)間隔開的協議版本。
Request-Line由CRLF結束。除了用做行結束標誌之外,不容許CR或者LF出如今其餘地方。在其餘域中,不容許出現線形的空白(liner whitespace LWS)
Request-Line = Method SP Request-URI SP SIP-VERSION CRLF
Method: 這個規範規定了6中方法:REGISTER用於登記聯繫信息,INVITE,ACK,CANCEL用於創建會話,BYE用於結束會話,OPTIONS用於查詢服務器負載。SIP擴展、標準RFC追加可能包含擴展的方法。
Request-URI: Request-URI是一個SIP或者SIPS URI,他們在19.1節由描述。也能夠是一個通用的URI(RFC 2396[5])。它標誌了這個請求所用到的用戶或者服務的地址。Request-URI禁止包含空白字符或者控制字符,而且禁止用」<>」括上。
SIP 元素能夠支持除了SIP或者SIPS以外所規定的Request-URIs。好比」tel」 URI模式(RFC 2806[9])。SIP元素能夠用他們本身的機制來轉換non-SIP URIs到SIP URI,SIPS URI或者其餘什麼格式的URI。
SIP-Version:請求和應答消息都包含當前使用的SIP版本,這個遵循[H3.1](相似HTTP用SIP替代,用SIP/2.0替代HTTP/1.1)中關於版本的規定,版本依賴,升級版本號。一個應用,發出的SIP消息必定包含了SIP-Version 「SIP/2.0」。這個SIP版本串是大小寫不銘感的,可是在實現中必須發送大寫。
不像HTTP/1.1,SIP把版本號看成一個文本串處理。在實現上,這個應該不會有區別。
7.2應答
SIP應答和SIP請求的區別在於在START-LINE中是否包含一個STATUS-LINE。一個status-line在由數字表達的status-code以前,是一個協議的版本串,每個元素之間用一個單個SP(空格)分開。
除了最後用做結束標誌之外,CR/LF不容許出如今其餘地方。
status-line = SIP-VERSION SP STATUS-CODE SP Reasong-Phrase CRLF
Status-Code 是一個3位的數字result code,用來標誌處理請求的一個結果。Reason-Phrase是一個簡短的Status-Code的說明。Status-Code是爲了能自動處理使用的,可是Reason-Phrase是用來給用戶看得。一個客戶端並不要求必定要顯示或者解釋這個Reason-Phrase。本文檔建議輸出這個reason-phrase,實現中能夠選擇其餘文本,好比用請求包頭中指定的合適語言來顯示。
status-code的第一個數字表示了應答的類型。接下來兩個數字並不做分類使用。基於這個緣由,任何status code在100到199的能夠統稱位」1xx應答」,相似的,在200到299的能夠統稱位」2xx應答」,依此類推。SIP/2.0容許6類應答:
1xx:臨時應答-請求已經接收,正在處理這個請求。
2xx:成功處理-請求已經成功接收,而且正確處理了這個請求。
3xx:重定向-還須要附加的操做才能完成這個請求,本請求轉發到其餘的服務器上處理。
4xx:客戶端錯誤--請求包含錯誤的格式或者不能在這個服務器上完成。
5xx:服務器錯誤-服務器不能正確的處理這個顯然合法的請求。
6xx:全局錯誤-請求不能被任何服務器處理。
21節定義了詳細的代碼說明。
7.3 頭域
SIP頭域和HTTP頭域在語法和語義上都比較相似。特別的,SIP頭域遵循[H4.2]關於消息頭的語法的定義,而且遵循多行的擴展頭域的規則。(後者 is specified in HTTP with implicit whitespace and folding)。這個規範遵循RFC2234[10],而且把清晰的空白和封裝做爲內在的語法規則。
[H4.2]也定義了具備相同域名的多個頭域,他們的值是用逗號分開的列表,能夠合併到一個頭域中。這個也適用於SIP,可是細節上略有不一樣,由於語法不一樣。實際上,任何SIP的包頭語法都是基於以下範式的:
header = 「 header-name」 HCOLON header-value *(COMMA header-value)
這個容許合併在具備同一個域名的多個頭域,到一個用逗號分割的單個頭域中。Contact頭域除了當域值是」*」以外,都容許用逗號分割的列表。
7.3.1 頭域格式。
頭域遵循在RFC2822的2.2節定義的通用頭域格式。每個頭域都由一個域名加上冒號(」:」)和域值組成。
field-name:field-value
消息頭的正則語法在25節中有介紹介紹。
在消息頭中,容許在冒號的左右有任意個數的空白;可是,在實現中,建議避免域名和冒號中間有空格,而且建議在冒號和值之間使用單個空格(SP)。
Subject: lunch
Subject : lunch
Subject :lunch
Subject: lunch
因此,上面的都是合法的,也是相等的,可是最後一種是咱們所推薦的。
頭域能夠擴展成爲多行的,只要在每個附加行前邊用至少一個SP或者水平TAB(HT)打頭就能夠了。這種多行的頭域在行結尾而且在下一行以前的空白SP(或者HT)將被認爲是一個單個的SP字符。因此,下邊的例子是相等的:
Subject: I know you’re there, pick up the phone and talk to me!
Subject: I know you’re there,
pick up the phone,
and talk to me!
頭域中的不一樣域名的相關順序並無什麼意義。雖然如此,咱們仍是強烈建議與路由相關的域(VIA,ROUTE,Record-Route,Proxy-Require,Max-Forwards,Proxy-Authorization等等)放在消息頭的最前邊,這樣能夠提升處理的速度。相同域名的域之間的順序很是重要。只有當單個頭域的域值是能夠用逗號分割的列表的時候,才能夠表達成爲同一個域名的多個頭域(這就是說,若是遵循7.3定義的語法)。也就是意味着必須能夠將同一個域名的多個頭域在不改變消息語義的前提下,改換表達成爲一對」域名: 域值」;這個轉換是經過順序增長每個域的域值,域值之間用逗號分割。這個規則有幾個例外,就是WWW-Authenticate,Authorization,Proxy-Authenticate,和Proxy-Authorization頭域。多個頭域行能夠在消息頭中出現,可是因爲他們的語法並不遵循7.3中定義的通用格式,因此,他們並不能合併成爲單個頭域行。
在實現上,必須可以既可以處理多個頭域行的狀況,也必須可以處理用逗號分割的合併的單個頭域行的狀況。
下邊的幾組頭域是相等的:
Route: <sip:alice@atlanta.com>
Subject: Lunch
Route: <sip:bob@biloxi.com>
Route: <sip:carol@chicago.com>
Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>
Route: <sip:carol@chicago.com>
Subject: Lunch
Subject: Lunch
Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>
<sip:carol@chicago.com>
下邊各組是合法的,可是並不相等。
Route: <sip:alice@atlanta.com>
Route: <sip:bob@biloxi.com>
Route: <sip:carol@chicago.com>
Route: <sip:bob@biloxi.com>
Route: <sip:alice@atlanta.com>
Route: <sip:carol@chicago.com>
Route: <sip:alice@atlanta.com>,<sip:carol@chicago.com>,<sip:bob@biloxi.com>
每個頭域值的格式是依賴於它的頭域名的。他能夠是任意順序的TEXT-UTF8字符,也能夠是一個空格,標記,分隔符,引號括起來的字串的組合。不少頭域都回附帶一個通用的域值格式。這個域值格式是由分號分開的參數名和參數值的組合:
field-name: field-value *(;parameter-name=parameter-value)
雖然在域值裏邊能夠有任意數量的parameter-name/parameter-value對,可是不能容許有相同的parameter-name存在(惟一性)。除了特別指出的頭域以外,頭域中的域名、域值、parameter name parameter-value都是大小寫不敏感的。標記詞始終是大小寫不銘感的。除非有特別的指定,引號串的字符串是大小寫敏感的。例如:
Contact: <sip:alice@atlanta.com>;expires=3600
和
CONTACT: <sip:alice@atlanta.com>; ExPiReS=3600
相同。
Content-Disposition: session;handling=optional
和
content-disposition: Session;HANDLING=OPTIONAL
相同。
下邊的兩個頭域不相同:
Warning: 370 devnull 「Choose a bigger pipe」
Warning: 370 devnull 「CHOOSE A BIGGER PIPE」
小虎 2006-05-25 00:03
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:bob@example.com)。若是但願通信在保密機制下進行,那麼就用用戶輸入的字串組成SIPS URI的部分,用戶輸入的將加上」@」和主機的名字做爲整個SIPS URI。這個主機的名字一般是請求方的主機名字,這個主機容許處理外發請求。這個很像」縮位撥號」的機制,這個機制要求請求者自身的主機可以解釋這個縮位撥號同樣。
若是UA不但願指定主機,那麼就須要將用戶輸入的電話號碼解釋成爲一個電話的URL。至關於,每個請求通過的主機都會有機會來處理這個請求。好比,一個用戶在機場可能登錄機場的代理服務器,而且經過機場的代理服務器發出一個請求。若是他輸入」411」(美國本地電話本查詢服務號碼),這個就須要機場的外發的代理服務器進行解釋和處理,而不是解釋成有主機的用戶。在這裏,tel:411是一個正確的解釋。
在會話外的請求中,不能包含To tag字段,在to頭域中的tag是用來在對話中作標誌的。既然對話尚未創建,那麼tag就不能存在。
20.39節有進一步的描述。
下邊這個例子是一個To頭域的例子:
To: Carol <sip:carol@chicago.com>
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:thisis@anonymous.invalid)。一般,用戶或者用戶的本地主機的管理人員會事先規定請求頭域中的From頭域的值。若是給定的UA是多個用戶共同使用的,那麼必須有一個URI對應身份的profile,這樣纔可以切用戶的profile。收到請求的服務方能夠根據這個用於分辯身份的URI來區分同一個UA上的不一樣的用戶,而且根據他們的From頭域來斷定他們的身份。(22節有更多的驗證說明)。
From域必須包含一個由UAC產生的新的」tag」參數。19.3節有tag的詳細描述。20.20節有更深刻的資料。
例子:
From: 「Bob」 <sips:bob@biloxi.com> ; tag=a48s
From: sip:+12125551212@phone2net.com;tag=887s
From: Anonymous <sip:c8oqz84zk7z@privacy.org>;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: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com
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增加了,客戶端可
小虎 2006-05-25 00:04
以對這個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:watson@bell-telephone.com 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
小虎 2006-05-25 00:05
一個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:bob@biloxi.com,轉換到一個或者一組更加」接近」目標用戶的URI,好比sip:bob@engineering.biloxi.com。基本上,一個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
| carol@chicago.com
chicago.com +--------+ V
+---------+ 2)Store |Location|4)Query +-----+
|Registrar|=======> | Service|<======= |Proxy|sip.chicago.com
+---------+ +--------+=======> +-----+
A 5)Resp |
| |
| |
1)REGISTER| |
| |
+----+ |
| UA | <-------------------------------+
cube2214a| | 6)INVITE
+----+ carol@cube2214a.chicago.com
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:carol@cube2214a.chicago.com),他們也能夠使用其餘的URI表示方法。一個SIP UA能夠選擇註冊一個電話號碼(好比使用tel URL, RFC 2806[9])或者一個email地址(好比用mailto URL, RFC2368[32])來做爲address-of-record的聯繫地址Contact域。
例如,Carol,有一個address-of-record」sip:carol@chicago.com」,將會在區域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:carol@chicago.com」地址的註冊服務應該是」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: carol@chicago.com
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9Hg4bKhjhs8ass877
Max-Forwards: 70
To: <sip:carol@chicago.com>
小虎 2006-05-25 00:07
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710
Cseq : 63104 OPTIONS
Contact: <sip:alice@pc33.atlanta.com>
Accept: application/sdp
Content-Length: 0
11.2 處理OPTIONS請求
給OPTIONS的應答的構造遵循標準的構造規則(8.2.6節描述)。應答碼的選擇必須和處理INVITE請求同樣的應答碼(就像處理INVITE請求同樣的返回)。這就是說,200(OK)應當在UAS可以接收請求的時候返回,486(忙)應當在UAS若是忙的時候返回。這樣OPTIONS能夠用來檢測UAS的基本狀態,這就是說,咱們能夠用OPTIONS來知道UAS可否接收INVITE請求。
在一個對話中的OPTIONS請求會產生一個200(OK)的應答,這是和在對話外建立的而且對對話沒有任何影響的請求相同。
這個OPTIONS的使用有必定的限制,由於對於proxy處理OPTIONS和INVITE請求的不一樣。一個分支的INVITE能夠有多個200(OK)的應答返回,可是一個分支的OPTIONS只能有單個200(OK)應答返回。由於這是因爲proxy處理OPTIONS請求是看成非INVITE的處理。參見16.7節有詳細的說明。
若是OPTIONS請求的應答是由proxy服務器給出的,proxy返回一個200(OK)的應答,列出這個服務器的各類選項和能力。
應答沒有消息體
Allow,Accept,Accept-Encoding,Accept-Language,和Supported頭域應當在200(OK)應答中出現。若是這個是由proxy產生的應答,那麼Allow頭域應當忽略,由於proxy是方法無關的(也就是說不知道該如何處理方法的)。Contact頭域能夠在200(OK)的應答中出現,而且與3xx應答有相同的語義。這就是說,他們能夠列出指向客戶的一串名字和方法的集合(用以轉發請求)。一個Warning頭域是能夠存在的。消息體也能夠存在,消息體的類型是由OPTIONS請求的Accept頭域指明的(application/sdp是缺省的,若是Accpet頭域不存在的話)。若是Accept頭域中包含了一個類型能描述媒體接收能力,UAS應當在應答中包含一個消息體用於這個用途。詳細的application/sdp包體說明在[13]中描述。
UAS生成的OPTIONS應答例子。(對應11.1節中的請求例子)
SIP/2.0 200 OK
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877
; received = 192.0.2.4
To: <sip:carol@chicago.com>;tag=93810874
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710
Cseq: 63104 OPTIONS
Contact: <sip:carol@chicago.com>
Contact: mailto:carol@chicago.com
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE
Accept: application/sdp
Accept-Encoding: gzip
Accept-Language: en
Supported: foo
Content-Type: application/sdp
Content-Length:274
(SDP not shown)
12 對話(Dialog)
一個UA的核心概念就是對話。對話是表現爲兩個用戶代理(UA)之間的持續一段時間的點對點的SIP關係。對話(Dialog)使得用戶代理之間的消息順序傳遞和兩個用戶代理之間的請求正確路由更加容易。對話(Dialog)能夠認爲是對SIP消息解釋的上下文關係。第8節講述了方法無關的UA處理和響應對話(Dialog)外的請求。本節將討論如何經過請求和應答來建立一個對話(Dialog),而且在對話(Dialog)中如何發起和響應後續的請求。
一個對話在參與對話的UA中都有一個dialog ID做爲標記,這個ID由Call-ID,和一個本地tag和遠程tag組成。各個UA的dialog ID在對話中是不同的。特別是,在一邊UA的本地tag,在另一方就是遠程tag。這些tag都是互相不透明的,而且使得整個dialog ID是惟一的。
dialog ID一樣是和全部的To頭域中包含了tag參數的請求及應答相關。
填寫一個消息中的dialog ID的規則依賴於SIP元素是UAC仍是UAS。對於UAC來講,dialog ID中的Call-ID的值會填寫到消息中的Call-ID域中,遠程tag放在消息中的To的tag參數中,本地tag放在From的tag參數中。(這些規則對請求和應答都適用)。對於UAS來講,dialog ID的Call-ID值放在消息的Call-ID頭域中,遠程tag放在From頭域的tag中,本地tag放在To頭域的tag參數中。
一個對話包含一些特定的狀態用於之後的對話中的消息傳送。這個狀態由dialog ID,本地序列號(用來排序UA到對方的請求的序列),遠程序列號(用來排序請求從遠端到本UA),本地URI,遠端URI,remote target,一個布爾類型的標記」secure」,路由集合(一組有序的URI)組成。
路由集合是由發送請求到對方須要途徑的一組服務器列表組成。一個對話能夠處於」early」狀態,這是因爲當這個對話收到了臨時應答而建立,而且當收到了2xx終結應答的時候轉換到」confirmed」狀態。對於其餘應答,或者沒有應答,」early」對話將會終結。
12.1 建立一個對話
對話是由對一組特定請求的沒有失敗的應答來建立的。在本規範中,只有包含To tag的2xx和101-199應答,而且請求是INVITE的,會創建一個對話。當收到一個非終結應答的時候,對話會創建成」early」狀態,而且成爲early dailog。建立對話的時候能夠使用Extension來定義擴展。13節描述了INVITE請求的更多細節。在這裏,咱們描述與方法無關的對建立對話狀態的處理。
UA必須按照下邊描述的方法對dialog ID進行賦值。
12.1.1 UAS行爲
當UAS響應一個請求給出一個應答,而且這個應答會創建一個對話的時候(好比對INVITE的2xx應答),UAS必須拷貝全部的請求中的Record-Route頭域到應答中去(包括URI,URI參數,和其餘任何Record-Route頭域的參數,不管UAS是否是認識的參數都須要原樣拷貝),而且必須維持這些參數的順序。UAS必須增長一個Contact頭域給應答。這個Contact頭域包含一個UAS在後續對話請求中接收請求的地址(這個包含了給INVITE請求的2xx應答的ACK請求處理的地址)。一般狀況下,UAS會用IP地址或者FQDN形式來發布本身的這個Contact地址。這個在Contact頭域中的URI必須是一個SIP或者SIPS URI。若是建立對話的請求在Request-URI中包含的是SIPS URI,或者在Record-Route頭域的最上的一個值是SIPS URI,或者若是請求中沒有Record-Route頭域可是請求中的Contact頭域是SIPS URI,那麼給出的應答中的Contact頭域必須是一個SIPS URI。 這個URI應該是全局有效的(就是說,這個URI能夠用於對話外的消息)。一樣的,在請求INVITE中的Contact頭域的URI也不該當僅限於這個對話中使用。所以它能夠用於對話外的消息中。
UAS接着建立這個對話的狀態。對話狀態必須維持直到對話結束。
若是請求是經過TLS過來的,而且Request-URI包含一個SIPS URI,」secure」標誌將被賦值成爲TRUE。
路由集合必須設置成爲請求中的Record-Route的URI列表,保留全部的URI參數和順序。若是請求中沒有Record-Route頭域,那麼路由集合必須設置成爲空。這個路由集合,即使是空的,爲了之後的對話中的請求,也要覆蓋任何預先存在(pre-existing)的路由集合。remote taget必須設置成爲請求的Contact頭域中的URI。
遠程序列號必須設置成爲請求中的Cseq頭域的序列號。本地序列號必須設置成爲空。dialog ID中的呼叫標誌應該設置成爲請求的Call-ID頭域的值。dialog ID的本地tag必須設置成爲對請求的應答包中的To頭域的tag,而且dialog ID的遠程tag必須設置成爲請求中的From 頭域中的tag。UAS必須可以處理接收到的請求中的From頭域沒有tag標誌,在這種狀況下,這個tag就是空值。這是爲了兼容RFC2543協議,它並無定義From tag。
遠程URI(remote URI)必須設置成爲From頭域中的URI,而且本地URI必須設置成爲TO頭域中的URI。
12.1.2 UAC行爲
當一個UAC發出一個請求,這個請求可以創建一個對話(好比這個請求是INVITE),它必須在Contact頭域中提供一個基於全局的SIP或者SIPS URI(例如,能夠在對話外使用的SIP URI)。若是請求包含一個Request-URI或者最上的Route頭域是SIPS URI,Contact頭域也必須包含的是SIPS URI。
當一個UAC接收到應答,而且這個應答創建對話的時候,它也一樣構造這個對話的狀態。這個狀態必須維持到對話的結束。
若是這個請求是基於TLS發送的,而且Request-URI包含一個SIPS URI,那麼」secure」標誌被設置成爲TRUE。
路由集合必須設置成爲應答中的Record-Route頭域的URI列表,保留全部的URI參數和順序。若是在應答中沒有Record-Route頭域,那麼這個路由集合必須設置成爲空集合。這個路由集合即使是空的,爲了之後的對話中的請求,也要覆蓋任何預先存在(pre-existing)的路由集合。remote taget必須設置成爲應答中的Contact頭域的URI。
本地序列號必須設置成爲請求中的Cseq頭域的序列號。遠程序列號必須設置成爲空(他會由遠端的UA在對話中發送請求而創建)。dialog ID中的呼叫標誌必須設置成爲請求的Call-ID頭域的值。dialog ID的本地tag必須設置成爲請求中的From頭域的tag,dialog ID的遠程tag必須設置成爲應答中的To頭域的tag。UAC必須可以處理接收到的應答的To頭域中沒有tag的狀況,在這個狀況下,tag值取值成爲空。這是爲了可以向下兼容RFC2543,它沒有規定To的tag。
remote URI必須設置成爲To頭域的URI,local URI必須設置成爲From頭域的URI。
12.2 對話中的請求
當兩個UA之間的對話創建之後,他們均可以在對話中初始化一個新的事務(transaction)。若是UA發送請求,將遵循UAC的事務規則。UA接收請求將遵循UAS的規則。在創建對話的事務過程當中,UA扮演的角色多是不同的。
在對話中的請求能夠包含Record-Route和Contact頭域。不過,雖然他們會修改remote target的URI,可是這些請求也不會致使對話的路由集被改變。明確說,若是請求不是刷新target的請求,那麼這個請求不會更改對話的remote target URI,若是請求是刷新target的請求,那麼這個請求才會更改對話的remote target URI。對於用INVITE創建的對話來講,惟一的可以刷新target的請求就是re-INVITE(見14節說明)。可能會有其餘擴展定義經過其餘方法來刷新target的請求。
注意ACK不是一個刷新target的請求。
刷新target請求只會更改對話的remote target URI,而且更改由Record-Route指定的路由集合。若是更新路由集合會帶來嚴重的和RFC2543向後兼容問題。
12.2.1 UAC行爲
12.1.1.1 產生請求
在對話中的請求是經過用許多對話的狀態部分來構造的。在TO頭域中的URI部分必須設置成爲對話狀態中的remote URI。To頭域的tag參數必須設置成爲dialog ID中的remote tag部分。請求的From URI必須設置成爲對話狀態中的local URI。From頭域的tag參數必須設置成爲dialog ID的local tag部分。若是remote或者local tag是空值,那麼tag參數必須分別從From或者To頭域中去除。
在請求序列中的原始請求的To和From頭域的URI的使用方法是爲了向下兼容RFC2543協議的,在RFC2543協議中,使用URI做爲對話的標誌。在這個規範中,只有tags用於區分對話。有可能在本協議的後續版本中,在對話中的請求必須強制反應原始請求的To和From頭域的URI將會去除。
請求的Call-ID必須設置成爲對話的Call-ID。在對話中的請求必須嚴格遵循單個遞增的Cseq序列號(每次增長1)(固然要除了ACK和CANCEL,這兩個請求中的Cseq必須和原始的請求或者確認請求同樣)。所以,若是本地序列號(local sequence number)不爲空,那麼本地序列號碼必須依次增長1,而且這個數值要存放到Cseq頭域中。若是本地序列號碼是空的,那麼在8.1.1.5節約定的初始值必須填寫進去。在Cseq頭域中的method字段必須和請求的方法(method)一致。
經過使用32位的長整數,使得即便每秒種產生1筆請求,也會要136年纔會用完這個整數出現重複。這個序列號的初始值的選取是爲了讓對話中後續的請求序列號不會重複。非0的初始值能夠考慮採用時間來做爲初始的序列號。一個客戶端能夠用31位有符號整數或者32位無符號整數來存放時間做爲初始化的序列號。
UAC使用remote target和路由集合來構造請求中的Request-URI和Route頭域。若是路由集合是空的,那麼UAC必須把remote target URI放到Request-URI中,而且UAC不能添加Route頭域到請求中。
若是路由集合不爲空,而且路由集合的第一個URI包含lr參數(見19.1.1),那麼UAC必須填寫remote target URI到Request-URI,而且必須包含Route頭域,這個Route頭域按照順序填寫路由集合和路由集合的參數。
若是路由集合不爲空,而且路由集合的第一個URI沒有包含lr參數,那麼UAC必須把第一個URI放在Request-URI中,而且拆去全部不被Request-URI容許的參數。UAC必須增長一個Route頭域順序包含全部剩下的路由集合元素,及其參數。UAC接着必須把remote target URI放在Route頭域的最後一項。
例如,若是remote targe是: sip:user@remoteua 而且路由集合包括:
<sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>
那麼請求應該有下列的Request-URI和Route頭域
METHOD sip:proxy1
Route: <sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>,<sip:user@remoteua>
若是路由集合的第一個URI不包含lr參數,那麼對應的說明proxy並不能支持本文檔所約定的路由機制,而是支持RFC2543文檔所約定的路由機制,那麼在發送信息的時候須要經過替換Request-URI爲接收到的第一個Route頭域的值。將Request-URI的值放在Route頭域的目的是爲了保護Request-URI,使得它通過嚴格路由的時候不丟失(當請求遇到一個鬆散路由的時候會返回到Request-URI中?????。)
在對話內的任何一個刷新target的請求中,都應當包含一個Contact頭域,而且這個URI除非有必要,不然都應當是和對話內上次請求的URI值同樣。若是」secure」標誌設置成爲TRUE,那麼URI也應當是SIPS URI。
若是在12.2.2節討論的那樣,在刷新target請求中的Contact頭域會更新remote target URI。這個容許UA提供一個新的聯繫地址(Contact address),代表它在對話中改變了本身的地址。不過,若是請求不是刷新target的請求,那麼不會影響對話中的remote target URI。請求中的剩下的部分請按照8.1.1節描述的填寫。一旦請求被建立了,請求將按照對話外請求發送標準步驟(8.1.2節)來解析服務器的地址而且發送請求。
8.1.2節中的步驟通常把請求發送到Route頭域的最上一個地址,或者若是沒有Route頭域,那麼就發送到Request-URI地址。因爲受到特定的限制,這些步驟也容許把請求發送到另一個地址(好比在route set中沒有的缺省的外發proxy)
12.2.1.2 處理應答
UAC將會從transaction層收到請求的應答。若是客戶端的事務層返回一個超時,這會等同於一個408(請求超時)的應答。UAC處理3xx應答的時候,在這個應答是在對話內的請求的應答的處理方法和在對話外的處理方法是同樣的。這個方法在8.1.3.4節中描述。須要注意的是,雖然UAC會嘗試新的地址(處理3xx應答的時候),可是它依舊使用對話內的路由集合來構造請求的Route頭域。
當UAC收到一個刷新target請求的2xx應答的時候,若是對話的remote target URI存在,那麼它必須用這個應答的Contact頭域的值來替換對話的remote target URI。
若是對話那的請求的應答是481應答(呼叫/事務不存在Call/Transaction Does Not Exits)或者一個408(請求超時),那麼UAC應當終止這個對話。而且UAC應當在請求徹底沒有應答的時候(客戶端transaciton將會通知TU這個超時)客戶端transaction終止這個對話。
對於INVITE初始化的對話,終止對話須要發送一個BYE。
12.2.2 UAS行爲
在對話中發送的請求,就像其餘請求同樣,是原子請求。若是UAS收到某個請求,全部的相關狀態要麼一塊兒改變,要麼就一塊兒不變。在某些請求中,請求會影響好幾個狀態(好比INVITE請求)。
UAS從transaction層收到請求。若是請求的To頭域有tag字段,UAS的處理核心須要校驗對話的ID,拿請求中的tag和現存的對話相比較。若是匹配成功,那麼就是一個在對話中的請求。在這種狀況下,UAS首先使用8.2節中的對話外請求處理的步驟。若是請求To頭域包括了一個tag字段,可是對話的ID並不匹配現存的對話,UAS多是由於崩潰而從新啓動,或者收到了一個另外(多是錯誤的)UAS(UAS能夠構造To的tags,這樣UAS在災備恢復下,能夠把這個tag當作它本身的)。還有一種簡單的多是請求發送錯誤了。在這個基礎上,UAS能夠選擇接受或者拒絕請求。在容許的狀況下,儘可能處理這些請求會提供災難恢復的機制。UAS若是但願支持這樣的特性就必須遵循一些原則,好比用始終使用單調遞增的Cseq序列號,甚至是在從新啓動以後也這樣,在重啓動後重建路由集合,處理越界的RTP時間戳和序列號等等。
若是UAS因爲不但願重構對話而拒絕這個請求,它必須應答對方一個481(呼叫/事務不存在。Call / Transaction不存在)應答。
對於在對話中接收到的,那些不會用任何形式更改對話狀態的請求,好比OPTIONS請求,他們等同於在對話外的處理請求。
若是遠端的序列號(remote sequence number)是空的,它必須設置成爲請求中的Cseq頭域的序列號(sequence number)。若是remote sequence number不是空的,可是請求中的sequence number小於這個remote sequence number,請求就是非順序的,而且必須經過應答500(服務器內部錯誤)打回去。若是remote sequence number不是空的,而且請求中的序列號大於這個remote sequence number,請求就是按照順序的。這個請求中的Cseq的序列號能夠比remote sequence number大不止1。在這種狀況下,並不是是錯誤的,而且UAS應當準備接收和處理比上次處理的請求Cseq值大於1 的請求。UAS必須設置remote sequence number成爲請求中的Cseq頭域中的序列號。
若是一個proxy廢棄掉一個UAC產生的請求,而且UAC從新遞交這個請求的時候。這個請求是會具備一個全新的Cseq序列號。UAS是不會收到第一個請求的,這樣,Cseq序列號就會出現間隔,這樣的間隔並不是是一種錯誤的狀況。
當UAS接收到一個target刷新請求的時候,若是請求中存在Contact頭域,它必須用Contact頭域中的URI來替換對話的remote target URI。
12.3 終止對話
在創建對話中的終結對話,跟請求方法無關,若是對話外的請求產生了一個非2xx終結應答,任何前邊請求建立的」早期對話」(early dialogs)將會終止。在已經創建的對話中,終結對話就是請求方法相關的。在這個定義中,BYE方法將會終結一個對話。15節有細緻的討論。
13 初始化一個會話
13.1 概覽
當UAC但願初始化一個會話(好比,audio,video或者遊戲),它首先構造一個INVITE請求。這個INVITE請求一個服務器來創建一個會話。這個請求可能會由proxy層層轉發,最後到達一個或者多個可能可以處理這個邀請的UAS。這些UAS須要看看是否用戶接收這個邀請。而後UAS能夠接收這個請求(也就是會話創建了),經過發送2xx應答。若是邀請被拒絕,根據拒絕的緣由,3xx,4xx,5xx或者6xx應答將會發送。在發送終結應答以前,UAS能夠發送一些臨時應答(1xx)應答給UAC,以便UAC可以掌握創建會話的進度。
當收到了一個或者多個臨時應答,UAC可能收到一個或者多個2xx應答或者一個非2xx終結應答。因爲在INVITE終結應答以前,可能有很多時間,在INVITE事務的可靠性機制和其餘的請求不一樣(好比OPTIONS)。當UAC收到了終結應答,UAC須要給每個INVITE的終結應答,發送一個ACK請求。發送ACK請求的步驟依賴於應答的類別。對於在300到699的終結應答,ACK是在transaction層處理的,而且遵循一系列規則(17節)。對於2xx應答,ACK是由UAC處理核心產生的。
INVITE的一個2xx應答會創建一個會話,同時也創建了一個基於發送INVITE請求的UA和產生2xx應答的UA之間的對話。所以,當從多個遠程UA收到了多個2xx應答(可能因爲INVITE的分支),每個2xx創建一個不一樣的對話(dialog)。全部這些對話都是同一個呼叫的組成部分。
本節介紹了INVITE請求創建會話的詳細過程。支持INVITE的UA也必定同時支持ACK,CANCEL和BYE。
13.2 UAC處理
13.2.1 建立一個初始化的INVITE
因爲初始化的INVITE請求是一個對話外的請求,它遵循8.1.1節的步驟建立。除此以外還有專門針對INVITE的附加處理步驟。
在INVITE中應當包括一個Allow頭域(20.5節)。它用來標誌在這個INVITE創建的這個對話(dialog)中什麼樣的方法能夠接受。好比,一個UA能夠在對話中接收和處理INFO請求[34],那麼在INVITE請求的Allow頭域中應當列出這個INFO方法。在INVITE請求中,Supported頭域應當包含。這個頭域包含了全部這個UAC支持的擴展部分。
在INVITE中能夠包含一個Accept頭域(20.1節)。這個標誌了UA在後續創建的對話中,能兼容的接收和發送的Content-Type。Accept頭域支持不一樣會話描述格式(session descrioption format)的時候特別有用。
UAC能夠經過包含一個Expire頭域(20.19節)來限制邀請的有效期限。若是Expire頭域的時間到了尚未接收到INVITE的終結應答,UAC處理核心應當像9節描述的那樣產生一個對INVITE請求的CANCEL請求,
UAC還能夠根據須要增長Subject(20.36節),Organization(20.25節)和User-Agent(20.41節)頭域。這些頭域都包含了INVITE的相關資料。UAC能夠給INVITE增長一個消息體。8.1.1.10節講述瞭如何構造Content-Type頭域來描述消息體。
對於消息體,有一些特別的規定――他們是基於某種磋商機制的,他們對應的Content-Disposition 是」session」(會話的)。SIP使用一個請求/應答模型,UA發出一個會話描述,稱做是請求,裏邊包含了會話的描述。這個請求標誌了特定的聯繫內涵(好比audio,vidio,game),這些內涵的參數(好比解碼器等等),而且從應答方接收媒體信息的地址。對方UA會迴應另一個會話的描述,稱之爲應答,標誌了能接受的聯繫內涵,這些內涵的參數。這個請求/應答的交換實在對話的上下文進行中的,因此若是一個SIP INVITE請求致使了多個對話,每個對話都包含本身獨立的請求/應答的交換。請求/應答模型定義了對於請求和應答的限制。(好比在上一個請求還沒有處理完成狀況下不能發起下一個請求)。這也致使了請求/應答在SIP消息中出現的位置限制。在這個規範中,請求和應答只能出如今INVITE、ACK請求和其應答中。請求和應答的使用中更進一步被限制。在初始化一個INVITE事務中,規則以下:
o 初始化請求必須在INVITE中,若是不在INVITE請求中,就必須在UAS回送給UAC的第一個非失敗的可靠消息中。在這個規範中,這個應答就是2xx應答。
o 若是初始的請求是一個INVITE,那麼應答必須是由UAS發送回給對應發出INVITE請求的UAC的可靠的非失敗的消息。在本規範中,只有2xx應答對應這個INVITE請求。一樣相同的應答可能在以前發送的零食應答中存在。UAC必須把它接收到的第一個會話描述看成是應答,而且必須忽略任何在初始INVITE請求中後續的會話描述應答描述。
o 若是初始請求是在第一個可靠的非失敗的UAS回送給UAC的消息中,那麼應答必須在這個消息的確認消息中(在本規範中,就是給2xx應答的ACK確認消息)
o 在發送或者接收到第一個請求的應答以後,UAC能夠一樣依據這樣的問答方法產生後續的請求。可是隻能在收到每個請求的應答以後才能發起下一個請求。不能在上一個請求還沒有收到應答的時候發起下一個請求。
o 當UAS發送或者接收到初始化的請求的時候,禁止在它給初始的INVITE請求的應答中產生後續的請求(協商會話描述請求)。這就意味着基於本規範的UAS在完成初始化的事務以前,不會產生任何會話描述請求。
具體來講,根據本規範,上邊的規則分別定義了兩種UA之間交換信息的方法。請求實在INVITE中,應答是在2xx(可能在1xx中也存在,具有相同的值)中,或者請求在2xx中,應答在ACK中。(這個意思是說,兩個UA之間創建鏈接的時候,首先須要協商一下兩個UA可以支持的消息體正文,那麼這個協商關係也是經過問答形式的,也就是經過請求/應答的,這個媒體磋商的請求既能夠在UAC發起的INVITE請求中,也能夠在UAS迴應的2xx應答中。一樣的,媒體磋商的應答既能夠在UAS的2xx應答或者1xx應答中,也能夠在ACK確認請求中)。全部的支持INVITE請求的UA都必須支持
小虎 2006-05-25 00:07
兩種交換方式。會話描述協議(session description protocol sdp)(RFC 2327[1])在全部的UA中都必須獲得支持,而且它的用法和請求/應答的構造必須遵循[13]中定義的步驟。
在上邊講述的請求/應答模型中,只能適用於在包頭域Content-Disposition中的值是」session」的包體狀況。所以,有可能會INVITE和ACK請求中都包含一個包體信息(好比,INVITE包含一個相片(Content-Disposition:render)而且ACK包含一個會話描述(Content-Disposition:session))。
若是Content-Disposition頭域不存在,Content-Type 是application/sdp的包體實現就等同於Content-Disposition」session」,其餘Content-Type的狀況就是實現」render」。
當INVITE請求建立之後,UAC遵循對話外請求發送的步驟進行發送(8節)。這也就是建立一個客戶事務而且由這個客戶事務發送請求而且處理應答。
13.2.2 處理INVITE應答
當INVITE請求被傳送給INVITE的客戶事務層進行處理,UAS等待INVITE的應答。若是INVITE客戶事務層返回一個超時而不是收到一個應答,那麼這個TU就應當像收到一個408(請求超時)應答(8.1.3節)那樣進行處理。
13.2.2.1 1xx應答
有可能在收到一個或者多個終結應答以前,UAC會收到0個或者1個或者多個臨時應答。INVITE的臨時應答會創建」early dialogs」(早期對話)。若是一個臨時應答在To頭域中有一個tag子頓,而且應答的dialog ID並非已經存在的對話的ID,那麼就應當遵循12.1.2節定義的步驟建立一個對話(早期對話)。
early dialog只會在下邊這個狀況中須要:若是一個UAC須要在完成初始的INVITE事務以前,給對方發送一個對話內的請求的時候,就須要early dialog。在臨時應答中的頭域能夠在當對話是early state的時候都有效(也就是說,好比一個臨時應答的Allow 頭域包含的方法,在對話狀態是early state的時候都是有效的。[因爲Allow是容許的方法集合,因此,當對話狀態是早期對話的時候,這個Allow的集合是不會改變的,可是當建立正式的dialog以後,Allow的集合可能會改變哦]。)
13.2.2.2 3xx應答
一個3xx應答可能包含一個或者多個Contact頭域值,這個頭域值提供了被叫方可能存在的地點。UAC能夠根據3xx應答的狀態碼(21.3節)來決定是否嘗試這些新的地址。
13.2.2.3 4xx,5xx,6xx應答
在INVITE請求中,可能會收到單個非2xx終結應答。4xx,5xx,6xx應答若是包含了Contact頭域,那麼這個頭域值指示了錯誤的詳細信息的解釋地點。後續的終結應答(只有可能在發生錯誤的狀況下),必須被忽略掉。
全部的早期對話都會因爲接收到非2xx終結應答而結束。
一旦接收到了非2xx終結應答,UAC處理核心就認爲INVITE事務結束了。INVITE客戶事務處理生成對這個應答的ACK(參見17節)。
13.2.2.4 2xx 應答
單個INVITE請求可能會致使多個2xx應答返回給UAC,這是由於proxy能夠分支。每個應答都是由To中的tag參數來進行區分的,而且每個應答都表明了一個獨立的對話,具有單獨的對話ID。
若是在2xx應答中的對話ID和一個現存的對話匹配,那麼這個對話必須切換到」confirmed」狀態,而且對話的路由集合必須基於2xx的應答進行從新計算(參見12.2.1.2)。若是不匹配,那麼必須建立一個新的對話,這個對話具有」confirmed」狀態,參見12.1.2的步驟進行建立。
注意在對話狀態中,只有路由集合不須要從新計算。其餘部分好比對話內的最大的序列號(遠程的和本地的)等都不須要從新計算。路由集合只是因爲須要向後兼容而須要從新計算。RFC 2543並無要求在1xx應答中反射Record-Route頭域回來,只在2xx請求中要求了。咱們不能更新對話狀態的所有部分,由於在早期對話(early dialog)中可能會存在對話中的請求,好比更改序列號等等。UAC核心必須爲每個2xx應答,產生一個ACK請求。除了在Cseq和身份認證相關的頭域以外,ACK請求的頭域的建立和在對話中的請求建立的方法同樣(12節)。Cseq頭域的序列號部分必須和須要確認的INVITE請求同樣,可是Cseq的方法部分必須是ACK。ACK必須包含和INVITE請求相同的信任狀。若是2xx包含一個媒體磋商請求(基於上述的規則),ACK必須在包體中包含一個媒體磋商應答。若是2xx應答的媒體磋商請求不能被接收,UAC核心必須產生一個有合法的應答ACK,而且馬上發送一個BYE請求。
當ACK建立之後,[附件4]中規定的步驟用來檢測對方地址,端口和transport。這個請求是直接交給通信層進行通信的,而不是交給一個客戶事務層進行發送。這是因爲UAC核心直接處理ACK的重發,而不是事務層進行重發的處理。每次收到一個重發的2xx終結應答的時候都必須發送一個ACK到通信層。
UAC核心認爲INVITE事務在接收到第一個2xx應答後的64×T1秒後完成。在這個時間點後,全部沒有轉換成爲創建鏈接狀態的早期對話都會被終止。一旦UAC確認INVITE事務完成了,那麼缺省認爲不會收到新的2xx應答了。若是,在相應了對INVITE請求的所有應答以後,UAC並不但願建立這個對話,那麼UAC必須經過15節描述的那樣發送BYE請求來結束對話。
13.3 UAS處理
13.3.1 處理INVITE
UAS核心從事務層收到INVITE請求。首先根據8.2節定義的步驟進行處理請求,8.2節中定義的是跟對話內外無關的請求的處理。若是處理順利完成(沒有產生應答),UAS核心根據以下步驟進行額外處理:
1、 若是INVITE請求包含一個Expires頭域,UAS核心就設置一個時鐘計數=這個頭域值。若是時鐘到了,這個邀請就過時了。若是在UAS還沒有產生終結應答的時候就超時了,那麼487(請求終止)應答應當產生給UAC。
2、 若是請求是一個對話中的請求,12.2.2節定義的方法無關的處理步驟將首先進行處理。這個處理可能會影響到會話;14節講述了細節。
3、 若是請求的To頭域包含了一個tag,可是對話的ID與現存的任何一個對話都不匹配,那麼UAS多是因爲崩潰而從新啓動的,或者是因爲接收到了本應當發送給另一個UAS的請求(或者就簡單是因爲請求填寫錯誤)。12.2.2節提供了這種狀況的處理指引。從這開始的處理將假定這個INVITE是在對話外的,而且INVITE請求的目的是創建一個新的會話。INVITE請求可能包含一個會話描述,在這種狀況下是但願和UAS進行會話媒體的磋商。即便INVITE請求是對話外發出的,這個INVITE參與的用戶也有可能正是那個會話中的參與方。這個是因爲在多方會議中,某個正在會議中的用戶,被其餘參與方邀請參加。若是須要鑑別這樣的狀況,UAS能夠使用會話描述來檢查是否重複邀請。好比,SDP包含了會話的ID和版本號。若是這個用戶自己就是會話中的一方,而且session參數包含的會話描述沒有改變,UAS可能就悄悄接受這個邀請(就是說,在不提示用戶的狀況下發送2xx應答)。
若是INVITE並無包含某個會話描述(session description),UAS就是被邀請建立一個會話,而且UAC已經但願UAS來提供這個會話offer。UAS必須在它的給UAC的第一個非失敗的可靠消息中提供這個offer。在本規範中,給INVITE請求的2xx應答中就應當提供這個offer。
UAS能夠提示進度,接受,轉發,或者拒絕這個邀請。在這些狀況下,它經過按照8.2.6節描述的步驟創建應答。
13.3.1.1 提示進度
若是UAS不能立刻接受或者拒絕邀請,那麼它能夠提示某種形式的進度給UAC(好比提示一個回鈴聲等等)。這是經過一個101到199的臨時應答實現的。這些臨時應答創建了早期對話(early dialog)(經過8.2.6和12.1.1)。若是UAS願意,UAS能夠發送多個臨時應答。每個臨時應答都必須包含相同的dialog ID。這些臨時應答都並不是可靠傳送的。
若是UAS打算延長一點時間來響應這個INVITE請求,它須要請求一個」extension」來防止proxy來取消這個事務。proxy有權利來取消超過3分鐘未完成的事務。要防止這個取消,UAS必須每分鐘發送一個非100臨時應答,防止因爲1xx臨時應答的非可靠傳輸致使的臨時應答丟失。
若是呼叫出於等待狀態(好比用戶設置成爲呼叫等待的)或者這個呼叫正在和PSTN電話系統進行通信(PSTN系統容許呼叫沒有應答),一個INVITE事務是能夠被延長處理時間的。
13.3.1.2 INVITE請求轉發
若是UAS決定轉發這個呼叫,就須要發出3xx的應答。300(多重選擇),301(永久轉移),302(臨時轉移)應答中應當包含一個Contact頭域,這個頭域包含了一個或者多個代表須要重試的URI新地址。這個應答交給INVITE服務端事務層,由服務端事務層負責應答的重發。
13.3.1.3 INVITE請求的拒絕
拒絕INVITE請求的常見情景是被叫方不想或者不能在終端系統上接收這個呼叫。486(用戶忙)應當在這樣的狀況下返回。若是UAS知道沒有其餘終端系統可以響應這個呼叫,就應當返回一個600(Busy Everywhere)。不過,一般狀況下UAS是不太會知道這個狀況的,而且這個應答也是罕見的。這些應答是交給INVITE服務端的事務層進行發送的,由這個事務層來保證應答的重發機制的。若是UAS拒絕的是INVITE請求包含的媒體磋商offer,UAS應當返回一個488(Not Acceptable Here)應答。這個應答應當包含一個Warning頭域來解釋爲什麼offer被拒絕。
13.3.1.4 接受INVITE請求
UAS核心產生一個2xx應答。這個應答創建一個對話,而後遵循8.2.6節和12.1.1節的描述進行處理。
響應INVITE請求的2xx應答包含Allow頭域和Supported頭域,而且可能包含Accept頭域。包含這些頭域的目的是爲了讓UAC不須要再次請求就可以知道UAS的特性以及UAS的擴展支持。
若是INVITE請求包含了一個媒體磋商請求offer,而且UAS尚未發送應答,2xx應答中必須包含針對這個offer的應答。若是INVITE請求沒有包含這個offer,並且UAS也還沒有發出offer,2xx應答必須包含這個媒體磋商offer。
當應答構建好了之後,它會交給INVITE的服務端事務層進行發送。注意,INVITE的服務端事務將會因爲收到這個終結應答而且交給通信層進行發送而銷燬。所以,有必要在沒有收到ACK的時候,每隔必定的時間就直接交給通信層進行發送。2xx交給通信層進行發送的時間間隔是從T1秒開始,而且每次發送後就加倍,直到到達T2秒的時間間隔(T1和T2的時間間隔定義在17節)。當收到了針對這個應答的ACK請求以後,重發就終止了。這個是與使用什麼通信協議來發送這個應答是無關的。
因爲2xx的重發是端到端的,而且在UAS和UAC之間存在採用UDP通信的節點。因此要保證經過這些節點進行可靠的傳送,就必須採用間隔時間重發的機制,哪怕UAS自己的通信機制是可靠的。
若是服務端的對2xx應答的重發通過了64×T1秒尚未收到ACK請求,那麼dialog就認爲是confirmed,可是會話卻應當終止。這個是用過15節描述的方法發送BYE請求來結束。
14 更改已經存在的會話
一個成功的INVITE請求(13節)既會建立一個基於兩個用戶之間的對話,也會基於請求/應答模式(offer-answer)建立一個會話。12節講述瞭如何經過target refresh 請求來修改一個現存的會話(好比,修改對話的remote target URI)。本節描述如何修改實際的會話(session)。
這個修改能夠包括修改地址或者端口、增長媒體流、刪除媒體流等等。這是經過發起新的INVITE請求來完成的,而且這個新的INVITE請求是基於創建會話所相同的對話的。在一個現存對話中發出INVITE請求就是re-INVITE.
注意,單個的re-INVITE請求能夠同時更改對話和會話的參數。
呼叫方或者被叫方均可以更改現存的會話。
在本協議中,UA檢測本地媒體有效性是基於自身的策略的。可是,咱們並不建議自動產生re-INVITE或者BYE請求,由於這樣可能會致使網絡上的阻塞。在任何狀況下,若是某些消息將被自動發送,那麼他們應當等待一個隨機的時間間隔。
注意,上邊的這些描述是特指自動產生的BYE和re-INVITE。若是用戶因爲媒體不兼容而掛機,UA應當正常發出BYE請求,而不視爲自動產生的BYE。
14.1 UAC行爲
與INVITE相同的會話描述磋商offer-answer模式(13.2.1節)在re-INVITE中也同樣採用。假設UAS但願增進一個媒體流,那麼UAC將會建立一個新的offer包含這個媒體流,而且發送INVITE請求給他的對方。特別須要注意的是,這個會話的全描述,而不是變化部分須要傳送。這個支持無狀態的會話處理,而且支持錯誤恢復機制。固然,UAC能夠發送一個re-INVITE請求而不包含會話描述,在這樣的狀況下,就是在這個re-INVITE的第一個可靠的非失敗的應答中將會包含這個會話描述offer(在這個規範中,就是2xx應答)。
若是會話描述格式具備版本號碼,那麼這個磋商的offer應當標誌這個變化了的媒體描述版本。
re-INVITE請求中的To,From,Call-ID,Cseq,Request-URI頭域應當和正常的在對話中的請求構造方法同樣(12節)。
在re-INVITE請求中,UAC能夠選擇不增長一個Alert-Infor頭域或者具備Content-Disposition=」alert」的消息體。由於UAS一般不會要求提示操做者來響應這個re-INVITE請求。
和INVITE不一樣的是,INVITE能夠分支(分岔成爲多份INVITE),re-INVITE是不會分支的,因此,只會由一個單個的終結應答。re-INVITE不會分岔的緣由是由於Request-URI標誌的是創建對話的UA的目標地址,而不是用戶的address-of-record地址。
須要注意的是,在相同的對話中,UAC不能在上一個INVITE請求完成前(不管是那一方發起的INVITE)再次發起一個新的INVITE。
1、 若是有正在處理的INVITE客戶事務,TU必須等待這個事務終結或者完成,才能初始化一個新的INVITE。
2、 若是有正在處理的INVITE服務事務,TU必須等待這個事務確認或者終結,才能開始處理一個新的INVITE。
不過,UA能夠在INVITE事務正在處理的同時,處理一個普通的事務。也能夠在一個普通事務正在處理的同時來初始化一個INVITE事務。若是UA接收到一個針對re-INVITE的非2xx終結應答,則會話參數不能改變,應當就像沒有收到過這個re-INVITE請求同樣。注意,就像在12.2.1.2節一開始講的那樣,若是非2xx終結應答是一個481(Call/Transaction Does Not Exists),或者一個408(Request Timeout),或者徹底沒有re-INVITE請求的應答(也就是說從INVITE客戶事務端返回一個超時),UAC會終止這個對話。
若是UAC收到一個re-INVITE的491應答,他應當啓動一個值爲T的時鐘,這個T的取值以下:
1、 若是UAC是這個dialog ID的Call-ID的擁有者。(也就是說是UAC產生的Call-ID),那麼T取值爲一個2.1到4秒的隨機數,單位是10毫秒。
2、 若是UAC並不是是dialog ID的Call-ID的擁有者,T應當取值是0到2秒的隨機數,單位是10毫秒。
當這個時鐘到了,若是UAC還但願再次嘗試更改會話參數,UAC應當再次嘗試re-INVITE請求一次。這個意思是說,若是這個呼叫已經被BYE所掛掉了,那麼re-INVITE請求就沒有再發的必要。
發送re-INVITE請求的規則,以及針對re-INVITE請求產生的2xx應答而產生的ACK請求的發送規則,等同於初始的INVITE請求(13.2.1節)。
14.2 UAS行爲
13.3.1節描述了區分初始的INVITE請求和re-INVITE請求的方法,以及處理對現存的對話中處理re-INVITE請求的步驟。
UAS在發送第一個INVITE的終結應答以前,收到第二個INVITE請求,而且這個請求的Cseq序列號大於第一個INVITE請求,那麼就應當給第二個INVITE請求返回一個500(服務器內部錯誤)應答,而且必須包含一個Retry-After頭域,這個頭域中應當包含一個0-10秒的隨機數。
若是UAS正在處理一個INVITE請求的時候又收到了一個在同一個對話上的INVITE請求必須返回一個491(Request Pending)應答給接收到的INVITE。
若是UA接收到一個對現存的對話的re-INVITE請求,那麼就必須檢查有關會話描述(session description)的版本標誌(version identifiers),或者,若是沒有版本標誌,那麼就須要檢查會話描述的正文看看有沒有變化。若是會話描述改變了,UAS必須由此調整會話參數,在調整參數的時候可能會要求用戶確認。
會話描述的版本能夠用來提供給會議的新近加入者,增長或者刪除媒體,或者由單點會議更改爲爲多方會議。
若是新的會話描述是不能被UA接受的,UAS能夠用返回一個488(Not Acceptable Here)來拒絕這個re-INVITE請求。這個響應應當包含一個Warning頭域(用來提供給請求方,提供這個拒絕的緣由)。若是UAS產生一個2xx應答,可是沒有收到ACK,它應當產生一個BYE來結束這個對話。
UAS能夠不產生180(Ringing)應答給re-INVITE,由於UAC通常不展現這個信息給用戶。一樣的,UAS能夠增長一個Alert-Info頭域或者一個由Content-Disposition「alert」的消息體來應答給re-INVITE來讓UAC展現這個信息。
若是UAS在2xx應答中提供了一個媒體磋商offer(由於INVITE沒有包含一個offer),那麼它應當看成新呼叫同樣的構造這個offer,就像在[13]中SDP描述同樣,遵循發送更改現有的會話的offer的限制。特別須要注意的是,這個意味着它應當包含所有的UA支持的媒體類型和媒體格式。UAS必須確保會話描述在媒體格式,通信方式,或者其餘要求對方支持的參數上,新的會話描述和舊的會話描述同樣。這個能夠避免對方拒絕這個會話描述。若是,UAC任然是不能接受這個會話描述,UAC應當產生一個它可以接受的會話描述應答,而且發送一個BYE來結束這個會話。
15 結束一個會話
本節描述告終束由SIP創建的會話的步驟。會話的狀態和對話的狀態是密切相關的。當一個會話由INVITE創建的時候,每個由不一樣UAS的1xx或者2xx的應答建立一個對話,而且當完成了會話描述的請求/應答(offer/answer)交互以後,它也就建立了一個會話。這就是說,每個會話都和單個對話」相關」-會話是對話所建立的。若是初始化的INVITE產生了非2xx的終結應答,它也終結了由本次請求建立的任何會話(若是有的話),而且終結了全部的本次請求建立的對話(若是有的話)。因爲事務完整性的保證,一個非2xx的終結應答一樣也防止了本次INVITE之後可能建立的會話。BYE請求用於終結指定的會話或者嘗試創建的會話。在這裏,特定的會話是一個和與之相對的對話的對方UA。當在對話中接收到了一個BYE,任何與該對話相關的會話都應當終止。UA禁止在對話外發送BYE請求。請求方UA能夠在已經創建好的對話或者早期對話中發起BYE請求;被叫方只能在創建好的對話中發起BYE請求,不能在早期對話中發起BYE請求。
不過,在一個創建好的對話中,被叫方的UA不能在接收到對應2xx應答的ACK請求前發送BYE請求,或者不能在服務器事務超時前發送BYE請求。若是沒有SIP擴展定義了和這個對話相關的其餘應用層狀態,這個BYE請求一樣結束了對話。
在對話和會話中,給INVITE的非2xx的終結應答,使得使用CANCEL比較有吸引力。CANCEL是嘗試強制給INVITE請求一個非2xx應答(好比,487應答)。所以,若是UAS但願放棄整個呼叫,它能夠發送一個CANCEL。若是INVITE會有2xx終結應答,這個意味着UAS在CANCEL正在處理的時候,接收到一個邀請。UAC能夠繼續用這個2xx應答創建會話,也能夠用BYE終結這個會話。(這個意思是說,通常狀況下,若是UAC但願cancel 這個INVITE請求,那麼就會發出CANCEL請求,若是接收到了非2xx的終結應答,就意味着CANCEL掉了,可是若是接收到的仍是2xx應答,就說明沒有CANCEL掉,沒有CANCEL掉呢,就能夠選擇繼續創建會話,或者說發送一個BYE來終結會話)
在SIP中,並無一個很好的」hangin up」(掛機中)定義。它屬於一個用戶界面的普一般見的細節。一般,當用戶掛機,它意味着結束創建會話的嘗試,而且終止全部已經創建的會話。對於呼叫方的UA來講,若是沒有收到初始INVITE請求的終結應答,這個多是產生對初始INVITE請求的一個CANCEL請求,而且收到終結應答以後給每個創建好的對話發出一個BYE。對於被叫方的UA,就是很普通的BYE;粗略來講,當用戶(由於響應振鈴)摘機,就會產生一個2xx應答,因而掛機會在收到ACK請求以後發送一個BYE。這不是說在收到ACK以前用戶不能掛機,這只是表達在用戶的電話中的軟件,須要保持一小會兒狀態,來正確釋放狀態。若是某個UI(用戶界面)容許用戶在不摘機的狀況下拒絕呼叫,能夠用403(Forbidden)來做爲INVITE的應答,在這樣的狀況下,BYE就不能發送。
15.1 使用BYE請求終止一個會話
15.1.1 UAC行爲
BYE請求就像其餘在對話內的請求同樣的構造,參見12節的描述。
當BYE請求建立好了以後,UAC核心處理部分建立一個新的非-INVITE客戶端事務,而且用它來處理BYE請求。UAC必須認爲當BYE請求一發送到客戶端事務,會話就結束了(所以也就中止發送或者接收媒體流)。若是BYE請求的應答是481(Call/Transaction Does Not Exists)或者408(Request Timeout)或者BYE請求壓根沒有應答(就是說客戶端事務返回一個超時),UAC必須認爲會話和對話都已經結束。
15.1.2 UAS行爲
UAS首先按照通用的UAS接收到請求的處理步驟進行BYE請求的處理(8.2節)。UAS核心處理部分接收到BYE請求之後,首先檢查它是否和現存的對話匹配。若是BYE並不匹配現存的任何一個對話,那麼UAS應當產生一個481(Call / Transaction Does Not Exists )應答,而且傳送給服務器事務。
這個規則意味着若是UAC發送沒有帶tag標誌的BYE請求會被拒絕。這個是一個對RFC2543的改動,RFC2543容許BYE不帶tag標誌。
UAS核心處理部分接收到BYE請求,而且發現和現存的對話匹配,那麼它必須遵循12.2.2的步驟來處理請求。一旦處理完成,UAS應當終止這個會話(所以中止發送和接收媒體流)。惟一一個能夠選擇不終止的狀況是多方會話,在多方會話中參與者容許對話中的其餘參與方終止他們本身的會話。無論是否終止會話中的參與方,UAS核心處理都必須給BYE產生2xx的應答,而且必須由服務器的通信層進行傳輸。
UAS必須依舊響應在這個對話中接收到的未決的請求。咱們建議用487(請求終止)來給這些未決的請求以應答。
16 proxy行爲
16.1 概述
SIP代理服務器是路由SIP請求到UAS的,而且路由SIP應答到UAC的。一個請求可能經過多個proxy到達UAS。每個都會做出路由決定,在發送給下一個節點前對請求作一點修改。應答會經過和請求相同的proxy路徑,只是順序是逆序的。
proxy是一個SIP邏輯上的概念。當接收到一個請求,在作代理服務器以前,首先應該有一個部件來決定是否自身須要響應這個請求。例如,在做爲代理服務器處理請求以前,首先斷定請求多是非法的或者請求須要一個信任狀。這個元素能夠使用任何合適的錯誤代碼來響應這個請求。當直接應答請求的時候,這個元素(proxy)將做爲UAS角色,而且必須遵循8.2節描述的UAS行爲規範。
proxy對於每個新的請求來講,既能夠做爲有狀態的也能夠做爲無狀態的模式來處理。看成爲無狀態的處理模式的時候,proxy就是簡單的轉發。它轉發每個請求下行到一個由請求所決定的目的地。而且簡單轉發從上行流取得的應答。一個無狀態的proxy在處理完一個消息以後就會丟棄這個消息的相關資料。有狀態的proxy會保留這些信息(尤爲是事務信息),保留每個接收的請求和每個接收請求的應答的相關信息。它保留這些信息用於處理與這個請求相關的後續消息。一個有狀態的proxy能夠選擇」分支」一個請求,路由它到多個地點。任何被路由到多個地點的請求都必須看成有狀態的處理。在某些狀況下,proxy能夠用有狀態的通信協議(好比TCP)來轉發請求,而不用自身成爲事務有狀態的。例如,proxy能夠簡單轉發請求從一個TCP鏈接到另一個TCP鏈接,而不用自身做爲有狀態的,只要它放置足夠的信息在須要轉發的消息裏,使得可以正確把應答發送到接收到對應請求的鏈接發送出去。若是在不一樣傳輸通信協議之間進行請求的轉發,那麼就必需要求proxy的TU採用某種手段來保證可靠的從一個協議有狀態的轉到另外一個協議。
有狀態的proxy能夠在處理請求中的任什麼時候候轉換成爲無狀態的,只要它不做任何可能致使不能無狀態的操做(好比分支,好比產生100應答)。當作這樣的轉換的時候,全部的狀態就只是簡單的廢棄掉。proxy不該當發起一個CANCEL請求。
在做爲無狀態的或者有狀態的時候,處理請求的步驟是同樣複雜的。接下來的步驟是從有狀態的proxy角度來些的。最後一節是講述無狀態proxy的區別。
16.2 有狀態的proxy
做爲有狀態的proxy,它必須是一個純粹的SIP事務處理引擎。它在這裏的定義遵循17節講述的服務端和客戶端的事務處理規定。有狀態的proxy有一個服務端事務,這個事務與一個或者多個客戶端事務相關,這些客戶端事務是由高層proxy處理元素產生的(圖3),這些高層proxy處理元素就是proxy處理核心。一個輸入的請求是經過一個服務端事務來處理的。請求由服務端事務交給proxy處理核心進行處理。proxy處理核心檢查請求應當路由到哪裏,選擇一個或者多個下一個節點。每個發往下一個節點的外發請求都由客戶端事務進行處理。proxy處理核心從客戶端事務中獲得請求的應答而且把他們的應答交給服務端事務進行發送。
有狀態的proxy爲每個接收到的新的請求建立一個服務端事務。任何請求的重複都是由這個服務端事務來處理(參見17節)。proxy處理核心必須遵循UAS的模式,發送一個直接臨時應答(好比100 trying)到這個服務端事務上(8.2.6節)。所以,有狀態的proxy不該當給非INVITE請求產生100(trying)應答。
這是一個proxy的模型,並不是軟件實現。在實現上能夠擴展而且複用用這個模型定義。
對於全部的新請求來講,包括那些未知方法的請求,proxy處理請求必須:
1、 驗證請求(16.3)
2、 預處理路由信息(16.4)
3、 決定請求的目的(targets)(16.5)
+--------------------+
| | +---+
| | | C |
| | | T |
| | +---+
+---+ | Proxy | +---+ CT = Client Transaction
| S | | "Higher" Layer | | C |
| T | | | | T | ST = Server Transaction
+---+ | | +---+
| | +---+
| | | C |
| | | T |
| | +---+
+--------------------+
Figure 3: Stateful Proxy Model
4、 轉發請求到每個目的地(16.6)
5、 處理全部的應答(16.7)
小虎 2006-05-25 00:07
16.3 驗證請求
在proxy轉發請求以前,它必須檢查消息的合法性。一個合法的消息必須通過以下的檢查:
1、 合法的語法
2、 URI scheme
3、 最大轉發次數
4、 (可選)循環檢測(loop detection)
5、 proxy-require
6、 proxy-authorization
若是任何一步失敗了,proxy都必須做爲UAS(8.2)同樣,應答一個錯誤碼。
注意proxy並不要求檢查合併的請求,而且不能把合併的請求看成一個錯誤的狀況。終端接收到合併的請求會根據8.2.2.2節講述的內容進行分解。
1、 合法的語法。
請求要可以被服務端事務處理,那麼請求就必須是語法無誤的。請求中的任何與檢查相關的部分或者與請求轉發節相關的部分都必須語法嚴格無誤。在檢查中,其餘部分的嚴格與否,在檢查中都被忽略,而且在轉發消息過程當中保持不變。例如,proxy不會因爲非法的Date頭域而拒絕請求。一樣的proxy不會在轉發請求的時候移去非法的Date頭域。這個是爲了設計成爲可擴展的。之後的擴展可能定義新的方法、新的頭域。proxy不能拒絕因爲包含了不認識的方法或者不認識的頭域而拒絕轉發這個請求。
2、 URI scheme檢查
若是Request-URI包含一個proxy所不能理解的URI形式,那麼proxy應當經過返回一個416來拒絕這個請求(Unsupported URI scheme)。
3、 最大轉發次數檢查
最大轉發次數Max-Forwards頭域(20.22)是用來限制轉發的次數的。若是請求沒有包含Max-Forwards頭域,那麼這個檢查將被忽略。若是請求包含了一個Max-Forwards頭域,而且這個頭域大於0,那麼這個檢查就跳過。若是請求包含一個Max-Forwards頭域,而且這個頭域爲0,那麼這個proxy不能轉發這個請求。若是請求是OPTIONS請求,那麼proxy能夠做爲最終響應者來響應這個請求,而且遵循11節講述的產生應答。不然proxy應當返回一個483(too many hops)應答。
4、 可選的Loop Detection檢查
proxy能夠檢查看看轉發是否可能致使循環。若是請求包含一個Via頭域,而且這個頭域值,和proxy早先保留的請求的頭域值相同,那麼這個請求就是之前通過過本proxy。要麼這個請求就是循環處理了,要麼就是合法的循環處理。要檢測請求是否循環處理,proxy能夠用branch參數,根據16.6節的第8步來計算,而且和接收到的Via頭域作比較。若是參數相等,那麼請求就循環了。若是不等,那麼請求就是合理的通過,而且繼續處理。若是檢測到了循環,那麼proxy應當返回一個482(LoopDetechted)應答。
5、 Proxy-Require檢查
本協議的之後的擴展可能會要求額外的proxy特性。因此終端會在請求中包含一個Proxy-Require頭域來代表會使用到那些特性,這樣proxy就能夠根據Proxy-Require斷定本身是否可以支持這些特性。
若是請求包含一個Proxy-Require頭域(20.29)而且有一個或者多個本proxy不能理解的option-tags。那麼這個proxy必須返回一個420(Bad Extension)錯誤,而且這個錯誤應答必須包括一個Unsupported(20.40)頭域列明瞭那些option-tags這個proxy不能支持。
6、 Proxy-Authorization 檢查
若是proxy要求在轉發請求以前進行身份認證,那麼必須根據22.3節中描述的那樣進行請求的檢查。22.3節也定義了proxy應當怎樣處理檢查失敗的狀況。
16.4 路由信息預處理
proxy必須檢查請求中的Request-URI部分。若是Request-URI包含了一個本proxy早先放在Record-Route頭域中的值(參見16.6,4),proxy必須用Route頭域中的最後一個值來替換Request-URI,而且從Route頭域中刪去這個值。proxy必須接着按照個修改後的請求進行處理。
這個只會在某元素髮送請求到proxy(proxy自己多是一個終端),而且這個請求是基於嚴格路由的。在接收到請求後重寫這個字段是必須的,由於要保持向後兼容性。同時也容許按照本規範實現的元素保護Request-URI經過嚴格路由的proxy(12.2.1.1節)。
這個要求並無強制proxy保留狀態來檢查其早先放在Record-Route頭域中的URI。做爲替換的方法,proxy只須要保留足夠的信息在那些URI裏邊,這樣,在之後出現的時候就能識別了。
若是Request-URI包含了maddr參數,proxy必須檢查這個參數來看看是否在proxy配置的可信任的地址列表或者可信任的區域列表中。若是Request-URI包含一個maddr參數,而且這個參數包含了一個proxy能夠信任的地址,而且這個請求是經過Request-URI中(指明或者缺省)的端口和協議接收到的,proxy必須抽掉maddr和其餘非缺省的端口和通信參數,而且繼續處理。
proxy可能收到一個帶有匹配maddr的請求,可是不是在URI中指出的端口和transport接收到的。這個請求須要經過指明的port和transport轉發到對應的proxy。
若是Route頭域的第一個值就是這個proxy,那麼proxy必須從請求中把它移去。
16.5 肯定請求的目的
接着,proxy計算請求的目的(或者多個目的地)。目的地集合能夠由請求的內容決定或者由絕對位置服務提供。目的地集合中的每個目的地都由URI來表達。
若是請求中的Request-URI包含了maddr參數,必須把Request-URI放在目標集合中,而且是做爲惟一一個目標URI,而且proxy必須按照16.6節中的約定進行處理。
若是Request-URI的區域並不是本proxy負責的區域,那麼Request-URI必須放在目標集合中,而且做爲惟一一個目標URI,而且proxy必須按照16.6節中的約定進行處理。
有不少種狀況都會致使proxy收到並不是本proxy負責的區域的請求。一個防火牆proxy處理外發的請求(就像HTTPproxy處理外發的請求)就是一個典型的例子。
若是請求的目標集合沒有像上邊講述的這樣預先設定,那麼這就意味着proxy是負責Request-URI所指明的區域的,而且proxy能夠用任何機制來決定往哪裏發送這個請求。這些機制均可以歸結成爲訪問一個絕對位置服務的形式。這個可能由從SIP註冊服務器建立的位置服務器得到信息、讀取數據庫、查閱服務器、利用其餘協議、或者就簡單的替代Request-URI來實現。當訪問由註冊服務器建立的位置服務的時候,在做爲索引查詢以前,Request-URI必須首先根據10.3節進行規範處理。這些機制的輸出結果將做爲目的地集合。
若是Request-URI沒有提供足夠的信息來讓proxy可以產生目的地集合,它應當返回一個485(Ambiguous)應答。這個應答應當包含一個Contact頭域包含一些應當嘗試的新位置。好比,一個到sip:John.Smith@company.com的INVITE可能在某一個proxy是不明確的,由於這個proxy有多個JohnSmith。21.4.23節有細節描述。
任何與這個請求有關的,或者與proxy當前環境有關的信息均可以用來構造目的地集合。例如,因爲請求的內容不一樣或者包頭域的不一樣,能夠有不一樣的目的地集合,又或者不一樣時間到達的請求也能夠有不一樣的目的地集合,或者不一樣的時間間隔,上一次失敗的請求,甚至是當前proxy的利用率均可以致使目的地集合的不一樣。
經過這些機制,咱們能夠有一個可能的目的地列表,他們的URI被增長到目的地集合。每個目的地只能在目的地列表中出現一次。若是目的URI已經在這個集合中存在了(基於URI類型的相等定義),那麼它不能再次增長。
若是原請求的Reuqest-URI指明的區域並不是本proxy所負責的區域,那麼本proxy不能增長任何額外的目的地到目的地集合。
若是proxy負責Request-URI所指明的區域,那麼這個proxy只能夠在轉發的時候改變請求的Request-URI。若是proxy並不是負責這個URI,那麼它不會在3xx或者416應答的時候查生遞歸。
若是原始請求的Request-URI是屬於本proxy負責的區域的,那麼proxy能夠在請求轉發的時候增長目的地。他能夠在處理過程當中,用任何能夠得到的信息來決定新的目的地。 例如,proxy能夠選擇把一個轉發應答(3xx)所包含的聯繫地址合併到目的地集合中。若是proxy使用一個動態的信息源來構造目的地集合(例如訪問SIP的註冊服務器),它應當在處理請求的過程當中監測這個信息源。當有新的目的地出現的時候,就應當加到這個目的地集合裏邊。就像上邊說得,每個URI只能在集合中出現1次。
只能出現1次的緣由是能夠下降網絡衝突,在合併重定向請求的聯繫地址的狀況下能夠防止無限遞歸的出現。
舉例來講,一個簡單的位置服務是一個」no-op」(無操做的),返回的目的URI就是輸入的請求URI。請求將送到一個特定的下一個節點proxy。在16.6節/6小節定義請求轉發中,經過SIP或者SIPS URI表達的,下一個節點的身份, 將在Route的頭域最上一層插入。
若是Request-URI是這個proxy所負責的,可是在本proxy中找不到,那麼proxy必須返回404(Not Found)應答。
若是目的集合通過上邊的處理依舊是空的,那麼proxy必須返回一個錯誤應答,這個錯誤應答應當是408(暫時不可用)。
16.6 請求轉發
當目的地集合不是空的時候,proxy能夠開始轉發這個請求。有狀態的proxy能夠按照任意的順序處理這個目的地集合。它能夠順序處理多個目的地,上一個完成前下一個不能開始。也能夠採用並行的處理多個目的地。也能夠經過分組的形式,每組之間是串行的,組內是並行的。
一般的處理順序機制是使用一個Contact頭域的qvalue參數來處理(20.10節)。目的地從最高的qvalue開始處理到最低的qvalue。相同qvalue的目的地能夠並行處理。
有狀態的proxy必須包含針對目的地集合的一個接收到應答和轉發出去的原始請求進行匹配的機制。爲了完成這樣的目的,這個機制是一個由proxy層在轉發第一個請求前建立的」response context」(應答上下文)來保障的。
對於每個目的地,proxy轉發請求都遵循下列步驟:
1、 拷貝一個接收到的請求
2、 更新Request-URI
3、 更新Max-Forwards頭域
4、 可選增長一個Record-Route頭域
5、 可選增長附加的頭域
6、 路由信息後處理
7、 決定下一個節點地址、端口、通信協議。
8、 增長一個Via頭域值
9、 若是須要,增長一個Content-Length頭域
10、 轉發這個新的請求
11、 設置定時器C
下面詳細介紹每一步。
1、 拷貝請求
proxy首先把接收到的請求作一個拷貝。拷貝必須包含接收到的請求的所有頭域。在接下來的處理步驟中未說起的頭域不能刪除。拷貝應當保留接收到的請求的頭域的順序。proxy不能用合併的域名來進行域值的從新排序(參見7.3.1)。proxy不能增長、修改、刪除消息體。
實際上,在實現中並不是只是作一個拷貝;首要的事情是爲每個下一個節點準備一個相同的請求。
2、 Request-URI
在拷貝好的請求中的Request-URI必須用目的地的URI進行替換。若是這個目的URI包含任何在Request-URI中所不能容許的參數,那麼這些參數必須被刪去。
這個步驟是proxy的本質步驟。proxy經過這個機制來把請求轉發到目的地。在某些狀況下,接收到的Request-URI會不做更改的添加到目的地集合中。對於這樣的目的地來講,上邊講的替換就等因而沒有任何操做。
3、 Max-Forwards
若是拷貝的頭域包含一個Max-Forwards,proxy必須把這個域值減一。
若是拷貝的頭域沒有包含一個Max-Forwards頭域,proxy必須本身增長一個頭域,缺省值是70。如今有一些UA不會在請求中填寫Max-Forwards頭域。
4、 Record-Route
(假設proxy接收到的這個請求會建立一個對話的狀況下),若是但願保留這個請求建立的對話中,後續的請求依舊是要通過本proxy,那麼本proxy必須增長一個Record-Route頭域值在這個拷貝中,而且增長的這個頭域值應當是在其餘現存的Record-Route頭域以前。經過請求創建的對話能夠包含一個預置的Route頭域。
若是這個請求已是一個對話的一部分,proxy若是但願之後這個對話的請求依舊通過本proxy,那麼proxy應當增長一個Record-Route頭域值。在12節描述的普通的終端操做中,這些Record-Route頭域值不會對終端使用的路由集合形成任何影響。
若是請求自己已經在對話中的話,若是proxy不增長一個Record-Route頭域在請求的包頭,後續的請求也會通過本proxy。可是,若是當終端中斷而且從新構造這個對話的時候,本proxy就會從對話所通過的節點中刪去。
一個proxy能夠在任何請求中增長這個Record-Route頭域值。若是請求並無初始化一個對話,終端將會忽略這個頭域值。12節講述了終端如何使用Record-Route頭域來構造Route頭域的。
在請求路徑上的每個proxy都是獨立的決定是否增長一個Record-Route頭域值的-在請求的Record-Route頭域上的值並不影響這個proxy決定增長仍是不增長Record-Route頭域值。
在Record-Route頭域中防止的URI必須是SIP或者SIPS URI。這個URI必須包含一個lr參數(參見19.1.1)。這個URI能夠和請求將被轉發的地方不一樣。這個URI不該當包含通信參數,除非該proxy確認在後續請求將會通過的下行節點中,都支持這個通信參數(好比本地網絡等等)。
本proxy提供的這個URI可能會讓其餘元素(其餘proxy)做出路由決定。本proxy,一般,並不知道其餘節點的處理能力,因此,它必須嚴格律己,讓本身遵循規範的SIP實現:SIP URI和TCP或者UDP通信協議。
在Record-Route中的URI必須指向插入它的元素(或者替代元素),這個意思是說經過附件[4]的服務器定位步驟能夠順利找到這個元素,這樣後續的請求才能順利到達同一個SIP元素。若是Request-URI包含一個SIPS URI,或者Route頭域的最上的值(通過後續第6步的處理)包含一個SIPS URI,那麼插入Record-Route頭域的值必須是一個SIPS URI。並且,若是請求不是基於TLS接受的,那麼proxy必須增長一個Record-Route頭域。在類似的狀況下,proxy若是從TLS上接收的請求,可是產生的是一個在Record-Route中或者Route頭域最上值中沒有SIPS URI的請求(在第6步後處理以後),必須在Record-Route頭域中增長一個非SIPS URI。
在安全範疇內的proxy必須在對話中保持這個安全範疇。
當Record-Route頭域的URI在應答中又從新到達的時候,若是這個URI值須要重寫的時候,這個URI必須是可以惟一肯定的URI。(就是說,請求可能會通過這個proxy好幾回,形成一個或者多個Record-Route頭域值的增長)。16.7節的第8步提供了一個可以讓這個URI惟一的一個機制。
這個proxy能夠在Record-Route頭域中增長一些參數。這些參數在某些請求的應答中會被反射(echo)回來,好比給INVITE請求的200(OK)應答。經過在消息的參數中保持狀態比在proxy中保持狀態更加有效。
若是proxy想在任何類型的對話中都保持在請求的路徑上(好比在跨越防火牆的對話中),它須要給每個接收到的請求中,都增長Record-Route頭域,即便是它所不能理解的方法的請求也要增長,由於這些方法多是對話相關的,具備對話語義的方法。
在Record-Route頭域中增長的URI只是在當這個請求建立對話的時候有效。舉一個例子,對於一個對話-有狀態的proxy(dialog-stateful proxy),當在對話結束後,若是再收到一個請求,這個請求的Request-URI的值中包含這個URI,那麼它就能夠選擇拒絕這個請求。一個對話狀態無關的proxy,固然,沒有對話結束的概念,可是他們能夠再這個值中填寫足夠多的信息,這樣就能夠在之後的請求來到的時候作對話的ID的比較,而且能夠選擇拒毫不匹配這個信息的請求。終端不能在對話外使用這個對話中的Record-Route頭域的URI。參見12節描述的終端使用Record-Route頭域的細節。
當proxy須要查看全部對話中的消息的時候,咱們就須要Record-routeing。可是,他會下降處理性能和影響擴展性,所以proxy應當只在特定狀況下使用record-route。任何初始化一個對話的SIP請求均可以適用Record-Route。在本文檔中,只有INVITE請求是能夠適用的,之後的擴展文檔可能包含其餘的方法。
5、 增長附加的頭域
在這一步,proxy可能增長其餘適當的頭域。
6、 處理路由信息
proxy能夠有一個本地的策略,這個策略要求請求在傳遞到目的地以前,必須經歷一個proxy集合。這樣的proxy必須可以確保全部的相似的proxy都是鬆路由(loose routers)的。一般,只有當這些proxy都是在相同的區域管理的時候,咱們纔可能知道這些proxy是否都是鬆路由的。這個proxy的集合是經過一組URI的集合表示(每個都包含一個lr參數)。這個集合必須被放置到Route頭域中,而且放置在其餘頭域值以前。若是Route頭域不存在,必須增長一個Route頭域,包含這組URI的列表。
若是proxy有一個本地策略要求請求通過一個指定的proxy,在壓棧Route頭域以外的一個方法就是旁路下邊的第10步的邏輯轉發,而是直接發送這個請求到這個指定的proxy的地址,端口,和協議。若是請求有一個Route頭域,這個額外的方法就不能用了,除非它知道下一個節點proxy是一個鬆路由的節點。不然,使用上邊講的增長Route頭域的方法會更有效,更靈活,適應性更好,而且操做更一致。並且,若是Request-URI包含了一個SIPS URI,這個proxy必須用TLS來進行通信。
若是請求的拷貝中包含了Route頭域,這個proxy必須檢查這個Route頭域的第一個值。若是這個URI並無包含lr參數,那麼proxy必須根據下列步驟修改這個請求:
- proxy必須把Request-URI放在Route頭域中的最後一個值。
- proxy必須把第一個Route頭域的值放在Request-URI中,而且從Route頭域中刪去。
把Request-URI添加到Route頭域的最後是爲了讓Request-URI的信息可以經過嚴格路由的proxy。」Popping」彈掉第一個Route頭域值到Request-URI中是爲了可以讓嚴格路由元素可以接收到這個請求(而且用它本身的在Request-URI中的URI和在Route頂部下一個節點的URI)。
7、 肯定下一個節點的地址,端口和通信協議。
proxy能夠有本身的策略來決定發送請求到特定的IP地址,端口和transport,能夠和Route的值或者Request-URI的值無關。當本proxy不能肯定對應ip,端口,transport的服務器是一個鬆路由(loose router)的時候,這樣的策略就不能使用了。可是,除了Route頭域應當像上邊講的這樣使用,咱們並不推薦這樣的發送請求的機制。
在沒有這樣一個替代機制的時候,proxy應用附件[4]的步驟來決定應當向哪裏發送這個請求。若是proxy從新規格化請求,而且發送到一個像上邊6點講的嚴格路由的元素,proxy必須應用這些步驟到請求中的Request-URI。不然,若是Route頭域存在,proxy必須應用這些步驟到Route頭域的第一個值;若是Route不存在,proxy必須應用這些步驟到Request-URI。這些步驟最終獲得一個序列集合(地址,port,transport)。與使用那個URI做爲附件[4]處理的輸入,若是Request-URI指定了一個SIPS URI,那麼proxy必須把輸入[4]的URI看成是SIPS URI而後遵循[4]的處理步驟進行處理。
就像在附件[4]中講述的,proxy必須嘗試序列集合中的第一組元素,而且依次嘗試序列集合中的每一組元素,直到成功爲止。
對於每一組的嘗試,proxy必須按照這組的通信要求,對消息進行適當的格式化,而且用一個新的客戶端事務(第8到第10點講述的),進行請求的發送。
因爲每一組的發送都是使用心得客戶端事務,這就體現了一個新的分支。於是,第8步插入的Via頭域中的分支參數必須每組發送的都不同。
若是客戶端事務報告發送請求失敗,或者它自身的狀態機超時,proxy就應當繼續處理序列集合中的下一組元素。當遍歷完序列集合以後,請求就不能發送到目的地集合。proxy不須要在應答上下文中放什麼應答,然而在別的方面卻須要就像從目的地集合收到一個408(Request Timeout)終結響應同樣的操做。
8、 增長一個Via頭域值
proxy必須在請求的拷貝中增長一個Via頭域值,而且在其餘Via頭域值以前增長。這個值的構造能夠參見8.1.1.7。這意味着proxy須要計算本身的分支參數,而且應當是全局惟一的分支,而且包含必要的magic cookie。注意這意味着若是請求循環通過本proxy的時候(也就是數次通過同一個proxy),每次的分支參數都不一樣。
在proxy構造分支參數的值上,有一個附加的約束,用來進行循環的檢測。一個要檢測循環的proxy應當建立一個由兩部分組成的分支參數。第一部分必須知足8.1.1.7的約束。第二部分是用來作循環檢測的,而且是從螺旋中斷定是否存在循環(請求數次通過同一個proxy是正常的,這是螺旋,可是若是是循環,那就不正常了。假定proxy是X,CàX,XàY,YàZ,ZàX,XàA,Aà目的地是正常的,可是若是CàX, XàY, YàZ, ZàX, XàY, 這就是循環了)。
循環檢測是經過這樣的方法檢測的:當請求返回給一個proxy,與處理請求相關的字段並未改變,那麼這個就是循環了。這個分支參數的後一部分應當反應全部的這些頭域(包括全部的Route,Proxy-Require和Proxy-Authorization頭域)。這是確保若是請求從別處從新路由回來,並且這些字段改變了,那麼這就是一個螺旋而不是循環(參見16.3)。一般創建這個比較值的方法是計算一個hash值,經過基於To tag,From tag,Call-ID頭域,收到請求的Request-URI(而不是通過處理事後的Request-URI),Via頭域的最上一個,Cseq頭域的序列號,任何附加的Proxy-Require或者Proxy-Authorization頭域。具體的hash算法是基於實現相關的,可是MD5(RFC1321[35]),用16進製表達,是一個有道理的選擇。(基於64位表達的是不太合適的)。
若是proxy但願檢測循環,那麼」branch」參數必須用包含可能影響處理請求的所有信息構成,包括輸入的Request-URI和其餘可能會影響proxy處理路由的字段,經過計算獲得。這是檢測循環所必須的,由於若是請求在路由相關的字段改變之後,從新發回這個服務器,那麼新的處理可能會發送到另外的地方,而不是形成一個循環。
在branch參數的計算上,請求的方法不能計算進去。可是做爲特例,CANCEL和ACK請求(給非2xx應答的)必須和他們對應的請求有相同的branch值。branch參數用於在服務器處理這些請求的時候體現請求之間的相關性(17.2.3和9.2)
9、 若是須要,增長一個Content-Length頭域
若是請求會經過一個基於流的通信協議發送到下一個節點,而且發送的請求拷貝中沒有包含一個Content-Length頭域,那麼proxy必須增長一個正確的請求包體大小在這個頭域(20.14)。
10、 轉發請求
一個有狀態的proxy必須爲這個請求建立一個新的客戶端事務(根據17.1節描述的那樣),而且指示事務層用第7步指定的地址,端口和協議進行發送。
11、 設定時鐘C
爲了可以處理INVITE請求沒有產生終結應答的狀況,TU使用一個定時器(稱做定時器C)。當INVITE請求被轉發的時候,必須爲客戶端事務設定一個定時器C。這個定時器C必須大於3分鐘。16.7節的2步講述了這個定時器是如何根據臨時應答來更新的,而且16.8節講述了定時器到時的處理步驟。
16.7 應答的處理
當proxy收到一個應答的時候,它首先嚐試定位一個與這個應答匹配的客戶端事務(17.1.3)。若是沒有匹配,proxy必須做爲無狀態的proxy來處理這個應答(即便這個應答是信息性質的應答)。若是與應答匹配的客戶端事務找到了,那麼這個應答將轉給這個客戶端事務進行處理。
將應答轉給對應的客戶端事務(或者更一般的說法是發出請求的或者相關的事務),並非爲了更強大的處理能力,它是保證了」晚到」的給INVITE請求的2xx應答可以正確的轉發。
當客戶端事務把應答交給proxy層,將會執行下列步驟:
1、 尋找適當的應答上下文。
2、 用臨時應答來更新定時器C
3、 從最上邊移除Via
4、 在應答上下文中增長應答
5、 檢查這個應答是否須要馬上發送
6、 若是須要,從應答上下文中選擇最好的終結應答。
若是在與這個應答上下文相關的每個客戶端事務都結束的之後,仍是沒有終結應答轉發,那麼proxy必須選擇從已經收到的應答中,選擇轉發」best」應答回去。
下列步驟必須在每個被轉發的應答上執行。就像每個請求有超過一個應答被轉發同樣:至少有一個終結應答和0個或者多個臨時應答。
7、 須要合併認證頭域值。
8、 可選的重寫Record-Route頭域值
9、 轉發應答
10、 產生合適的CANCEL請求。
上述每一步在下邊有詳細的描述:
1、 尋找上下文
proxy經過16.6節定義的方法來在尋找轉發原始請求前建立的」應答上下文」 。在這個上下文中進行後續的處理步驟。
2、 爲臨時應答更新定時器C
對於INVITE事務,若是應答是一個返回碼是101到199的臨時應答(就是說,除了100的臨時應答),proxy必須給這個客戶端事務從新設置定時器C。這個定時器能夠設置成爲其餘的值,和原始值不同,可是這個數字必須大於3分鐘。
3、 Via
proxy從應答中移去Via頭域中最上的值。
若是在這個應答中沒有這個Via頭域值,那麼應答的含義就是說這個應答不該當被這個proxy轉發。本節描述的後續處理步驟也不須要繼續處理,而是用8.1.3節定義的UAC處理規則進行處理(傳輸層處理已經進行)。
這種狀況可能會發生,好比,當某一個元素產生一個第10節規定的CANCEL請求。
4、 增長應答到上下文
收到的終結應答都會保存在應答的上下文中,直到收到一個由服務端事務產生的針對這個上下文的終結應答爲止。這個應答是從那個服務端事務中收到最佳終結應答的一個候選。即便這個應答不會被選中做爲最佳應答,這個應答的信息也須要用來構形成爲最佳應答。
若是proxy決定嘗試調用3xx應答返回的聯繫地址,而且把他們添加到目的地集合,它必須在把這個應答添加到應答上下文以前把聯繫地址從應答中移除。不過,proxy不該當在源請求的Request-URI是一個SIPS URI的狀況下,嘗試調用非SIPS URI。若是proxy嘗試每個3xx應答給回的聯繫地址,proxy不該當把這個應答添加到應答上下文中。
從應答中刪去聯繫地址的目的是爲了防止下一個節點嘗試本proxy已經嘗試的地址。
3xx應答可能包含SIP,SIPS和非SIP URI。proxy能夠自行決定本身調用那些SIP或者SIPS URI,而且把剩下的放在應答上下文中返回。
若是proxy收到一個對於一個Rquest-URI並不是SIP URI的請求的416(不支持的URI scheme)應答,可是原始請求的Request-URI是SIP或者SIPS(就是說,proxy在轉發請求的時候本身調換了請求的SIP或者SIPS爲一個什麼其餘的東西),proxy應當增長一個新的URI到目的地集合。這個URI應當是剛纔嘗試的非SIP URI的SIP URI版本。對於電話URL來講,這個就是把電話URL的電話號碼部分放在SIP URI的用戶部分,而且設置SIP URI的主機部分紅爲當前請求發送者的區域。19.1.6節有電話URL到SIP URI的轉換細節。
在3XX應答的狀況下,若是proxy在416上會產生」遞歸」(由於嘗試SIP或者SIPS URI而致使遞歸),那麼應當在應答上下文中增長這個416應答。
5、 檢查轉發的應答
當終結應答到達服務端事務的時候,下列應答包必須馬上轉發。
- 任何非100(trying)的臨時應答
- 任何2xx應答。
若是收到一個6xx應答,那麼就不馬上進行轉發,若是是有狀態的proxy,那麼還須要cancel全部的依賴於這個事務的客戶端(在10節中描述的那樣),而且不能在上下文中建立新的分支。
這個是和RFC 2543的不一樣之處,2543要求proxy馬上轉發6xx應答。對於一個INVITE事務來講,若是馬上轉發6xx應答,會使得2xx應答到達別的分支。這個結果就是讓UAC在2xx應答以後收到一個6xx應答,這個是不容許發生的。在新的規則下,基於接收到一個6xx應答,proxy應當產生一個CANCEL請求,那麼這個會給全部等待的客戶端事務一個487應答,這就是6xx應答應當給上行隊列的一個結果。
在服務端事務上發送了終結應答以後,下列的應答應當馬上被髮送:
- 任何給INVITE請求的2xx應答。
一個有狀態的proxy必須不能馬上轉發其餘的應答。特別是,一個有狀態的poxy必須不能轉發任何100(Trying)應答。這些應答是做爲後續將被轉發」最佳」應答的候選,經過上邊的」在上下文中增長應答」的步驟增長到應答上下文中。
任何將被馬上發送的應答都必須遵守」7、 須要合併認證頭域值。」和」8、可選的重寫Record-Route頭域值」來處理。
這一步,合併下一步,確保有狀態的proxy可以精確轉發一個終結應答到一個非-INVITE請求,或者給一個INVITE請求的非2xx應答或者一個或者多個2xx應答。
6、 選擇最佳的應答
對於一個有狀態的proxy來講,若是根據上邊的步驟,沒有任何終結應答被馬上發送,而且在客戶端事務中的全部的客戶端服務都已經終結,那麼這個proxy必須發送一個終結應答到一個應答上下文的服務端事務層。
那麼這個有狀態的proxy就必須從接收到的應答上下文中選擇一個」最佳」的終結應答。若是在上下文中沒有一個終結應答,那麼proxy就必須返回一個408(請求超時)的應答到服務端事務層。
若是應答上下文中有終結應答,那麼proxy就必須從這個應答上下文中取得應答來發送。若是應答上下文中有6xx應答,那麼就必須選擇這個6xx應答。若是沒有6xx應答,那麼proxy應當選擇最小的應答(應答返回代碼比較小)。proxy能夠選擇對應最小應答系列中的任意一個應答(好比2xx系列中的任意一個應答)。proxy應當給那些提供對影響請求的應答更多的機會,好比在4xx系列中,選擇401,407,415,420或者484應該稍稍優先一些。
當proxy收到503(Service Unavailable)應答的時候,不該當轉發到上行隊列中,除非它可以知道這個後續的請求隊列都能產生503的應答。換句話說,就是轉發503就意味着proxy確實不能處理任何請求,不只僅是Request-URI裏邊的這個地址不能處理請
小虎 2006-05-25 00:08
求。若是隻有某個應答會產生503,proxy應當產生500應當到上行隊列中。
被轉發的應答都必須遵守」7、 須要合併認證頭域值。」和」8、可選的重寫Record-Route頭域值」來處理。
例如,若是一個proxy轉發一個請求到4個地方,而且收到了503,407,501,和404應答,它可能選擇407(Proxy Authentication Required)應答。
1xx和2xx應答可能和創建對話有關。當請求沒有包含一個To tag,UAC使用在應答中的To tag來區分請求建立的對話的多個應答。若是請求中沒有包含To的tag,那麼proxy必須不能爲1xx或者2xx應答增長這個tag到To頭域。一個proxy不能修改1xx或者2xx應答中的To頭域的tag字段。
在請求的1xx應答中,若是應答沒有To頭域的tag字段的時候,因爲proxy不能添加tag字段到這個To頭域,它就不能產生它本身的非100臨時應答。可是它能夠把這個請求分支到其餘一個UAS上,這個UAS能夠和proxy共享一樣的元素。這個UAS能夠返回它本身的臨時應答,進入請求建立早期對話中。這個UAS並無必要做爲一個proxy的嚴格處理步驟存在。它能夠是一個在proxy內部的一個虛擬的UAS實現。
3到6xx的應答是節點到節點傳遞的。當產生了一個3-6系列的應答的時候,每個節點都做爲UAS同樣,產生它本身的應答,一般基於下行隊列的應答產生本身的應答。對於每個節點來講,在轉發3到6系列應答回去的時候,若是這個應答沒有包含To tag,那麼這個節點也應當不改變這個to tag。
當收到的應當包含了一個To tag,那麼這個proxy不可以修改這個To tag。
恩,實際上在proxy轉發3到6系列應答的時候,若是替換了To tag也不會讓上行隊列所通過的節點有影響,保留原始的tag值能夠有助於調試。
當proxy須要合併多個應答的信息的時候,從這些應答中選取To tag的方式是任意的,而且產生一個新的To tag可能能夠使得調試更加容易。舉例來講,當合並401(Unauthorized)和407(Proxy Authentication Required)信息的時候,或者合併一個未加密的Contact值和未經過驗證的3xx應答的時候,產生一個新的To tag就會讓調試比較容易。
7、 合併認證頭域值
若是選擇的應答是401(Unauthorized)或者407(Proxy Authentication Required),那麼proxy就必須從本應答上下文中的全部其餘401(Unauthorized)和407應答中搜集WWWAuthenticate和Proxy-Authenticate 頭域值。而且把這些信息增長到這個應答中。最後的401或者407應答中可能會包含多個WWWAuthenticate和Proxy-Authenticate頭域值。
因爲這個請求的一個或者多個目的地多是須要請求身份驗證的,因此這個蒐集步驟就是必須的。客戶端須要接收到這些全部目的者的應答而且在下一次嘗試的時候,爲每個目的地提供相關的身份證實。在26節有相關的說明。
8、 Record-Route
若是最終發送的應答中包含Record-Route頭域值,而且是這個proxy所原創提供的值,那麼在發送這個應答前,proxy可能須要重寫這個值。這提供了一個機制,讓proxy可以給下一個上行節點或者下行節點提供非本機的一個URI地址。這種狀況是很常見的,好比,在多地址主機系統就很是有用。
若是proxy是經過TLS收到請求的,而且經過非TLS轉發出去,proxy必須重寫在Record-Route頭域中的URI,重寫成SIPS URI。若是proxy經過非TLS接收到請求,轉發是經過TLS轉發的,那麼proxy必須重寫Record-Route請求頭域的URI爲一個SIP URI。
proxy提供的新的URI必須知足一樣的Record-Route頭域的URI約束(16.6節的第四步)。而且遵循下列的修改:
URI不該當包含通信參數除非proxy知道下一個上行(同下行隊列對應的)節點,對於後續的請求都支持相關的通信參數。
若是proxy打算修改應答中的Record-Route頭域,要作的一件事情就是定位插入的Record-Route頭域值。若是請求是螺旋通過的,而且proxy在每次螺旋的時候都插入了Record-Route值,在應答中(必須在反向路徑中的正確位置)找到正確的須要修改的值就須要一點技巧。上邊的規則強調proxy在增長Record-Route頭域值的時候是必須增長惟一的URI,這樣才能找到正確的一個可以重寫。咱們推薦proxy爲每個URI的user portion增長一個惟一個proxy實例標誌。
當應答到達的時候,proxy修改第一個和proxy實例標誌匹配的Record-Route。這個修改致使產生一個在user portion部分去掉proxy實例的URI。到下一個循環回來處理的時候,一樣的算法(用參數從上而下的尋找Record-Route頭域值)會更改這個proxy插入的下一個Record-Route頭域值。
對於proxy增長Record-Route頭域值的請求來講,並不是每個應答都包含一個Record-Route頭域。若是應答包含一個Record-Route頭域,那麼就包含這個proxy增長的值。
9、 轉發應答
當」合併認證頭域」和」Record-Route」步驟完成之後,proxy能夠對這個應答作其餘的附加處理。可是這個proxy不能增長、修改、刪除消息體。而且除非另有指示,除了Via頭域值(在16.7節3步)以外,proxy不能刪除任何頭域值。特別是,proxy不能刪除任何可能增長到與處理和這個應答相關的下一個請求的Via頭域值的」接收到」的參數。proxy必須把應答傳遞到跟這個應答上下文相關的服務端事務。這回致使應答發送到最上的Via頭域值的地方。若是服務端事務不在處理這個發送,這個節點必須做爲無狀態proxy轉發這個應答到服務端通信層。服務端事務可能已經標誌這個發送應答失敗或者內部狀態機已經設置成爲超時狀態。這些錯誤都應當記錄下來用於診斷錯誤,可是協議並無要求proxy作補救措施。
proxy必須維持應答上下文直到全部相關事務都已經終結,甚至在發送完成終結應答後還須要維持。
10、 產生CANCEL請求
若是轉發的應答是一個終結應答,proxy必須給依賴於這個應答上下文的全部客戶端事務,產生CANCEL請求。在收到6xx應答的時候,proxy一樣應當爲全部等待在這個應答上下文的客戶端事務產生CANCEL請求。等待的客戶端事務就是收到了臨時應答,可是沒有收到終結應答(仍是出於處理中的狀態),而且沒有任何CANCEL請求與之相關的請求。產生CANCEL請求請參見9.1節。
對於要求基於轉發終結應答而CANCEL的客戶端事務並無保證終端不會收到給一個INVITE的多個200(OK)應答。基於多餘一個分支的200(OK)應答可能會在CANCEL請求處理前到達。進一步說,後續的擴展可能會改掉這個產生CANCEL請求的要求。
16.8 處理定時器C
若是定時器C 被出發了,proxy必需要麼用另一個數值從新設定定時器,要麼終結客戶端事務。若是客戶端事務已經收到了臨時應答,那麼proxy必須產生一個與之匹配的CANCEL請求。若是客戶端事務尚未收到臨時應答,那麼proxy必須就像收到一個408(Request Timeout)同樣的處理。
容許proxy重設定定時器就意味着容許proxy基於當前條件(好比服務器利用率等等)動態的擴展事務的生命週期。
16.9 處理通信層的錯誤
若是在轉發請求(參見18.4)的時候,通信層報告了一個錯誤,那麼proxy必須就像收到了一個503(Service Unavailable)應答同樣的處理。
若是proxy在轉發應答的時候接收到錯誤,那麼他就丟棄應答。proxy不能因爲通信的緣由而cancel任何和這個應答上下文相關的客戶端事務。
若是proxycancel了這些客戶端事務,那麼一個惡意的或者出錯的客戶端能夠用一個Via頭域致使全部的事務都失敗。
16.10 CANCEL處理
一個有狀態的proxy能夠給他本身產生的其餘請求在任什麼時候候都產生CANCEL請求(參見9.1聽從接收到對應請求的一個臨時應答)。在接收到一個匹配的CANCEL請求的時候,proxy必須取消任何與應答上下文相關的客戶端事務。
當INVITE請求有一個Expires頭域而且這個頭域值已經超時的狀況下,一個有狀態的proxy能夠對這個處於pending的INVITE客戶端事務發出CANCEL請求。但是,一般來講,這是沒必要要的,由於相關的終端會發出結束事務的信號。
當有狀態的proxy在它本身的服務端事務上處理CANCEL請求的時候,並無新的應答上下文會建立。相反,proxy層尋找與這個CANCEL對應請求的現存的應答上下文。若是找到了對應的應答上下文,那麼這個節點應當馬上返回一個200(OK)應答給這個CANCEL請求者。在這個狀況下,這個節點就像8.2節定義的UAS同樣的工做。進一步說,這個節點應當爲每個依賴於這個上下文的客戶端事務產生一個CANCEL請求(就像在16.7節第10步描述的那樣)。
若是一個應答上下文沒有找到,這個節點就沒法CANCEL這個請求。它就必須像無狀態proxy同樣轉發這個CANCEL請求(可能這個節點把被CANCEL的請求在先前也看成無狀態的proxy轉發了)。
16.11 無狀態的proxy
看成爲無狀態的時候,proxy就是一個簡單的消息轉發者。不少無狀態的處理步驟和有狀態的時候很相似。不一樣的地方在下邊描述。
一個無狀態的proxy並無事務的概念,或者用於描述有狀態proxy行爲的應答上下文。相反的是,無狀態的proxy處理消息,不管是請求仍是應答,都是直接從通信層處理的(參見18節)。固然,無狀態proxy本身也不重發這些消息。他們只是轉發他們收到的任何重發的消息(他們自己並無能力來分辯那些消息是重發的,那些消息是原始消息)。進一步說,當無狀態的處理一個請求的時候,這個節點並不產生它本身的100(Trying)或者其餘臨時應答。
無狀態的proxy必須用16.3節描述的那樣來驗證一個請求。
無狀態的proxy必須聽從16.4到16.5節定義的步驟來處理請求,有以下幾點例外:
o 無狀態的proxy必須從目的地集合中,選擇一個而且只能選擇一個目的地。這個選擇必須是根據消息的頭域而且是和服務器時間無關的。特別是,一個重發的請求必須可以每次都轉發到相同的目的地。進一步說,CANCEL和非路由的ACK請求必須和他們相關的INVITE請求有相同的轉發目的地。
一個無狀態的proxy必須遵循16.6節定義的請求處理步驟,而且有下列的不一樣:
o無狀態proxy的branchID來講,必需要求在時間上和空間上都是惟一的。也就是說,無狀態的proxy不能簡單的使用一個隨機數產生器來計算branchID的第一個部分(16.6節8步)。這是因爲請求的重發須要相同的值,而且無狀態的proxy不能區分重發的請求和原始請求。所以,branch參數的組成部分要求惟一,這樣使得重發的時候可以填寫相同的值。對於無狀態的proxy來講,branch參數必須做爲一個重發無關的消息處理參數存在。
咱們沒有規定無狀態proxy採用何種手段保證branchID的惟一性。不過,下列步驟是推薦的方法。proxy檢查在接收到請求的最上Via頭域值的branchID。若是它是由magic cookie打頭的,那麼branchID的第一個部分就是看成接收到的branchID的hash值。不然branchID的第一個部分就看成是Via頭域的最上值、To頭域的tag、From頭域的tag,Call-ID頭域,Cseq序列號(除了方法部分),接收到的請求的Request-URI的一個hash值。這些頭域值在不一樣事務中老是不同的。
o全部其餘的消息轉換(16.6節)必須保證轉發重發的請求的時候可以轉發到相同的節點。特別是,若是proxy在Record-Route頭域中增長了值,或者在Route頭域中增長了值,proxy必須在轉發重發的請求的時候增長相同的值。至於Via 的branch參數,這就意味着轉發必須是基於時間無關的配置或者請求重發無關的屬性。
o一個無狀態proxy決定轉發的地點是像16.6節10步描述的有狀態的proxy同樣。可是請求是直接交給通信層發送的,而不是交給客戶端事務。
因爲一個無狀態的proxy必須轉發重發的請求到相同的地方,而且增長標誌性的branch參數,它只能用消息中自己的信息和時間無關的配置來計算。若是配置狀態不是時間無關的(好比,若是路由表更新了),這個改變相關的請求,在這個改動開始之後,到在事務超時的時間範圍內,就不能做爲無狀態的轉發了。這個處理這段時間的請求是實現相關的。一般處理的方法,是把這些請求看成事務有狀態的進行轉發。
無狀態的proxy必須不能對CANCEL作特別的處理。CANCEL的處理就像對其餘請求的處理同樣進行。特別是,一個無狀態的proxy使用相同的Route頭域來處理CANCEL請求,就像處理其餘請求同樣。
對於16.7節中定義的應答處理,對於無狀態proxy來講,並不適用。當一個應答到達一個無狀態proxy,proxy必須檢查最上的Via頭域值的sent-by參數。若是這個地址和這個proxy同樣(就是和proxy插入的先前的請求中的值同樣),那麼這個proxy必須從應答中移除這個頭域值,而且轉發這個應答到下一個Via頭域值。這個proxy必須不能增長,修改或者刪除消息體。除非有特別的說明,proxy必須不能移除其餘的頭域值。若是地址不匹配本proxy,消息就必須簡單的悄悄扔掉。
16.12 Proxy Route處理的總結
在沒有本地策略的狀況下,proxy對於包含Route頭域的請求處理能夠歸結於以下的步驟:
1、 proxy會檢查Request-URI。若是它指向的是本proxy所負責的區域,那麼proxy會用位置服務的結果來替換這個URI。不然,proxy不改變這個URI。
2、 proxy會檢查Route頭域的最上URI。若是這個URI指向這個proxy,這個proxy從Route頭域中移除(這個路由節點已經到達)。
3、 proxy會轉發請求到最上的Route頭域值所標誌的URI,或者Request-URI(若是沒有Route頭域)。proxy經過附件[4]的步驟來產生地址,端口,通信協議等等用來轉發請求所必須的參數。
若是在請求的路徑中,沒有嚴格路由節點,Request-URI會始終標誌着請求的目的地。
16.12.1例子
16.12.1.1 基本SIP四邊形
本例子是一個基本的SIP四邊傳送,U1->P1->P2->U2,使用proxy來傳送。下邊是過程。
U1 發送:
INVITE sip:callee@domain.com SIP/2.0
Contact: sip:caller@u1.example.com
發給P1,P1是一個外發的proxy。P1並無論轄domain.com,因此它查找DNS而且發送請求到那裏。它也增長一個Record-Route頭域值:
INVITE sip:callee@domain.com SIP/2.0
Contact: sip:caller@u1.example.com
Record-Route: <sip:p1.example.com; lr>
P2收到這個請求。這是domain.com因此它查找位置服務器而且重寫Request-URI。它也增長一個Record-Route頭域值。請求中沒有Route頭域,因此它解析一個新的Request-URI來決定把請求發送到哪裏。
INVITE sip:callee@u2.domain.com SIP/2.0
Contact: sip:caller@u1.example.com
Record-Route: <sip:p2.domain.com; lr>
Record-Route: <sip:p1.example.com; lr>
在u2.domain.com的被叫方接收到這個請求而且返回一個200OK應答:
SIP/2.0 200 OK
Contact: sip: callee@u2.domain.com
Record-Route: <sip:p2.domain.com;lr>
Record-Route: <sip:p1.example.com;lr>
u2的被叫方而且設置對話的狀態的remote target URI爲:
sip: caller@u1.example.com而且它的路由集合是:
(<sip:p2.domain.com;lr>,<sip:p1.example.com;lr>)
這個轉發經過P2到P1到U1。如今U1設置它本身的對話狀態的remote target URI爲:sip:calle@u2.domain.com而且它的路由集合是:
(<sip:p1.example.com;lr>,<sip:p2.domain.com;lr>)
因爲全部的路由集合元素都包含了lr參數,那麼U1構造最後的BYE請求:
BYE sip:callee@u2.domain.com SIP/2.0
Route: <sip:p1.example.com;lr>,<sip:p2.domain.com;lr>
就像其餘全部的節點(包括proxy)會作的那樣,它會使用DNS來解析最上的Route頭域的URI值,這樣來決定往哪裏發送這個請求。這就發到了P1。P1發現Request-URI中標記的URI不是它負責的域,因而它就不改變這個Request-URI。而後看到它是Route頭域的第一個值,因而就從Route頭域中移去,而且轉發這個請求到P2:
BYE sip:callee@u2.domain.com SIP/2.0
Route: <sip:p2.domain.com;lr>
P2也發現它本身並不是負責這個Request-URI的域(P2負責的是domain.com並不是u2.domain.com),因而P2並不改變它。它看到本身在Route的第一個值,因而移去這個,而且向u2.domain.com轉發(根據在Request-URI上查找DNS):
BYE sip:callee@u2.domain.com SIP/2.0
16.12.1.2 穿越一個嚴格路由proxy
在這個例子中,對話創建經過4個proxy,每個增長Record-Route頭域值。第三個proxy是由嚴格路由實現的(RFC 2543)。
U1->P1->P2->P3->P4->U2
INVITE請求到達U2包括了:
INVITE sip:callee@u2.domain.com SIP/2.0
Contact: sip:caller@u1.example.com
Record-Route: <sip:p4.domain.com;lr>
Record-Route: <sip:p3.middle.com>
Record-Route: <sip:p2.example.com;lr>
Record-Route: <sip:p1.example.com;lr>
而且U2返回了一個200 OK。接着,U2根據第一個Route頭域值發送下邊的BYE請求到P4:
BYE sip:caller@u1.example.com SIP/2.0
Route: <sip:p4.domain.com;lr>
Route: <sip:p3.middle.com>
Route: <sip:p2.example.com;lr>
Route: <sip:p1.example.com;lr>
P4並無論轄Request-URI指出的域,因而就不更改這個Reqeust-URI。它發現本身在第一個Route頭域中,因而把本身從Route頭域移除。而後準備發送請求到如今的第一個Route頭域值:sip:p3.middle.com,可是它發現這個URI並無包含lr參數,因而在發送前,它把這個請求更改爲爲:
BYE sip:p3.middle.com SIP/2.0
Route: <sip:p2.example.com;lr>
Route: <sip:p1.example.com;lr>
Route: <sip:caller@u1.example.com>
P3是一個嚴格路由,因而它轉發到P2:
BYE sip:p2.example.com;lr SIP/2.0
Route: <sip:p1.example.com;lr>
Route: <sip:caller@u1.example.com>
P2看到Request-URI是它放在Record-Route頭域中的值,因而在進一步處理前,它把這個請求改寫爲:
BYE sip:caller@u1.example.com SIP/2.0
Route: <sip:p1.example.com; lr>
P2本身並無論轄u1.example.com,因而它根據Route頭域的值,轉發這個請求到P1。
P1發現本身在Route頭域的最上,因而把本身移除,獲得:
BYE sip:caller@u1.example.com SIP/2.0
因爲P1並無論轄u1.example.com而且沒有其餘的Route頭域,P1會基於Request-URI轉發這個請求到u1.example.com。
16.12.1.3 重寫Record-Route頭域值。
在這裏例子中,U1和U2是在不一樣的私有域空間中,而且他們經過proxy P1開始一個對話,這個P1做爲不一樣私有namespace的一個網關存在。
U1->P1->U2
U1發送:
INVITE sip:callee@gateway.leftprivatespace.com SIP/2.0
Contact: <sip:caller@u1.leftprivatespace.com>
P1使用本身的定位服務而且發送下邊的信息到U2:
INVITE sip:callee@rightprivatespace.com SIP/2.0
Contact: <sip:caller@u1.leftprivatespace.com>
Record-Route: <sip:gateway.rightprivatespace.com;lr>
U2發送200 OK應答回給P1:
SIP/2.0 200 OK
Contact: <sip:callee@u2.rightprivatespace.com>
Record-Route: <sip:gateway.rightprivatespace.com;lr>
P1重寫它的Record-Route頭域參數,提供成爲U1可以使用的參數,而且發送給P1:
SIP/2.0 200 OK
Contact: <sip:callee@u2.rightprivatespace.com>
Record-Route: <sip:gateway.leftprivatespace.com;lr>
稍後,U1發送接下來的BYE到P1:
BYE sip:callee@u2.rightprivatespace.com SIP/2.0
Route: <sip:gateway.leftprivatespace.com;lr>
P1轉發到U2:
BYE sip:callee@u2.rightpriatespace.com SIP/2.0
17事務
SIP是一個基於事務處理的協議:部件之間的交互是經過一系列無關的消息交換所完成的。特別是,一個SIP 事務由一個單個請求和這個請求的全部應答組成,這些應答包括了零個或者多個臨時應答以及一個或者多個終結應答。在事務中,當請求是一個INVITE(叫作INVITE事務),當終結應答不是一個2xx應答的時候,事務還包括一個ACK。若是應答是一個2xx應答,那麼ACK並不認爲是事務的一部分。
這個分開的緣由是基於傳遞所有200(OK)應答到UAC的INVITE請求的重要性所決定的。要把全部的200應答所有發給UAC,那麼UAS獨自負責這些應答的從新傳送(參見13.3.1.4),UAC肚子負責挨個ACK確認(參見13.2.2.4)。因爲ACK的重傳只由UAC發起,因此在本身的事務中進行重傳會比較有效。
事務分爲客戶端和服務端兩方。客戶端的事務是客戶端事務,服務器端的事務就是服務端事務。客戶端事務發出請求,而且服務端事務送回應答。客戶端和服務端事務都是邏輯上的概念,他們能夠被無數部件所包含。特別是,他們在UA中和有狀態的proxy服務器中存在。以第四節的例子來講明。在這個例子中,UAC執行客戶端事務,它的外發proxy執行服務端事務。外發proxy同時也執行客戶端事務,把請求發送到一個那發proxy的服務端事務。這個proxy也同時執行一個客戶端事務,把請求發到一個UAS的服務端事務上去。這個在圖四中比較明白:
小虎 2006-05-25 00:08
+---------+ +---------+ +---------+ +---------+
| +-+|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:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
To: Bob <sip:bob@biloxi.com>
From: Alice <sip:alice@atlanta.com>;tag=88sja8x
Max-Forwards: 70
Call-ID: 987asjd97y7atg
Cseq: 986759 INVITE
給非2xx終結應答的ACK請求應當是:
ACK sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
To: Bob <sip:bob@biloxi.com>;tag=99sa0xk
From: Alice <sip:alice@atlanta.com>;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中表示。
小虎 2006-05-25 00:09
當收到一個不是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:bob@Biloxi.com SIP/2.0
Via: SIP/2.0/UDP bobspc.biloxi.com:5060
請求是從源IP:192.0.2.4收到的。在請求轉交到上層以前,通信層增長了一個」received」參數,這樣請求的部分就是:
INVITE sip:bob@Biloxi.com 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地址。若是存
小虎 2006-05-25 00:10
在」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的狀況。例如,爲了指定一個到alice@atlanta.com的呼叫,使用多點廣播到239.255.255.1,而且ttl=15,那麼應該使用下邊的一個URI:
sip:alice@atlanta.com;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:alice@atlanta.com
sip:alice:secretword@atlanta.com;transport=tcp
sip:alice@atlanta.com?subject=project%20x&priority=urgent
sip:+1-212-555-1212:1234@gateway.com;user=phone
sips:1212@gateway.com
sip:alice@192.0.2.4
sip:atlanta.com;method=REGISTER?to=alice%40atlanta.com
sip:alice;day=Tuesday@atlanta.com
最後一個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:%61lice@atlanta.com;transport=TCP
sip:alice@AtLanTa.CoM;Transport=tcp
sip:carol@chicago.com
sip:carol@chicago.com;newparam=5
sip:carol@chicago.com;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:alice@atlanta.com?subject=project%20x&priority=urgent
sip:alice@atlanta.com?priority=urgent&subject=project%20x
下列URI是不相等的:
SIP:ALICE@AtLanTa.CoM;Transport=udp (用戶名不一樣)
sip:alice@AtLanTa.CoM;Transport=UDP
sip:bob@biloxi.com (端口不一樣)
sip:bob@biloxi.com:5060
sip:bob@biloxi.com (通信協議不一樣)
sip:bob@biloxi.com;transport=udp
sip:bob@biloxi.com (通信協議和端口不一樣)
sip:bob@biloxi.com:6000;transport=tcp
sip:carol@chicago.com (header部件不一樣)
sip:carol@chicago.com?Subject=next%20meeting
sip:bob@phone21.boxesbybob.com (就算是phone21.boxesbybob.com
sip:bob@192.0.2.4 解析到192.0.2.4也不能算相等的。)
注意相等性是不能傳遞的。
好比 sip:carol@chicago.com 和sip:carol@chicago.com;security=on相等
sip:carol@chicago.com 和 sip:carol@chicago.com;security=off相等
可是:
sip:carol@chicago.com;security=on和sip:carol@chicago.com;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;postd=pp22@foo.com;user=phone
或者
sips:+358-555-1234567;postd=pp22@foo.com;user=phone
而不是
sip:+358-555-1234567@foo.com;postd=pp22;user=phone
或者
sips:+358-555-1234567@foo.com;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;postd=pp22@foo.com;user=phone
sip:+358-555-1234567;POSTD=PP22@foo.com;user=phone
倒是不等價的。
相似的:
tel:+358-555-1234567;postd=pp22;isub=1411
tel:+358-555-1234567;isub=1411;postd=pp22
是等價的,可是
sip:+358-555-1234567;postd=pp22;isub=1411@foo.com;user=phone
sip:+358-555-1234567;isub=1411;postd=pp22@foo.com;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;postd=pp22@foo.com;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;tsp=a.b@foo.com;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頭域意味着不接受任何格式。
小虎 2006-05-25 00:10
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: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@biloxi.com
i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6@192.0.2.4
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:watson@worcester.bell-telephone.com>;q=0.7;
expires=3600,
「Mr. Watson」 mailto:watson@bell-telephone.com ;q=0.1
m: <sips:bob@192.0.2.4>;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:not-in-service-recording@atlanta.com>
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:agb@bell-telephone.com> ; tag=a48s
From: sip:+12125551212@server.phone2net.com;tag=887s
f: Anonymous <sip:c8oqz84zk7z@privacy.org>;tag=hyh8
20.21 In-Reply-To
In-Reply-To頭域列舉了本次呼叫相關的或者返回的Call-ID。這些Call-ID能夠備客戶端cache起來,這樣能夠在這個頭域中返回。
這容許自動呼叫奮發系統來路由這些返回的呼叫到第一個呼叫的原始請求地點。這也容許被叫方過濾呼叫,這樣只有在呼叫中原始請求創建的呼叫纔會被接受。這個字段不是對請求驗證的一個替代。
例如:
In-Reply-To: 70710@saturn.bell-tel.com,17320@saturn.bell-tel.com
20.22 Max-Forwards
Max-Forwards頭域必須在任何一個SIP請求中使用,來限制中間轉發請求到下一個節點的proxy或者gateway的個數。這個在客戶端trace一個請求,若是路由失敗或者在中間出現循環的時候特別有用。
Max-Forwards是一個0-255的整數,代表了在這個請求消息中容許被轉發的剩餘次
小虎 2006-05-25 00:11
數。每當服務器轉發這個請求一次,這個數字就減一。建議的初始值是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:bob@biloxi.com>
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:operator@cs.columbia.edu>;tag=287447
t: sip:+12125551212@server.phone2net.com
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
保留/之後使用
小虎 2006-05-25 00:11
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: lee@example.com:
SIP/2.0 485 Ambiguous
Contact: Carol Lee <sip:carol.lee@example.com>
Contact: Ping Lee <sip:p.lee@example.com>
Contact: Lee M.Foote <sips:lee.foote@example.com>
部分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:bob@biloxi.com 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:bob@biloxi.com」,
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)的時候,若是可能,
小虎 2006-05-25 00:11
它應當使用正確的信任書從新組織請求。它應當和對前邊講述的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格式,相似bob@biloxi.com),最多見的就是和用戶的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自身能夠根據下列的方法發佈公鑰。