#2 CMPP: UDH 头

2022-05-13

中国移动 CMPP 协议中的 UDH 头设计源自 SMPP 协议,SMPP 协议又是参考的 GSM 短信服务的相关标准。

  1. TP_UDHI 字段,1 bit,对应 GSM 协议中的 UDHI,表示短信中是否包含 UDH。

UDH

UDH,User Data Header,定义在 GSM 03.40 / 3GPP 23.040 中。
UDH 是短信中可能包含的一个二进制头部,对短信服务进行拓展。
可以实现以下功能:

  1. 长短信(级联短信):切割成多条,需要通过 UDH 中的总条数和序号来组装。
  2. EMS,增强型消息服务,支持颜色,文件格式,图片,动画,音乐
  3. MMS,彩信
  4. 本地语言转换表(Nation Language Shift Table):在 GSM-7 的框架上支持其他国家的语言。

概念:

  • TP(Transfer Layer Protocol,传输层协议)
  • TP-UD(User Data,用户数据),就是短信的正文部分
  • 如果存在 UDH,那就在 TP-UD 的开头
  • TP-UDHI(User Data Header Indicator,用户数据头指示器)
  • 消息的第六 bit,表示短信中是否存在 UDH

UDHL:UDH Length,UDH 的第一字节,表示 UDH 的长度。
UDH 剩余部分是若干标签 + 长度 + 值的组合。其中标签又叫做 IEI(Information-Element-Identifier,信息元素标识符),占一字节。

例如:05 00 03 5F 03 01

  • 第一字节 05,表示后面还有 5 Byte 是 UDH
  • 第二字节 00,按照下面的 IEI 表,表示级联短信
  • 第三字节 03,表示 IEI Length,也就是说这个 IEI 还有 3 Byte
  • 第四字节 5F,按照级联短信的设计,这个 Byte 是一个随机 int8,避免不同批次短信搞混
  • 第五字节 03,按照级联短信的设计,这个 Byte 表示总短信长度
  • 第六字节 01,按照级联短信的设计,这个 Byte 表示当前短信在这一批次短信中的序号

重点:如果短信采用 GSM-7 编码,则需要对齐到 7 bit,也就是说真正需要的 bit 数是 math.ceil(6 * 8 / 7) * 7
上面这个例子,8 bit _ 6 = 48 bit,需要增加 1 bit,对齐成 7 bit _ 7 = 49 bit。

UDH Information Elements

IEI (hex) Meaning Classification Length May repeat
00 Concatenated short messages, 8-bit reference number SMS Control 3 no
01 Special SMS Message Indication SMS Control 2 yes
02 Reserved N/A N/A yes
03 Not used to avoid misinterpretation as <LF> character N/A N/A yes
04 Application port addressing scheme, 8 bit address SMS Control 2 no
05 Application port addressing scheme, 16 bit address SMS Control 4 no
06 SMSC Control Parameters SMS Control 1 no
07 UDH Source Indicator SMS Control 1 yes
08 Concatenated short message, 16-bit reference number SMS Control 4 no
09 Wireless Control Message Protocol SMS Control 1-255 yes
0A Text Formatting EMS Control 3-4 yes
0B Predefined Sound EMS Content 2 yes
0C User Defined Sound (iMelody max 128 bytes) EMS Content 2-129 yes
0D Predefined Animation EMS Content 2 yes
0E Large Animation (1616 times 4 = 324 =128 bytes) EMS Content 129 yes
0F Small Animation (88 times 4 = 84 =32 bytes) EMS Content 33 yes
10 Large Picture (32*32 = 128 bytes) EMS Content 129 yes
11 Small Picture (16*16 = 32 bytes) EMS Content 33 yes
12 Variable Picture EMS Content 4-255 yes
13 User prompt indicator EMS Control 1 yes
14 Extended Object EMS Content 7-255 yes
15 Reused Extended Object EMS Control 3 yes
16 Compression Control EMS Control 3-255 no
17 Object Distribution Indicator EMS Control 2 yes
18 Standard WVG object EMS Content 1-255 yes
19 Character Size WVG object EMS Content 1-255 yes
1A Extended Object Data Request Command EMS Control 0-255 no
1B Reserved for future EMS features N/A 0-255 yes
1C Reserved for future EMS features N/A 0-255 yes
1D Reserved for future EMS features N/A 0-255 yes
1E Reserved for future EMS features N/A 0-255 yes
1F Reserved for future EMS features N/A 0-255 yes
20 RFC 822 E-Mail Header SMS Control 1 no
21 Hyperlink format element SMS Control 0-255 yes
22 Reply Address Element SMS Control 1-255 no
23 Enhanced Voice Mail Information SMS Control 0-255 no
24 National Language Single Shift SMS Control 1 no
25 National Language Locking Shift SMS Control 1 no
26 – 6F Reserved for future use N/A 0-255 N/A
70 – 7F (U)SIM Toolkit Security Headers SMS Control 0-255 ?
80 – 9F SME to SME specific use SMS Control 0-255 ?
A0 – BF Reserved for future use N/A 0-255 ?
C0 – DF SC specific use SMS Control 0-255 ?
E0 – FF Reserved for future use N/A 0-255 ?

