天天看點

WAP PUSH解析(1)——SMS PDU編碼

WAP PUSH是封裝在SMS PDU中的,是以要解析WAP PUSH,首先要先看SMS PDU編碼,這是SMS / MMS / WAP PUSH等業務的基礎。WAP PUSH是通過發送給終端的,是以本文主要看Delivery類型的PDU編碼。另外,如果PDU要封裝的内容過長,會接收到拆分過的多條SMS,本文對接收到的多條Concatenated SMS的拼接也做了闡述。

一、單個SMS PDU的封裝

下面是接收到的一個完整PDU:

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

(注:因顯示的原因,人為的進行了分行,其實這個包中間并沒有換行)

SMS PDU的封裝并不是在所有的位置都有固定的涵義,它是逐個掃描的,解析完上一個字段,才知道接下來的含義,或者後面字段的長度。

1. 短信中心

   SC長度

      為08,是以接下來的8位元組為短信中心内容

   SC 91683108200105f0

      91為國際号,加上’+’号;

      後面的号碼編碼規則為GSM BCD:683108200105f0 –> 8613800210500

   是以,得到短信中心号碼:+8613800210500

現在PDU掃描到了紅色處(綠色部分已經掃描結束):

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

2. FirstByte:

    0x44 = 0100 0100

    bit1.bit0: mti

          00 Delevery

          01 Submit

          10 Status Report

    bit7: TP-Reply-Path

          1 有

          0 無

    bit6: 訓示是否有userdata header (UDH)

          1 有

          0 無

    bit4.bit3: TP-Validity-Period (submit類型的PDU才有意義)

          00: len=0

          10: len=1

          01/11: len=7

現在PDU掃描到了紅色處(綠色部分已經掃描結束):

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

3. 發送方位址(Originating address)

   位址長度: 

     長度Length = 08 

     得到位址占用的位元組數(包含長度本身): 2 + (Length + 1) / 2 = 6

     位址在08a001560886

   08 a001560886

   TOA: 0xA0 = 1010 0000

     bit7: 必須為1

     bit6...bit4: ton = 010

          000 TON_UNKNOWN(0)

          001 TON_INTERNATIONAL(1)

          010 TON_NATIONAL(2)

          011 TON_NETWORK(3)

          100 TON_SUBSCRIBER(4)

          101 TON_ALPHANUMERIC(5)

          110 TON_ABBREVIATED(6)

   是以,發送方位址為:

          01560886 

       -> 10658068

現在PDU掃描到了紅色處(綠色部分已經掃描結束):

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

4. TP-Protocol-Identifier(TP-PID)

   TS 23.040 9.2.3.9

   01

現在PDU掃描到了紅色處(綠色部分已經掃描結束):

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

5. TP-Data-Coding-Scheme

 (TS 23.038)

     0x04 = 0000 0100

     bit7: 如果此位為0

           bit6: automaticDeletion

           bit5: userDataCompressed

           bit4: hasMessageClass

           if (!userDataCompressed)  // bit5

              bit3...bit2: 

                00 ENCODING_7BIT

                10 ENCODING_16BIT

                01/11: ENCODING_8BIT

     bit7...bit4: 如果這四位為1111 

           bit2:

             0 ENCODING_7BIT

             1 ENCODING_8BIT

     Bit7...bit4: 如果這四位為1100, 1101 or 1110

           1110 ENCODING_16BIT(UCS-2)

           1100/1101 ENCODING_7BIT

     bit1...bit0: 如果有Class

           00 CLASS_0

           01 CLASS_1

           10 CLASS_2

           11 CLASS_3

   是以,這個PDU包資料是8Bit編碼,沒有Class類型。

現在PDU掃描到了紅色處(綠色部分已經掃描結束):  

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

6.TP-Service-Centre-Time-Stamp

   短信中心下發的時間戳,這個編碼和長度固定

  21609290251223

   21 Year:   12

   60 Month:  06

   92 Day:    29

   90 Hour:   09

   25 Minute: 52

   12 Second: 21

   23 TimeZone Byte

     時區同樣高4bit在低位,低4bit在高位

     Bit3為時區+/-标志位

     計算的結果為1/4時區

     0x23 = 0010 0011

         Bit3: sign symbol

           0 +

           1 -

         0010 x011 -> x011 0010 = 0011 0010 = 32 [quarter-hour]

     TimeZone: + 32 / 4 = +8

   是以,得到時間戳為:12-06-29 09:52:21 GMT+8

現在PDU掃描到了紅色處(綠色部分已經掃描結束):  

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

7. UserDataHeader – UDH

    UserDataLength: 長度包含UDH和UD,但不包含這個位元組本身

      0x6E = 110

    UserDataHeaderLength: 該長度不包含這個位元組本身

      0x06 = 6

    UserDataHeader: 05040b8423f0

      UDH中可能有多段,是以要不斷解析,直到UDH結束

      UDH每段含義開頭都有個id做标示,接下來是後面具體含義的資料的位元組個數,然後才是具體資料

      id - 0x05

        0x00 ELT_ID_CONCATENATED_8_BIT_REFERENCE

        0x08 ELT_ID_CONCATENATED_16_BIT_REFERENCE

        0x05 ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT

        0x04 ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT

        0x24 ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT

        0x25 ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT

      length: 4

      dest port: 0b84 -> 0x0B84 = 2948

          2948 for WAP_PUSH

      src port: 23f0 -> 0x23F0

   PDU是用端口來識别具體業務的,比如這個PDU的目的端口是2948,就是WAP PUSH的PDU封裝。

   另外,如果還是長SMS,UDH中還會有長SMS拼接所需要的資訊,UDH中就有了多重的含義。

現在PDU掃描到了紅色處(綠色部分已經掃描結束):  

