2018年12月22日 星期六

SDP simcap

RFC 3407:SDP Simple Capability Declaration (simcap)
SDP 簡易通話能力宣告

定義一組新 SDP 屬性,在一個 session 描述裡放一個 capability set,列出所有支援的媒體功能,可作為其它 session 協商的資訊來源。

SDP simcap 新增的屬性有:
a=sqn: <sqn-num>
a=cdsc: <cap-num> <media> <proto> <fmt list>
a=cpar: <cap-par>
a=cparmin: <cap-par>
a=cparmax: <cap-par>
可以放在 session-level 或 media-level。一個 capability set 以 a=sqn 開始,緊接著第 1 個 a=cdsc,剩下可以散落各處。

a=sqn 說明 capability set 的序號 (sequence number),<sqn-num> 從 0 開始。每次新發表一個 capability set 取代舊的,序號加 1 後 modulo 256。接收端可能不會收到所有序號的 capability set,不能因為有跳號而拒絕。

a=cdsc 是 capability description,類似 m= 行,不需要 <port>,但多了 <cap-num>。全部 a=cdsc 中的 fmt 從 1 開始編號,<cap-num> 是每個 a=cdsc 中第一個 fmt 的編號。如此一來,傳送或接收端、<sqn-num>、加上 fmt 的編號就可以參照到一個特定媒體。接收端不能因為 fmt 編號有跳號而拒絕。
註:fmt 本身在不同 a=cdsc 可能重複。
註:包含在 m= 行的所有 fmt 也必須出現在 capability set。

cpar、cparmin、cparmax 可分別指定 capability 能支援的參數值、最小值、和最大值。
<cap-par> 可以是 "b=" 頻寬資訊或完整的 "a=" 屬性。

範例:
v=0
o=- 25678 753849 IN IP4 128.96.41.1
s=
c=IN IP4 128.96.41.1
t=0 0
m=audio 3456 RTP/AVP 18 96
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15,32-35
a=sqn: 0
a=cdsc: 1 audio RTP/AVP 0 18 96
a=cpar: a=fmtp:96 0-16,32-35
a=cdsc: 4 image udptl t38
a=cdsc: 5 image tcp t38
準備送收 G.729 語音和 telephone-event 0-15、32-35。告知對方另外還可以支援:
  • PCMU 語音
  • telephone event 16
  • udp 或 tcp T.38 傳真 (見 T.38 Annex D, "SIP/SDP Call Establishment Procedures").
註:a=rtpmap:96 已 specified,所以沒包含在 capability description

範例 (多個媒體串流):
v=0
o=- 25678 753849 IN IP4 128.96.41.1
s=
c=IN IP4 128.96.41.1
t=0 0
m=audio 3456 RTP/AVP 18
a=sqn: 0
a=cdsc: 1 audio RTP/AVP 0 18
m=video 3458 RTP/AVP 31
a=cdsc: 3 video RTP/AVP 31 34
準備送收 G.729 語音和 H.261 影像。告知對方還可以支援:
  • PCMU 語音
  • H.263 影像
等效範例 (capability set 改放在 session-level):
v=0
o=- 25678 753849 IN IP4 128.96.41.1
s=
c=IN IP4 128.96.41.1
t=0 0
a=sqn: 0
a=cdsc: 1 audio RTP/AVP 0 18
a=cdsc: 3 video RTP/AVP 31 34
m=audio 3456 RTP/AVP 18
m=video 3458 RTP/AVP 31

2018年12月14日 星期五

C Library rand()

產生虛擬亂數 (pseudo-random number),不是真的亂數,也不是機密的,而是一系列看起來像亂數的數列,這些數字實際上是有固定順序的。

#include <stdlib.h>

void srand(unsigned int seed); // 設定函式庫內部的 seed,一開始預設是 1。

int rand(void); // 依據 seed 運算產生範圍為 [0, RAND_MAX] 的虛擬亂數回傳,並儲存為新的 seed。

int rand_r(unsigned int *seedp); //

rand_r() 為 reentrant 版的 rand(),需要傳入儲存 seed 的記憶體指標,在 thread 程式得以不被其它 thread 干擾來產生同樣的數列。在 POSIX.1-2008 標注為廢棄。

POSIX.1-2001 rand() 和 srand() 的實作範例:

static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int myrand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}

