diff options
| author | Remko Tronçon <git@el-tramo.be> | 2011-12-24 14:27:33 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2011-12-24 14:44:44 (GMT) | 
| commit | c060049e759571ae02a3a970c6a3088e099e5c9f (patch) | |
| tree | 8512e2ca0ae0fba16238651b9d0edbb74e085b16 | |
| parent | b453b3bf94dcd40d71c30fd0053f7110cb52b211 (diff) | |
| download | swift-contrib-c060049e759571ae02a3a970c6a3088e099e5c9f.zip swift-contrib-c060049e759571ae02a3a970c6a3088e099e5c9f.tar.bz2 | |
Some BOSH refactoring.
| -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 @@ -17,84 +17,79 @@  #include <boost/lexical_cast.hpp>  #include <string>  #include <Swiften/Network/ConnectionFactory.h>  #include <Swiften/Base/Log.h>  #include <Swiften/Base/String.h>  #include <Swiften/Base/Concat.h>  #include <Swiften/Base/ByteArray.h>  #include <Swiften/Network/HostAddressPort.h>  #include <Swiften/Network/TLSConnection.h>  #include <Swiften/Parser/BOSHBodyExtractor.h>  namespace Swift {  BOSHConnection::BOSHConnection(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory)  	: boshURL_(boshURL),   	  connectionFactory_(connectionFactory),   	  parserFactory_(parserFactory),  	  sid_(),  	  waitingForStartResponse_(false),  	  pending_(false),  	  tlsFactory_(tlsFactory),  	  connectionReady_(false)  {  }  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);  }  void BOSHConnection::terminateStream() {  	write(createSafeByteArray(""), false, true);  }  void BOSHConnection::write(const SafeByteArray& data) {  	write(data, false, false);  }  std::pair<SafeByteArray, size_t> BOSHConnection::createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, long rid, const std::string& sid, const URL& boshURL) {  	size_t size;  	std::stringstream content;  	SafeByteArray contentTail = createSafeByteArray("</body>");  	std::stringstream header;  	content << "<body rid='" << rid << "' sid='" << sid << "'";  	if (streamRestart) {  		content << " xmpp:restart='true' xmlns:xmpp='urn:xmpp:xbosh'";  	}  	if (terminate) {  		content << " type='terminate'";  	}  	content << " xmlns='http://jabber.org/protocol/httpbind'>"; @@ -138,147 +133,148 @@ void BOSHConnection::handleConnectionConnectFinished(bool error) {  void BOSHConnection::startStream(const std::string& to, unsigned long rid) {  	assert(connectionReady_);  	// Session Creation Request  	std::stringstream content;  	std::stringstream header;  	content << "<body content='text/xml; charset=utf-8'"  			<< " hold='1'"  			<< " to='" << to << "'"  			<< " rid='" << rid << "'"  			<< " ver='1.6'"  			<< " wait='60'" /* FIXME: we probably want this configurable*/  			/*<< " ack='0'" FIXME: support acks */  			<< " xml:lang='en'"  			<< " xmlns:xmpp='urn:xmpp:bosh'"  			<< " xmpp:version='1.0'"  			<< " xmlns='http://jabber.org/protocol/httpbind' />";  	std::string contentString = content.str();  	header	<< "POST /" << boshURL_.getPath() << " HTTP/1.1\r\n"  			<< "Host: " << boshURL_.getHost() << ":" << boshURL_.getPort() << "\r\n"  		/*<< "Accept-Encoding: deflate\r\n"*/  			<< "Content-Type: text/xml; charset=utf-8\r\n"  			<< "Content-Length: " << contentString.size() << "\r\n\r\n"  			<< contentString;  	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;  	if (text == "bad-request") {  		condition = BOSHError::BadRequest;  	}  	else if (text == "host-gone") {  		condition = BOSHError::HostGone;  	}  	else if (text == "host-unknown") {  		condition = BOSHError::HostUnknown;  	}  	else if (text == "improper-addressing") {  		condition = BOSHError::ImproperAddressing;  	}  	else if (text == "internal-server-error") {  		condition = BOSHError::InternalServerError;  	}  	else if (text == "item-not-found") {  		condition = BOSHError::ItemNotFound;  	}  	else if (text == "other-request") {  		condition = BOSHError::OtherRequest;  	}  	else if (text == "policy-violation") {  		condition = BOSHError::PolicyViolation;  	}  	else if (text == "remote-connection-failed") {  		condition = BOSHError::RemoteConnectionFailed;  	}  	else if (text == "remote-stream-error") {  		condition = BOSHError::RemoteStreamError;  	}  	else if (text == "see-other-uri") {  		condition = BOSHError::SeeOtherURI;  	}  	else if (text == "system-shutdown") {  		condition = BOSHError::SystemShutdown;  	}  	else if (text == "") {  		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 @@ -1,103 +1,107 @@  /*   * Copyright (c) 2011 Thilo Cestonaro   * Licensed under the simplified BSD license.   * See Documentation/Licenses/BSD-simplified.txt for more information.   */  /*   * Copyright (c) 2011 Kevin Smith   * Licensed under the GNU General Public License v3.   * See Documentation/Licenses/GPLv3.txt for more information.   */  #pragma once  #include <boost/enable_shared_from_this.hpp>  #include <Swiften/Network/Connection.h>  #include <Swiften/Network/HostAddressPort.h>  #include <Swiften/Base/String.h>  #include <Swiften/Base/URL.h>  #include <Swiften/Base/Error.h>  #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,   						  RemoteConnectionFailed, RemoteStreamError, SeeOtherURI, SystemShutdown, UndefinedCondition,  						  NoError};  					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 @@ -165,86 +165,86 @@ void BOSHConnectionPool::tryToSendQueuedData() {  		bool pending = false;  		foreach (BOSHConnection::ref connection, connections) {  			if (connection && !connection->isReadyToSend()) {  				pending = true;  			}  		}  		if (!pending) {  			if (restartCount >= 1) {  				/* Don't open a second connection until we've restarted the stream twice - i.e. we've authed and resource bound.*/  				if (suitableConnection) {  					rid++;  					suitableConnection->setRID(rid);  					suitableConnection->write(createSafeByteArray(""));  				}  				else {  				/* My thought process I went through when writing this, to aid anyone else confused why this can happen...  				 *  				 * What to do here? I think this isn't possible.  				   If you didn't have two connections, suitable would have made one.  				   If you have two connections and neither is suitable, pending would be true.  				   If you have a non-pending connection, it's suitable.  				   If I decide to do something here, remove assert above.  				   Ah! Yes, because there's a period between creating the connection and it being connected. */  				}  			}  		}  	}  }  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();  	}  }  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));  	connection->onBOSHDataWritten.disconnect(boost::bind(&BOSHConnectionPool::handleBOSHDataWritten, this, _1));  	connection->onDisconnected.disconnect(boost::bind(&BOSHConnectionPool::handleConnectionDisconnected, this, _1, connection));  	connection->onConnectFinished.disconnect(boost::bind(&BOSHConnectionPool::handleConnectFinished, this, _1, connection));  	connection->onSessionTerminated.disconnect(boost::bind(&BOSHConnectionPool::handleSessionTerminated, this, _1));  	connection->onHTTPError.disconnect(boost::bind(&BOSHConnectionPool::handleHTTPError, this, _1));  }  void BOSHConnectionPool::handleSessionTerminated(BOSHError::ref error) {  	onSessionTerminated(error);  }  void BOSHConnectionPool::handleBOSHDataRead(const SafeByteArray& data) {  	onBOSHDataRead(data);  }  void BOSHConnectionPool::handleBOSHDataWritten(const SafeByteArray& data) {  	onBOSHDataWritten(data);  }  } 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 @@ -6,62 +6,62 @@  #pragma once  #include <vector>  #include <Swiften/Base/SafeString.h>  #include <Swiften/Network/BOSHConnection.h>  namespace Swift {  	class HTTPConnectProxiedConnectionFactory;  	class TLSConnectionFactory;  	class BOSHConnectionPool : public boost::bsignals::trackable {  		public:  			BOSHConnectionPool(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, const std::string& to, long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword);  			~BOSHConnectionPool();  			void write(const SafeByteArray& data);  			void writeFooter();  			void close();  			void restartStream();  			boost::signal<void (BOSHError::ref)> onSessionTerminated;  			boost::signal<void ()> onSessionStarted;  			boost::signal<void (const SafeByteArray&)> onXMPPDataRead;  			boost::signal<void (const SafeByteArray&)> onBOSHDataRead;  			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:  			URL boshURL;  			ConnectionFactory* connectionFactory;  			XMLParserFactory* xmlParserFactory;  			TLSContextFactory* tlsFactory;  			std::vector<BOSHConnection::ref> connections;  			std::string sid;  			unsigned long rid;  			std::vector<SafeByteArray> dataQueue;  			bool pendingTerminate;  			std::string to;  			size_t requestLimit;  			int restartCount;  			bool pendingRestart;  			HTTPConnectProxiedConnectionFactory* connectProxyFactory;  			TLSConnectionFactory* tlsConnectionFactory;  	};  } 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 @@ -13,224 +13,225 @@  #include <boost/bind.hpp>  #include <boost/smart_ptr/make_shared.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/lexical_cast.hpp>  #include <Swiften/Base/Algorithm.h>  #include <Swiften/Network/Connection.h>  #include <Swiften/Network/ConnectionFactory.h>  #include <Swiften/Network/BOSHConnection.h>  #include <Swiften/Network/HostAddressPort.h>  #include <Swiften/EventLoop/DummyEventLoop.h>  #include <Swiften/Parser/PlatformXMLParserFactory.h>  using namespace Swift;  class BOSHConnectionTest : public CppUnit::TestFixture {  	CPPUNIT_TEST_SUITE(BOSHConnectionTest);  	CPPUNIT_TEST(testHeader);  	CPPUNIT_TEST(testReadiness_ok);  	CPPUNIT_TEST(testReadiness_pending);  	CPPUNIT_TEST(testReadiness_disconnect);  	CPPUNIT_TEST(testReadiness_noSID);  	CPPUNIT_TEST(testWrite_Receive);  	CPPUNIT_TEST(testWrite_ReceiveTwice);  	CPPUNIT_TEST(testRead_Fragment);  	CPPUNIT_TEST(testHTTPRequest);  	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' "  								"ver='1.6' "  								"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"));  			boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(  				"\r\n<body xmlns='http://jabber.org/protocol/httpbind'>"  				"<bl"));  			boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray(  				"ah/>"  				"</body>"));  			connection->onDataRead(data1);  			connection->onDataRead(data2);  			CPPUNIT_ASSERT(dataRead.empty());  			connection->onDataRead(data3);  			CPPUNIT_ASSERT_EQUAL(std::string("<blah/>"), byteArrayToString(dataRead));  		}  		void testHTTPRequest() {  			std::string data = "<blah/>";  			std::string sid = "wigglebloom";  			std::string fullBody = "<body xmlns='http://jabber.org/protocol/httpbind' sid='" + sid + "' rid='20'>" + data + "</body>";  			std::pair<SafeByteArray, size_t> http = BOSHConnection::createHTTPRequest(createSafeByteArray(data), false, false, 20, sid, URL());  			CPPUNIT_ASSERT_EQUAL(fullBody.size(), http.second);  		}  		void testHTTPRequest_Empty() {  			std::string data = "";  			std::string sid = "wigglebloomsickle";  			std::string fullBody = "<body rid='42' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'>" + data + "</body>";  			std::pair<SafeByteArray, size_t> http = BOSHConnection::createHTTPRequest(createSafeByteArray(data), false, false, 42, sid, URL());  			CPPUNIT_ASSERT_EQUAL(fullBody.size(), http.second);  			std::string response = safeByteArrayToString(http.first);  			size_t bodyPosition = response.find("\r\n\r\n");  			CPPUNIT_ASSERT_EQUAL(fullBody, response.substr(bodyPosition+4));  		}  	private:  		BOSHConnection::ref createTestling() {  			BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL));  			c->onConnectFinished.connect(boost::bind(&BOSHConnectionTest::handleConnectFinished, this, _1));  			c->onDisconnected.connect(boost::bind(&BOSHConnectionTest::handleDisconnected, this, _1));  			c->onXMPPDataRead.connect(boost::bind(&BOSHConnectionTest::handleDataRead, this, _1));  			c->onSessionStarted.connect(boost::bind(&BOSHConnectionTest::handleSID, this, _1));  			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) {  			sid = s;  		}  		struct MockConnection : public Connection {  			public:  				MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) {  				}  				void listen() { assert(false); }  				void connect(const HostAddressPort& address) {  					hostAddressPort = address;  					bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end();  					eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail));  				}  				HostAddressPort getLocalAddress() const { return HostAddressPort(); }  				void disconnect() {   					disconnected = true;  					onDisconnected(boost::optional<Connection::Error>());  				}  				void write(const SafeByteArray& d) {  					append(dataWritten, d);  				} @@ -248,44 +249,44 @@ class BOSHConnectionTest : public CppUnit::TestFixture {  			boost::shared_ptr<Connection> createConnection() {  				boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop);  				connections.push_back(connection);  				return connection;  			}  			EventLoop* eventLoop;  			std::vector< boost::shared_ptr<MockConnection> > connections;  			std::vector<HostAddressPort> failingPorts;  		};  		void readResponse(const std::string& response, boost::shared_ptr<MockConnection> connection) {  			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: "));  			connection->onDataRead(data1);  			boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size())));  			connection->onDataRead(data2);  			boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n"));  			connection->onDataRead(data3);  			boost::shared_ptr<SafeByteArray> data4 = boost::make_shared<SafeByteArray>(createSafeByteArray(response));  			connection->onDataRead(data4);  		}  	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); | 
 Swift
 Swift