2018年12月8日 星期六

SIP Messages

SIP 訊息 [RFC3261 §7]

SIP 是文本協定,使用 UTF-8 字元集 和 CRLF換行,用一般的文字的使用者界面就可以看, 通用的訊息格式用  ABNF 描述是按呢:

generic-message  =  start-line       ;開始的一行標明請求方法或回應碼。
                    *message-header  ;批頭。每個結束是換行。每個可能多行。
                    CRLF             ;空白行,表示 message-header 結束。
                    [ message-body ] ;選擇性的訊息體。

訊息內容用換行區隔,第 1 行就是 start-line,可以看出是請求還是回應。回應一開始是「SIP/2.0」,擱來是 3 個數字的回應碼。請求一開始是 Method。

擱來是足多 message-header,簡稱 header、批頭。每一個生著「名:值」,嗎是用換行結束。猶毋過一個 header 也可以分成多行,多的行開頭有空白。每個批頭 可以用 CRLF 緊接著 White Space 分成多行。

header 的結束是用一個空白行表示。最尾有時陣有 message-body,譬如放 SDP。message-body 有可能是二進位資料。

內容大部分無分大小寫,比較時大寫和小寫是同款,除了 (case-sensitive or case-insensitive?)

  • Method 和 CSeq 內的 Method。
  • SIP 和 SIPS URI 的 userinfo 部份當作是分大小寫的字串,簡化比較,包含 password 或 telephone-subscriber 格式。所以,原本在 telephone-subscriber 轉換成 userinfo,不分大小寫的部份須轉為小寫,參數順序除了 isdn-subaddress 和 post-dial 先放按照順序,其它按照名稱 lexically 排。
  • SIP-Version 字串不分大小寫,但實做必須送大寫(為什麼?)。
  • Call-ID 值。
  • value 用 quoted string,除非特別指明。
  • Date 放 RFC 1123 date。
  • 其它特別定義的地方。

在 RFC 2543,換行可以是 CR、LF、或 CRLF,RFC 3261 只能是 CRLF。

start-line

開始行就是一行,欄位用單一空白 (SP) 區隔,訊息只有請求和回應兩種,辨別符合 Request-Line 是請求、符合 Status-Line 是回應。

start-line   =  Request-Line / Status-Line
Request-Line =  Method SP Request-URI SP SIP-Version CRLF
Status-Line  =  SIP-Version SP Status-Code SP Reason-Phrase CRLF

請求和回應都有協定版本 SIP-Version,開頭必須是「SIP/」,不分大小寫,但實作必須用大寫送。接著兩個數字以「.」隔開,在 RFC 3261 是「2.0」。Status-Line 開頭是 SIP-Version,和 Request-Line 的 Method 不會相同而區別。

SIP-Version    =  "SIP" "/" 1*DIGIT "." 1*DIGIT
Method 可以是 REGISTER、INVITE、ACK、CANCELBYE 等,不會有「/」,可以跟 SIP-Version 區別。
Method = INVITEm / ACKm / OPTIONSm / BYEm / CANCELm / REGISTERm / extension-method
extension-method = token
token = 1*(alphanum / "-" / "." / "!" / "%" / "*" / "_" / "+" / "`" / "'" / "~" )

請求對象的 URI (用戶或服務),描述在 RFC 3261 Section 19.1 的 sip: 或 sips: 或 RFC 2396 的通用 URI,不能有 unescaped spaces 或控制字元,也不能用 "<>" 包起來。SIP 元件可以支援如 RFC 2806 的 "tel" URI 方案,可以用任何機制轉換成 SIP URI、SIPS URI、或其它 scheme。

Request-URI    =  SIP-URI / SIPS-URI / absoluteURI

Status-Code (回應碼) 是 3 碼數字表示請求的回應狀態,方便機器判讀。

Status-Code    =  3DIGIT

Reason-Phrase 是回應碼的簡易描述,讓人方便理解。每個回應碼有預設內容,但可以修改,例如依據請求 Accept-Language 的語言。不能使用的可顯示 ASCII 碼有 "、#、%、<、>、[、\、]、^、{、|、},其中「%」作為 escaped 使用,可用來顯示這些排除的碼。其它為什麼要排除呢?

Reason-Phrase   =  *(reserved / unreserved / escaped
                   / UTF8-NONASCII / UTF8-CONT / SP / HTAB)

message-header

每個訊息至少會有多個基本的 header。每個 header 可能跨多行。因為有少數例外,實際批頭格式是依每種批頭名列舉,通用格式 依循 RFC 2822 Section 2.2:

