WAPPUSH 原理 基于短信网关WAP推送的实现

转自: http://blog.163.com/htlxyz@126/blog/static/168594029200962011411709/


基于短信网关WAP推送的实现
WAP PUSH既有信息发送主动、及时的特点,又有可随时随地接收信息的优势,因而具有良好的应用前景。该文简单介绍了WAP PUSH系统框架、推送协议和推送方式,重点介绍了通过短信网关实现WAP推送的实现方法。 
1 WAP推送技术简介

  1.1 什么是WAP推送

  WAP推送(PUSH)技术是一种建立在客户服务器上的机制,就是由服务器主动将信息发往客户端的技术。同传统的拉(PULL)技术相比,最主 要的区别在于推送(PUSH)技术是由服务器主动向客户机发送信息,而拉(PULL)技术则是由客户机主动请求信息。PUSH技术的优势在于信息的主动性 和及时性。

  PUSH技术在Internet中没能取得大的成功,原因是多方面的。主要原因在于固定网中计算机等固定设备为用户提供了足够的资源和能力去查 找信息所以用户通常将它作为一个浏览信息的窗口,而不是被动的信息接收者。同时固定网用户对于信息准确性的要求远甚于对其及时性的要求,因此PUSH技术 未能得到广泛的应用。

  而在移动网中,由于存在着网络带宽、移动终端能力以及自费标准高昂等诸多限制,使得用户查找信息受到了一定的限制,如果将重要的信息主动及时地 推送到用户的移动设备上无疑会大大方便用户。移动通信的优点是移动设备能够随时随地接收信息因此PUSH技术在移动网中可以大展拳脚,WAP PUSH正是PUSH技术和移动通信两者扬长避短相结合的产物。WAP PUSH是在移动网络中应用的PUSH技术,它结合了一般PUSH技术和移动网络的特点。它的系统框架、使用协议和服务方式与固定网上的PUSH技术有很 大不同。

  1.2 WAP PUSH系统框架

  WAP PUSH框架主要包括推送发起者(PI:PUSH Initiator)、推送代理网关(PPG:PUSH ProxyGateway)和推送客户(PC:PUSH Client)三个功能部分。PI位于Internet中,而PC在WAP领域,PI和WAP客户端所使用的协议是不同的,需要在中间建立一个协议转换 网关即PPG。PPG通过推送访问协议(PAP:PUSH AccessProtocol)与PI通信,通过推送空间传输协议(PUSH OTA:PUSH over-the-Air)完成向客户推送信息的数据传输任务。

  PPG完成推送体系结构中的大部分工作,包括从Internet到移动网的访问接入,以及与其有关的认证、安全、客户端控制等所有工作。PPG 所提供的主要服务包括:1)PI的标识、鉴权和访问控制;2)对推送内容进行语法分析,并依据数据类型定义(DTD)检错纠错;3)客户寻址与信息传 输;4)PAP与PUSH OTA间的协议转换;5)为提高无线信道中的传输效率,对信息进行压缩、编译等处理。

  另外,PPG还可以通过别名机制实现组播和广播,即将某些特定的地址别名映射到组播或广播的操作中,具体方案可以由系统实现者决定。不同的客户端,其能力是不同的,PPG还要负责响应PI的客户能力查询请求,以便于PI针对不同的客户端构造合适的内容格式。

  1.3 推送协议

  PAP是PI与PPG间的通信协议,它使用可扩展标记语言(XML)作为消息的描述语言,通过简单的请求响应机制完成数据的传输。PAP可以在多种通信协议(包括超文本传输协议(HTTP)、简单邮件传输协议(SMTP)等)之上实现。

  而PUSH OTA是运行于无线会话协议(WSP)之上的一个较为简单的协议层,负责从PPG到客户代理的数据传输。PUSH OTA可使用面向连接的会话和无连接会话两种WSP层服务,对于使用连接会话的推送,需要在PPG和客户端间预先有一个激活的会话上下文;对于无连接的推 送,则通过预留的端口来完成通信。

  1.4 推送服务方式

  WAP的推送协议中定义了服务指示(SI:Service Indication)和服务加载(SL:Service Load)两项服务,以给用户和网络运营者更多的选择。服务指示是将新信息的指示和相关的通用资源标识符(URI)推送给用户,由用户选择是立即处理信息 还是以后处理。服务加载是将一项服务的URI推送给用户,然后客户端自动地使用PULL技术根据该URI启动服务。两种服务的区别在于用户是否介入推送信 息的处理过程。SL对推送信息的处理对用户来说是透明的,而SI则在指示用户的同时,请用户对随后的处理做出选择。
