Files @ f8f37ecbdd59
Branch filter:

Location: libtransport.git/src/transport.cpp - annotation

HanzZ
Better logging in gateway mode
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
c5edfd19b1aa
c8006a0ebab6
1e8eb7076f17
c5edfd19b1aa
a6253712ccbc
778a11d5dc68
9275aa8c8e2b
9275aa8c8e2b
9275aa8c8e2b
d6c003bad3b6
d6c003bad3b6
64f1921f8d5c
64f1921f8d5c
b5c2a6e00113
b5c2a6e00113
b5c2a6e00113
0498acd07a1d
e678a46286f4
e678a46286f4
e678a46286f4
f9d40b961a35
e678a46286f4
e678a46286f4
f9d40b961a35
f9d40b961a35
b5c2a6e00113
79cc6dc63de8
1e8eb7076f17
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
e678a46286f4
e678a46286f4
c8006a0ebab6
828ae9d2cb88
1e8eb7076f17
e678a46286f4
0498acd07a1d
0498acd07a1d
0498acd07a1d
0498acd07a1d
0498acd07a1d
0498acd07a1d
0498acd07a1d
b5c2a6e00113
bf4183c181eb
e678a46286f4
e678a46286f4
e678a46286f4
f8f37ecbdd59
28ca4ba95e42
e678a46286f4
79cc6dc63de8
f9d40b961a35
79cc6dc63de8
57b59b8220e5
f9d40b961a35
57b59b8220e5
57b59b8220e5
57b59b8220e5
f9d40b961a35
f9d40b961a35
f9d40b961a35
28ca4ba95e42
79cc6dc63de8
79cc6dc63de8
edcb55d4ce22
778a11d5dc68
d6c003bad3b6
64f1921f8d5c
d6c003bad3b6
d6c003bad3b6
64f1921f8d5c
778a11d5dc68
edcb55d4ce22
edcb55d4ce22
79cc6dc63de8
79cc6dc63de8
f8f37ecbdd59
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
e678a46286f4
e678a46286f4
79cc6dc63de8
79cc6dc63de8
5f017bd15dc7
e678a46286f4
79cc6dc63de8
c5edfd19b1aa
e678a46286f4
79cc6dc63de8
c5edfd19b1aa
a6253712ccbc
79cc6dc63de8
a6253712ccbc
07859ef3936a
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
c5edfd19b1aa
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
07859ef3936a
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
79cc6dc63de8
e678a46286f4
e678a46286f4
e678a46286f4
79cc6dc63de8
79cc6dc63de8
2ae880ff94b5
2ae880ff94b5
2ae880ff94b5
2ae880ff94b5
2ae880ff94b5
2ae880ff94b5
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
28ca4ba95e42
28ca4ba95e42
f8f37ecbdd59
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
f9d40b961a35
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
28ca4ba95e42
f9d40b961a35
28ca4ba95e42
28ca4ba95e42
e678a46286f4
e678a46286f4
c5edfd19b1aa
99aff9256622
e678a46286f4
e678a46286f4
e678a46286f4
c5edfd19b1aa
99aff9256622
e678a46286f4
c5edfd19b1aa
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
f8f37ecbdd59
e678a46286f4
e678a46286f4
e678a46286f4
e678a46286f4
877d783276c0
b5c2a6e00113
99aff9256622
99aff9256622
877d783276c0
b5c2a6e00113
99aff9256622
99aff9256622
c5edfd19b1aa
1ebe5535c4f3
c5edfd19b1aa
e5fcbf00b799
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
f9d40b961a35
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
f9d40b961a35
c5edfd19b1aa
5f017bd15dc7
79cc6dc63de8
5f017bd15dc7
5f017bd15dc7
5f017bd15dc7
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
c5edfd19b1aa
5f017bd15dc7
f9d40b961a35
c5edfd19b1aa
c5edfd19b1aa
e678a46286f4
/**
 * libtransport -- C++ library for easy XMPP Transports development
 *
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */

#include "transport/transport.h"
#include <boost/bind.hpp>
#include "transport/storagebackend.h"
#include "transport/factory.h"
#include "transport/userregistry.h"
#include "discoinforesponder.h"
#include "discoitemsresponder.h"
#include "storageparser.h"
#include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h"
#include "Swiften/TLS/PKCS12Certificate.h"
#include "Swiften/TLS/OpenSSL/OpenSSLServerContextFactory.h"
#include "Swiften/Parser/PayloadParsers/AttentionParser.h"
#include "Swiften/Serializer/PayloadSerializers/AttentionSerializer.h"
#include "Swiften/Parser/PayloadParsers/XHTMLIMParser.h"
#include "Swiften/Serializer/PayloadSerializers/XHTMLIMSerializer.h"
#include "log4cxx/logger.h"
#include "log4cxx/consoleappender.h"
#include "log4cxx/patternlayout.h"
#include "log4cxx/propertyconfigurator.h"