参考资料与拓展阅读

#1 CMPP 短信网关协议

2022-03-29

术语

  • ISMG: Internet Short Message Gateway
  • SMPP: Short Message Peer to Peer
    一个国际上比较通用的短信网关协议
    CMPP 可能兼容 SMPP,因为 Wireshark 会将 CMPP 会话识别成 SMPP
  • CMPP: China Mobile Peer to Peer
    中国移动开发的的短信网关协议
  • SMC: Short Message Center
  • GNS: Gateway Name Server
    相当于 CMPP 网络的路由器
  • SP: Service Provider
  • SMC: Short Message Control
  • ISMG_Id: 网关代码
  • SP_Id: SP 企业代码
  • SP_Code: SP 服务代码
  • Service_Id: SP 业务类型
  • MO: 手机发送 Originate
  • MT: 手机接收 Terminated

网络连接

CMPP 基于 TCP 协议。可以长连接,也可以短连接。
长连接支持一次连接发送多次 CMPP 消息,没有消息的时候需要维持心跳。
短连接则是一次 CMPP 通信之后就断开连接。

关于心跳:
建议每 3 分钟一次心跳,如果 60 秒内没有心跳响应,应该再次心跳,总共 3 次没有响应就断开连接。
关于重试(网关与 SP 之间,网关之间):
60 秒之后没有响应,立即重试,总共 3 次没有响应就停发。

消息采用并发方式发送,加以滑动窗口流量控制,窗口大小参数 W 可配置,现阶段建议为 16,即接收方在应答前一次收到的消息最多不超过 16 条。

关于短连接:
60 秒超时,重试 2 次。

端口

  • 7890 长连接(SP 与网关之间)
  • 7900 短连接(SP 与网关之间,网关之间)
  • 7930 长连接(网关之间)
  • 9168 短连接(网关与 GNS 之间)

数据类型

var Total_Length uint32 // 消息总长度
var Command_Id uint32   // 命令或响应类型
var Sequence_Id uint32  // 消息流水号, 递增, 步长为 1, 循环使用
命令 Command_Id
CMPP_CONNECT 0x00000001
CMPP_TERMINATE 0x00000002
CMPP_SUBMIT 0x00000004
CMPP_DELIVER 0x00000005
CMPP_QUERY 0x00000006
CMPP_CANCEL 0x00000007
CMPP_ACTIVE_TEST 0x00000008
CMPP_FWD 0x00000009
CMPP_MT_ROUTE 0x00000010
CMPP_MO_ROUTE 0x00000011
CMPP_GET_ROUTE 0x00000012
CMPP_MT_ROUTE_UPDATE 0x00000013
CMPP_MO_ROUTE_UPDATE 0x00000014
CMPP_PUSH_MT_ROUTE_UPDATE 0x00000015
CMPP_PUSH_MO_ROUTE_UPDATE 0x00000016

RESP Command_Id 则是对应的 Command_Id 最高 4 位为 8,即 0x8X

SP 与 ISMG 之间的通信

对于一般开发来说就这 7 个接口。

  1. 建立连接 CMPP_CONNECT
  2. 断开连接 CMPP_TERMINATE
  3. 提交信息 CMPP_SUBMIT
  4. 获取状态 CMPP_DELIVER
  5. 撤回信息 CMPP_CANCEL
  6. 查询信息 CMPP_QUERY
    只是一些统计信息,我想不到这个接口的应用场景
  7. 链路检测 CMPP_ACTIVE_TEST

连接 CMPP_CONNECT

var Source_Addr [6]byte // SP_Id
var AuthenticatorSource [16]byte // SP_Code
// md5(Source_Addr + 9 字节 0 + shared secret + timestamp)
// timestamp: MMDDHHMMSS, 月日时分秒, 补 0
var Version uint8 // 版本号, 高 4 位表示主版本号, 低 4 位表示次版本号, 最大 15.15
var Timestamp uint32 // 时间戳, 默认为 0

CMPP_CONNECT_RESP

var Status uint8 // 状态, 0 正确, 1 结构错误, 2 非法源地址, 3 认证错误, 4 版本错误, 5 其他错误
var AuthenticatorISMG [16]byte // ISMG 认证码
// md5(Status + AuthenticatorSource + shared secret)
// 如果认证错误, 此项为空
var Version uint8 // 服务器支持的最大版本号

断开连接 CMPP_TERMINATE

无请求消息体,无响应消息体

提交信息 CMPP_SUBMIT