PUSH可以将某一站点或某一 业务的链接通过短信发送到支持WAP PUSH功能的手机上,这样用户只需要阅读这条短信,打开短信中的链接,就可以直接访问业务了。因此,WAP PUSH实现了短信和WAP业务的结合,节省了用户寻找业务的时间,方便用户直接找到并使用自己喜欢的业务。

  2 短消息网关简介

  短消息网关(ISMG)是处于短消息中心(SMSC)和业务提供商(SP)之间的设备,它为这两个实体的数据交换提供安全、快捷的通道。网关与 短消息中心之间使用SMPP协议(Short Message Peer to Peer,短消息点对点协议), 与SP之间使用CMPP协议(China Mobile Peer to Peer,中国移动点对点协议),因此短消息网关需要完成协议的转换、计费、路由、安全和网络管理等功能。具体说来, SMPP通信代理系统主要实现网关和GSM网中短消息中心(SMSC)的连接,确保准确接收和发送数据,实现高效、可靠的数据传输。为了达到规范要求的不 超过0.001%的数据丢包率,SMPP通信代理需要支持流量控制。CMPP通信代理系统主要是实现和SP服务提供商的连接,与SMPP通信代理系统不同 的是,由于协议的影响,CMPP通信代理是服务器端,需等待SP的连接,而SMPP通信代理是客户端,需要主动连接SMSC。短消息网关处理系统是网关中 最复杂的处理进程,它完成的任务包括:向GNS(汇接网关) 查询路由,维护路由表,进行协议转换和数据分发。防火墙系统主要为网关系统提供安全保障,它包括IP包过滤和身份验证。短信网关计费系统主要形成各种计费 话单,为计费提供依据。业务管理系统主要完成对业务进行统计报告,生成报表,为运营者对用户数据的添加、修改、删除以及对网关系统的监控、查询、操作和维 护提供接口和界面。

  3 基于短信网关发送WAP PUSH

  WAP PUSH的发送有两种途径,一个是通过PPG网关,另外一个是通过SMPP协议。其中SMPP是一个基本协议,在中国主要有三个由其派生的协议:中国移动 的CMPP协议,中国联通的SGIP(在CDMA上是ETIP),以及小灵通的SMGP。通过中国移动的PPG网关发送WAP PUSH有着开发周期长,调测流程较复杂等不足,而使用CMPP协议即基于短信网关来进行WAP PUSH发送灵活性比较高,相对比较简单。

  3.1 WAP PUSH发送的实现模式

  可通过计算机串口上连接GSM MODEM,用它向手机发送WAP PUSH。这种方法发WAP PUSH又分三种模式:BLOCK 模式、TEXT 模式和PDU 模式。BLOCK 模式现在用的很少了, TEXT 模式则只能发送ASCII 码,它不能发送中文的UNICODE码,而PDU 模式开发起来则较为复杂,它需要编写专门的函数来将文本转换为PDU 格式,但PDU 模式被所有手机支持,可以使用任何字符集,它也是手机默认的编码方式,所以选用PDU模式发送WAP PUSH.

  3.2 PDU 模式 

