diff options
-rw-r--r-- | Swiften/Network/BOSHConnection.cpp | 34 | ||||
-rw-r--r-- | Swiften/Network/BOSHConnection.h | 22 | ||||
-rw-r--r-- | Swiften/Network/BOSHConnectionPool.cpp | 4 | ||||
-rw-r--r-- | Swiften/Network/BOSHConnectionPool.h | 2 | ||||
-rw-r--r-- | Swiften/Network/UnitTest/BOSHConnectionTest.cpp | 21 |
5 files changed, 42 insertions, 41 deletions
diff --git a/Swiften/Network/BOSHConnection.cpp b/Swiften/Network/BOSHConnection.cpp index 09548e9..ea84400 100644 --- a/Swiften/Network/BOSHConnection.cpp +++ b/Swiften/Network/BOSHConnection.cpp @@ -43,32 +43,27 @@ BOSHConnection::BOSHConnection(const URL& boshURL, ConnectionFactory* connection BOSHConnection::~BOSHConnection() { if (connection_) { connection_->onConnectFinished.disconnect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); connection_->onDataRead.disconnect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); connection_->onDisconnected.disconnect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); } disconnect(); } -void BOSHConnection::connect(const HostAddressPort& server) { - /* FIXME: Redundant parameter */ +void BOSHConnection::connect() { Connection::ref rawConnection = connectionFactory_->createConnection(); connection_ = (boshURL_.getScheme() == "https") ? boost::make_shared<TLSConnection>(rawConnection, tlsFactory_) : rawConnection; connection_->onConnectFinished.connect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); connection_->onDataRead.connect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); connection_->onDisconnected.connect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); connection_->connect(HostAddressPort(HostAddress(boshURL_.getHost()), boshURL_.getPort())); } -void BOSHConnection::listen() { - assert(false); -} - void BOSHConnection::disconnect() { if(connection_) { connection_->disconnect(); sid_ = ""; } } void BOSHConnection::restartStream() { write(createSafeByteArray(""), true, false); @@ -164,50 +159,54 @@ void BOSHConnection::startStream(const std::string& to, unsigned long rid) { waitingForStartResponse_ = true; SafeByteArray safeHeader = createSafeByteArray(header.str()); onBOSHDataWritten(safeHeader); connection_->write(safeHeader); SWIFT_LOG(debug) << "write stream header: " << safeByteArrayToString(safeHeader) << std::endl; } void BOSHConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { - onBOSHDataRead(*data.get()); - buffer_ = concat(buffer_, *data.get()); + onBOSHDataRead(*data); + buffer_ = concat(buffer_, *data); std::string response = safeByteArrayToString(buffer_); if (response.find("\r\n\r\n") == std::string::npos) { onBOSHDataRead(createSafeByteArray("[[Previous read incomplete, pending]]")); return; } std::string httpCode = response.substr(response.find(" ") + 1, 3); if (httpCode != "200") { onHTTPError(httpCode); return; } BOSHBodyExtractor parser(parserFactory_, createByteArray(response.substr(response.find("\r\n\r\n") + 4))); if (parser.getBody()) { - if ((*parser.getBody()).attributes.getAttribute("type") == "terminate") { - BOSHError::Type errorType = parseTerminationCondition((*parser.getBody()).attributes.getAttribute("condition")); + if (parser.getBody()->attributes.getAttribute("type") == "terminate") { + BOSHError::Type errorType = parseTerminationCondition(parser.getBody()->attributes.getAttribute("condition")); onSessionTerminated(errorType == BOSHError::NoError ? boost::shared_ptr<BOSHError>() : boost::make_shared<BOSHError>(errorType)); } buffer_.clear(); if (waitingForStartResponse_) { waitingForStartResponse_ = false; - sid_ = (*parser.getBody()).attributes.getAttribute("sid"); - std::string requestsString = (*parser.getBody()).attributes.getAttribute("requests"); + sid_ = parser.getBody()->attributes.getAttribute("sid"); + std::string requestsString = parser.getBody()->attributes.getAttribute("requests"); int requests = 2; if (!requestsString.empty()) { - requests = boost::lexical_cast<size_t>(requestsString); + try { + requests = boost::lexical_cast<size_t>(requestsString); + } + catch (const boost::bad_lexical_cast&) { + } } onSessionStarted(sid_, requests); } - SafeByteArray payload = createSafeByteArray((*parser.getBody()).content); + SafeByteArray payload = createSafeByteArray(parser.getBody()->content); /* Say we're good to go again, so don't add anything after here in the method */ pending_ = false; onXMPPDataRead(payload); } } BOSHError::Type BOSHConnection::parseTerminationCondition(const std::string& text) { BOSHError::Type condition = BOSHError::UndefinedCondition; @@ -251,34 +250,31 @@ BOSHError::Type BOSHConnection::parseTerminationCondition(const std::string& tex condition = BOSHError::NoError; } return condition; } const std::string& BOSHConnection::getSID() { return sid_; } -void BOSHConnection::setRID(unsigned long rid) { +void BOSHConnection::setRID(unsigned long long rid) { rid_ = rid; } void BOSHConnection::setSID(const std::string& sid) { sid_ = sid; } -void BOSHConnection::handleDisconnected(const boost::optional<Error>& error) { +void BOSHConnection::handleDisconnected(const boost::optional<Connection::Error>& error) { onDisconnected(error); sid_ = ""; connectionReady_ = false; } -HostAddressPort BOSHConnection::getLocalAddress() const { - return connection_->getLocalAddress(); -} bool BOSHConnection::isReadyToSend() { /* Without pipelining you need to not send more without first receiving the response */ /* With pipelining you can. Assuming we can't, here */ return connectionReady_ && !pending_ && !waitingForStartResponse_ && !sid_.empty(); } } diff --git a/Swiften/Network/BOSHConnection.h b/Swiften/Network/BOSHConnection.h index 283ea10..4d53253 100644 --- a/Swiften/Network/BOSHConnection.h +++ b/Swiften/Network/BOSHConnection.h @@ -23,18 +23,20 @@ #include <Swiften/Session/SessionStream.h> namespace boost { class thread; namespace system { class error_code; } } +class BOSHConnectionTest; + namespace Swift { class ConnectionFactory; class XMLParserFactory; class TLSContextFactory; class BOSHError : public SessionStream::Error { public: enum Type {BadRequest, HostGone, HostUnknown, ImproperAddressing, InternalServerError, ItemNotFound, OtherRequest, PolicyViolation, @@ -43,61 +45,63 @@ namespace Swift { BOSHError(Type type) : SessionStream::Error(SessionStream::Error::ConnectionReadError), type(type) {} Type getType() {return type;} typedef boost::shared_ptr<BOSHError> ref; private: Type type; }; - class BOSHConnection : public Connection, public boost::enable_shared_from_this<BOSHConnection> { + class BOSHConnection : public boost::enable_shared_from_this<BOSHConnection> { public: typedef boost::shared_ptr<BOSHConnection> ref; static ref create(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory) { return ref(new BOSHConnection(boshURL, connectionFactory, parserFactory, tlsFactory)); } virtual ~BOSHConnection(); - virtual void listen(); - virtual void connect(const HostAddressPort& address); + virtual void connect(); virtual void disconnect(); virtual void write(const SafeByteArray& data); - virtual HostAddressPort getLocalAddress() const; const std::string& getSID(); - void setRID(unsigned long rid); + void setRID(unsigned long long rid); void setSID(const std::string& sid); void startStream(const std::string& to, unsigned long rid); void terminateStream(); bool isReadyToSend(); void restartStream(); - static std::pair<SafeByteArray, size_t> createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, long rid, const std::string& sid, const URL& boshURL); + boost::signal<void (bool /* error */)> onConnectFinished; + boost::signal<void (bool /* error */)> onDisconnected; boost::signal<void (BOSHError::ref)> onSessionTerminated; boost::signal<void (const std::string& /*sid*/, size_t /*requests*/)> onSessionStarted; boost::signal<void (const SafeByteArray&)> onXMPPDataRead; boost::signal<void (const SafeByteArray&)> onBOSHDataRead; boost::signal<void (const SafeByteArray&)> onBOSHDataWritten; boost::signal<void (const std::string&)> onHTTPError; + private: - BOSHConnection(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory); + friend class ::BOSHConnectionTest; + BOSHConnection(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory); + static std::pair<SafeByteArray, size_t> createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, long rid, const std::string& sid, const URL& boshURL); void handleConnectionConnectFinished(bool error); void handleDataRead(boost::shared_ptr<SafeByteArray> data); - void handleDisconnected(const boost::optional<Error>& error); + void handleDisconnected(const boost::optional<Connection::Error>& error); void write(const SafeByteArray& data, bool streamRestart, bool terminate); /* FIXME: refactor */ BOSHError::Type parseTerminationCondition(const std::string& text); URL boshURL_; ConnectionFactory* connectionFactory_; XMLParserFactory* parserFactory_; boost::shared_ptr<Connection> connection_; std::string sid_; bool waitingForStartResponse_; - unsigned long rid_; + unsigned long long rid_; SafeByteArray buffer_; bool pending_; TLSContextFactory* tlsFactory_; bool connectionReady_; }; } diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index 4886ede..a30bf7b 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -191,19 +191,19 @@ void BOSHConnectionPool::tryToSendQueuedData() { } } } } void BOSHConnectionPool::handleHTTPError(const std::string& /*errorCode*/) { handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); } -void BOSHConnectionPool::handleConnectionDisconnected(const boost::optional<Connection::Error>& error, BOSHConnection::ref connection) { +void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection::ref connection) { destroyConnection(connection); if (false && error) { handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); } else { /* We might have just freed up a connection slot to send with */ tryToSendQueuedData(); } } @@ -212,19 +212,19 @@ boost::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() { BOSHConnection::ref connection = BOSHConnection::create(boshURL, connectProxyFactory ? connectProxyFactory : connectionFactory, xmlParserFactory, tlsFactory); connection->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1)); connection->onSessionStarted.connect(boost::bind(&BOSHConnectionPool::handleSessionStarted, this, _1, _2)); connection->onBOSHDataRead.connect(boost::bind(&BOSHConnectionPool::handleBOSHDataRead, this, _1)); connection->onBOSHDataWritten.connect(boost::bind(&BOSHConnectionPool::handleBOSHDataWritten, this, _1)); connection->onDisconnected.connect(boost::bind(&BOSHConnectionPool::handleConnectionDisconnected, this, _1, connection)); connection->onConnectFinished.connect(boost::bind(&BOSHConnectionPool::handleConnectFinished, this, _1, connection)); connection->onSessionTerminated.connect(boost::bind(&BOSHConnectionPool::handleSessionTerminated, this, _1)); connection->onHTTPError.connect(boost::bind(&BOSHConnectionPool::handleHTTPError, this, _1)); - connection->connect(HostAddressPort(HostAddress("0.0.0.0"), 0)); + connection->connect(); connections.push_back(connection); return connection; } void BOSHConnectionPool::destroyConnection(boost::shared_ptr<BOSHConnection> connection) { connections.erase(std::remove(connections.begin(), connections.end(), connection), connections.end()); connection->onXMPPDataRead.disconnect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1)); connection->onSessionStarted.disconnect(boost::bind(&BOSHConnectionPool::handleSessionStarted, this, _1, _2)); connection->onBOSHDataRead.disconnect(boost::bind(&BOSHConnectionPool::handleBOSHDataRead, this, _1)); diff --git a/Swiften/Network/BOSHConnectionPool.h b/Swiften/Network/BOSHConnectionPool.h index 2264c90..cc354b8 100644 --- a/Swiften/Network/BOSHConnectionPool.h +++ b/Swiften/Network/BOSHConnectionPool.h @@ -32,19 +32,19 @@ namespace Swift { boost::signal<void (const SafeByteArray&)> onBOSHDataWritten; private: void handleDataRead(const SafeByteArray& data); void handleSessionStarted(const std::string& sid, size_t requests); void handleBOSHDataRead(const SafeByteArray& data); void handleBOSHDataWritten(const SafeByteArray& data); void handleSessionTerminated(BOSHError::ref condition); void handleConnectFinished(bool, BOSHConnection::ref connection); - void handleConnectionDisconnected(const boost::optional<Connection::Error>& error, BOSHConnection::ref connection); + void handleConnectionDisconnected(bool error, BOSHConnection::ref connection); void handleHTTPError(const std::string& errorCode); private: BOSHConnection::ref createConnection(); void destroyConnection(BOSHConnection::ref connection); void tryToSendQueuedData(); BOSHConnection::ref getSuitableConnection(); private: diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index 9215725..8062bea 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -39,30 +39,31 @@ class BOSHConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testHTTPRequest_Empty); CPPUNIT_TEST_SUITE_END(); public: void setUp() { eventLoop = new DummyEventLoop(); connectionFactory = new MockConnectionFactory(eventLoop); connectFinished = false; disconnected = false; + disconnectedError = false; dataRead.clear(); } void tearDown() { eventLoop->processEvents(); delete connectionFactory; delete eventLoop; } void testHeader() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); testling->startStream("wonderland.lit", 1); std::string initial("<body wait='60' " "inactivity='30' " "polling='5' " "requests='2' " "hold='1' " "maxpause='120' " "sid='MyShinySID' " @@ -70,82 +71,82 @@ class BOSHConnectionTest : public CppUnit::TestFixture { "from='wonderland.lit' " "xmlns='http://jabber.org/protocol/httpbind'/>"); readResponse(initial, connectionFactory->connections[0]); CPPUNIT_ASSERT_EQUAL(std::string("MyShinySID"), sid); CPPUNIT_ASSERT(testling->isReadyToSend()); } void testReadiness_ok() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); testling->setSID("blahhhhh"); CPPUNIT_ASSERT(testling->isReadyToSend()); } void testReadiness_pending() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); testling->setSID("mySID"); CPPUNIT_ASSERT(testling->isReadyToSend()); testling->write(createSafeByteArray("<mypayload/>")); CPPUNIT_ASSERT(!testling->isReadyToSend()); readResponse("<body><blah/></body>", connectionFactory->connections[0]); CPPUNIT_ASSERT(testling->isReadyToSend()); } void testReadiness_disconnect() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); testling->setSID("mySID"); CPPUNIT_ASSERT(testling->isReadyToSend()); connectionFactory->connections[0]->onDisconnected(false); CPPUNIT_ASSERT(!testling->isReadyToSend()); } void testReadiness_noSID() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); CPPUNIT_ASSERT(!testling->isReadyToSend()); } void testWrite_Receive() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); testling->setSID("mySID"); testling->write(createSafeByteArray("<mypayload/>")); readResponse("<body><blah/></body>", connectionFactory->connections[0]); CPPUNIT_ASSERT_EQUAL(std::string("<blah/>"), byteArrayToString(dataRead)); } void testWrite_ReceiveTwice() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); testling->setSID("mySID"); testling->write(createSafeByteArray("<mypayload/>")); readResponse("<body><blah/></body>", connectionFactory->connections[0]); CPPUNIT_ASSERT_EQUAL(std::string("<blah/>"), byteArrayToString(dataRead)); dataRead.clear(); testling->write(createSafeByteArray("<mypayload2/>")); readResponse("<body><bleh/></body>", connectionFactory->connections[0]); CPPUNIT_ASSERT_EQUAL(std::string("<bleh/>"), byteArrayToString(dataRead)); } void testRead_Fragment() { BOSHConnection::ref testling = createTestling(); - testling->connect(HostAddressPort(HostAddress("127.0.0.1"), 5280)); + testling->connect(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), connectionFactory->connections.size()); boost::shared_ptr<MockConnection> connection = connectionFactory->connections[0]; boost::shared_ptr<SafeByteArray> data1 = boost::make_shared<SafeByteArray>(createSafeByteArray( "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; charset=utf-8\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Headers: Content-Type\r\n" "Content-Length: 64\r\n")); @@ -192,19 +193,19 @@ class BOSHConnectionTest : public CppUnit::TestFixture { c->setRID(42); return c; } void handleConnectFinished(bool error) { connectFinished = true; connectFinishedWithError = error; } - void handleDisconnected(const boost::optional<Connection::Error>& e) { + void handleDisconnected(bool e) { disconnected = true; disconnectedError = e; } void handleDataRead(const SafeByteArray& d) { append(dataRead, d); } void handleSID(const std::string& s) { @@ -274,18 +275,18 @@ class BOSHConnectionTest : public CppUnit::TestFixture { } private: DummyEventLoop* eventLoop; MockConnectionFactory* connectionFactory; bool connectFinished; bool connectFinishedWithError; bool disconnected; - boost::optional<Connection::Error> disconnectedError; + bool disconnectedError; ByteArray dataRead; PlatformXMLParserFactory parserFactory; std::string sid; }; CPPUNIT_TEST_SUITE_REGISTRATION(BOSHConnectionTest); |