1、背景介紹
如果熟悉SIP響應的讀者都一定知道,請求和響應是信令協(xié)商的基本手段。在RFC3261中規(guī)定了響應的定義,響應主要分為最終響應和臨時響應。根據(jù)其概念名稱,讀者也大致理解了最終響應和臨時響應的基本含義。簡單來說,最終響應是可靠的,而臨時響應是臨時的,不可靠的響應。根據(jù)RFC3261-7.2的說明,其定義是:
1xx: Provisional -- request received, continuing to process the request;
https://tools.ietf.org/html/rfc3261#section-7.2
在針對臨時響應的定義中,讀者可以非常明確地知道,對端已經(jīng)收到請求,對端正在處理其請求。以下示例說明了啟用PRACK的和使用最終響應處理的呼叫:
在當前的呼叫環(huán)境中,包括現(xiàn)代的IMS網(wǎng)絡中,呼叫需要經(jīng)過多個網(wǎng)絡環(huán)境和處理路徑,需要更多的協(xié)商和資源支持。因此,在實際呼叫流程中可能發(fā)生更多的問題,對端需要耗費一定的時間來處理請求,具體需要處理的內(nèi)容很多,包括:編碼協(xié)商,對端服務器資源不足,會話時間太長,編碼能力匹配問題,QoS,承載服務,和PSTN接續(xù)時間太長都會導致響應丟失的問題。因此,為了保證對端有充足的時間處理請求,UAS先返回一個臨時響應通知對端本地正在處理這個請求,現(xiàn)在僅發(fā)一個臨時性的響應。
2、UAS工作方式說明
根據(jù)RFC3262的說明,只要初始的請求包含了一個Supported,它的可選項是100rel,UAS可以對INVITE發(fā)送任何非100的響應。這里的初始請求的響應是一個臨時的可靠性響應。此規(guī)范除了支持INVITE以外,不支持其他的可靠性臨時響應的method。如果初始請求包含了Require頭域,其包含了100rel可選項的話,UAS必須發(fā)送一個非100臨時可靠響應。如果UAS不愿意那樣處理的話,它必須拒絕此初始請求,返回一個420響應(Bad Extension),并且在響應消息中包含一個Unsupported 頭域,可選項是100rel。具體示例,參考后續(xù)介紹。
根據(jù)RFC3262說明,UAS一定不能通過100(Trying)發(fā)送可靠的響應。UAS只能通過101到109中間的響應碼發(fā)送臨時可靠響應。如果請求中既不包含Supported 頭域也不包含Require頭來表示臨時可靠響應功能的話,UAS一定不能發(fā)送臨時可靠響應。
100(Trying)響應只能支持hop-by-hop之間的響應。因為此原因,這里討論的可靠性機制是介于end-to-end的響應,因此不能使用100(Trying)。這里,關于end-to-end 和hop-by-hop的使用方式,讀者一定要小心理解,因為各種method涉及了代理之間的通信和用戶身份安全的問題。例如,BYE method是end-to-end之間的處理,而CANCEL是hop-by-hop的請求處理。
在一些場景中,一個網(wǎng)絡要素可以當作proxy來使用,此proxy也可以可靠臨時響應。其工作方式類似于一個UAS,它的作用就是作為一個事務功能。但是,它不能嘗試發(fā)送攜帶To頭標簽的請求。這里,一個proxy不能對已經(jīng)在一個dialog內(nèi)容中發(fā)送過的請求生成可靠臨時響應。簡單來說,就是已在一個dialog中發(fā)送過請求內(nèi)容的,就不能對其請求生成臨時可靠響應。當然,不像UAS一樣,當proxy的一個網(wǎng)絡要素收到一個PRACK時,這個PRACK不能匹配任何未處理的可靠臨時響應,此PRACK必須經(jīng)過代理格式化處理。
很多讀者可能有疑問,為什么UAS可能會發(fā)送可靠臨時響應?我們在此文章中也討論了關于響應之前的準備工作的問題,讀者可參考。這里,其中的一個原因就是,如果INVITE事務需要耗費一定的時間生成最終響應,UAS響應經(jīng)過一定的流程來做出最終響應,為了保證有足夠的時間來回復最終響應,并且能夠保持事務的正常狀態(tài),因此,在回復最終響應前,需要一個周期性的臨時響應消息返回到請求對象端。因此,拓展功能100rel是一個必要的選擇,也是規(guī)范推薦的使用方式。
在UAS的核心構(gòu)件中,針對UAS的臨時可靠響應處理流程是根據(jù)RFC3261的8.2.6章節(jié)處理。讀者可查閱讀者歷史文章了解處理流程。除了遵守其處理流程以外,臨時可靠響應必須包含一個Require 頭,支持100rel可選項和一個RSeq頭域。在事務中的第一次可靠臨時響應中的這個RSeq頭的取值必須介于1到2**31-1之間。此規(guī)范推薦此值取值范圍一律在此范圍之內(nèi)。不同請求的臨時響應可以使用同樣的RSeq數(shù)值。
響應管理也需要定時器來處理。在規(guī)范說明中,可靠臨時響應會周期性的定期傳輸?shù)绞聞諏。通過T1定時器來實現(xiàn)定時傳輸,如果重新傳輸?shù)脑,則對T1定時器翻倍設置。關于T1定時器的規(guī)范說明,讀者可以參考RFC3261的17章節(jié)。一旦可靠臨時響應被傳輸?shù)搅朔⻊掌鞯氖聞諏雍,可靠臨時響應就會被添加到一個內(nèi)部未確認的可靠臨時響應列表中,等待處理。事務層會把重傳的響應數(shù)據(jù)發(fā)送到UAS core中。
當UA core收到一個匹配的PRACK后,可靠臨時響應的重傳就退出處理機制。收到PRACK后,UAS對對PRACK進行處理,處理流程和其他的method一樣。關于PRACK的處理,讀者可查閱RFC3261的第八章節(jié)和第十二章節(jié)。
在RFC3262中,匹配PRACK是這樣定義的。在同一dialog中,響應和其請求的所攜帶的參數(shù)匹配。具體包括,響應中RAck頭中的method,CSeq-num和response-num需要匹配請求中的CSeq,RSeq的臨時響應消息。
如果UA core收到的PRACK請求,這個請求不能匹配列表中任何一個的未確認可靠臨時響應數(shù)值。UAS必須回復一個PRACK,返回481錯誤響應碼。如果這個PRACK請求不能匹配任何未確認可靠臨時響應,對端必須對它返回一個2xx響應。這里,UAS可以確認,已經(jīng)收到臨時響應,這些響應正在被按序處理。PRACK應該退出可靠臨時響應的重傳流程,并且必須從未確認的可靠臨時響應列表中移除。
如果在一定時間內(nèi)沒有收到重傳響應怎么辦呢?在RFC3262中說明,如果在64×T1秒內(nèi),重新傳輸?shù)目煽颗R時響應沒有收到相應的PRACK反饋,UAS必須拒絕此初始請求,并且返回一個5xx響應消息。
對于發(fā)送可靠臨時響應的方式,本規(guī)范也做了進一步的說明。在第一個可靠臨時響應被確認接收以后,UAS可以發(fā)送其他的可靠臨時響應。這里一定要注意,直到第一個可靠臨時響應確認以后,UAS才能發(fā)送第二個可靠臨時響應。本規(guī)范推薦前一個可靠臨時響應沒有被確認之前,一定不能發(fā)送接下來的可靠臨時響應。如果第一個可靠臨時響應還沒有被確認,緊接著發(fā)送后續(xù)的可靠臨時響應的話,UAS不能確認這些可靠臨時響應的接收順序。
對于同樣一個請求,在后續(xù)的可靠臨時響應中的RSeq值必須是大于1。簡單來說,就是后一個可靠臨時響應比前一個大1。
對于UAS來說,其實,在發(fā)送臨時響應過程中可能也存在一些特別的情況,例如何時發(fā)送最終響應。規(guī)范中有明確的說明,除非最終響應是2xx,并且未確認的可靠臨時響應的其中一個響應中包含了會話描述,否則,在收到所有對未確認可靠臨時響應的PRACK之前,UAS可以發(fā)送對初始請求發(fā)送一個最終響應。那種情況下,在它們的臨時響應完全被確認之前,UAS一定不能發(fā)送最終響應,需要等到那些臨時響應被完全確認以后才能發(fā)送最終響應。如果可靠響應仍然是未確認狀態(tài)時,如果UAS不能發(fā)送最終響應的話,UAS不應該繼續(xù)重傳這些未確認的可靠臨時響應。這時,UAS必須準備處理剩下的PRACK的響應。對UAS來說,它對請求發(fā)送了一個最終響應以后,一定不能發(fā)送一個新的可靠臨時響應。
3、UAC工作方式說明
在上個章節(jié)我們討論了UAS使用100rel的工作方式,F(xiàn)在,我們討論100rel在UAC端的工作方式。根據(jù)rfc3262的說明,當UAC創(chuàng)建一個新的請求時,它可以插入一個可靠臨時響應。具體的做法是,在請求中添加一個頭域Require,攜帶100rel可選項標簽。注意,這個Require頭和100rel可選標簽只能出現(xiàn)在INVITE method中,不能出現(xiàn)在其他的method中。具體的頭域查看RFC3262的table1和table2,那兩個table中有完整介紹。
如果UAC不希望一直使用可靠臨時響應的話,它僅表示支持臨時響應,而且UAS又需要UAC發(fā)送一個可靠臨時響應的話,UAC必須在請求中添加一個Supported 頭域,攜帶一個100rel可選標簽。UAC應該包括這個頭域在所有的INVITE中。
關于此處理方式具體的示例,讀者可查閱PJSIP中100rel的代碼說明。
If the UAC wants to mandate 100rel support, it can specify PJSIP_INV_REQUIRE_100REL in the options argument when calling pjsip_inv_create_uac(). In this case, PJSIP will add 100rel tag in the Require header of the outgoing INVITE request.
https://www.pjsip.org/pjsip/docs/html/group__PJSIP__100REL.htm
如果收到一個針對初始請求的臨時響應,響應中包含了一個Require頭和100rel可選標簽項,這個響應是一個可靠臨時響應。如果這個響應是100(Trying)的話,必須忽略它的可選標簽,也不能使用下面的處理流程。
這里,我們開始討論具體的處理流程。如果沒有創(chuàng)建dialog的話,臨時響應一定要創(chuàng)建一個dialog。這里,假設傳輸可靠響應,UAC必須創(chuàng)建一個新的PRACK請求。這個請求通過dialog關聯(lián)的臨時響應被發(fā)送出去,PRACK可以包含一個自己的消息體,繼續(xù)其消息體是按照其格式來解析。
這里,我們開始討論具體的處理流程。如果沒有創(chuàng)建dialog的話,臨時響應一定要創(chuàng)建一個dialog。這里,假設傳輸可靠響應,UAC必須創(chuàng)建一個新的PRACK請求。這個請求通過dialog關聯(lián)的臨時響應被發(fā)送出去,PRACK可以包含一個自己的消息體,繼續(xù)其消息體是按照其格式來解析。
注意,在一個dialog中,處理重傳時,PRACK請求和其他的非INVITE請求一樣。具體來說,當收到一個臨時響應重傳,并且這個重傳正在被確認時,UAC不應該重傳PRACK請求。提醒讀者,盡管UAC那樣做,但是也不會導致協(xié)議錯誤。
一旦收到一個可靠臨時響應,那個響應重傳必須馬上丟棄。那么,我們?nèi)绾闻袛嗍且粋重傳響應呢?規(guī)范規(guī)定,當響應的dialog ID,CSeq和RSeq匹配了原始的響應中的這些參數(shù)時,這個響應就是重傳響應。UAC中必須包含一個序列號,這個序列號可以表示針對初始請求所收到的最新的可靠臨時響應。這個序列號必須一直包含在響應中,直到收到針對初始請求的最終響應。這個值必須是在初始請求的第一個可靠臨時響應的RSeq中定義。
處理后續(xù)的可靠臨時響應和初始請求處理的規(guī)則是一樣的。但是,還有一些不同,其原則是:可靠臨時需要保證其傳輸順序。因此,針對同樣的請求,如果UAC收到其他的可靠臨時響應,而且它的RSeq值不大于序列號值的話,這個響應一定不是在PRACK中被確認的,并且UAC一定不要繼續(xù)處理這個響應。使用這個響應的部署環(huán)境可以丟棄這個響應,或者對其做一個緩沖處理,用來支持可能丟失的響應。
UAC可以在最終響應以后確認收到的可靠臨時響應,也可以丟棄這些可靠臨時響應。
4、Offer/Answer模式和PRACK的處理方式討論
Offer/Answer模式是SIP協(xié)議的一個非常重要的概念。在RFC3261中有具體的規(guī)范說明。筆者也曾經(jīng)發(fā)布了很多關于這個概念的介紹,讀者可以查閱歷史文檔做進一步的理解。同樣,在SIP的拓展協(xié)議中-PRACK也支持同樣的處理方式。接下來,我們具體討論一下如何在PRACK中使用Offer/Answer的模式。
如果在請求中提供了一個offer,UAC可以在可靠臨時響應中生成一個answer(這里假設,UAC支持它們)。這樣的話,它們之間就會創(chuàng)建一個會話。同樣的道理,如果一個可靠臨時響應是第一個可靠消息,這個消息返回到UAC,并且此INVITE沒有包含一個offer的話,必須在那個可靠臨時響應中添加一個offer。
這里,我們討論關于UAC收到offer或者answer的處理方式。如果UAC收到了一個可靠臨時響應,攜帶一個offer,它必須在PRACK中生成一個answer。如果UAC收到一個可靠臨時響應,攜帶一個answer,它可以在PRACK中生成其他offer。如果UAS收到一個PRACK,攜帶了一個offer,UAS必須對此PRACK在2xx中包含一個answer。
一旦answer被發(fā)送或接收,即使原始INVITE自己本身還沒有收到回復,UA應該創(chuàng)建基于offer/answer的參數(shù)來會話。
當INVITE被接受時,如果UAS已經(jīng)在可靠臨時響應中包含了會話描述,這個可靠臨時響應未被確認,UAS必須推遲發(fā)送2xx,一直到這個臨時需要被確認。否則,1xx的可靠性不能被保證,并且可靠性操作需要offer/answer交互的適當操作才能完成。
規(guī)范明確說明,所有支持此SIP拓展可靠性響應協(xié)議的代理必須支持offer/answer交互模式,此模式工作方式是基于rfc3261中13章節(jié)的規(guī)則來處理;谀壳癐NVITE和PRACK存在的請求,2xx和可靠性1xx作為非失敗可靠響應。
在rfc3262中定義了PRACK,具體語法,讀者可以參考rfc3262的tabel 1,table 2和RFC3261中的table3。
在本規(guī)范中定義了兩個新的頭域,包括RAck和RSeq。在臨時響應中,RSeq是用來支持參數(shù)的可靠性。RAck頭是通過PRACK請求定義的,用來支持臨時響應的可靠性。RAck包含兩個號碼和一個method標簽。第一個號碼數(shù)值是被確認的臨時響應中的RSeq頭的值,第二個號碼值和method是從被確認響應中的CSeq中拷貝出來的數(shù)值和method。在RAck頭中的method名稱是對大小寫敏感的名稱。例如:
RAck: 776656 1 INVITE
5、其他相關問題討論
很多情況下,關于PRACK的請求處理涉及了很多具體的環(huán)境。筆者歸納了幾個檢測時容易出現(xiàn)的問題進行討論。
在某些環(huán)境下,我們經(jīng)?赡苡龅浇K端或者服務器端是否支持PRACK請求的問題。很多時候,我們可能需要及時調(diào)整設備或者服務器端的設置就可以解決問題,F(xiàn)在我們給讀者一個示例,讓讀者理解開啟或者關閉PRACK的處理流程:
通過以上流程,結(jié)合我們前面討論的rfc3262,讀者可以非常清楚了解PRACK的處理過程。一些用戶仍然對100rel的協(xié)商非常迷惑,筆者這里耗費一點時間專門針對具體的業(yè)務場景做一個簡單總結(jié)。具體到實際的UAS/UAC環(huán)境中,100rel可選項的處理完全取決于哪一側(cè)的請求狀態(tài)和是否開啟關閉(Supported/Require頭)。例如以下幾個不同場景最終協(xié)商的結(jié)果:
注意,這是一般的協(xié)商過程。在其他終端設備的處理可能有一些不同,這結(jié)果完全取決于接入網(wǎng)關和服務器端的兼容性設置。
有時,用戶可能在SIP消息中看到一個和PRACK相關的頭域-precondition。Precondition是另外一個比較大的討論話題,此頭值在RFC3312/RFC4031中做了非常詳細的定義,其中也包括了Precondition和Offer/Answer模式交互的關系,示例如下:
- SIP/2.0 183 Session Progress
- Max-Forwards: 70
- Via: SIP/2.0/TCP [2001:0:0:2::1]:5060;branch=z9hG4bK932432170smg;transport=TCP
- From: <sip:310410123456789@one.att.net>;tag=2763466811
- To: <sip:0123456789;phone-context=one.att.net@one.att.net;user=phone>;tag=1111111111
- Call-ID: 2270680280
- CSeq: 1 INVITE
- Contact: <sip:0123456789@[2001:0:0:2::2]:65094;transport=tcp>
- Record-Route: <sip:[2001:0:0:2::2];lr>
- Content-Type: application/sdp
- Require: precondition // Indicate "precondition" is required
- Require: 100rel // Indicate "PRACK" is Required
- RSeq: 1
- Content-Length: 763
- Privacy: none
很多呼叫在3GPP和非3GPP網(wǎng)絡呼叫中,Preconditon協(xié)商中仍然有失敗的可能:
圖片來自于3GPP規(guī)范
當前,我們的手機呼叫已經(jīng)在移動網(wǎng)絡IMS中廣泛使用。手機呼叫的流程需要經(jīng)過更多節(jié)點的處理。在每個節(jié)點都需要耗費一定的時間。其協(xié)商過程也非常復雜。為了為讀者提供一個比較全面的呼叫流程設置情況,讀者可以參考相對完整的示例來進一步學習。以下是一個LTE網(wǎng)絡中手機呼叫的協(xié)商流程(包括了100 trying,183, 180的基本使用場景):
圖片來自于:https://telecomtutorial.info/volte-call-flow/
因為文章篇幅的關系,筆者這里不再做過多介紹。讀者可以查閱以上圖片鏈接,針對LTE呼叫的流程做具體了解。當然,在3GPP中,關于IMS中的SIP呼叫協(xié)商流程涉及了大概54個請求響應消息內(nèi)容(如果沒有記錯的話),這里不能一一介紹。
另外,在3GPP網(wǎng)絡中有針對UAS/AUC關于PRACK頭中的Supported和Require的一些調(diào)整,并且3GPP組織對其給出了一些建議(查閱3GPP T Release 6 37 R 29.962 V6.1.1或者更新版本)。用戶需要根據(jù)具體的網(wǎng)絡環(huán)境和3GPP的說明做進一步的了解。筆者沒有查閱中國的IMS網(wǎng)絡中關于和RFC3262的兼容性說明,中國在3GPP網(wǎng)絡的規(guī)范也有一些調(diào)整。這些調(diào)整可能會影響實際SIP呼叫的使用,所以,讀者一定要注意。
如果我們把應用場景縮小到一般的企業(yè)業(yè)務場景中,看看接入網(wǎng)關和服務器端的使用狀態(tài)。有時,一些網(wǎng)關產(chǎn)品和服務器端存在兼容性問題。很多時候,可能是服務器端或者終端沒有開啟PRACK選項支持。一些網(wǎng)關產(chǎn)品和服務器都可能包含三種設置方式:默認關閉PRACK,Supported和Require PRACK。因此用戶可以檢查雙方關于PRACK的設置來解決這些問題。當然,如果出現(xiàn)了三種設置的話,事實上,根據(jù)雙方配置的平臺,經(jīng)過協(xié)商以后,終端和服務器端就會產(chǎn)生多種響應結(jié)果。這完全取決于UAC和UAS的協(xié)商結(jié)果:
具體的呼叫跟蹤記錄示例,網(wǎng)關側(cè)成功的呼叫(183/200 ):
- 16:32:35.762 CALL(SIP) (00:0004:00) SENT 183 Session Progress Reliable (100rel) to 10.129.45.102:8000 UDP
- 16:32:35.782 CALL(SIP) (00:0004:00) RCVD PRACK from 10.129.45.102:8000 Cseq:2 with Via sent-by: 10.129.45.102 UDP
- 16:32:35.782 CALL(SIP) (00:0004:00) SENT 200 OK PRACK to 10.129.45.102:8000 UDP
- 21:16:47.845 CALL(SIP) (01:00004:00) SENT 421 Extension Required [PRACK support is required] to 10.129.45.104:5060 Cseq:1
- 21:18:09.286 CALL(SIP) (01:00005:00) SENT 420 Bad Extension [Unsupported SIP request arrived at L3UA-TUC] to 10.129.45.104:5060 Cseq:1
6、總結(jié)
筆者通過5個篇幅的內(nèi)容,具體介紹關于SIP拓展協(xié)議RFC3262和100rel拓展,PRACKmethod的使用協(xié)商方式。首先,我們介紹了臨時響應的具體內(nèi)容,為什么使用臨時響應,以及涉及的相關協(xié)議RFC3262。然后,我們介紹了如何在UAS和UAC端處理100rel/PRACK。當然,UAS/UAC的協(xié)商過程是非常復雜的,很多細節(jié)需要讀者根據(jù)實際的配置才能決定。接下來,我們介紹了關于RFC3262中幾個主要的定義和Offer/Answer模式下的配合PRACK交互的流程。最后,我們針對一些在業(yè)務場景中具體的使用方式和終端/服務器端配置所產(chǎn)生的響應做了比較詳細地分析。
另外,筆者這里提醒讀者,關于SIP拓展協(xié)議RFC3262的100rel處理涉及了3GPP中非常復雜的流程。在實際部署環(huán)境中還要配合運營商的網(wǎng)絡來調(diào)整終端和SIP服務器端的配置,包括具體的呼叫業(yè)務流程操作都可能出現(xiàn)問題。筆者水平有限,這里僅是拋磚引玉,讀者仍然需要對照具體的規(guī)范來排查。
筆者再次提醒,如果讀者使用開源的媒體服務器,例如Asterisk(建議使用PJSIP)或者FreeSWITCH,用戶一定要開啟100rel的相關選項,包括Supported和Require選項。
參考資料:
https://tools.ietf.org/html/rfc3262
https://tools.ietf.org/html/rfc4032
https://www.ietf.org/rfc/rfc3312.txt
https://www.3gpp.org/technologies/keywords-acronyms/97-lte-advanced
https://telecomtutorial.info/volte-call-flow/
https://wiki.freepbx.org/
https://tools.ietf.org/html/rfc3960
https://github.com/alticelabs/asterisk-i/blob/master/p019_prack_support/asterisk-i-p019-prack-support.patch
關注微信公眾號:asterisk-cn,獲得有價值的Asterisk/SIP技術和行業(yè)分享
權威Asterisk freepbx FreeSBC技術文檔: www.freepbx.org.cn
完整企業(yè)融合通信商業(yè)解決方案:www.hiastar.com
如何使用FreeSBC+FreeSWITCH/Asterisk,qq技術分享群:334023047