SASL → Resource Bind → Create Session まで
#include <cassert>
#include <iostream>
#include <boost/make_shared.hpp>
#include <gloox/iq.h>
#include <gloox/parser.h>
#include <gloox/base64.h>
#include <gloox/connectiontcpclient.h>
#include <gloox/connectiontls.h>
class Bot : public gloox::ConnectionDataHandler, gloox::TagHandler, gloox::TLSHandler
{
public:
Bot() :
client_(new gloox::ConnectionTCPClient(this, log_, "talk.google.com", 5222)),
raw_client_(client_),
parser_(this)
{
gloox::ConnectionError ret = client_->connect();
assert(ret == gloox::ConnNoError);
client_->receive();
}
virtual void handleReceivedData(const gloox::ConnectionBase* con, const std::string& data)
{
std::cerr << "[recv] " << data << std::endl;
std::string copied = data;
int pos = parser_.feed(copied);
assert(pos < 0);
}
virtual void handleConnect(const gloox::ConnectionBase* con)
{
send(
"<?xml version='1.0' ?>"
"<stream:stream "
"xmlns:stream=\"http://etherx.jabber.org/streams\" "
"version=\"1.0\" xmlns=\"jabber:client\" "
"to=\"gmail.com\" "
"xml:lang=\"en\" "
"xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" >");
}
virtual void handleTag(gloox::Tag* tag)
{
if (tag->name() == "stream" && tag->xmlns() == "http://etherx.jabber.org/streams") {
sid_ = tag->findAttribute( "id" );
}
else {
if(tag->name() == "features" && tag->xmlns() == "http://etherx.jabber.org/streams")
{
if(tag->hasChild("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls") )
{
send(gloox::Tag("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls").xml());
}
else if(tag->hasChild("mechanisms", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl") &&
tag->findChild("mechanisms")->hasChildWithCData("mechanism", "PLAIN"))
{
gloox::Tag a("auth", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
a.addAttribute("mechanism", "PLAIN");
std::string tmp;
tmp += '\0';
tmp += "seijro";
tmp += '\0';
tmp += "PASSWORD";
a.setCData(gloox::Base64::encode64(tmp));
send(a.xml());
}
else if(tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind"))
{
gloox::Tag iq("iq", "xmlns", "jabber:client");
iq.addAttribute("type", "set");
iq.addAttribute("id", "binding");
gloox::Tag *bind = new gloox::Tag("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
gloox::Tag *resource = new gloox::Tag("resource");
resource->setCData("myresource");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
else if(tag->name() == "proceed" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-tls")
{
gloox::ConnectionTLS* encryption_client = new gloox::ConnectionTLS(this, client_.get(), log_);
client_.reset(encryption_client);
encryption_client->registerTLSHandler(this);
gloox::ConnectionError ret = client_->connect();
assert(ret == gloox::ConnNoError);
}
else if(tag->name() == "success" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-sasl")
{
send(
"<?xml version='1.0' ?>"
"<stream:stream "
"xmlns:stream=\"http://etherx.jabber.org/streams\" "
"version=\"1.0\" xmlns=\"jabber:client\" "
"to=\"gmail.com\" "
"xml:lang=\"en\" "
"xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" >");
}
else if (tag->name() == "iq")
{
if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind"))
{
resource_ = tag->findChild("bind")->findChild("jid")->cdata();
gloox::Tag iq("iq", "xmlns", "jabber:client");
iq.addAttribute("type", "set");
iq.addAttribute("id", "create_session");
iq.addChild(new gloox::Tag("session", "xmlns", "urn:ietf:params:xml:ns:xmpp-session"));
send(iq.xml());
}
}
}
}
virtual void handleEncryptedData(const gloox::TLSBase* tls, const std::string& data)
{
std::cout << "handleEncryptedData" << std::endl;
}
virtual void handleDecryptedData(const gloox::TLSBase* tls, const std::string& data)
{
std::cout << "handleDecryptedData" << std::endl;
}
virtual void handleHandshakeResult(const gloox::TLSBase* tls, bool, gloox::CertInfo& cert)
{
std::cout << "handleHandshakeResult" << std::endl;
}
virtual void handleDisconnect(const gloox::ConnectionBase* con, gloox::ConnectionError)
{
std::cout << "handleDisonnect" << std::endl;
}
private:
void send(const std::string &data)
{
std::cerr << "[send] " << data << std::endl;
client_->send(data);
}
gloox::LogSink log_;
boost::shared_ptr<gloox::ConnectionBase> client_;
boost::shared_ptr<gloox::ConnectionBase> raw_client_;
gloox::Parser parser_;
std::string sid_;
std::string resource_;
};
int main()
{
Bot bot;
}
[send] <?xml version='1.0' ?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="gmail.com" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace" >
[recv] <stream:stream from="gmail.com" id="7D3EB506BD78CED4" version="1.0" xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client"><stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>X-GOOGLE-TOKEN</mechanism></mechanisms></stream:features>
[send] <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
[recv] <proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
handleHandshakeResult
[send] <?xml version='1.0' ?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="gmail.com" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace" >
[recv] <stream:stream from="gmail.com" id="B2A71EB8DE19C974" version="1.0" xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">
[recv] <stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>X-GOOGLE-TOKEN</mechanism></mechanisms></stream:features>
[send] <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>XXXXXXXXXXXXXXXXXXXXXXX</auth>
[recv] <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
[send] <?xml version='1.0' ?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="gmail.com" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace" >
[recv] <stream:stream from="gmail.com" id="0522E247621D8813" version="1.0" xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">
[recv] <stream:features><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>
[send] <iq xmlns='jabber:client' type='set' id='binding'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>myresource</resource></bind></iq>
[recv] <iq id="binding" type="result"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>seijro@gmail.com/myresource65631060</jid></bind></iq>
[send] <iq xmlns='jabber:client' type='set' id='create_session'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>
[recv]
[recv] <iq type="result" id="create_session"/>
[recv]
[recv] <message type="chat" to="seijro@gmail.com/myresource65631060" id="test_002" from="seijro@gmail.com/amachang4B803057"><body>Hello, World!!</body></message>