最近项目上需要用到gloox的开源代码,结合项目的特性,对XMPP有了部分了解,期间碰到的问题大致如下:
1. Gloox工程的移植
网上有不少Gloox的测试代码,找一份XCode平台下能编译通过的即可,笔者找的一份为“glooxForIos”,
wiki的地址为:http://code.google.com/p/gloox-for-ios/
2. Connect.h分析
Connect.h是gloox的测试类代码,它实现了ConnectionListener, LogHandler, MessageHandler, TLSHandler等几个接口,分别对连接,日志,消息,TLS进行管理,具体的功能看其源码就知道了。
其主要的成员变量有:
Client *j; TLSBase* m_tls; std::string m_send; const JID rcpt;Client就是自身的客户端,构建的时候需要传入一个JID作为构造参数;
TLSBase负责对数据的加密,解密,构建安全通道(负责握手)等;
m_send就是传递的消息实体;
rcpt是要与之通信的对象,也需要jid来进行构造。
主要的接口有:
void xtlsSend() void start()
前者负责给其它client发送消息,后再负责初始化client;
在项目中,会发现xtlsSend完全不够用,它发送的消息格式需要重构,发送server能认识的消息。
3. 初始化工作
a. jid的设置jid不能直接挂上邮件名,比如“**@xx.com”, 这样的设置不会影响认证的过程,但认证之后的present,message会收不到。在后面需要挂上reource标签,比如“/ios”,标明是来自ios的,以示区别。
b.server的地址
这个地址值,在JID中,通过setServer的方式设置进去。
c.auth的方式
在连接成功后,server端会发送认证方式到client,具体如下:
<stream:stream from='im.example.com' id='vgKi/bkYME8OAj4rlXMkpucAqe4=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>SCRAM-SHA-1-PLUS</mechanism> <mechanism>SCRAM-SHA-1</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> <pipelining xmlns='urn:xmpp:features:pipelining'/> <c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://prosody.im/' ver='ItBTI0XLDFvVxZ72NQElAzKS9sU='/> </stream:features>
http://xmpp.org/extensions/xep-0305.html
d. 修改认证方式
由于项目中server提供的认证方式中有一个token的,没能搞清楚XMPP中是如何通过Token的方式跟系统认证。
于是修改了clientBase中的
void ClientBase::startSASL( SaslMechanism type )
case SaslMechPlain: { // a->addAttribute( "mechanism", "PLAIN" ); // std::string tmp; // if( m_authzid ) // tmp += m_authzid.bare(); // // tmp += '\0'; // if( !m_authcid.empty() ) // tmp += m_authcid; // else // tmp += m_jid.username(); // tmp += '\0'; // tmp += m_password; // a->setCData( Base64::encode64( tmp ) ); a->addAttribute( "mechanism", "TOKEN" ); a->setCData( ((XMPPJabberInfo)XMPPCoreMgr::sharedInstance()->getJabberData()).getJabberToken() ); break;
5. 密码的设置
密码的认证,XMPP要求不高,可以为任意一个密码,但不能为空。
bool Client::handleNormalNode( Tag* tag )
会进行判定,如果密码为空,则不进行登录。
else if( !username().empty() && !password().empty() ) { if( !login() ) { logInstance().err( LogAreaClassClient, "The server doesn't support" " any auth mechanisms we know about" ); disconnect( ConnNoSupportedAuth ); } }
TBD...