用PDU 模式发送 WAP PUSH可以使用三种编码: 7-bit 编码、8-bit 编码和UCS2 编码。7-bit 编码用于发送普通的ASCII 字符,8-bit 编码通常用于发送数据消息,UCS2 编码用于发送Unicode 字符。由于要实现中文WAP PUSH的发送,所以选择用UCS2 编码,即中文Unicode 码。 
⑴ UCS2 编码原理 所谓UCS2 编码,是将单个的字符(1-2 个字节)按ISO/IEC10646 的规定,转变为16 位 的Unicode 宽字符。即将单个的字符转换为由四位的‘0’-‘9’、‘A’-‘F’的数字和字 母组成的字符串。待发送的消息以UCS2 码的形式进行发送。 
⑵ 通过UCS2 编码我们得到中文Unicode 码,接着就可以进行发送PDU 串的编制了。从表面上看,PDU 串是ASCII 码串,同样由‘0’-‘9’、‘A’-‘F’这些数字和字母组成。它们是8 位字节的十六进制数,或者BCD 码十进制数。PDU 串除了包含所发送的消息本身外,还包含很多其它参数信息,如服务中心号码、目标号码和编码方式等

  例如

0051000BA13108086406F600F5A7850B05040B8423F_
0000303010129060603AE81EA8DCA02056A0045C6080C033231312e_
3133362e3135332e33302f776170707573682f70757368496e6465782e_
6a73703f7075736849643d3035303531313134313630353231000103E8A_
FB7E782B9E587BBE4BBA5E4B88BE993BEE68EA5E88EB7E58F96E5BDA9E4BFA1E58685
E5AEB9000101_

  为一串可以成功发送的WAP PUSH,其中包括了汉字描述和WAP页面地址。具体分析如下

  00 SMSC 地址信息的长度 00表示用手机上设置短信中心号码,PDU 串的“SMSC 址格式”段和“SMSC 地址”段将省去

  51 基本参数(TP-MTI/VFP) 不要求发送回复

  00 消息基准值(TP-MR)

  0B 对方电话的长度

  A1 目标地址格式 A1表示为国内格式

  3108086406F6 目标地址,补‘F’凑成偶数位后奇偶位互换

  00 协议标识(TP-PID) 是普通GSM 类型,点到点方式

  F5 用户信息编码方式 (TP-DCS)

  A7 有效期(TP-VP)

  85 用户信息长度(TP-UDL)

  0B WAP PUSH头部的总长度

  05040B8423F0表示接下来是一个WAP PUSH

  00 表示是Concatenated Short Messages

  03 长度

  03 reference number

  01 表示分成1个短信发送

  01 当前包的序号

  29060603AE81EA8DCA WSP

  02 标记位

  05 -//WAPFORUM//DTD SI 1.0//EN

  6A UTF-8

  00 标记开始

  45

  C6

  08

  0C href="http://

  03 字符串开始

3231312e3133362e3135332e33302f776170707573682f
70757368496e6465782e6a73703f7075736849643d3035303531313134313630353231 URL

  00 URL 字符串结束

  01 >

  03 内容描述字符串开始

  E8AFB7E782B9E587BBE4BBA5E4B88BE993BEE68EA_
5E88EB7E58F96E5BDA9E4BFA1E58685E5AEB9 内容描述字符串

  00 内容描述字符串结束

  01

  01

  由以上分析可以看出,WAP PUSH可以被当作一种特殊的短信来发送,WAP PUSH包发送的内容实际上跟通过PPG网关发送的XML原理相同,但是经过了压缩。压缩之后的格式称为WBXML,这种格式将一些标记用代码来表示。然 而WBXML的缩略标记分为两部分,一部分是所有类型的XML都通用的,另一部分是不同类型的XML有着不同的解释。
