Я пытаюсь выполнить XMPP Handshake Flow, упомянутый в https://developers.google.com/cloud-print/docs/rawxmpp.
Это позволяет устройству подписываться и получать уведомления.
На данный момент я изучил следующие варианты:
1) libcurl
2) Gloox C / C ++
3) TXMPP
4) Либингл
Какой вариант будет хорошим выбором для начала? Я хотел бы рассмотреть поддержку и обслуживание библиотеки в качестве основного фактора.
Спасибо
Ниже приводится мое решение с использованием библиотеки Gloox C / C ++ для выполнения XMPP Handshake Flow:
#include <cassert>
#include <iostream>
#include <boost/make_shared.hpp>
#include <iq.h>
#include <parser.h>
#include <base64.h>
#include <connectiontcpclient.h>
#include <connectiontls.h>
#include <connectiondatahandler.h>
#include <connectionhttpproxy.h>
#include <logsink.h>
#include <client.h>
#include <connectionsocks5proxy.h>
using namespace gloox;
using namespace std;
const string proxyHost = ""; //specify proxy server name
const int proxyPort = 0; //specify proxy port number
const string xmppHost = "talk.google.com";
const int xmppPort = 5222;
Client *c;
ConnectionBase *client_ ;
ConnectionTCPClient* conn0;
ConnectionHTTPProxy* conn2;
class Bot: public ConnectionDataHandler, TagHandler, TLSHandler{
public:
Bot(): parser_(this)
{
conn0 = new ConnectionTCPClient(this, log_, proxyHost, proxyPort);
ConnectionHTTPProxy* conn2 = new ConnectionHTTPProxy( this, conn0, log_, xmppHost, xmppPort);
client_ = conn0;
ConnectionError ce = ConnNoError;
ce = conn2->connect();
assert(ce == ConnNoError);
conn2->receive();
}
virtual void handleConnect(const ConnectionBase* con) {
send("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">\r\n");
}
virtual void handleReceivedData(const ConnectionBase* con, const string& data) {
cerr << "[recv] " << data << endl;
string copied = data;
int pos = parser_.feed(copied);
assert(pos < 0);
}
virtual void handleTag(Tag* tag) {
if (tag->name() == "stream" && tag->xmlns() == "http://etherx.jabber.org/streams") {
sid_ = tag->findAttribute("id");
} else{
if (tag->name() == "features") {
if (tag->hasChild("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls")) {
send(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", "X-OAUTH2"))
{
Tag a("auth", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
a.addAttribute("mechanism", "X-OAUTH2");
a.addAttribute("service", "chromiumsync");
a.addAttribute("allow-generated-jid", "true");
a.addAttribute("client-uses-full-bind-result", "true");
a.addAttribute("auth", "http://www.google.com/talk/protocol/auth");
string credential;
credential.append("\0", 1);
credential.append(""); //Specify Bare JID
credential.append("\0", 1);
credential.append(""); //Specify Access Token
a.setCData(Base64::encode64(credential));
send(a.xml());
}
else if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind")) {
Tag iq("iq", "xmlns", "jabber:client");
iq.addAttribute("type", "set");
iq.addAttribute("id", "0");
Tag *bind = new Tag("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
Tag *resource = new Tag("resource");
resource->setCData("GCPResource");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
else if (tag->name() == "proceed" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-tls") {
ConnectionTLS* encryption_client = new ConnectionTLS(this, conn0, log_);
encryption_client->registerTLSHandler(this);
client_ = encryption_client;
ConnectionError ret = encryption_client->connect();
assert(ret == ConnNoError);
}
else if (tag->name() == "success" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-sasl") {
send("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">\r\n");
}
else if (tag->name() == "iq") {
if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind")) {
resource_ = tag->findChild("bind")->findChild("jid")->cdata();
Tag iq("iq");
iq.addAttribute("type", "set");
iq.addAttribute("id", "1");
iq.addChild(new Tag("session", "xmlns", "urn:ietf:params:xml:ns:xmpp-session"));
send(iq.xml());
//Step 2: Subscribing for notifications
if (tag->hasAttribute("type", "result")) {
Tag iq("iq");
iq.addAttribute("type", "set");
iq.addAttribute("to", ""); //Specify Bare JID
iq.addAttribute("id", "3");
Tag *bind = new Tag("subscribe", "xmlns", "google:push");
Tag *resource = new Tag("item");
resource->addAttribute("channel", "cloudprint.google.com");
resource->addAttribute("from", "cloudprint.google.com");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
}
}
}
virtual void handleEncryptedData(const TLSBase* tls,
const string& data) {
cout << "handleEncryptedData" << endl;
}
virtual void handleDecryptedData(const TLSBase* tls,
const string& data) {
cout << "handleDecryptedData" << endl;
}
virtual void handleHandshakeResult(const TLSBase* tls, bool,
CertInfo& cert) {
cout << "handleHandshakeResult" << endl;
}
virtual void handleDisconnect(const ConnectionBase* con, ConnectionError) {
cout << "handleDisconnect" << endl;
}
private:
LogSink log_;
string sid_;
string resource_;
Parser parser_;
ConnectionBase *client_;
void send(const string &data) {
cerr << "[send] " << data << endl;
client_->send(data);
}
};
int main() {
Bot bot;
}