void mysrand(unsigned int seed) {
    next = seed;
}

注意

  • 虛擬亂數是有一定順序的,知道 seed 就知道下一個產生的值。假設初始 seed 設為目前的時間秒數,已知是今年的話,大約有 225 個可能的值,縮小範圍後依現今運算能力很容易試出來。
  • 產生序列的最低 bit 固定 01010101..,其實不夠亂。
  • 1995 發現 Netscape 瀏覽器產生的 SSL session keys 使用時間和 process ID 作為 seed,猜得到,所以 SSL sessions 可在幾分鐘內破壞。...

以上經驗告訴我們,作為 secure 的虛擬亂數產生器,有兩個基本原則:

  1. seed 必須是無法預測的 (實際上只能難以預測?)。要有足夠的可能性,例如 2128 就足夠 (隨著計算能力越來越強,暴力破解越容易,需要更多 bit),所有可能出現的機率相同,沒有東西讓攻擊者可以縮小範圍。
  2. 產生虛擬亂數的 algorithm 必須是 secure,pseudorandom bits 沒有可辨別的 patterns。即使攻擊者學到或猜到一些 pseudorandom bits,也無法預測其它 pseudorandom bits。

參考

  1. https://inst.eecs.berkeley.edu//~cs161/fa08/Notes/random.pdf

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,但文法不同而特定規則不同。

2018年11月25日 星期日

SIP Header fields

SIP 信頭欄位 [RFC3261 §20]

有些信頭欄位只在特定請求或回應有意義,不該出現的或不認識的都忽略。一些常見的信頭欄位名稱也定義了 compact (abbreviated ) 形式,當整個訊息過長造成問題時使用,例如使用 UDP 時超過 MTU。compact form 可以在任何時候使用,也可以混合使用。

完整信頭欄位見 https://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-2

信頭欄位相關於 method 和 proxy 處理的資訊如下表。
Header fieldwhereproxyACKBYECANINVOPTREGPRACK
Accept請求
-o-om*oo
2xx
---om*o-
415
-c-cc cc
Accept-Encoding請求
-o-oo oo
2xx
---om*o-
415
-c-cc cc
Accept-Language請求
-o-oo oo
2xx
---om*o-
415
-c-cc cc
Alert-Info請求ar---o- --
180ar---o- --
Allow請求
-o-oo oo
2xx
-o-mm*oo
回應
-o-oo oo
405
-m-mm mm
Authentication-Info2xx
-o-oo oo
Authorization請求
ooooo oo
Call-IDcopyrmmmmm mm
Call-Info任何ar---oo o-
Contact請求
o--mo o-
1xx
---m- --
2xx
---mo o-
3xxd-o-oo oo
485
-o-oo oo
Content-Disposition任何
oo-oo oo
Content-Encoding任何
oo-oo oo
Content-Language任何
oo-oo oo
Content-Length任何arttttt tt
Content-Type任何
**-** **
CSeq複製rmmmmm mm
Date任何aooooo oo
Error-Info300-699a-oooo oo
Expires任何
---o- o-
From複製rmmmmm mm
In-Reply-To請求
---o- --
Max-Forwards請求ammmmmm mm
Min-Expires423
----- m-
MIME-Version任何
oo-oo oo
Organization任何ar---oo o-
Priority請求ar ---o - --
Proxy-Authenticate407ar -m-m m mm
401ar -ooo o oo
Proxy-Authorization請求dr oo-o o oo
Proxy-Require請求ar -o-o o oo
Record-Route請求ar oooo o -o
2xx,18xmr -ooo o -o
Reply-To任何
---o - --
Require任何ar -c-c c cc
Retry-After404,413,480,486
500,503
600,603