用户接收到此类信息时,在客 户端手机支持WAP的情况下,可以直接访问到信息中加载的WAP网站地址,这样服务器也达到了推广业务方便用户使用的目的。由于在UCS2 编码方式下,可发送短消息的最大字符数是140字节,即WAP PUSH中的推送URL与描述文字的总字符数为140,因此描述文字的字数限制与推送的URL长度有关。

  4 结束语

  WAP PUSH技术结合了PUSH技术的优势和移动通信服务的特性,具有良好的应用前景。但是WAP PUSH技术仍然存在着一些亟待解决的问题,如信息的鉴权与认证、信息的准确性、如何避免垃圾信息等。如何解决好这些问题将是WAP PUSH技术成功的关键。另外,随着GPRS技术和3G无线通信技术的发展,无线信道的带宽将逐步增大,WAP PUSH也将能进一步推送多媒体信息,有着更宽广的应用前景

0:12 | 添加评论 | 固定链接 | 引用通告 (0) | 记录它 | WAP开发
9月15日
什么是WAP PUSH?

所 谓推(PUSH)技术是一种基于客户服务器机制、由服务器主动将信息发往客户端的技术,其传送的信息通常是用户事先预订的。同传统的拉(PULL)技术相 比,最主要的区别在于前者是由服务器主动向客户机发送信息,而后者则是由客户机主动请求信息。PUSH技术的优势在于信息的主动性和及时性,而弱势则是信 息的准确性较差。

    PUSH技术在Internet中没能取得大的成功,原因是多方面的。在固定网中 计算机等固定设备为用户提供了足够的资源和能力去查找信息 所以用户通 常将它作为一个浏览信息的窗口,而不是被动的信息接收者。固定网用户对于信息准确性的要求远甚于对其及时性的要求。

    而在移动网中,由于存在着网络带宽、移动设备能力以及高昂的资费标准等诸多限制,用户无法像在固定网中一样方便地查找信息,如果将重要的信息主动及时地推 送到用户的移动设备上 无疑会大大方便用户。移动通信的优点是移动设备能够随时随地接收信息 因此PUSH技术可以在移动网中大显身手,WAP PUSH正是PUSH技术和移动通信两者扬长避短相结合的产物。

    WAP PUSH是在移动网络中应用的PUSH技术 它既具有一般PUSH技术的特点 又拥有移动网络的特点。它的系统框架、使用协议和服务方式与固定网上的PUSH技术有很大不同。

         WAP PUSH技术结合了PUSH技术的优势和移动通信服务的特性,具有良好的应用前景。将PUSH技术应用于移动通信领域可以产生许多电信增值业务 这包括移 动中收发电子邮件,随时获得股价信息、天气预报、新闻以及位置相关服务等。所有这些服务的共同特点在于用户对信息的及时性要求比较高,用户希望能够通过手 机、PDA等移动设备随时随地地得到该种服务。但是,WAP PUSH技术仍然存在着一些亟待解决的问题,如信息的鉴权与认证、信息的准确性、如何避免垃圾信息等。如何解决好这些问题将是WAP PUSH技术成功的关键。另外,随着GPRS技术和3G无线通信技术的发展,无线信道的带宽将逐步增大,WAP PUSH也将能进一步推送多媒体信息。 
其实WAP Push没有那么神秘- -
                                      


只要写一个XML文件,然后用WBXML编码就可以了。下面是一个Sample

    挑战脉动,挑战你我

这个XML的DTD定义在http://www.openmobilealliance.org/tech/dtd/si.dtd

WMXML定义在http://www.w3.org/1999/06/NOTE-wbxml-19990624/

编码后作为二进制短消息发送给用户,记得讲tp_udhi设为1就可以了

WBXML编码的代码如下:

#include
#include
#include
#include
#pragma warning(disable : 4267)
#include
#pragma warning(default : 4267)
#include

#include
#include

using boost::uint8_t;
using std::cout;
using std::endl;
using std::setw;
using std::hex;
using std::setfill;

///


/// Series of well known constants and static uint8_t values used when encoding
/// a document to WBXML
///

