#include "Slimber/Server.h" #include #include #include "Swiften/Session/SessionTracer.h" #include "Swiften/Elements/IQ.h" #include "Swiften/Elements/VCard.h" #include "Swiften/Server/UserRegistry.h" #include "Swiften/Base/String.h" #include "Swiften/LinkLocal/LinkLocalServiceInfo.h" #include "Swiften/LinkLocal/LinkLocalRoster.h" #include "Swiften/LinkLocal/OutgoingLinkLocalSession.h" #include "Swiften/LinkLocal/IncomingLinkLocalSession.h" #include "Swiften/Network/ConnectionServer.h" #include "Slimber/VCardCollection.h" #include "Swiften/Server/ServerFromClientSession.h" namespace Swift { Server::Server(int clientConnectionPort, int linkLocalConnectionPort, boost::shared_ptr linkLocalRoster, boost::shared_ptr dnsSDService, VCardCollection* vCardCollection) : dnsSDServiceRegistered_(false), rosterRequested_(false), clientConnectionPort_(clientConnectionPort), linkLocalConnectionPort_(linkLocalConnectionPort), linkLocalRoster_(linkLocalRoster), dnsSDService_(dnsSDService), vCardCollection_(vCardCollection) { 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(); dnsSDService_->onServiceRegistered.connect (boost::bind(&Server::handleServiceRegistered, this, _1)); linkLocalRoster_->onRosterChanged.connect( boost::bind(&Server::handleRosterChanged, this, _1)); linkLocalRoster_->onPresenceChanged.connect( boost::bind(&Server::handlePresenceChanged, this, _1)); dnsSDService_->start(); } void Server::handleNewClientConnection(boost::shared_ptr c) { if (serverFromClientSession_) { c->disconnect(); } serverFromClientSession_ = boost::shared_ptr(new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, &userRegistry_)); serverFromClientSession_->onSessionStarted.connect(boost::bind(&Server::handleSessionStarted, this)); 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 Server::handleNewLinkLocalConnection(boost::shared_ptr connection) { boost::shared_ptr session( new IncomingLinkLocalSession( selfJID_, connection, &payloadParserFactories_, &payloadSerializers_)); registerLinkLocalSession(session); } void Server::handleServiceRegistered(const DNSSDService::Service& service) { std::cout << "Service registered " << service.name << " " << service.type << " " << service.domain << std::endl; selfJID_ = JID(service.name); } void Server::handleSessionStarted() { onSelfConnected(true); } void Server::handleSessionFinished(boost::shared_ptr) { serverFromClientSession_.reset(); unregisterService(); selfJID_ = JID(); rosterRequested_ = false; onSelfConnected(false); lastPresence_.reset(); } void Server::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 Server::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 Server::unregisterService() { if (dnsSDServiceRegistered_) { dnsSDServiceRegistered_ = false; dnsSDService_->unregisterService(); } } void Server::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)); } lastPresence_ = 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 (boost::shared_ptr vcard = iq->getPayload()) { if (iq->getType() == IQ::Get) { session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), vCardCollection_->getOwnVCard())); } else { vCardCollection_->setOwnVCard(vcard); session->sendElement(IQ::createResult(iq->getFrom(), iq->getID())); if (lastPresence_) { dnsSDService_->updateService(getLinkLocalServiceInfo(lastPresence_)); } } } 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 Server::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 Server::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 Server::getLinkLocalSessionForJID(const JID& jid) { foreach(const boost::shared_ptr session, linkLocalSessions_) { if (session->getRemoteJID() == jid) { return session; } } return boost::shared_ptr(); } boost::shared_ptr Server::getLinkLocalConnectorForJID(const JID& jid) { foreach(const boost::shared_ptr connector, connectors_) { if (connector->getRemoteJID() == jid) { return connector; } } return boost::shared_ptr(); } void Server::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 Server::handlePresenceChanged(boost::shared_ptr presence) { if (rosterRequested_) { serverFromClientSession_->sendElement(presence); } } LinkLocalServiceInfo Server::getLinkLocalServiceInfo(boost::shared_ptr presence) { LinkLocalServiceInfo info; boost::shared_ptr vcard = vCardCollection_->getOwnVCard(); if (!vcard->getFamilyName().isEmpty() || !vcard->getGivenName().isEmpty()) { info.setFirstName(vcard->getGivenName()); info.setLastName(vcard->getFamilyName()); } else if (!vcard->getFullName().isEmpty()) { std::pair p = vcard->getFullName().getSplittedAtFirst(' '); info.setFirstName(p.first); info.setLastName(p.second); } if (!vcard->getNickname().isEmpty()) { info.setNick(vcard->getNickname()); } if (!vcard->getEMail().isEmpty()) { info.setEMail(vcard->getEMail()); } info.setMessage(presence->getStatus()); 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; } }