-ooo o oo
Route請求adrcccc c cc
Server回應
-ooo o oo
Subject請求
---o - --
Supported請求
-oom*o oo
2xx
-oom*m*oo
Timestamp任何
oooo o oo
To複製(1)r mmmm m mm
Unsupported420
-m-m m mm
User-Agent任何
oooo o oo
Via請求amrmmmm m mm
回應,複製dr mmmm m mm
Warning回應
-ooo o oo
WWW-Authenticate401ar -m-m m mm
407ar -o-o o oo
  • where 欄表示用在請求、回應、特定回應、或是任何請求和回應。複製是指由請求複製到回應,(1) 含可能的 tag 一起複製。
  • proxy 欄表示在 proxy 可進行的動作:
    • a (add):如沒有可新增或 concatenate
    • m (modify):可修改。
    • d (delete):可移除。
    • r (read):必須可讀,所以不能加密。
  • 各個 method 欄說明是否要有:
    • c (conditional):視訊息內容需要。
    • m (mandatory):必要,且接收端必須了解。
    • m*:應該要有,但接收端沒收到時要能處理。
    • o (optional):選擇性的。可有可無,接收端可忽略,例外是 RFC 3261 §20.32 的 Require。
    • t:應該要有,但接收端沒收到時要能處理。如果 transport 用 stream-based 協定 (例如 TCP),則是必要的。
    • *:有訊息 body 時必要。見 RFC 3261 §20.14、§20.15 和 §7.4。
    • -:不能有,接收端遇到的話忽略。
UA 忽略不認識的 extension header parameters。

如果 Contact、From、和 To 包含的 URI 有「,」、「?」、或「;」,必須 用 < and > 包起來。沒包在內的「;」是分割出 header 參數,不是 URI 參數。

Accept

指定回應內容可接受的媒體類型,預設是「application/sdp」,空的 Accept 欄位值表示不接受任何格式,其它語法和語意依循 HTTP Accept

譬喻:
Accept: application/sdp;level=1, application/x-private, text/html

Accept-Encoding

類似 Accept,但限制回應內容可接受的編碼,一般是指壓縮方式。語意跟 HTTP Accept-Encoding 相同。

空的 Accept-Encoding 相當於「Accept-Encoding: identity」,也就是沒有編碼。
沒有 Accept-Encoding 欄位預設 identity。

註:在 HTTP,沒有 Accept-Encoding 欄位表示任何編碼都可以,但偏好 identity。

譬喻:
Accept-Encoding: gzip

Accept-Language

用在請求表示回應訊息內容的 reason phrases、session descriptions、或 status responses 的偏好語言,如果沒有則假設接受任何語言。

依循 HTTP Accept-Language 語法,包括 "q" 參數 (quality) 的偏好順序。

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

Alert-Info

在 INVITE 請求,提供不同的鈴聲給 UAS。在 180 (Ringing),提供不同的回鈴音給 UAC。典型用途是 proxy 用來提供不同聲音識別用。

Call-Info 一樣存在安全風險,被放入惡意音訊。應該提供使用者可關閉此功能。

譬喻:
Alert-Info: <http://www.example.com/sounds/moo.wav>

Allow

告知對方所有支援的 Method 列表。沒有 Allow 代表沒講支援哪些 Method,不是不支援任何 Method。

在 method OPTIONS 以外的回應提供 Allow 欄位,減少需要的訊息數目 (???)。

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

Authentication-Info

提供跟 HTTP Digest 的相互認證,UAS 可以在成功認證請求的 2xx 回應放這個 header,使用基於 Authorization 的 digest。

語法和語意遵循 RFC 2617

譬喻:
Authentication-Info: nextnonce="47364c23432d2e131a5fb210812c"

Authorization

UA 的認證憑證。RFC 3261 Section 22.2 概述 Authorization 的使用,Section 22.4 說明和 HTTP 認證一起使用時的語法和語意。

Authorization (和 Proxy-Authorization) 多個信頭欄位值不能合併成逗號分隔的列表,要分成多個信頭欄位行。

下面列子,Digest 參數沒用引號刮起來。

Authorization: Digest username="Alice", realm="atlanta.com",
  nonce="84a4cc6f3082121f32b42a2187831a9e",
  response="7587245234b3434cc3412213e5f113a5"

Call-ID (i)

Call 的唯一識別碼,所有 SIP 訊息都需要,關聯的 SIP 訊息都會有相同的值。
  • 一個 UA 註冊應該都使用相同的 Call-ID。
  • dialog 內所有 SIP 訊息的 Call-ID 都相同。Call-ID 加上 From tag 及 To tag 形成一個 peer-to-peer 的 SIP 關係,稱為一個 dialog。一個 Call 可能有多個 dialog。
  • 其它可能的特殊 Method 行為。
Call-ID 用字串比對是否符合,需減少無意的碰撞可能性。 
建議產生方式:由隨機字串加上 UAC 的主機名或 IP 位址組合而成。
使用加密的亂數識別碼 (RFC 1750)
https://tools.ietf.org/html/rfc1750
https://tools.ietf.org/html/rfc4086
實作可使用 "localid@host" 的 form. 
使用加密亂數提供一些保護 against session hijacking (為什麼???)。