class WBXML
{
public:
static const uint8_t CHAR_NULL = 0x00;

static const uint8_t VERSION_1_1 = 0x01;
static const uint8_t VERSION_1_2 = 0x02;

static const uint8_t CHARSET_UTF_8 = 0x6A;

static const uint8_t TAGTOKEN_END = 0x01;
static const uint8_t TOKEN_INLINE_STRING_FOLLOWS = 0x03;
static const uint8_t TOKEN_OPAQUEDATA_FOLLOWS = 0xC3;

static uint8_t setTagTokenIndications(uint8_t token, bool hasAttributes, bool hasContent)
{
if (hasAttributes)
   token |= 0xC0;
if (hasContent)
   token |= 0x40;

return token;
}
};

///


/// Encapsulates the Service Indication WAP Push instruction.
/// Full documentation can be found athttp://www.openmobilealliance.org/tech/affiliates/wap/wap-167-serviceind-20010731-a.pdf?doc=wap-167-serviceind-20010731-a.pdf
///

class ServiceIndication
{
public:
// Allowed values of the action attribute of the indication tag
enum Action {NotSet = -1, signal_none = 0, signal_low, signal_medium, signal_high, Delete};
// Well known DTD token
static const uint8_t DOCUMENT_DTD_ServiceIndication = 0x05;   // ServiceIndication 1.0 Public Identifier

// Tag Tokens
static const uint8_t TAGTOKEN_si = 0x5;
static const uint8_t TAGTOKEN_indication = 0x6;
static const uint8_t TAGTOKEN_info = 0x7;
static const uint8_t TAGTOKEN_item = 0x8;

// Attribute Tokens
static const uint8_t ATTRIBUTESTARTTOKEN_action[5];
static const uint8_t ATTRIBUTESTARTTOKEN_created = 0xA;
static const uint8_t ATTRIBUTESTARTTOKEN_href = 0xB;
static const uint8_t ATTRIBUTESTARTTOKEN_href_http = 0xC;   // http://
static const uint8_t ATTRIBUTESTARTTOKEN_href_http_www = 0xD; // http://www.
static const uint8_t ATTRIBUTESTARTTOKEN_href_https = 0xE;   // https://
static const uint8_t ATTRIBUTESTARTTOKEN_href_https_www = 0xE; // https://www.
static const uint8_t ATTRIBUTESTARTTOKEN_si_expires = 0x10;
static const uint8_t ATTRIBUTESTARTTOKEN_si_id = 0x11;
static const uint8_t ATTRIBUTESTARTTOKEN_ // Attribute Value Tokens
static const uint8_t ATTRIBUTEVALUETOKEN_com = 0x85;      // .com/
static const uint8_t ATTRIBUTEVALUETOKEN_edu = 0x86;      // .edu/
static const uint8_t ATTRIBUTEVALUETOKEN_net = 0x87;      // .net/
static const uint8_t ATTRIBUTEVALUETOKEN_org = 0x88;      // .org/

private:
static std::map m_hrefStartTokens;
static std::map m_attributeValueTokens;
static int initializeServiceIndication()
{
m_hrefStartTokens["https://www."] = ATTRIBUTESTARTTOKEN_href_https_www;
m_hrefStartTokens["http://www."] = ATTRIBUTESTARTTOKEN_href_http_www;
m_hrefStartTokens["https://"] = ATTRIBUTESTARTTOKEN_href_https;
m_hrefStartTokens["http://"] = ATTRIBUTESTARTTOKEN_href_http;

m_attributeValueTokens[".com/"] = ATTRIBUTEVALUETOKEN_com;
m_attributeValueTokens[".edu/"] = ATTRIBUTEVALUETOKEN_edu;
m_attributeValueTokens[".net/"] = ATTRIBUTEVALUETOKEN_net;
m_attributeValueTokens[".org/"] = ATTRIBUTEVALUETOKEN_org;
return 0;
}

std::string m_href;
std::string m_text;
time_t m_createdAt;
time_t m_expiresAt;
Action m_action;

public:
ServiceIndication(const std::string & href, const std::string & text, Action action) :
   m_href(href), m_text(text), m_action(action)
{
static int __unused = initializeServiceIndication();
}

ServiceIndication(const std::string & href, const std::string & text, time_t createdAt, time_t expiresAt) :
m_href(href), m_text(text), m_action(Action::NotSet), m_createdAt(createdAt), m_expiresAt(expiresAt)
{
}

ServiceIndication(const std::string & href, const std::string & text, time_t createdAt, time_t expiresAt, Action action) :
m_href(href), m_text(text), m_action(action), m_createdAt(createdAt), m_expiresAt(expiresAt)
{
}

///


/// Generates a uint8_t array comprising the encoded Service Indication
///

/// The encoded body
//01 05 6a 00 45 c6 0c 03 77 61 702e6672616374616c6973742e636e0008 01034120574150205075736820
//746f20746865204672616374616c6973742073697465000101

//01 05 6a 00 45 c6 0b 03 68 74 74703a2f2f7761702e6672616374616c6973742e636e0008010341205741
//50205075736820746f20746865204672616374616c6973742073697465000101

std::vector getWBXMLBytes() const
{
std::vector vec;
vec.push_back(WBXML::VERSION_1_1);
vec.push_back(DOCUMENT_DTD_ServiceIndication);
vec.push_back(WBXML::CHARSET_UTF_8);
vec.push_back(WBXML::CHAR_NULL);

// start xml doc
vec.push_back(WBXML::SetTagTokenIndications(TAGTOKEN_si, false, true));
vec.push_back(WBXML::SetTagTokenIndications(TAGTOKEN_indication, true , true));

// href attribute
// this attribute has some well known start tokens that 
// are contained within a static hashtable. Iterate through
// the table and chose the token.
size_t i = 0;
uint8_t hrefTagToken = ATTRIBUTESTARTTOKEN_href;
for(std::map::const_iterator it = m_hrefStartTokens.begin(); it != m_hrefStartTokens.end(); ++it)
{
   const std::string & startString = (*it).first;
   if(m_href.find(startString) == 0)
   {
    hrefTagToken = (*it).second;
    i = startString.length();
    break;
   }
}
vec.push_back(hrefTagToken);

writeInlineString(vec, m_href.substr(i));
/* 
* Date elements removed as does not seem to be supported
* by all handsets, or I"m doing it incorrectly, or it"s a version 1.2
* thing.

// created attrbute
stream.WriteByte(ATTRIBUTESTARTTOKEN_created);
WriteDate(stream, this.CreatedAt);

// si-expires attrbute
stream.WriteByte(ATTRIBUTESTARTTOKEN_si_expires);
WriteDate(stream, this.ExpiresAt);
*/
// action attibute
if (m_action != Action::NotSet)
   vec.push_back(getActionToken(m_action));

// close indication element attributes
vec.push_back(WBXML::TAGTOKEN_END);

// text of indication element
writeInlineString(vec, m_text);

// close indication element
vec.push_back(WBXML::TAGTOKEN_END);
// close si element
vec.push_back(WBXML::TAGTOKEN_END);

return vec;
}


private:
///


/// Gets the token for the action attribute
///

/// Interruption level instruction to the handset
/// well known uint8_t value for the action attribute
uint8_t getActionToken(Action action) const
{
return ATTRIBUTESTARTTOKEN_action[(int)action];
}

///


/// Encodes an inline string into the stream using UTF8 encoding
///

/// The target stream
/// The text to write
void writeInlineString(std::vector & vec, const std::string & text) const
{
// indicate that the follow bytes comprise a string
vec.push_back(WBXML::TOKEN_INLINE_STRING_FOLLOWS);

// write character bytes
std::string utf8Text = stringutil::w2utf8(stringutil::a2w(text));
copy(utf8Text.begin(), utf8Text.end(), back_inserter(vec));

// end is indicated by a null uint8_t
vec.push_back(WBXML::CHAR_NULL);
}
///


/// Encodes the DateTime to the stream.
/// DateTimes are encoded as Opaque Data with each number in the string represented
/// by its 4-bit binary value
/// eg: 1999-04-30 06:40:00
/// is encoded as 199904300640.
/// Trailing zero values are not included.
///

/// Target stream
/// DateTime to encode
void writeDate(std::vector & vec, time_t date) const
{
struct tm * gm = gmtime(&date);
uint8_t buffer[7];

buffer[0] = (uint8_t)( (gm->tm_year + 1900) / 100);
buffer[1] = (uint8_t)((gm->tm_year + 1900) % 100);
buffer[2] = (uint8_t)(gm->tm_mon + 1);
buffer[3] = (uint8_t)(gm->tm_mday);

uint8_t dateLength = 4;

if(gm->tm_hour != 0)
{
   buffer[4] = (uint8_t)gm->tm_hour;
   dateLength = 5;
}

if(gm->tm_min != 0)
{
   buffer[5] = (uint8_t)gm->tm_min;
   dateLength = 6;
}

if(gm->tm_sec != 0)
{
   buffer[6] = (uint8_t)gm->tm_sec;
   dateLength = 7;
}

// write to stream
vec.push_back(WBXML::TOKEN_OPAQUEDATA_FOLLOWS);
vec.push_back(dateLength);
copy(buffer, buffer + dateLength, back_inserter(vec));
}
};