using namespace Swift;
using namespace boost;
using namespace log4cxx;

namespace Transport {
	
static LoggerPtr logger = Logger::getLogger("Component");
static LoggerPtr logger_xml = Logger::getLogger("Component.XML");

Component::Component(Swift::EventLoop *loop, Config *config, Factory *factory, Transport::UserRegistry *userRegistry) {
	m_component = NULL;
	m_userRegistry = NULL;
	m_server = NULL;
	m_reconnectCount = 0;
	m_config = config;
	m_factory = factory;
	m_loop = loop;
	m_userRegistry = userRegistry;

	if (CONFIG_STRING(m_config, "logging.config").empty()) {
		LoggerPtr root = Logger::getRootLogger();
		root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
	}
	else {
		log4cxx::PropertyConfigurator::configure(CONFIG_STRING(m_config, "logging.config"));
	}

	m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid"));

	m_factories = new BoostNetworkFactories(loop);

	m_reconnectTimer = m_factories->getTimerFactory()->createTimer(3000);
	m_reconnectTimer->onTick.connect(bind(&Component::start, this)); 

	if (CONFIG_BOOL(m_config, "service.server_mode")) {
		LOG4CXX_INFO(logger, "Creating component in server mode on port " << CONFIG_INT(m_config, "service.port"));
		m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_INT(m_config, "service.port"));
		if (!CONFIG_STRING(m_config, "service.cert").empty()) {
			LOG4CXX_INFO(logger, "Using PKCS#12 certificate " << CONFIG_STRING(m_config, "service.cert"));
			TLSServerContextFactory *f = new OpenSSLServerContextFactory();
			m_server->addTLSEncryption(f, PKCS12Certificate(CONFIG_STRING(m_config, "service.cert"), createSafeByteArray(CONFIG_STRING(m_config, "service.cert_password"))));
		}
		else {
			LOG4CXX_WARN(logger, "No PKCS#12 certificate used. TLS is disabled.");
		}
// 		m_server->start();
		m_stanzaChannel = m_server->getStanzaChannel();
		m_iqRouter = m_server->getIQRouter();

		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<StorageParser>("private", "jabber:iq:private"));
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::AttentionParser>("attention", "urn:xmpp:attention:0"));
		m_server->addPayloadParserFactory(new GenericPayloadParserFactory<Swift::XHTMLIMParser>("html", "http://jabber.org/protocol/xhtml-im"));

		m_server->addPayloadSerializer(new Swift::AttentionSerializer());
		m_server->addPayloadSerializer(new Swift::XHTMLIMSerializer());

		m_server->onDataRead.connect(bind(&Component::handleDataRead, this, _1));
		m_server->onDataWritten.connect(bind(&Component::handleDataWritten, this, _1));
	}
	else {
		LOG4CXX_INFO(logger, "Creating component in gateway mode");
		m_component = new Swift::Component(loop, m_factories, m_jid, CONFIG_STRING(m_config, "service.password"));
		m_component->setSoftwareVersion("", "");
		m_component->onConnected.connect(bind(&Component::handleConnected, this));
		m_component->onError.connect(bind(&Component::handleConnectionError, this, _1));
		m_component->onDataRead.connect(bind(&Component::handleDataRead, this, _1));
		m_component->onDataWritten.connect(bind(&Component::handleDataWritten, this, _1));
		m_stanzaChannel = m_component->getStanzaChannel();
		m_iqRouter = m_component->getIQRouter();
	}

	m_capsMemoryStorage = new CapsMemoryStorage();
	m_capsManager = new CapsManager(m_capsMemoryStorage, m_stanzaChannel, m_iqRouter);
	m_entityCapsManager = new EntityCapsManager(m_capsManager, m_stanzaChannel);
 	m_entityCapsManager->onCapsChanged.connect(boost::bind(&Component::handleCapsChanged, this, _1));
	
	m_presenceOracle = new PresenceOracle(m_stanzaChannel);
	m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1));

	m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter);
	m_discoInfoResponder->start();

	m_discoItemsResponder = new DiscoItemsResponder(m_iqRouter);
	m_discoItemsResponder->start();