var Msg_Id uint64       // 消息标识, 网关负责自主生成,SP 留空
var Pk_total uint8      // 消息总条数, 从 1 开始
var Pk_number uint8     // 消息序号, 从 1 开始
var Registered_Delivery uint8 // 是否要求返回状态确认报告, 0 不需要, 1 需要, 2 产生 SMC 话单 (该类型短信仅供网关计费使用,不发送给目的终端)
var Msg_level uint8     // 信息级别, 0 低, 1 中, 2 高
var Service_Id [10]byte // 业务类型
var Fee_UserType uint8  // 计费用户类型, 0 普通用户, 1 行业用户, 2 用户组
var Fee_terminal_Id [32]byte // 被计费用户的号码
var TP_pid uint8        // GSM协议类型, 0 GSM 03.40, 1 CDMA, 2 WCDMA, 3 CDMA2000, 4 联通移动TD专用协议
var TP_udhi uint8       // GSM协议类型
var Msg_Fmt uint8       // 信息格式, 0 ASCII 串, 3 短信写卡操作, 4 二进制, 8 UCS2 编码, 15 含 GB 汉字
var Msg_src [6]byte     // 消息发送者, SP_Id
var FeeType [2]byte     // 资费类别
var FeeCode [6]byte     // 资费代码, 以分为单位
var ValId_Time [17]byte // 存活有效期,格式遵循 SMPP3.3 协议
var At_Time [17]byte    // 定时发送时间, YYMMDDhhmmsstnnp, t 是 1/10 秒,nn 是与 UTS 时间的差值 00-48,p `+/-`
var Src_Id [21]byte     // 源号码
// SP 的服务代码或前缀为服务代码的长号码,
// 网关将该号码完整的填到 SMPP 协议 Submit_SM 消息相应的 source_addr 字段
// 该号码最终在用户手机上显示为短消息的主叫号码
var DestUsr_tl uint8    // 接收信息的用户数量, 小于 100
var Dest_terminal_Id [][21]byte // 接收短信的用户号码 (MSISDN), 21 * DestUsr_tl
var Msg_Length uint8    // 短消息长度
var Msg_Content []byte  // 短消息内容
var Reserve [8]byte     // 保留

注意:关于短信群发的问题,若 SP 对于群发消息不要求状态报告的回送时,才可以考虑群发,否则必须逐条发送。

关于 TP_udhi 的解释:

如果 = 1,则需要在 Msg_Content 中加入一个 udhi 头,定义如下:

  1. 六字节
    05 00 03 开头,分别表示剩余 5 字节,xxx,剩余标识长度为 3
    第四字节,唯一标识
    第五字节,短信条数
    第六字节,序号
  2. 七字节
    06 08 04 开头,分别表示剩余 6 字节,xxx,剩余标识长度为 4
    第四五字节,唯一标识
    第六字节,短信条数
    第七字节,序号

CMPP_SUBMIT_RESP

var Msg_Id uint64       // 消息表示, SP 自主生成
var Result uint8        // 结果, 0 正确, 1 消息结构错, 2 命令字错, 3 消息序号重复, 4 消息长度错,
                        //       5 资费代码错, 6 超过最大信息长, 7 业务代码错, 8 流量控制错, 9~ 其他错误
  • MMDDHHMMSS,26 位
    月份 4 位, 1-12
    日期 5 位, 1-31
    小时 5 位, 0-23
    分钟 6 位, 0-59
    秒钟 6 位, 0-59
  • 网关代码,22 位
  • 序列号,16 位,递增, 步长为 1, 循环使用

查询 CMPP_QUERY

var Time [8]byte // YYYYMMDD
var Query_Type uint8 // 查询类型, 0 总数查询, 1 按业务类型查询
var Query_Code [10]byte // 查询码, 查询类型为 0 时无效, 查询类型为 1 时此处为业务类型
var Reserve [8]byte // 保留

CMPP_QUERY_RESP

var Time [8]byte
var Query_Type uint8
var Query_Code [10]byte
var MT_TLMsg uint32 // 接收消息总数
var MT_TLusr uint32 // 接收用户总数
var MT_Scs uint32   // 转发成功总数
var MT_WT uint32    // 待转发总数
var MT_FL uint32    // 转发失败总数
var MO_Scs uint32   // 发送成功总数
var MO_WT uint32    // 待发送总数
var MO_FL uint32    // 发送失败总数

送交短信 CMPP_DELIVER

从网关发送出来的消息

var Msg_Id uint64
var Dest_Id [21]byte            // 目的号码
var Service_Id [10]byte
var TP_pid uint8
var TP_udhi uint8
var Msg_Fmt uint8
var Src_terminal_Id [21]byte    // 源号码
var Registered_Delivery uint8
var Msg_Length uint8
var Msg_Content []byte          // Msg_Length
var Reserved [8]byte
var Msg_Id uint64
var Stat [7]byte
// DELIVRD 送达
// EXPIRED 过期
// DELETED 删除
// UNDELIV 未送达
// ACCEPTD 接收
// UNKNOWN 非法
// REJECTD 拒绝
var Submit_time [10]byte
var Done_time [10]byte
var Dest_terminal_Id [21]byte
var SMSC_sequence uint32

SP 等待状态报告 48 小时。

CMPP_DELIVER_RESP

var Msg_Id uint64
var Result uint8

删除短信 CMPP_CANCEL

var Msg_Id uint64

CMPP_CANCEL_RESP

var Success_Id uint8 // 0 成功, 1 失败

链路检测 CMPP_ACTIVE_TEST

无消息体。

CMPP_ACTIVE_TEST_RESP

var Reserved [8]byte