From a328466bc492c50c443e406b9325542a75182327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Fri, 17 Jul 2009 21:15:54 +0200 Subject: Implemented clean session/connection shutdown. diff --git a/Limber/main.cpp b/Limber/main.cpp index c478924..2a2197d 100644 --- a/Limber/main.cpp +++ b/Limber/main.cpp @@ -31,18 +31,18 @@ class Server { private: void handleNewConnection(boost::shared_ptr c) { - ServerFromClientSession* session = new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, userRegistry_); + boost::shared_ptr session(new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, userRegistry_)); serverFromClientSessions_.push_back(session); session->onStanzaReceived.connect(boost::bind(&Server::handleStanzaReceived, this, _1, session)); session->onSessionFinished.connect(boost::bind(&Server::handleSessionFinished, this, session)); + session->start(); } - void handleSessionFinished(ServerFromClientSession* session) { + void handleSessionFinished(boost::shared_ptr session) { serverFromClientSessions_.erase(std::remove(serverFromClientSessions_.begin(), serverFromClientSessions_.end(), session), serverFromClientSessions_.end()); - delete session; } - void handleStanzaReceived(boost::shared_ptr stanza, ServerFromClientSession* session) { + void handleStanzaReceived(boost::shared_ptr stanza, boost::shared_ptr session) { stanza->setFrom(session->getJID()); if (!stanza->getTo().isValid()) { stanza->setTo(JID(session->getDomain())); @@ -74,7 +74,7 @@ class Server { UserRegistry* userRegistry_; BoostIOServiceThread boostIOServiceThread_; boost::shared_ptr serverFromClientConnectionServer_; - std::vector serverFromClientSessions_; + std::vector< boost::shared_ptr > serverFromClientSessions_; FullPayloadParserFactoryCollection payloadParserFactories_; FullPayloadSerializerCollection payloadSerializers_; }; diff --git a/Nim/main.cpp b/Nim/main.cpp index 6747d4a..7c7105e 100644 --- a/Nim/main.cpp +++ b/Nim/main.cpp @@ -53,14 +53,15 @@ class Server { private: void handleNewConnection(boost::shared_ptr c) { - ServerFromClientSession* session = new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, &userRegistry_); + boost::shared_ptr session(new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, &userRegistry_)); serverFromClientSessions_.push_back(session); session->onStanzaReceived.connect(boost::bind(&Server::handleStanzaReceived, this, _1, session)); session->onSessionStarted.connect(boost::bind(&Server::handleSessionStarted, this, session)); session->onSessionFinished.connect(boost::bind(&Server::handleSessionFinished, this, session)); + session->start(); } - void handleSessionStarted(ServerFromClientSession* session) { + void handleSessionStarted(boost::shared_ptr session) { if (!dnsSDServiceRegistered_) { dnsSDServiceRegistered_ = true; dnsSDService_->onServiceRegistered.connect(boost::bind(&Server::handleServiceRegistered, this, _1)); @@ -81,16 +82,15 @@ class Server { std::cout << "Service registered " << service.name << " " << service.type << " " << service.domain << std::endl; } - void handleSessionFinished(ServerFromClientSession* session) { + void handleSessionFinished(boost::shared_ptr session) { serverFromClientSessions_.erase(std::remove(serverFromClientSessions_.begin(), serverFromClientSessions_.end(), session), serverFromClientSessions_.end()); - delete session; if (serverFromClientSessions_.empty()) { dnsSDServiceRegistered_ = false; dnsSDService_->unregisterService(); } } - void handleStanzaReceived(boost::shared_ptr stanza, ServerFromClientSession* session) { + void handleStanzaReceived(boost::shared_ptr stanza, boost::shared_ptr session) { stanza->setFrom(session->getJID()); if (!stanza->getTo().isValid()) { stanza->setTo(JID(session->getDomain())); @@ -124,7 +124,7 @@ class Server { boost::shared_ptr dnsSDService_; boost::shared_ptr linkLocalRoster_; boost::shared_ptr serverFromClientConnectionServer_; - std::vector serverFromClientSessions_; + std::vector< boost::shared_ptr > serverFromClientSessions_; FullPayloadParserFactoryCollection payloadParserFactories_; FullPayloadSerializerCollection payloadSerializers_; bool dnsSDServiceRegistered_; diff --git a/Swiften/Client/Session.cpp b/Swiften/Client/Session.cpp index dbeddb7..2f0e076 100644 --- a/Swiften/Client/Session.cpp +++ b/Swiften/Client/Session.cpp @@ -44,7 +44,7 @@ void Session::start() { state_ = Connecting; connection_ = connectionFactory_->createConnection(); connection_->onConnected.connect(boost::bind(&Session::handleConnected, this)); - connection_->onError.connect(boost::bind(&Session::handleConnectionError, this, _1)); + connection_->onDisconnected.connect(boost::bind(&Session::handleDisconnected, this, _1)); connection_->connect(jid_.getDomain()); } @@ -75,20 +75,22 @@ void Session::initializeStreamStack() { streamStack_ = new StreamStack(xmppLayer_, connectionLayer_); } -void Session::handleConnectionError(Connection::Error error) { - switch (error) { - case Connection::DomainNameResolveError: - setError(DomainNameResolveError); - break; - case Connection::ReadError: - setError(ConnectionReadError); - break; - case Connection::WriteError: - setError(ConnectionWriteError); - break; - case Connection::ConnectionError: - setError(ConnectionError); - break; +void Session::handleDisconnected(const boost::optional& error) { + if (error) { + switch (*error) { + case Connection::DomainNameResolveError: + setError(DomainNameResolveError); + break; + case Connection::ReadError: + setError(ConnectionReadError); + break; + case Connection::WriteError: + setError(ConnectionWriteError); + break; + case Connection::ConnectionError: + setError(ConnectionError); + break; + } } } diff --git a/Swiften/Client/Session.h b/Swiften/Client/Session.h index 1b4d1fe..17c10b9 100644 --- a/Swiften/Client/Session.h +++ b/Swiften/Client/Session.h @@ -87,7 +87,7 @@ namespace Swift { void sendSessionStart(); void handleConnected(); - void handleConnectionError(Connection::Error); + void handleDisconnected(const boost::optional&); void handleElement(boost::shared_ptr); void handleStreamStart(); void handleTLSConnected(); diff --git a/Swiften/Client/UnitTest/SessionTest.cpp b/Swiften/Client/UnitTest/SessionTest.cpp index 5d43736..45c0996 100644 --- a/Swiften/Client/UnitTest/SessionTest.cpp +++ b/Swiften/Client/UnitTest/SessionTest.cpp @@ -488,7 +488,7 @@ class SessionTest : public CppUnit::TestFixture { void connect(const String& domain) { if (fail_) { - MainEventLoop::postEvent(boost::bind(boost::ref(onError), Connection::ConnectionError)); + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), Connection::ConnectionError)); } else { domain_ = domain; @@ -497,7 +497,7 @@ class SessionTest : public CppUnit::TestFixture { } void setError() { - MainEventLoop::postEvent(boost::bind(boost::ref(onError), Connection::ConnectionError)); + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), Connection::ConnectionError)); } void write(const ByteArray& data) { diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp index 99f83b8..8ee7ae0 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp @@ -45,4 +45,70 @@ ByteArray LinkLocalServiceInfo::getEncoded(const String& s) { return sizeByte + ByteArray(s); } +LinkLocalServiceInfo LinkLocalServiceInfo::createFromTXTRecord(const ByteArray& record) { + LinkLocalServiceInfo info; + size_t i = 0; + while (i < record.getSize()) { + std::pair entry = readEntry(record, &i); + if (entry.first.isEmpty()) { + break; + } + else if (entry.first == "1st") { + info.setFirstName(entry.second); + } + else if (entry.first == "last") { + info.setLastName(entry.second); + } + else if (entry.first == "email") { + info.setEMail(entry.second); + } + else if (entry.first == "jid") { + info.setJID(JID(entry.second)); + } + else if (entry.first == "msg") { + info.setMessage(entry.second); + } + else if (entry.first == "nick") { + info.setNick(entry.second); + } + else if (entry.first == "port.p2pj") { + info.setPort(boost::lexical_cast(entry.second)); + } + else if (entry.first == "status") { + if (entry.second == "away") { + info.setStatus(Away); + } + else if (entry.second == "dnd") { + info.setStatus(DND); + } + } + } + return info; +} + +std::pair LinkLocalServiceInfo::readEntry(const ByteArray& record, size_t* index) { + size_t& i = *index; + String key; + String value; + + size_t entryEnd = i + 1 + record[i]; + ++i; + bool inKey = true; + while (i < entryEnd && i < record.getSize()) { + if (inKey) { + if (record[i] == '=') { + inKey = false; + } + else { + key += record[i]; + } + } + else { + value += record[i]; + } + ++i; + } + return std::make_pair(key, value); +} + } diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.h b/Swiften/LinkLocal/LinkLocalServiceInfo.h index bd5286b..d78b70c 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.h +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.h @@ -40,8 +40,11 @@ namespace Swift { ByteArray toTXTRecord() const; + static LinkLocalServiceInfo createFromTXTRecord(const ByteArray& record); + private: static ByteArray getEncoded(const String&); + static std::pair readEntry(const ByteArray&, size_t*); private: String firstName; diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp index 8efe4ae..b850f14 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp @@ -8,6 +8,8 @@ using namespace Swift; class LinkLocalServiceInfoTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(LinkLocalServiceInfoTest); CPPUNIT_TEST(testGetTXTRecord); + CPPUNIT_TEST(testCreateFromTXTRecord); + CPPUNIT_TEST(testCreateFromTXTRecord_InvalidSize); CPPUNIT_TEST_SUITE_END(); public: @@ -21,6 +23,20 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(ByteArray("\x09txtvers=1\x09" + String("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away")), info.toTXTRecord()); } + + void testCreateFromTXTRecord() { + LinkLocalServiceInfo info = LinkLocalServiceInfo::createFromTXTRecord(ByteArray("\x09txtvers=1\x09" + String("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away"))); + + CPPUNIT_ASSERT_EQUAL(String("Remko"), info.getFirstName()); + CPPUNIT_ASSERT_EQUAL(String("Tron\xc3\xe7on"), info.getLastName()); + CPPUNIT_ASSERT_EQUAL(LinkLocalServiceInfo::Away, info.getStatus()); + } + + void testCreateFromTXTRecord_InvalidSize() { + LinkLocalServiceInfo info = LinkLocalServiceInfo::createFromTXTRecord(ByteArray("\x10last=a")); + + CPPUNIT_ASSERT_EQUAL(String("a"), info.getLastName()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceInfoTest); diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp index f837b50..d374221 100644 --- a/Swiften/Network/BoostConnection.cpp +++ b/Swiften/Network/BoostConnection.cpp @@ -59,7 +59,7 @@ void BoostConnection::connect(const String& domain) { boost::bind(&BoostConnection::handleConnectFinished, shared_from_this(), boost::asio::placeholders::error)); } catch (const DomainNameResolveException& e) { - onError(DomainNameResolveError); + onDisconnected(DomainNameResolveError); } } @@ -79,7 +79,7 @@ void BoostConnection::handleConnectFinished(const boost::system::error_code& err doRead(); } else if (error != boost::asio::error::operation_aborted) { - MainEventLoop::postEvent(boost::bind(boost::ref(onError), ConnectionError), shared_from_this()); + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), ConnectionError), shared_from_this()); } } @@ -94,14 +94,23 @@ void BoostConnection::handleSocketRead(const boost::system::error_code& error, s MainEventLoop::postEvent(boost::bind(boost::ref(onDataRead), ByteArray(&readBuffer_[0], bytesTransferred)), shared_from_this()); doRead(); } + else if (error == boost::asio::error::eof) { + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), boost::optional()), shared_from_this()); + } else if (error != boost::asio::error::operation_aborted) { - MainEventLoop::postEvent(boost::bind(boost::ref(onError), ReadError), shared_from_this()); + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), ReadError), shared_from_this()); } } void BoostConnection::handleDataWritten(const boost::system::error_code& error) { - if (error && error != boost::asio::error::operation_aborted) { - MainEventLoop::postEvent(boost::bind(boost::ref(onError), WriteError), shared_from_this()); + if (!error) { + return; + } + if (error == boost::asio::error::eof) { + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), boost::optional()), shared_from_this()); + } + else if (error && error != boost::asio::error::operation_aborted) { + MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), WriteError), shared_from_this()); } } diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h index 16d5d7b..c34c21d 100644 --- a/Swiften/Network/Connection.h +++ b/Swiften/Network/Connection.h @@ -26,7 +26,7 @@ namespace Swift { public: boost::signal onConnected; - boost::signal onError; + boost::signal&)> onDisconnected; boost::signal onDataRead; }; } diff --git a/Swiften/Server/ServerFromClientSession.cpp b/Swiften/Server/ServerFromClientSession.cpp index fe4388e..9a3cf83 100644 --- a/Swiften/Server/ServerFromClientSession.cpp +++ b/Swiften/Server/ServerFromClientSession.cpp @@ -32,6 +32,15 @@ ServerFromClientSession::ServerFromClientSession( authenticated_(false), initialized_(false) { xmppLayer_ = boost::shared_ptr(new XMPPLayer(payloadParserFactories_, payloadSerializers_)); + connectionLayer_ = boost::shared_ptr(new ConnectionLayer(connection_)); + streamStack_ = new StreamStack(xmppLayer_, connectionLayer_); +} + +ServerFromClientSession::~ServerFromClientSession() { + delete streamStack_; +} + +void ServerFromClientSession::start() { xmppLayer_->onStreamStart.connect( boost::bind(&ServerFromClientSession::handleStreamStart, this, _2)); xmppLayer_->onElement.connect( @@ -42,12 +51,7 @@ ServerFromClientSession::ServerFromClientSession( boost::bind(boost::ref(onDataRead), _1)); xmppLayer_->onWriteData.connect( boost::bind(boost::ref(onDataWritten), _1)); - connectionLayer_ = boost::shared_ptr(new ConnectionLayer(connection_)); - streamStack_ = new StreamStack(xmppLayer_, connectionLayer_); -} - -ServerFromClientSession::~ServerFromClientSession() { - delete streamStack_; + connection_->onDisconnected.connect(boost::bind(&ServerFromClientSession::handleDisconnected, shared_from_this(), _1)); } void ServerFromClientSession::handleElement(boost::shared_ptr element) { @@ -114,5 +118,9 @@ void ServerFromClientSession::sendStanza(boost::shared_ptr stanza) { xmppLayer_->writeElement(stanza); } +void ServerFromClientSession::handleDisconnected(const boost::optional&) { + onSessionFinished(); +} + } diff --git a/Swiften/Server/ServerFromClientSession.h b/Swiften/Server/ServerFromClientSession.h index 0110d5d..e7df99d 100644 --- a/Swiften/Server/ServerFromClientSession.h +++ b/Swiften/Server/ServerFromClientSession.h @@ -2,9 +2,11 @@ #include #include +#include #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" +#include "Swiften/Network/Connection.h" namespace Swift { class Element; @@ -18,7 +20,7 @@ namespace Swift { class Connection; class ByteArray; - class ServerFromClientSession { + class ServerFromClientSession : public boost::enable_shared_from_this { public: ServerFromClientSession( const String& id, @@ -28,6 +30,8 @@ namespace Swift { UserRegistry* userRegistry); ~ServerFromClientSession(); + void start(); + void sendStanza(boost::shared_ptr); const JID& getJID() const { @@ -45,6 +49,7 @@ namespace Swift { boost::signal onDataRead; private: + void handleDisconnected(const boost::optional& error); void handleElement(boost::shared_ptr); void handleStreamStart(const String& domain); -- cgit v0.10.2-6-g49f6