一個多媒體會議可能需要多個不同 Call-ID 的呼叫。

譬喻:
Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@biloxi.com
i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6@192.0.2.4

Call-Info

提供發話者 (請求) 或受話者 (回應) 額外資訊的 URI,在其 "purpose" 參數說明目的:
  • "icon" 表示適合顯示為 icon 的影像。
  • "info" 是用戶一般描述,例如經由網頁。
  • "card" 提供 vCardLDIF 等格式的名片。
使用 Call-Info 存在安全風險,而被放入惡意訊息,可能是 peer UA,也可能是中間的 proxy。建議只有在放 Call-ID 的設備可以驗證真偽,並且是可信任的,才顯示資訊。

譬喻:
Call-Info: <http://wwww.example.com/alice/photo.jpg> ;purpose=icon,
   <http://www.example.com/alice/> ;purpose=info

Contact (m)

後續請求的接洽窗口 URI,其意義依據所在的請求或回應。可以包含顯示名稱、URI 參數、header 參數。如果有顯示名稱、或 URI 參數、或者 URI 含有「,」「;」「?」時,URI 和 URI 參數要用「<」和「>」包起來。沒包起來的參數都視為 header 參數。顯示名稱可以是 token,要較大的字元集的話用一個 quoted string。這些規則也應用在 To 和 From。

URI 通常有 username,位於某個 FQDN 或者沒註冊的 domain names 則用 IP 位址。

Contact 和 HTTP 的 Location 有類似的角色,然而 HTTP 只允許一個 unquoted 位址。

Contact 參數 "q" 和 "expires" 只用在 REGISTER 請求和回應,或者 3xx 回應。

格式

STAR / (contact-param *(COMMA contact-param))
contact-param  = (name-addr / addr-spec) *(SEMI contact-params)
contact-params = "q" EQUAL qvalue / "expires" EQUAL 1*DIGIT / generic-param
qvalue         =  ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] )
譬喻:
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
  • UAC 建立 dialog 的請求 (在 RFC 3261 只有 INVITE),必須提供只有一個 URI 的 Contact,無論後續請求在不在 dialog 內都可以作為接受請求使用。
  • 如果 Request-URI 或 top Route 含有一個 SIPS URI,Contact 也必須是 SIPS URI。
  • REGISTER
  • Contact alias
  • 只有 * 允許 comma-separated list
註:m 意思 moved。
比較:Via

Content-Disposition

訊息體或其中 multipart 的部署,擴展 RFC 2183 的 MIME Content-Type

Content-Disposition 在 RFC 3261 新增,並在 IANA 註冊了 4 種新 disposition-types:
  • alert:alert 使用者的客製化鈴聲。
  • icon:顯示給使用者的 icon 影像。
  • render:顯示給使用者。
  • session :作為通話媒體的 session 描述,如 SDP
為了向前相容,如果沒 Content-Disposition, Content-Type 是 application/sdp 時假設為 "session",其它為 "render"。

如果收到不了解的 Content-Type 或 Content-Disposition,參數 handling 說明 UAS 應
該如何反應。 有定義的值有 "optional" 和 "required",預設是 "required"。handling 參數說明在 RFC 3204。

譬喻:
Content-Disposition: session

Content-Encoding (e)

訊息體的編碼,需要解壓縮或解碼才能得到 Content-Type 所參照的 media-type 時才需要,可依序列出多個施加的編碼。

Content-Encoding 欄位值不分大小寫,登記在 IANA。
https://tools.ietf.org/html/rfc2616#section-3.5 定義的語法。

Client 可對請求的訊息體編碼。
Server 可用列在請求 Accept-Encoding 的編碼,對回應的訊息體編碼。

譬喻:
Content-Encoding: gzip
e: tar

Content-Language

訊息體的語言,見 https://tools.ietf.org/html/rfc2616#section-14.12

譬喻:
Content-Language: fr

Content-Length (l)

訊息體的長度。十進位數字表示位元組數目,不含分隔 body 的 CRLF,0 以上的 值都是 valid。如果使用 stream-based transport 協定 (例如 TCP) 是必要的。沒 body 時,Content-Length 是 0。