const uint8_t ServiceIndication::ATTRIBUTESTARTTOKEN_action[5] = {0x5, 0x6, 0x7, 0x8, 0x9};
std::map ServiceIndication::m_hrefStartTokens = std::map();
std::map ServiceIndication::m_attributeValueTokens = std::map();

///


/// Well known values used when generating WSP (Wireless Session Protocol) headers
///

class WSP
{
public:
static const uint8_t TRANSACTIONID_CONNECTIONLESSWSP = 0x25;

static const uint8_t PDUTYPE_PUSH = 0x06;

static const uint8_t HEADER_CONTENTLENGTH = 0x8D;

static const uint8_t HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[4];

static const uint8_t HEADER_APPLICATIONTYPE = 0xaf;
static const uint8_t HEADER_APPLICATIONTYPE_x_wap_application_id_w2 = 0x82;

static const uint8_t HEADER_PUSHFLAG[2];

};

const uint8_t WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[4] = {0x03,0xAE,0x81,0xEA};
const uint8_t WSP::HEADER_PUSHFLAG[2] = {0xB4, 0x84};

///


/// Well known values used when generating a WDP (Wireless Datagram Protocol) header
///

class WDP
{
public:
static const uint8_t INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT = 0x05;
};

///


/// Encapsulates an SMS WAP Push message
///