// 
// 	m_registerHandler = new SpectrumRegisterHandler(m_component);
// 	m_registerHandler->start();
}

Component::~Component() {
	delete m_presenceOracle;
	delete m_entityCapsManager;
	delete m_capsManager;
	delete m_capsMemoryStorage;
	delete m_discoInfoResponder;
	if (m_component)
		delete m_component;
	if (m_server)
		delete m_server;
	delete m_factories;
}

Swift::StanzaChannel *Component::getStanzaChannel() {
	return m_stanzaChannel;
}

Swift::PresenceOracle *Component::getPresenceOracle() {
	return m_presenceOracle;
}

void Component::setTransportFeatures(std::list<std::string> &features) {
	m_discoInfoResponder->setTransportFeatures(features);
}

void Component::setBuddyFeatures(std::list<std::string> &features) {
	// TODO: handle caps change
	m_discoInfoResponder->setBuddyFeatures(features);
}

void Component::start() {
	if (m_component) {
		LOG4CXX_INFO(logger, "Connecting XMPP server " << CONFIG_STRING(m_config, "service.server") << " port " << CONFIG_INT(m_config, "service.port"));
		m_reconnectCount++;
		m_component->connect(CONFIG_STRING(m_config, "service.server"), CONFIG_INT(m_config, "service.port"));
		m_reconnectTimer->stop();
	}
	else if (m_server) {
		LOG4CXX_INFO(logger, "Starting component in server mode on port " << CONFIG_INT(m_config, "service.port"));
		m_server->start();
	}
}

void Component::stop() {
	if (m_component) {
		m_reconnectCount = 0;
		m_component->disconnect();
		m_reconnectTimer->stop();
	}
	else if (m_server) {
		LOG4CXX_INFO(logger, "Stopping component in server mode on port " << CONFIG_INT(m_config, "service.port"));
		m_server->stop();
	}
}

void Component::handleConnected() {
	onConnected();
	m_reconnectCount = 0;
}

void Component::handleConnectionError(const ComponentError &error) {
	onConnectionError(error);
// 	if (m_reconnectCount == 2)
// 		Component::instance()->userManager()->removeAllUsers();
	std::string str = "Unknown error";
	switch (error.getType()) {
		case ComponentError::UnknownError: str = "Unknown error"; break;
		case ComponentError::ConnectionError: str = "Connection error"; break;
		case ComponentError::ConnectionReadError: str = "Connection read error"; break;
		case ComponentError::ConnectionWriteError: str = "Connection write error"; break;
		case ComponentError::XMLError: str = "XML Error"; break;
		case ComponentError::AuthenticationFailedError: str = "Authentication failed error"; break;
		case ComponentError::UnexpectedElementError: str = "Unexpected element error"; break;
	}
	LOG4CXX_INFO(logger, "Disconnected from XMPP server. Error: " << str);

	m_reconnectTimer->start();
}

void Component::handleDataRead(const Swift::SafeByteArray &data) {
	LOG4CXX_INFO(logger_xml, "XML IN " << safeByteArrayToString(data));
}

void Component::handleDataWritten(const Swift::SafeByteArray &data) {
	LOG4CXX_INFO(logger_xml, "XML OUT " << safeByteArrayToString(data));
}

void Component::handlePresence(Swift::Presence::ref presence) {
	bool isMUC = presence->getPayload<MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
	// filter out login/logout presence spam
	if (!presence->getTo().getNode().empty() && isMUC == false)
		return;

	// filter out bad presences
	if (!presence->getFrom().isValid()) {
		return;
	}

	// check if we have this client's capabilities and ask for them
// 	bool haveFeatures = false;
	if (presence->getType() != Swift::Presence::Unavailable) {
		boost::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
		if (capsInfo && capsInfo->getHash() == "sha-1") {
			/*haveFeatures = */m_entityCapsManager->getCaps(presence->getFrom()) != DiscoInfo::ref();
		}
// 		else {
// 			GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(presence->getFrom(), m_iqRouter);
// 			discoInfoRequest->onResponse.connect(boost::bind(&Component::handleDiscoInfoResponse, this, _1, _2, presence->getFrom()));
// 			discoInfoRequest->send();
// 		}
	}

	onUserPresenceReceived(presence);
}

void Component::handleCapsChanged(const Swift::JID& jid) {
	m_entityCapsManager->getCaps(jid) != DiscoInfo::ref();
}

}