能夠省略 Content-Length 簡化建立動態產生回應的像 cgi scripts。

譬喻:
Content-Length: 349
l: 173

Content-Type (c)

訊息體媒體類型,有 message-body 時是必要的。

譬喻:
Content-Type: application/sdp
c: text/html; charset=ISO-8859-4

CSeq

Command Sequence,每個 SIP 訊息都要有,包含一個序號及一個 Method 名稱,譬喻:
CSeq: 314159 INVITE
序號是某個 UAC 在同一個 Call-ID 下 Command 的順序,大致來講就是 Transaction 的順序,一開始是比 231 小的亂數,後續每次發出仝款 Call-ID 的新請求時,序號就加 1,讓 UAS 辨別是新的 Transaction 還是重傳。
  • 例外是 ACK 和 CANCEL,他們算是 INVITE 的延伸,沿用 INVITE 的序號。PRACK 序號會加 1。
  • 一個 UA 的 REGISTER 原則上開機後都使用仝款 Call-ID,CSeq 序號是註冊請求的順序。

Date

請求或回應首次送時的 GMT 日期和時間。不同於 HTTP/1.1,SIP 只支援最新的 RFC 1123 格式的日期,但如同 HTTP/1.1,SIP 限制時區為 "GMT"。RFC 1123 Date 有分大小寫。

Date 可讓沒 battery-backed clock 的簡易終端系統獲得目前時間。

譬喻:
      Date: Sat, 13 Nov 2010 23:29:00 GMT

Expires

訊息或內容從接收到請求開始的過期時間,值是 0 到 (2**32)-1 之間的秒數,精確的意思
視 Method 而定。

INVITE 的過期不影響邀請成功後實際 session 可使用的時間。session 可使用的時間限制
可表達在 Session 描述協定裡。

Error-Info

提供關於錯誤狀態回應的額外資訊。

UAC 用戶界面可能從有彈出式視窗和聲音的 PC softclients,到透過 gateway 連接、只有聲音的「黑」話機或端點。與其強迫 server 選擇在 Reason-Phrase 傳送細節還是播放錄音,Error-Info 允許兩者都送,由 UAC 選擇用哪種呈現給發話者。

UAC 可視 Error-Info 的 SIP 或 SIPS URI 如同 redirect 的 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>

From (f)

請求的發出端。可能跟請求建立 dialog 的發出端不同。和 Contact 有相同規則的顯示名稱、URI、URI 參數、和信頭參數。 

選擇性的顯示名稱用來顯示在人機界面,要隱藏的話用「Anonymous」。

格式是 name-addr 或 addr-spec 加上 tag 參數,和其它參數

( name-addr / addr-spec ) SEMI "tag" EQUAL token *( SEMI generic-param )

addr-spec 是 name-addr 的簡化,不能有 display-name、「,」、「?」、「;」。

兩個 From 相等:URI 且參數 match。擴充參數一個沒有則忽略。display name 和有無 angle bracket 不影響是否相等。

譬喻:
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

Organization

送出請求或回應的 SIP 元件所屬組織名稱。Client 可用來過濾呼叫。

譬喻:
Organization: Boxes by Bob

Record-Route

格式
rec-route *(COMMA rec-route)
rec-route = name-addr *( SEMI generic-param )

Reply-To

格式
( name-addr / addr-spec ) *( SEMI generic-param )

Route

格式
route-param *(COMMA route-param)
route-param = name-addr *( SEMI generic-param )

To (t)

格式
( name-addr / addr-spec ) *( SEMI to-param )
to-param  =  "tag" EQUAL token / generic-param

Via (v)

一開始的 UAC 和後續途經的每個 proxy 都會加一個 Via 放 transport 及位址,依序作為回應的路徑。