class PushMessage
{
private:
// Ports for the WDP information element, instructing the handset which 
// application to load on receving the message
static const uint8_t WDP_DESTINATIONPORT[2];
static const uint8_t WDP_SOURCEPORT[2];

ServiceIndication serviceIndication;

public:
PushMessage(const std::string & href, const std::string & text) :
serviceIndication(href, text, ServiceIndication::signal_high)
{
}

///


/// Generates the body of the SMS message
///

/// uint8_t array
std::vector getSMSBytes() const
{
std::vector vec;

getWDPHeaderBytes(vec);
#ifdef _DEBUG
cout << "getWDPHeaderBytes\n";
for(size_t i = 0; i < vec.size(); ++i)
{
   cout << hex << setw(2) << setfill("0") << ((int)vec[i]);
}
cout << "\n" << endl;
size_t start = vec.size();
#endif
getPDUBytes(vec);
#ifdef _DEBUG
cout << "getPDUBytes\n";
for(size_t i = start; i < vec.size(); ++i)
{
   cout << hex << setw(2) << setfill("0") << ((int)vec[i]);
}
cout << "\n" << endl;
#endif

return vec;
}

///


/// Generates the PDU (Protocol Data Unit) comprising the encoded Service Indication
/// and the WSP (Wireless Session Protocol) headers
///

/// uint8_t array comprising the PDU
void getPDUBytes(std::vector & vec) const
{
std::vector body = serviceIndication.getWBXMLBytes();

std::vector header = getWSPHeaderBytes((uint8_t)body.size());
#ifdef _DEBUG
cout << "getWSPHeaderBytes\n";
for(size_t i = 0; i < header.size(); ++i)
{
   cout << hex << setw(2) << setfill("0") << ((int)header[i]);
}
cout << "\n" << endl;

cout << "serviceIndication.getWBXMLBytes\n";
for(size_t i = 0; i < body.size(); ++i)
{
   cout << hex << setw(2) << setfill("0") << ((int)body[i]);
}
cout << "\n" << endl;
#endif

copy(header.begin(), header.end(), back_inserter(vec));
copy(body.begin(), body.end(), back_inserter(vec));
}

///


/// Generates the WSP (Wireless Session Protocol) headers with the well known
/// uint8_t values specfic to a Service Indication
///

/// the length of the encoded Service Indication
/// uint8_t array comprising the headers
//25060a03ae81eaaf828dc1b484
//25060a03ae81eaaf828dc8b484

std::vector getWSPHeaderBytes(uint8_t contentLength) const
{
std::vector vec;

vec.push_back(WSP::TRANSACTIONID_CONNECTIONLESSWSP);
vec.push_back(WSP::PDUTYPE_PUSH);

uint8_t headerLength = sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8) / sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[0])
   + sizeof(WSP::HEADER_APPLICATIONTYPE)
   + sizeof(WSP::HEADER_APPLICATIONTYPE_x_wap_application_id_w2)
   + sizeof(WSP::HEADER_CONTENTLENGTH)
   + 1
   + sizeof(WSP::HEADER_PUSHFLAG) / sizeof(WSP::HEADER_PUSHFLAG[0]);
