#include #include #include #include "Swiften/Base/Platform.h" #include "Swiften/Session/SessionTracer.h" #include "Swiften/Network/BoostConnectionFactory.h" #include "Swiften/Elements/IQ.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/RosterPayload.h" #include "Swiften/Elements/VCard.h" #include "Swiften/Server/UserRegistry.h" #include "Swiften/JID/JID.h" #include "Swiften/Base/String.h" #include "Swiften/Server/UserRegistry.h" #include "Swiften/Base/IDGenerator.h" #include "Swiften/EventLoop/MainEventLoop.h" #include "Swiften/EventLoop/SimpleEventLoop.h" #include "Swiften/EventLoop/EventOwner.h" #include "Swiften/Elements/Element.h" #include "Swiften/LinkLocal/LinkLocalConnector.h" #include "Swiften/LinkLocal/LinkLocalServiceInfo.h" #include "Swiften/LinkLocal/LinkLocalRoster.h" #include "Swiften/LinkLocal/OutgoingLinkLocalSession.h" #include "Swiften/LinkLocal/IncomingLinkLocalSession.h" #include "Swiften/LinkLocal/DNSSDService.h" #include "Swiften/Network/ConnectionServer.h" #include "Swiften/Network/BoostConnection.h" #include "Swiften/Network/BoostIOServiceThread.h" #include "Swiften/Network/BoostConnectionServer.h" #include "Swiften/Server/ServerFromClientSession.h" #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" #include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" #if defined(SWIFTEN_PLATFORM_MACOSX) || defined(SWIFTEN_PLATFORM_WINDOWS) #include "Swiften/LinkLocal/AppleDNSSDService.h" #else #include "Swiften/LinkLocal/AvahiDNSSDService.h" #endif using namespace Swift; class DummyUserRegistry : public UserRegistry { public: DummyUserRegistry() { } virtual bool isValidUserPassword(const JID&, const String&) const { return true; } }; class Server { public: Server(int clientConnectionPort, int linkLocalConnectionPort) : dnsSDServiceRegistered_(false), rosterRequested_(false), clientConnectionPort_(clientConnectionPort), linkLocalConnectionPort_(linkLocalConnectionPort) { serverFromClientConnectionServer_ = boost::shared_ptr(new BoostConnectionServer( clientConnectionPort, &boostIOServiceThread_.getIOService())); serverFromClientConnectionServer_->onNewConnection.connect( boost::bind(&Server::handleNewClientConnection, this, _1)); serverFromClientConnectionServer_->start(); serverFromNetworkConnectionServer_ = boost::shared_ptr(new BoostConnectionServer( linkLocalConnectionPort, &boostIOServiceThread_.getIOService())); serverFromNetworkConnectionServer_->onNewConnection.connect( boost::bind(&Server::handleNewLinkLocalConnection, this, _1)); serverFromNetworkConnectionServer_->start(); #if defined(SWIFTEN_PLATFORM_MACOSX) || defined(SWIFTEN_PLATFORM_WINDOWS) dnsSDService_ = boost::shared_ptr( new AppleDNSSDService()); #else dnsSDService_ = boost::shared_ptr( new AvahiDNSSDService()); #endif dnsSDService_->onServiceRegistered.connect (boost::bind(&Server::handleServiceRegistered, this, _1)); linkLocalRoster_ = boost::shared_ptr( new LinkLocalRoster(dnsSDService_)); linkLocalRoster_->onRosterChanged.connect( boost::bind(&Server::handleRosterChanged, this, _1)); linkLocalRoster_->onPresenceChanged.connect( boost::bind(&Server::handlePresenceChanged, this, _1)); dnsSDService_->start(); } private: void handleNewClientConnection(boost::shared_ptr c) { if (serverFromClientSession_) { c->disconnect(); } serverFromClientSession_ = boost::shared_ptr(new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, &userRegistry_)); serverFromClientSession_->onElementReceived.connect(boost::bind(&Server::handleElementReceived, this, _1, serverFromClientSession_)); serverFromClientSession_->onSessionFinished.connect(boost::bind(&Server::handleSessionFinished, this, serverFromClientSession_)); tracers_.push_back(boost::shared_ptr(new SessionTracer(serverFromClientSession_))); serverFromClientSession_->startSession(); } void handleNewLinkLocalConnection(boost::shared_ptr connection) { boost::shared_ptr session( new IncomingLinkLocalSession( selfJID_, connection, &payloadParserFactories_, &payloadSerializers_)); registerLinkLocalSession(session); } void handleServiceRegistered(const DNSSDService::Service& service) { std::cout << "Service registered " << service.name << " " << service.type << " " << service.domain << std::endl; selfJID_ = JID(service.name); } void handleSessionFinished(boost::shared_ptr) { serverFromClientSession_.reset(); unregisterService(); selfJID_ = JID(); rosterRequested_ = false; } void handleLinkLocalSessionFinished(boost::shared_ptr session) { std::cout << "Link local session from " << session->getRemoteJID() << " ended" << std::endl; linkLocalSessions_.erase(std::remove(linkLocalSessions_.begin(), linkLocalSessions_.end(), session), linkLocalSessions_.end()); } void handleLinkLocalElementReceived(boost::shared_ptr element, boost::shared_ptr session) { if (boost::shared_ptr stanza = boost::dynamic_pointer_cast(element)) { JID fromJID = session->getRemoteJID(); if (!linkLocalRoster_->hasItem(fromJID)) { return; // TODO: Queue } stanza->setFrom(fromJID); serverFromClientSession_->sendElement(stanza); } } void unregisterService() { if (dnsSDServiceRegistered_) { dnsSDServiceRegistered_ = false; dnsSDService_->unregisterService(); } } void handleElementReceived(boost::shared_ptr element, boost::shared_ptr session) { boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); if (!stanza) { return; } stanza->setFrom(session->getRemoteJID()); if (!stanza->getTo().isValid()) { stanza->setTo(session->getLocalJID()); } if (boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza)) { if (presence->getType() == Presence::Available) { if (!dnsSDServiceRegistered_) { dnsSDServiceRegistered_ = true; dnsSDService_->registerService(session->getRemoteJID().toBare().toString(), linkLocalConnectionPort_, getLinkLocalServiceInfo(presence)); } else { dnsSDService_->updateService(getLinkLocalServiceInfo(presence)); } } else { unregisterService(); } } else if (!stanza->getTo().isValid() || stanza->getTo() == session->getLocalJID() || stanza->getTo() == session->getRemoteJID().toBare()) { if (boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza)) { if (iq->getPayload()) { if (iq->getType() == IQ::Get) { session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), linkLocalRoster_->getRoster())); rosterRequested_ = true; foreach(const boost::shared_ptr presence, linkLocalRoster_->getAllPresence()) { session->sendElement(presence); } } else { session->sendElement(IQ::createError(iq->getFrom(), iq->getID(), Error::Forbidden, Error::Cancel)); } } if (iq->getPayload()) { if (iq->getType() == IQ::Get) { boost::shared_ptr vcard(new VCard()); vcard->setNickname(iq->getFrom().getNode()); session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), vcard)); } else { session->sendElement(IQ::createError(iq->getFrom(), iq->getID(), Error::Forbidden, Error::Cancel)); } } else { session->sendElement(IQ::createError(iq->getFrom(), iq->getID(), Error::FeatureNotImplemented, Error::Cancel)); } } } else { JID toJID = stanza->getTo(); boost::shared_ptr outgoingSession = getLinkLocalSessionForJID(toJID); if (outgoingSession) { outgoingSession->sendElement(stanza); } else { if (linkLocalRoster_->hasItem(toJID)) { boost::shared_ptr connector = getLinkLocalConnectorForJID(toJID); if (!connector) { connector = boost::shared_ptr( new LinkLocalConnector( toJID, linkLocalRoster_->getHostname(toJID), linkLocalRoster_->getPort(toJID), dnsSDService_, boost::shared_ptr(new BoostConnection(&boostIOServiceThread_.getIOService())))); connector->onConnectFinished.connect( boost::bind(&Server::handleConnectFinished, this, connector, _1)); connectors_.push_back(connector); connector->connect(); } connector->queueElement(element); } else { session->sendElement(IQ::createError( stanza->getFrom(), stanza->getID(), Error::RecipientUnavailable, Error::Wait)); } } } } void handleConnectFinished(boost::shared_ptr connector, bool error) { if (error) { std::cerr << "Error connecting" << std::endl; // TODO: Send back queued stanzas } else { boost::shared_ptr outgoingSession( new OutgoingLinkLocalSession( selfJID_, connector->getRemoteJID(), connector->getConnection(), &payloadParserFactories_, &payloadSerializers_)); foreach(const boost::shared_ptr element, connector->getQueuedElements()) { outgoingSession->queueElement(element); } registerLinkLocalSession(outgoingSession); } connectors_.erase(std::remove(connectors_.begin(), connectors_.end(), connector), connectors_.end()); } void registerLinkLocalSession(boost::shared_ptr session) { session->onSessionFinished.connect(boost::bind(&Server::handleLinkLocalSessionFinished, this, session)); session->onElementReceived.connect(boost::bind(&Server::handleLinkLocalElementReceived, this, _1, session)); linkLocalSessions_.push_back(session); tracers_.push_back(boost::shared_ptr(new SessionTracer(session))); session->startSession(); } boost::shared_ptr getLinkLocalSessionForJID(const JID& jid) { foreach(const boost::shared_ptr session, linkLocalSessions_) { if (session->getRemoteJID() == jid) { return session; } } return boost::shared_ptr(); } boost::shared_ptr getLinkLocalConnectorForJID(const JID& jid) { foreach(const boost::shared_ptr connector, connectors_) { if (connector->getRemoteJID() == jid) { return connector; } } return boost::shared_ptr(); } void handleRosterChanged(boost::shared_ptr roster) { if (rosterRequested_) { boost::shared_ptr iq = IQ::createRequest(IQ::Set, serverFromClientSession_->getRemoteJID(), idGenerator_.generateID(), roster); iq->setFrom(serverFromClientSession_->getRemoteJID().toBare()); serverFromClientSession_->sendElement(iq); } } void handlePresenceChanged(boost::shared_ptr presence) { if (rosterRequested_) { serverFromClientSession_->sendElement(presence); } } LinkLocalServiceInfo getLinkLocalServiceInfo(boost::shared_ptr presence) { LinkLocalServiceInfo info; info.setFirstName("Remko"); info.setLastName("Tron\xc3\xa7on"); info.setEMail("email@example.com"); info.setJID(JID("jid@example.com")); info.setMessage(presence->getStatus()); info.setNick("Remko"); switch (presence->getShow()) { case StatusShow::Online: case StatusShow::None: case StatusShow::FFC: info.setStatus(LinkLocalServiceInfo::Available); break; case StatusShow::Away: case StatusShow::XA: info.setStatus(LinkLocalServiceInfo::Away); break; case StatusShow::DND: info.setStatus(LinkLocalServiceInfo::DND); break; } info.setPort(linkLocalConnectionPort_); return info; } private: IDGenerator idGenerator_; BoostIOServiceThread boostIOServiceThread_; DummyUserRegistry userRegistry_; boost::shared_ptr dnsSDService_; boost::shared_ptr linkLocalRoster_; boost::shared_ptr serverFromClientConnectionServer_; boost::shared_ptr serverFromClientSession_; boost::shared_ptr serverFromNetworkConnectionServer_; std::vector< boost::shared_ptr > tracers_; std::vector< boost::shared_ptr > linkLocalSessions_; std::vector< boost::shared_ptr > connectors_; FullPayloadParserFactoryCollection payloadParserFactories_; FullPayloadSerializerCollection payloadSerializers_; bool dnsSDServiceRegistered_; bool rosterRequested_; int clientConnectionPort_; int linkLocalConnectionPort_; JID selfJID_; }; int main() { SimpleEventLoop eventLoop; Server server(5222, 5562); eventLoop.run(); return 0; }