格式 sent-protocol host[:port];branch=branch[;參數...]

  • sent-protocol 格式是「SIP/2.0/transport」,transport 可以是 UDPTCPTLSSCTP 等。
  • host 可以是主機名稱或網路位址,可以加上 port number。(沒用途?)
  • 參數 branch:
    • 意思是分支。在 RFC3261 以「z9hG4bK」開頭,是必要的。值對某個 UAC 而言是時空上唯一,用來快速識別 Transaction,但在 CANCEL 和 INVITE 失敗的 ACK 是沿用原始請求的 branch。
    • 在 RFC2543,forking proxy 插入 branch 用來區分不同分支,同一個 call 在不同 proxy 可能用相同的 branch 值,沒有唯一的特性,不適合作為 Transaction ID。某種程度上不會產生「z9hG4bK」開頭的值。
    • Proxy 也用來偵測 loop。
  • 參數 sent-by:Client Transport 紀錄送出的位址「host:port」,host 建議 FQDN。port 可省略,預設值依據傳輸協定,UDP/TCP/SCTP 是 5060、TLS 是 5061。在 用來送回應。
    • 收到請求的 Via 中有 sent-by 且 branch 符合自己送的,
  • 參數 received: Server Transport 收到請求檢查頂頭 Via 的 sent-by,
    如果是網域主機名稱,或不同於封包的來源 IP 位址時,紀錄封包的來源位址,助於之後 server transport 送回應。
  • 參數 maddr:Client Transport 紀錄
  • 參數 ttl:Client Transport 紀錄
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds
比較:Contact

2018年11月10日 星期六

lightning

Lightning to USB-C

Lightning 訊號 (接頭單面有 8 接腳點對稱到另一面,插座只有單面)

1A8B8GNDGround
2A7B2L0+Lane 0 positive
3A6B3L0-Lane 0 negative
4A5B1ID0Identification/Control 0
5A4B4VBUSPower
6A3B6D-Lane 1 negative
7A2B7D+Lane 1 positive
8A1B5GNDIdentification/Control 1

USB 線含有 4 IC

  • NXP SP3D2
  • STMicroelectronics USB2A
  • Texas Instruments BQ2025
  • markings identified as 4S (functionality is known)
週邊
  • 母 USB-A + 母 Lightning (Lightning 對 USB 3 相機轉接器 $1190):轉成母 USB 3 + Lightning,讀取相片、影片,連接各種 USB 周邊設備,如集線器、乙太網路、音訊/MIDI 介面、讀卡機 (可轉HDMI?)
  • 母 micro USB (Lightning 對 Micro USB 轉接器 $590):可連接 micro USB 連接線進行同步與充電。
  • Ethernet + 母 Lightning (Belkin 乙太網路 + 電源轉接器 $3290):支援 PoE,Belkin Connect app 韌體更新
  • 轉成 HDMI 或 VGA + Lightning $1490 https://www.techbang.com/posts/12467
  • 轉成兩個 Lightning:可同時聽音樂和充電 (Belkin Lightning Audio + Charge Rockstar)
  • 轉成 3.5mm Audio + Lightning:可同時聽音樂和充電 (Belkin 3.5 mm Audio + Charge Rockstar)
  • 母 3.5mm Audio 或 EarPods:內有 DAC「338S00140/A0QK1623/TW」,有可能來自 Cirrus Logic。
  • SD 相片讀卡機 (只能讀相片?)
  • USB 相片轉接器 (只能讀相片?)

Apple iPad Camera Connection Kit 裡面的 Camera Connector (轉 USB 母頭那個)

lightning:USB slave、USB master (SD reader)、HDMI/VGA output

參考

  1. https://www.techinsights.com/blog/systems-analysis-apple-lightning-usb-cable
  • https://www.techinsights.com/blog/apple-lightning-cable-teardown
  • https://zh.ifixit.com/News/8448/apple-audio-adapter-teardown

2018年11月4日 星期日

bash: SHELL GRAMMAR

bash 基本指令以 control operator 結束,組成成份用 blank 分隔,格式依序如下:
[變數指定...] 指令 [引數...][輸出入導向]
用到的 metacharacter 除了輸出入轉向,就只有 blank。

回傳值是 exit status。如果被 signal n 結束,回傳 128+n 。

基本指令可以組合成 Pipeline 和 Lists。另外還有 Compound Commands、Coprocesses、Function。

Pipelines

pipeline 是一系列用控制運算子「|」或「|&」分隔的一個以上基本指令 (一個也算!?)。
[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]
前一個指令的標準輸出透過 pipe 導到下個指令的標準輸入。如果使用「|&」包含標準錯誤一併導向,相當於「2>&1 |」。


所有指令結束後才回傳最後指令的離開狀態。但如果啟用 pipefail 選項時,回傳最後回傳非 0 指令的狀態。如果 pipeline 前面有 !,邏輯反向離開狀態。