vec.push_back(headerLength);

copy(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8
   , WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8 + sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8) / sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[0])
   , back_inserter(vec));


vec.push_back(WSP::HEADER_APPLICATIONTYPE);
vec.push_back(WSP::HEADER_APPLICATIONTYPE_x_wap_application_id_w2);

vec.push_back(WSP::HEADER_CONTENTLENGTH);
vec.push_back((uint8_t)(contentLength + 128));

copy(WSP::HEADER_PUSHFLAG
   , WSP::HEADER_PUSHFLAG + sizeof(WSP::HEADER_PUSHFLAG) / sizeof(WSP::HEADER_PUSHFLAG[0])
   , back_inserter(vec));

return vec;
}

///


/// Generates the WDP (Wireless Datagram Protocol) or UDH (User Data Header) for the 
/// SMS message. In the case comprising the Application Port information element
/// indicating to the handset which application to start on receipt of the message
///

/// uint8_t array comprising the header
void getWDPHeaderBytes(std::vector & vec) const
{
uint8_t headerLength = sizeof(WDP::INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT)
   + 1
   + sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0])
   + sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0]);
vec.push_back(headerLength);

vec.push_back(WDP::INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT);
vec.push_back((uint8_t)(sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0]) + sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0])));
copy(WDP_DESTINATIONPORT
   , WDP_DESTINATIONPORT + sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0])
   , back_inserter(vec));
copy(WDP_SOURCEPORT
   , WDP_SOURCEPORT + sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0])
   , back_inserter(vec));
}
};

const uint8_t PushMessage::WDP_DESTINATIONPORT[] = {0x0b, 0x84};
const uint8_t PushMessage::WDP_SOURCEPORT[] = {0x23, 0xf0};

你可能感兴趣的:(WAPPUSH 原理 基于短信网关WAP推送的实现)