0891683108200105f04408a0015608860104216092902512236e0605040b8423f0120601ae02056a

0045c60c033231312e3133362e3130372e37382f646f776e2e7068703f703d413063303026733d38

3500080103e68e8ce68fa1e882a1e5b882e58588e69cbaefbc8ce6aca2e8bf8ee4bdbfe794a8e689

8be69cbae8af81e588b8e38082000101

現在, PDU封裝的基本資訊已經解析完畢,剩下的是UserData,也已經區分出具體的業務,可以交給具體業務子產品去解析。

二、多條SMS PDU的封裝

因為單條SMS長度的限制,一條長SMS的發送是拆分成多條SMS發送的,接收時也是多條接收,然後拼接。

下面執行個體是分兩次接收到的一條長SMS的兩個SMS PDU:

PDU[0]

0891683108200105f04405a02125f00004216092717455238c0b05040b8423f000030b0201790601

ae02056a0045c6080c03662e31303038362e636e2f662f736a6678000103e689bee69c8be58f8be3

8081e69fa5e5a4a9e6b094e38081e79c8be5b08fe8afb4e38081e79c8be696b0e997bbe280a6e689

8be69cbae9a39ee4bfa1efbc8ce7ae80e58d95e4bda0e79a84e7949fe6b4bbefbc81e8b5b6e5bfab

e4b88be8bd

PDU[1]

0891683108200105f04405a02125f0000421609271745523220b05040b8423f000030b0202bde4bd

93e9aa8ce6898be69cbae9a39ee4bfa1000101

UserDataHeader裡有多SMS的資訊,我們就從這裡開始分析。

1. UDH之前部分

PDU[0]與PDU[1]的UDH之前的部分完全相同,與前面講的單條SMS PDU的封裝也相同,是以這裡不再贅述這部分的解析。

2. UserDataHeader– UDH

    UserDataLength: 

      長度包含UDH和UD,但不包含這個位元組本身

      長度指的是本PDU中的長度

      PDU[0]: 0x8C = 140

      PDU[1]: 0x22 = 34

    UserDataHeaderLength: 該長度不包含這個位元組本身

      0x0B = 11

    UserDataHeader:

      UDH中可能有多段,是以要不斷解析,直到UDH結束

      UDH每段含義開頭都有個id做标示,接下來是後面具體含義的資料的位元組個數,然後才是具體資料

      PDU[0]: 05040b8423f0 00030b0201

      PDU[1]: 05040b8423f0 00030b0202

      id - 0x05

        0x00 ELT_ID_CONCATENATED_8_BIT_REFERENCE

        0x08 ELT_ID_CONCATENATED_16_BIT_REFERENCE

        0x05 ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT

        0x04 ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT

        0x24 ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT

        0x25 ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT

      length: 4

      dest port: 0b84 -> 0x0B84 = 2948

        2948 PORT_WAP_PUSH

      src port: 23f0 -> 0x23F0 

      這段說明這是WAP PUSH的PDU封裝

      id - 0x00

      length: 03

      ConcatRef.refNumber: 0B

      ConcatRef.msgCount: 02

      ConcatRef.seqNumber:

        PDU[0]: 01

        PDU[1]: 02

      這段說明這是長SMS的分拆出來的PDU封裝包:

        refNumber辨別是屬于哪個長SMS,分拆出來的各個分拆包都有相同的refNumber

        msgCount長SMS分拆出來的包的個數

        seqNumber訓示到達的該包在各個分拆包中的順序:取值1.. msgCount

                 因為分拆出來的包到達接收端的順序不一定是按次序的,是以拼接時,要按照這個順序。

3. UserData

這是一條長SMS拆分出的兩條,是以UserData要按seqNumber次序拼接起來。

PDU[0]

0891683108200105f04405a02125f00004216092717455238c0b05040b8423f000030b0201790601

ae02056a0045c6080c03662e31303038362e636e2f662f736a6678000103e689bee69c8be58f8be3

8081e69fa5e5a4a9e6b094e38081e79c8be5b08fe8afb4e38081e79c8be696b0e997bbe280a6e689

8be69cbae9a39ee4bfa1efbc8ce7ae80e58d95e4bda0e79a84e7949fe6b4bbefbc81e8b5b6e5bfab

e4b88be8bd

PDU[1]

0891683108200105f04405a02125f0000421609271745523220b05040b8423f000030b0202bde4bd

93e9aa8ce6898be69cbae9a39ee4bfa1000101

把PDU[0]和PDU[1]中的紅色的UserData拼接起來,得到完整的UserData。

790601ae02056a0045c6080c03662e31303038362e636e2f662f736a6678000103e689bee69c8be5

8f8be38081e69fa5e5a4a9e6b094e38081e79c8be5b08fe8afb4e38081e79c8be696b0e997bbe280

a6e6898be69cbae9a39ee4bfa1efbc8ce7ae80e58d95e4bda0e79a84e7949fe6b4bbefbc81e8b5b6

e5bfabe4b88be8bdbde4bd93e9aa8ce6898be69cbae9a39ee4bfa1000101

至此,完整的UserData已經得到,在UDH中也已經區分出具體的業務,可以交給具體業務子產品去解析。

三、小結            

Delivery SMS PDU中可以解析出:Service Centre(可無)、有無UDH、PDU類型的識别、發送方号碼、TP-PID、編碼格式、Class類型(可無)、時間戳、UDH(可無。含:UserData長度、UserDataHeader長度,可能有端口号或Concat資訊,等)以及包含具體業務資料的UserData。

關于UserData中具體WAP PUSH業務的封裝格式,在後續文章《WAP PUSH解析(2)——WSP以及WBXML編碼》和《WAP PUSH解析(3)——Android中實作》中解讀。