如果前面有保留字 time,結束時回報執行歷經的時間、耗用的使用者及系統時間。加選項 -p 採用 POSIX 輸出格式。如果在 posix 模式,下個 token 以「-」開始,time 不作為保留字。可設定變數 TIMEFORMAT 指定時間訊息的顯示格式。

如果在 posix 模式,time 之後可能跟著換行,此時顯示 shell 和其 children 耗用的全部使用者和系統時間。

pipeline 的每個指令都在獨立的行程 (i.e., subshell) 執行。
一個 pipeline 稱為一個 job。

Lists

list 是一系列用控制運算子 「;」、「&」、「&&」或「||」分隔的一個以上 pipeline,最後可以「;」或「&」結束。<newline> 可取代「;」。

這些 list 運算子前後有特定的執行關係:
  • 「&&」:執行成功 (回傳 0) 才執行後面的指令。
  • 「||」:執行失敗 (回傳非 0) 才執行後面的指令。
  • 「;」或換行:等候執行完成後再執行後面的指令。
  • 「&」:在 subshell 背景執行,不等候完成直接回傳 0,後面指令開始執行。
其中「&&」和「||」有相同 precedence,再來是「;」和「&」有相同 precedence。
List 最後回傳最後指令執行的結果。

Compound Commands

複合指令

(list)

在 subshell 環境執行 list (見 bash COMMAND EXECUTION ENVIRONMENT),結束不影響原本環境變數。

{ list; }

在目前 shell 環境執行 list。需要以 <newline> 或「;」結束,是由於「{」、「 }」只是保留字,不是 metacharacter 能區隔出字,需要有 metacharacter 區隔出字來,且 list 必須有「;」或換行表示最後的指令結束。

((expression))

進行算術運算,結果 0 回傳 1;否則回傳 0。

[[ expression ]]

依據 conditional expression 是 true 回傳 0,否則回傳 1。不進行 Word splitting 和 pathname expansion。進行 tilde expansion、parameter and variable expansion、arithmetic expansion、command  substitution、process  substitution、和 quote removal。Conditional operators such as -f must be unquoted to be recognized as primaries.