header = header-name HCOLON header-value *(COMMA header-value) CRLF
header-name  = token                              ;至少一個字元
HCOLON       =  *( WSP ) ":" SWS                  ;冒號,和名稱在同一行,前可有 WSP,後可有 LWS。
header-value = *(TEXT-UTF8char / UTF8-CONT / LWS) ;使用 UTF8 編碼,可有 WSP,WSP 前可換行。
COMMA        =  SWS "," SWS                       ;逗號,前後可有 LWS,讓每個值可獨立一行。

名稱 (header-name) 和值 (header-value) 用冒號區隔,如有多個值則用逗號分隔。冒號必須和名稱同行,中間可以有空白(sp 或 tab)。值可以在同一行或換行,換行開頭是 WSP。值內容中的 WS 處,可變成 LWS 換行,在接收或轉送時可取代回 SP。

不同名 header 的相對順序不重要,但需要 proxy 處理的 header (譬如 Via、Route、Record-Route、Proxy-Require、Max-Forwards、和 Proxy-Authorization) 建議放頭前,較快解析到。

有的 header 可以出現多次,相對順序就重要了。欄位允許有多個逗號分隔的值,可以分成多個同款 header,意思相同。另外 WWW-Authenticate、Authorization、Proxy-Authenticate、和 Proxy-Authorization 也可以出現多次,但不能合併成一個 header。

欄位值的格式定義是跟著每個欄位名稱,不是 TEXT-UTF8 octets 的 opaque 系列, 就是 whitespace、tokens、separators、和 quoted strings 的組合。大部分值遵循通用格式,後面可以有一系列分號分隔的成對 parameter-name 和 parameter-value:

field-name: field-value *(;parameter-name=parameter-value)

雖然可以有任意數目的參數,相同參數名稱不能出現超過 1 次。

當比較 header,header 名稱是不分大小寫的。除非額外特別說明,欄位值、參數名稱、和參數值是不分大小寫的。token 總是不分大小寫的。除非額外特別說明,值用 quoted strings 表示是分大小寫的。

https://lirobo.blogspot.com/2018/11/sip-header-fields.html

message-body

請求和回應的 message-body 使用、類型和解釋取決於請求的 Method

message-body 的媒體類型必須由 Content-Type 決定,也可以說明字元集。Content-Encoding 必須省略,除非有任何編碼 (例如壓縮) 才使用。

也可以使用定義在 RFC 2046 的 "multipart" MIME 類型。如果要送包含 multipart 的 message-body,但請求的 Accept 不含 multipart,必須送一個 session 描述為非 multipart 的 message-body。

message-body 可由二進位資料組成。
當 sender 沒有提供明確字元集參數,媒體子類型 "text" 預設使用 UTF-8。

詳細用法見 RFC 5621

message-body 長度見  Content-Length

不能使用 HTTP/1.1 的 "chunked" transfer 編碼。
註:chunk 編碼改變訊息內容傳送為一系列每個有自己大小的 chunk。

transport

一個 SIP 訊息可用一個 UDP 或其它不可靠 transport 協定的 datagram 攜帶,限制請見 RFC 3261 Section 18。

在 stream 導向 transport 之上使用 SIP 訊息,必須忽略 start-line 之前的 CRLF
[參見 RFC 2616 Section 4.1],而且 header 欄位 Content-Length 是必要的,訂出在 stream 中每個 SIP 訊息的結束。

延伸閱讀

  • SIP 訊息雖然語法在字元集和規範和 RFC 2822 有所不同,但基本格式是一樣的。
  • 除了字元集和 HTTP/1.1 不同,SIP 訊息和 header 欄位語法大部分相同,但 SIP 不是 HTTP 的擴充。此外 HTTP 只用可靠的 transport 協定傳送。
  •  SIP-Version 依循 HTTP Version (HTTP 取代為 SIP,HTTP/1.1 取代為 SIP/2.0) 關於版本順序、合規要求、和版號更新。 不像 HTTP/1.1,SIP-Version 視為文字字串,但實際上應該沒有什麼不同。
  • SIP header 欄位依循 HTTP header 欄位的語法定義,以及延伸到多行的規則。但 HTTP 是用 implicit whitespace and folding,而 RFC 3261 符合 RFC 2234 使用 explicit whitespace and folding 作為文法整體的一部分。多個名稱相同的 header 欄位,其值是逗號分隔的列表,可以結合成一個 header 欄位也應用在 SIP,但文法不同而特定規則不同。

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...