最近项目上需要用到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;
这样就能通过server端的认证,但没有走正途。
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...