當 == (或 =) 或 != 用在 [[ 指令,右邊是 pattern 進行 Pattern Matching,如同啟用選項 extglob。如果啟用選項 nocasematch,比對不分大小寫。pattern 任何部份可以 quoted 來強迫直接字串比對。

另外還有額外 binary operator「=~」使用 extended  regular  expression (regex()),如果  regular  expression syntactically 錯誤回傳 2。Substrings  matched  by parenthesized subexpressions within the regular expression 存在 BASH_REMATCH 陣列,其中 index 0 是整個符合的部份,index n 是第 n 個parenthesized subexpression 符合的部份。

用下列優先權,表示式可以結合:
( expression ):優先進行。
! expression:True if expression is false.
expression1 && expression2:expression1 false 回傳 false,否則看 expression2 是否 true。
expression1 || expression2:expression1 true 回傳 true,否則看 expression2 是否 true。

for name [ [ in [ word ... ] ] ; ] do list ; done

擴展 in 之後的 word 列表產生許多項目,變數 name 依序設成每個項目來執行 list。如果省略 in word,則拿有設的位置參數當作項目。

for (( expr1 ; expr2 ; expr3 )) ; do list ; done

expr1、expr2、和 expr3 都是 arithmetic expression,如有省略則 evaluate 為 1。首先計算 expr1,然後重複計算 expr2 直到為 0。每次 expr2 算出不為 0,執行 list 後計算 expr3。

select name [ in word ] ; do list ; done

擴展 in 之後的 word 列表產生許多項目,在標準錯誤前置順序數字印出。如果省略 in word,則拿有設的位置參數當作項目。然後顯示 PS3 prompt,讀取標準輸入選擇項目設為 name 執行 list。直到讀到 EOF 後結束。讀到其它不合理的值 name 會設為 null。讀到的會存在變數 REPLY。

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

首先擴展 word,然後依序比對每個 pattern,採用 pathname 擴展的比對方式。word 用到的擴展有 tilde expansion、parameter  and  variable  expansion、arithmetic  expansion、command substitution、process substitution、和 quote removal。每個檢查的 pattern 用到的擴展有 tilde expansion、parameter and variable expansion、arithmetic expansion、command substitution、和 process substitution。如果啟用選項 nocasematch,比對不管大小寫。當找到一個符合,執行對應的 list。如果使用 ;; operator,不進行後續比對。如果使用 ;&,持續執行下個 pattern 的 list。使用 ;;& 持續比對剩下的 patten,如果符合執行其 list。比對沒符合回傳 0。

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

執行 if list,回傳 0 則執行 then list,否則依序執行每個 elif  list 如果回傳 0 執行對應的 then list 後結束。都沒有回傳 0,執行 else list。

while list-1; do list-2; done
until list-1; do list-2; done

while:只要 list-1 回傳 0,不斷執行 list-2 。
until:只要 list-1 回傳 0,不斷執行 list-2 。 

Coprocesses

coprocess 是前置保留字 coproc 的 shell 指令,在子 shell 背景執行,並建立雙向 pipe。
coproc [NAME] command [redirections]
建立名為 NAME 的 coprocess,預設名稱是 COPROC。如果 command 是基本指令,不能提供 NAME,否則會被解釋成基本指令的第一個字。當 coprocess 執行時,會建立名為 NAME 的陣列。指令的標準輸出透過 pipe 連結到指定給 NAME[0] 的 file descriptor,指令的標準輸入透過 pipe 連結到指定給 NAME[1] 的 file descriptor。pipe 在任何 redirection 前建立。那些 file descriptor 可用標準 word expansion 作為其它指令的引數或導向。執行 coprocess 的 process ID 可見變數 NAME_PID。內建指令 wait 可用來等候 coprocess 結束。

Shell Function

shell 函數像基本指令一樣呼叫,暫時使用新的一組位置參數來自引數和參數 # 執行 compound command,結束後回復。如下宣告名為 name 的 shell 函數:

[function] name () compound-command [redirection]
function name { compound-command; } [redirection]
有 () 可以不需要保留字 function,沒有 () 需要 { list; }。

在 posix 模式,name 不可以跟 POSIX special builtins 一樣。shell 函數定義的離開狀態是 0,除非有 syntax 錯誤或 name 跟 readonly 函數相同。執行的離開狀態是裡面最後執行指令的離開狀態。

shell function stores  a  series  of commands for later execution.
Functions are executed
       in the context of the current shell;  no  new  process  is  created  to
       interpret  them  (contrast  this with the execution of a shell script).

特殊參數 0 不變,變數 FUNCTNAME 的 first  element 設為函數名稱。

其它執行環境不變,除了
  • DEBUG 和 RETURN traps (見 bash 內建指令 trap),除非函數有給 trace 屬性 (見內建指令 declare) 或透過內建指令 set 啟用 shell 選項 -o functrace
  • ERR trap,除非啟用 shell 選項 -o errtrace。
變數跟 caller 共享,函數 local 變數可以用內建指令 local 宣告。

函數可以 recursive 執行。變數 FUNCNEST 如果設為大於 0 的值,限制函數最大 nesting level,執行超過的話造成整個 command abort。

函數內執行內建指令 return,結束函數,RETURN  trap 的指令會執行。

函數名稱和定義可用有 -f 選項的內建指令 declare 或  typeset 列出。-F 選項只列出函數名稱。函數可用內建指令 export -f 匯出給子 shell 使用。內建指令 unset -f 可刪除函數。註:相同名稱的函數和變數會造成傳遞的環境變數 multiple identically-named  entries 而可能造成問題。

參考來源

bash mag-page 的 SHELL GRAMMAR 和 FUNCTIONS 節

2018年11月1日 星期四

[C] VLA

VLA (Variable-Length Array) 起自 C99,讓陣列大小可以在執行時才決定,雖然有方便性,但有缺點:
  • 執行時需要決定陣列大小,會慢一點,程式也會大一點。(或許最終使用的記憶體較少)
  • LLVM Clang 不支援在 struct 裡放 VLA (GCC 支援),只支援 C99 形式的 VLA。
  • 最重要的是 VLA 的使用在 kernel 堆疊有安全疑慮 (security implication)。 
Linux v4.20 移除了 VLA,並加了「-Wvla」來發出編譯告警,避免不經意再加入 VLA 的程式碼。

參考:
  1. The Linux Kernel Is Now VLA-Free: A Win For Security, Less Overhead & Better For Clang
延伸閱讀:
  • 大小 0 的陣列

SIP header Via

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