From ee3a46975986865fe5064f9d87a27277fc6c235a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Tue, 14 Jul 2009 19:27:32 +0200
Subject: Consolidating IncomingConnection & Connection.

BoostConnections no longer have their own thread, but are managed from
a central Boost IO thread instead.

diff --git a/Limber/main.cpp b/Limber/main.cpp
index be7387e..200f2e4 100644
--- a/Limber/main.cpp
+++ b/Limber/main.cpp
@@ -1,12 +1,8 @@
-
 #include <iostream>
 #include <string>
 #include <boost/asio.hpp>
-#include <boost/signal.hpp>
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/thread.hpp>
 
 #include "Swiften/Elements/IQ.h"
 #include "Swiften/Elements/RosterPayload.h"
@@ -18,6 +14,7 @@
 #include "Swiften/EventLoop/SimpleEventLoop.h"
 #include "Swiften/Elements/Stanza.h"
 #include "Swiften/Network/ConnectionServer.h"
+#include "Swiften/Network/BoostConnection.h"
 #include "Swiften/Network/BoostIOServiceThread.h"
 #include "Swiften/Server/ServerFromClientSession.h"
 #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
@@ -25,82 +22,6 @@
 
 using namespace Swift;
 
-static const size_t BUFFER_SIZE = 4096;
-
-// A reference-counted non-modifiable buffer class.
-class SharedBuffer {
-	public:
-		SharedBuffer(const ByteArray& data) : 
-				data_(new std::vector<char>(data.begin(), data.end())),
-				buffer_(boost::asio::buffer(*data_)) {
-		}
-
-		// ConstBufferSequence requirements.
-		typedef boost::asio::const_buffer value_type;
-		typedef const boost::asio::const_buffer* const_iterator;
-		const boost::asio::const_buffer* begin() const { return &buffer_; }
-		const boost::asio::const_buffer* end() const { return &buffer_ + 1; }
-
-	private:
-		boost::shared_ptr< std::vector<char> > data_;
-		boost::asio::const_buffer buffer_;
-};
-
-class IncomingBoostConnection : public IncomingConnection, public boost::enable_shared_from_this<IncomingBoostConnection> {
-	public:
-		typedef boost::shared_ptr<IncomingBoostConnection> pointer;
-
-		static pointer create(boost::asio::io_service& ioService) {
-			return pointer(new IncomingBoostConnection(ioService));
-		}
-
-		boost::asio::ip::tcp::socket& getSocket() {
-			return socket_;
-		}
-
-		void write(const ByteArray& data) {
-			boost::asio::async_write(socket_, SharedBuffer(data),
-					boost::bind(
-						&IncomingBoostConnection::handleDataWritten, 
-						shared_from_this(),
-						boost::asio::placeholders::error));
-		}
-
-		void start() {
-			read();
-		}
-
-	private:
-		IncomingBoostConnection(boost::asio::io_service& ioService) : socket_(ioService), readBuffer_(BUFFER_SIZE) {
-		}
-
-		void read() {
-			socket_.async_read_some(
-					boost::asio::buffer(readBuffer_),
-					boost::bind(&IncomingBoostConnection::handleDataRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
-		}
-
-		void handleDataRead(const boost::system::error_code& error, size_t bytesTransferred) {
-			if (!error) {
-				MainEventLoop::postEvent(boost::bind(boost::ref(onDataRead), ByteArray(&readBuffer_[0], bytesTransferred)), this);
-				read();
-			}
-			else if (error != boost::asio::error::operation_aborted) {
-				//MainEventLoop::postEvent(boost::bind(boost::ref(onError), ReadError), this);
-			}
-		}
-
-		void handleDataWritten(const boost::system::error_code& error) {
-			if (error && error != boost::asio::error::operation_aborted) {
-				//std::cerr << "ERROR: Unable to write data to socket" << std::endl;
-				//MainEventLoop::postEvent(boost::bind(boost::ref(onError), ReadError), this);
-			}
-		}
-
-		boost::asio::ip::tcp::socket socket_;
-		std::vector<char> readBuffer_;
-};
-
 class BoostConnectionServer : public ConnectionServer {
 	public:
 		BoostConnectionServer(int port, boost::asio::io_service& ioService) : acceptor_(ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) {
@@ -109,15 +30,15 @@ class BoostConnectionServer : public ConnectionServer {
 
 	private:
 		void acceptNextConnection() {
-			IncomingBoostConnection::pointer newConnection = IncomingBoostConnection::create(acceptor_.io_service());
+			boost::shared_ptr<BoostConnection> newConnection(new BoostConnection(&acceptor_.io_service()));
 			acceptor_.async_accept(newConnection->getSocket(), 
 				boost::bind(&BoostConnectionServer::handleAccept, this, newConnection, boost::asio::placeholders::error));
 		}
 
-		void handleAccept(IncomingBoostConnection::pointer newConnection, const boost::system::error_code& error) {
+		void handleAccept(boost::shared_ptr<BoostConnection> newConnection, const boost::system::error_code& error) {
 			if (!error) {
 				MainEventLoop::postEvent(boost::bind(boost::ref(onNewConnection), newConnection), this);
-				newConnection->start();
+				newConnection->listen();
 				acceptNextConnection();
 			}
 		}
@@ -137,7 +58,7 @@ class Server {
 		}
 
 	private:
-		void handleNewConnection(boost::shared_ptr<IncomingConnection> c) {
+		void handleNewConnection(boost::shared_ptr<Connection> c) {
 			ServerFromClientSession* session = new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, userRegistry_);
 			serverFromClientSessions_.push_back(session);
 			session->onStanzaReceived.connect(boost::bind(&Server::handleStanzaReceived, this, _1, session));
@@ -192,5 +113,5 @@ int main() {
 	userRegistry.addUser(JID("remko@limber"), "pass");
 	Server server(&userRegistry);
 	eventLoop.run();
-  return 0;
+	return 0;
 }
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 1af689c..77e531e 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -209,6 +209,7 @@ void MainController::handleError(const ClientError& error) {
 		case ClientError::DomainNameResolveError: message = "Unable to find server"; break;
 		case ClientError::ConnectionError: message = "Error connecting to server"; break;
 		case ClientError::ConnectionReadError: message = "Error while receiving server data"; break;
+		case ClientError::ConnectionWriteError: message = "Error while sending data to the server"; break;
 		case ClientError::XMLError: message = "Error parsing server data"; break;
 		case ClientError::AuthenticationFailedError: message = "Login/password invalid"; break;
 		case ClientError::NoSupportedAuthMechanismsError: message = "Authentication mechanisms not supported"; break;
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index e5bbf9d..d87673b 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -11,14 +11,14 @@ namespace Swift {
 
 Client::Client(const JID& jid, const String& password) :
 		IQRouter(this), jid_(jid), password_(password), session_(0) {
-	connectionFactory_ = new BoostConnectionFactory();
+	connectionFactory_ = new BoostConnectionFactory(&boostIOServiceThread_.getIOService());
 	tlsLayerFactory_ = new PlatformTLSLayerFactory();
 }
 
 Client::~Client() {
 	delete session_;
 	delete tlsLayerFactory_;
-  delete connectionFactory_;
+	delete connectionFactory_;
 }
 
 void Client::connect() {
@@ -101,6 +101,9 @@ void Client::handleSessionError(Session::SessionError error) {
 		case Session::ConnectionReadError:
 			clientError = ClientError(ClientError::ConnectionReadError);
 			break;
+		case Session::ConnectionWriteError:
+			clientError = ClientError(ClientError::ConnectionWriteError);
+			break;
 		case Session::XMLError:
 			clientError = ClientError(ClientError::XMLError);
 			break;
diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h
index 946bdbd..d876302 100644
--- a/Swiften/Client/Client.h
+++ b/Swiften/Client/Client.h
@@ -15,44 +15,46 @@
 #include "Swiften/Queries/IQRouter.h"
 #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
 #include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h"
+#include "Swiften/Network/BoostIOServiceThread.h"
 
 namespace Swift {
 	class TLSLayerFactory;
 	class ConnectionFactory;
 	class Session;
 
-  class Client : public StanzaChannel, public IQRouter {
-    public:
-      Client(const JID& jid, const String& password);
-      ~Client();
+	class Client : public StanzaChannel, public IQRouter {
+		public:
+			Client(const JID& jid, const String& password);
+			~Client();
 
 			void setCertificate(const String& certificate);
 
-      void connect();
+			void connect();
 			void disconnect();
 
-      virtual void sendIQ(boost::shared_ptr<IQ>);
+			virtual void sendIQ(boost::shared_ptr<IQ>);
 			virtual void sendMessage(boost::shared_ptr<Message>);
 			virtual void sendPresence(boost::shared_ptr<Presence>);
 
-    public:
-      boost::signal<void (ClientError)> onError;
-      boost::signal<void ()> onConnected;
+		public:
+			boost::signal<void (ClientError)> onError;
+			boost::signal<void ()> onConnected;
 			boost::signal<void (const String&)> onDataRead;
 			boost::signal<void (const String&)> onDataWritten;
 
 		private:
-      void send(boost::shared_ptr<Stanza>);
-      virtual String getNewIQID();
+			void send(boost::shared_ptr<Stanza>);
+			virtual String getNewIQID();
 			void handleElement(boost::shared_ptr<Element>);
 			void handleSessionError(Session::SessionError error);
 			void handleNeedCredentials();
 			void handleDataRead(const ByteArray&);
 			void handleDataWritten(const ByteArray&);
 
-    private:
+		private:
+			BoostIOServiceThread boostIOServiceThread_;
 			JID jid_;
-      String password_;
+			String password_;
 			IDGenerator idGenerator_;
 			ConnectionFactory* connectionFactory_;
 			TLSLayerFactory* tlsLayerFactory_;
@@ -60,7 +62,7 @@ namespace Swift {
 			FullPayloadSerializerCollection payloadSerializers_;
 			Session* session_;
 			String certificate_;
-  };
+	};
 }
 
 #endif
diff --git a/Swiften/Client/ClientError.h b/Swiften/Client/ClientError.h
index 38f20c0..d81cc0e 100644
--- a/Swiften/Client/ClientError.h
+++ b/Swiften/Client/ClientError.h
@@ -9,6 +9,7 @@ namespace Swift {
 				DomainNameResolveError,
 				ConnectionError,
 				ConnectionReadError,
+				ConnectionWriteError,
 				XMLError,
 				AuthenticationFailedError,
 				NoSupportedAuthMechanismsError,
diff --git a/Swiften/Client/Session.cpp b/Swiften/Client/Session.cpp
index c4adfa0..1ae97d6 100644
--- a/Swiften/Client/Session.cpp
+++ b/Swiften/Client/Session.cpp
@@ -52,10 +52,10 @@ Session::~Session() {
 void Session::start() {
 	assert(state_ == Initial);
 	state_ = Connecting;
-	connection_ = connectionFactory_->createConnection(jid_.getDomain());
+	connection_ = connectionFactory_->createConnection();
 	connection_->onConnected.connect(boost::bind(&Session::handleConnected, this));
 	connection_->onError.connect(boost::bind(&Session::handleConnectionError, this, _1));
-	connection_->connect();
+	connection_->connect(jid_.getDomain());
 }
 
 void Session::stop() {
@@ -93,6 +93,9 @@ void Session::handleConnectionError(Connection::Error error) {
 		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 c49d877..516cb5a 100644
--- a/Swiften/Client/Session.h
+++ b/Swiften/Client/Session.h
@@ -43,6 +43,7 @@ namespace Swift {
 				DomainNameResolveError,
 				ConnectionError,
 				ConnectionReadError,
+				ConnectionWriteError,
 				XMLError,
 				AuthenticationFailedError,
 				NoSupportedAuthMechanismsError,
diff --git a/Swiften/Client/UnitTest/SessionTest.cpp b/Swiften/Client/UnitTest/SessionTest.cpp
index c2b99db..da05a06 100644
--- a/Swiften/Client/UnitTest/SessionTest.cpp
+++ b/Swiften/Client/UnitTest/SessionTest.cpp
@@ -57,9 +57,9 @@ class SessionTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST(testSessionStart);
 		CPPUNIT_TEST(testSessionStart_Error);
 		CPPUNIT_TEST(testSessionStart_AfterResourceBind);
-    CPPUNIT_TEST(testWhitespacePing);
+		CPPUNIT_TEST(testWhitespacePing);
 		CPPUNIT_TEST(testReceiveElementAfterSessionStarted);
-    CPPUNIT_TEST(testSendElement);
+		CPPUNIT_TEST(testSendElement);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -74,8 +74,8 @@ class SessionTest : public CppUnit::TestFixture {
 		}
 
 		void tearDown() {
-      delete tlsLayerFactory_;
-      delete connectionFactory_;
+			delete tlsLayerFactory_;
+			delete connectionFactory_;
 			delete eventLoop_;
 		}
 
@@ -250,7 +250,7 @@ class SessionTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT_EQUAL(Session::Negotiating, session->getState());
 		}
 
-    void testAuthenticate_Unauthorized() {
+		void testAuthenticate_Unauthorized() {
 			std::auto_ptr<MockSession> session(createSession("me@foo.com/Bar"));
 			session->start();
 			getMockServer()->expectStreamStart();
@@ -265,9 +265,9 @@ class SessionTest : public CppUnit::TestFixture {
 
 			CPPUNIT_ASSERT_EQUAL(Session::Error, session->getState());
 			CPPUNIT_ASSERT_EQUAL(Session::AuthenticationFailedError, session->getError());
-    }
+		}
 
-    void testAuthenticate_NoValidAuthMechanisms() {
+		void testAuthenticate_NoValidAuthMechanisms() {
 			std::auto_ptr<MockSession> session(createSession("me@foo.com/Bar"));
 			session->start();
 			getMockServer()->expectStreamStart();
@@ -277,7 +277,7 @@ class SessionTest : public CppUnit::TestFixture {
 
 			CPPUNIT_ASSERT_EQUAL(Session::Error, session->getState());
 			CPPUNIT_ASSERT_EQUAL(Session::NoSupportedAuthMechanismsError, session->getError());
-    }
+		}
 
 		void testResourceBind() {
 			std::auto_ptr<MockSession> session(createSession("me@foo.com/Bar"));
@@ -389,7 +389,7 @@ class SessionTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT(sessionStarted_);
 		}
 
-    void testWhitespacePing() {
+		void testWhitespacePing() {
 			std::auto_ptr<MockSession> session(createSession("me@foo.com/Bar"));
 			session->start();
 			getMockServer()->expectStreamStart();
@@ -397,7 +397,7 @@ class SessionTest : public CppUnit::TestFixture {
 			getMockServer()->sendStreamFeatures();
 			processEvents();
 			CPPUNIT_ASSERT(session->getWhitespacePingLayer());
-    }
+		}
 
 		void testReceiveElementAfterSessionStarted() {
 			std::auto_ptr<MockSession> session(createSession("me@foo.com/Bar"));
@@ -407,11 +407,11 @@ class SessionTest : public CppUnit::TestFixture {
 			getMockServer()->sendStreamFeatures();
 			processEvents();
 
-      getMockServer()->expectMessage();
-      session->sendElement(boost::shared_ptr<Message>(new Message()));
+			getMockServer()->expectMessage();
+			session->sendElement(boost::shared_ptr<Message>(new Message()));
 		}
 
-    void testSendElement() {
+		void testSendElement() {
 			std::auto_ptr<MockSession> session(createSession("me@foo.com/Bar"));
 			session->onElementReceived.connect(boost::bind(&SessionTest::addReceivedElement, this, _1));
 			session->start();
@@ -421,9 +421,9 @@ class SessionTest : public CppUnit::TestFixture {
 			getMockServer()->sendMessage();
 			processEvents();
 
-      CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(receivedElements_.size()));
-      CPPUNIT_ASSERT(boost::dynamic_pointer_cast<Message>(receivedElements_[0]));
-    }
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(receivedElements_.size()));
+			CPPUNIT_ASSERT(boost::dynamic_pointer_cast<Message>(receivedElements_[0]));
+		}
 
 	private:
 		struct MockConnection;
@@ -446,9 +446,9 @@ class SessionTest : public CppUnit::TestFixture {
 			needCredentials_ = true;
 		}
 
-    void addReceivedElement(boost::shared_ptr<Element> element) {
-      receivedElements_.push_back(element);
-    }
+		void addReceivedElement(boost::shared_ptr<Element> element) {
+			receivedElements_.push_back(element);
+		}
 	
 	private:
 		struct MockConnection : public Connection, public XMPPParserClient {
@@ -463,12 +463,11 @@ class SessionTest : public CppUnit::TestFixture {
 						direction(direction), type(type), element(element) {}
 
 				Direction direction;
-				Type  type;
+				Type	type;
 				boost::shared_ptr<Element> element;
 			};
 
-			MockConnection(const String& domain, bool fail) : 
-					Connection(domain), 
+			MockConnection(bool fail) : 
 					fail_(fail), 
 					resetParser_(false),
 					parser_(0),
@@ -476,18 +475,23 @@ class SessionTest : public CppUnit::TestFixture {
 				parser_ = new XMPPParser(this, &payloadParserFactories_);
 			}
 
-      ~MockConnection() {
-        delete parser_;
-      }
+			~MockConnection() {
+				delete parser_;
+			}
 
 			void disconnect() {
 			}
 
-			void connect() {
+			void listen() {
+				assert(false);
+			}
+
+			void connect(const String& domain) {
 				if (fail_) {
 					MainEventLoop::postEvent(boost::bind(boost::ref(onError), Connection::ConnectionError));
 				}
 				else {
+					domain_ = domain;
 					MainEventLoop::postEvent(boost::bind(boost::ref(onConnected)));
 				}
 			}
@@ -510,7 +514,7 @@ class SessionTest : public CppUnit::TestFixture {
 			}
 
 			void handleStreamStart(const String&, const String& to, const String&) {
-				CPPUNIT_ASSERT_EQUAL(getDomain(), to);
+				CPPUNIT_ASSERT_EQUAL(domain_, to);
 				handleEvent(Event::StreamStartEvent);
 			}
 
@@ -544,7 +548,7 @@ class SessionTest : public CppUnit::TestFixture {
 			String serializeEvent(const Event& event) {
 				switch (event.type) {
 					case Event::StreamStartEvent: 
-						return serializer_.serializeHeader("", getDomain(), "");
+						return serializer_.serializeHeader("", domain_, "");
 					case Event::ElementEvent:
 						return serializer_.serializeElement(event.element);
 					case Event::StreamEndEvent:
@@ -571,7 +575,7 @@ class SessionTest : public CppUnit::TestFixture {
 			}
 
 			void expectAuth(const String& user, const String& password) {
-				String s  = String("") + '\0' + user + '\0' + password;
+				String s	= String("") + '\0' + user + '\0' + password;
 				events_.push_back(Event(Event::In, Event::ElementEvent, boost::shared_ptr<AuthRequest>(new AuthRequest("PLAIN", ByteArray(s.getUTF8Data(), s.getUTF8Size())))));
 			}
 
@@ -584,10 +588,10 @@ class SessionTest : public CppUnit::TestFixture {
 			void expectSessionStart(const String& id) {
 				events_.push_back(Event(Event::In, Event::ElementEvent, IQ::createRequest(IQ::Set, JID(), id, boost::shared_ptr<StartSession>(new StartSession()))));
 			}
-      
-      void expectMessage() {
+			
+			void expectMessage() {
 				events_.push_back(Event(Event::In, Event::ElementEvent, boost::shared_ptr<Message>(new Message())));
-      }
+			}
 
 			void sendInvalidXML() {
 				sendData("<invalid xml/>");
@@ -675,6 +679,7 @@ class SessionTest : public CppUnit::TestFixture {
 
 			bool fail_;
 			bool resetParser_;
+			String domain_;
 			FullPayloadParserFactoryCollection payloadParserFactories_;
 			FullPayloadSerializerCollection payloadSerializers_;
 			XMPPParser* parser_;
@@ -684,8 +689,8 @@ class SessionTest : public CppUnit::TestFixture {
 
 		struct MockConnectionFactory : public ConnectionFactory {
 			MockConnectionFactory() : fail_(false) {}
-			MockConnection* createConnection(const String& domain) {
-				MockConnection* result = new MockConnection(domain, fail_);
+			MockConnection* createConnection() {
+				MockConnection* result = new MockConnection(fail_);
 				connections_.push_back(result);
 				return result;
 			}
@@ -746,7 +751,7 @@ class SessionTest : public CppUnit::TestFixture {
 		FullPayloadSerializerCollection payloadSerializers_;
 		bool sessionStarted_;
 		bool needCredentials_;
-    std::vector< boost::shared_ptr<Element> > receivedElements_;
+		std::vector< boost::shared_ptr<Element> > receivedElements_;
 		typedef std::vector< boost::function<void ()> > EventQueue;
 		EventQueue events_;
 };
diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp
index f055f6a..ec15c96 100644
--- a/Swiften/Network/BoostConnection.cpp
+++ b/Swiften/Network/BoostConnection.cpp
@@ -14,53 +14,67 @@ namespace Swift {
 
 static const size_t BUFFER_SIZE = 4096;
 
-BoostConnection::BoostConnection(const String& domain) :
-		Connection(domain), ioService_(0), thread_(0), socket_(0), readBuffer_(BUFFER_SIZE) {
-  ioService_ = new boost::asio::io_service();
+// -----------------------------------------------------------------------------
+
+// A reference-counted non-modifiable buffer class.
+class SharedBuffer {
+	public:
+		SharedBuffer(const ByteArray& data) : 
+				data_(new std::vector<char>(data.begin(), data.end())),
+				buffer_(boost::asio::buffer(*data_)) {
+		}
+
+		// ConstBufferSequence requirements.
+		typedef boost::asio::const_buffer value_type;
+		typedef const boost::asio::const_buffer* const_iterator;
+		const boost::asio::const_buffer* begin() const { return &buffer_; }
+		const boost::asio::const_buffer* end() const { return &buffer_ + 1; }
+
+	private:
+		boost::shared_ptr< std::vector<char> > data_;
+		boost::asio::const_buffer buffer_;
+};
+
+// -----------------------------------------------------------------------------
+
+BoostConnection::BoostConnection(boost::asio::io_service* ioService) :
+		socket_(*ioService), readBuffer_(BUFFER_SIZE) {
 }
 
 BoostConnection::~BoostConnection() {
 	MainEventLoop::removeEventsFromOwner(this);
-  ioService_->stop();
-  thread_->join();
-	delete socket_;
-	delete thread_;
-	delete ioService_;
 }
 
-void BoostConnection::connect() {
-	thread_ = new boost::thread(boost::bind(&BoostConnection::doConnect, this));
+void BoostConnection::listen() {
+	doRead();
 }
 
-void BoostConnection::disconnect() {
-	if (ioService_) {
-		ioService_->post(boost::bind(&BoostConnection::doDisconnect, this));
-	}
-}
-
-void BoostConnection::write(const ByteArray& data) {
-	if (ioService_) {
-		ioService_->post(boost::bind(&BoostConnection::doWrite, this, data));
-	}
-}
-
-void BoostConnection::doConnect() {
+void BoostConnection::connect(const String& domain) {
 	DomainNameResolver resolver;
 	try {
-		HostAddressPort addressPort = resolver.resolve(getDomain().getUTF8String());
-		socket_ = new boost::asio::ip::tcp::socket(*ioService_);
+		HostAddressPort addressPort = resolver.resolve(domain.getUTF8String());
 		boost::asio::ip::tcp::endpoint endpoint(	
 				boost::asio::ip::address::from_string(addressPort.getAddress().toString()), addressPort.getPort());
-		socket_->async_connect(
+		// Use shared_from_this
+		socket_.async_connect(
 				endpoint,
 				boost::bind(&BoostConnection::handleConnectFinished, this, boost::asio::placeholders::error));
-		ioService_->run();
 	}
 	catch (const DomainNameResolveException& e) {
-		MainEventLoop::postEvent(boost::bind(boost::ref(onError), DomainNameResolveError), this);
+		onError(DomainNameResolveError);
 	}
 }
 
+void BoostConnection::disconnect() {
+	socket_.close();
+}
+
+void BoostConnection::write(const ByteArray& data) {
+	// Use shared_from_this
+	boost::asio::async_write(socket_, SharedBuffer(data),
+			boost::bind(&BoostConnection::handleDataWritten, this, boost::asio::placeholders::error));
+}
+
 void BoostConnection::handleConnectFinished(const boost::system::error_code& error) {
 	if (!error) {
 		MainEventLoop::postEvent(boost::bind(boost::ref(onConnected)), this);
@@ -72,15 +86,12 @@ void BoostConnection::handleConnectFinished(const boost::system::error_code& err
 }
 
 void BoostConnection::doRead() {
-	socket_->async_read_some(
-	    boost::asio::buffer(readBuffer_),
+	// Use shared_from_this
+	socket_.async_read_some(
+			boost::asio::buffer(readBuffer_),
 			boost::bind(&BoostConnection::handleSocketRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
 }
 
-void BoostConnection::doWrite(const ByteArray& data) {
-	boost::asio::write(*socket_, boost::asio::buffer(static_cast<const char*>(data.getData()), data.getSize()));
-}
-
 void BoostConnection::handleSocketRead(const boost::system::error_code& error, size_t bytesTransferred) {
 	if (!error) {
 		MainEventLoop::postEvent(boost::bind(boost::ref(onDataRead), ByteArray(&readBuffer_[0], bytesTransferred)), this);
@@ -91,9 +102,9 @@ void BoostConnection::handleSocketRead(const boost::system::error_code& error, s
 	}
 }
 
-void BoostConnection::doDisconnect() {
-	if (socket_) {
-		socket_->close();
+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), this);
 	}
 }
 
diff --git a/Swiften/Network/BoostConnection.h b/Swiften/Network/BoostConnection.h
index f8fa514..85de926 100644
--- a/Swiften/Network/BoostConnection.h
+++ b/Swiften/Network/BoostConnection.h
@@ -1,5 +1,4 @@
-#ifndef SWIFTEN_BoostConnection_H
-#define SWIFTEN_BoostConnection_H
+#pragma once
 
 #include <boost/asio.hpp>
 
@@ -15,29 +14,27 @@ namespace boost {
 namespace Swift {
 	class BoostConnection : public Connection {
 		public:
-			BoostConnection(const String& domain);
+			BoostConnection(boost::asio::io_service* ioService);
 			~BoostConnection();
 
-			virtual void connect();
+			virtual void listen();
+			virtual void connect(const String& domain);
 			virtual void disconnect();
 			virtual void write(const ByteArray& data);
 
-		private:
-			void doConnect();
-			void doDisconnect();
+			boost::asio::ip::tcp::socket& getSocket() {
+				return socket_;
+			}
 
+		private:
 			void handleConnectFinished(const boost::system::error_code& error);
 			void handleSocketRead(const boost::system::error_code& error, size_t bytesTransferred);
+			void handleDataWritten(const boost::system::error_code& error);
 			void doRead();
-			void doWrite(const ByteArray&);
 
 		private:
-			boost::asio::io_service* ioService_;
-			boost::thread* thread_;
-			boost::asio::ip::tcp::socket* socket_;
+			boost::asio::ip::tcp::socket socket_;
 			std::vector<char> readBuffer_;
 			bool disconnecting_;
 	};
 }
-
-#endif
diff --git a/Swiften/Network/BoostConnectionFactory.cpp b/Swiften/Network/BoostConnectionFactory.cpp
index 9c542ac..a1bef15 100644
--- a/Swiften/Network/BoostConnectionFactory.cpp
+++ b/Swiften/Network/BoostConnectionFactory.cpp
@@ -2,11 +2,11 @@
 
 namespace Swift {
 
-BoostConnectionFactory::BoostConnectionFactory() {
+BoostConnectionFactory::BoostConnectionFactory(boost::asio::io_service* ioService) : ioService(ioService) {
 }
 
-BoostConnection* BoostConnectionFactory::createConnection(const String& domain) {
-	return new BoostConnection(domain);
+BoostConnection* BoostConnectionFactory::createConnection() {
+	return new BoostConnection(ioService);
 }
 
 }
diff --git a/Swiften/Network/BoostConnectionFactory.h b/Swiften/Network/BoostConnectionFactory.h
index b6a27b2..d15770d 100644
--- a/Swiften/Network/BoostConnectionFactory.h
+++ b/Swiften/Network/BoostConnectionFactory.h
@@ -1,6 +1,8 @@
 #ifndef SWIFTEN_BoostConnectionFactory_H
 #define SWIFTEN_BoostConnectionFactory_H
 
+#include <boost/asio.hpp>
+
 #include "Swiften/Network/ConnectionFactory.h"
 #include "Swiften/Network/BoostConnection.h"
 
@@ -9,9 +11,12 @@ namespace Swift {
 
 	class BoostConnectionFactory : public ConnectionFactory {
 		public:
-			BoostConnectionFactory();
+			BoostConnectionFactory(boost::asio::io_service*);
+
+			virtual BoostConnection* createConnection();
 
-			virtual BoostConnection* createConnection(const String& domain);
+		private:
+			boost::asio::io_service* ioService;
 	};
 }
 
diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h
index 6d05eee..16d5d7b 100644
--- a/Swiften/Network/Connection.h
+++ b/Swiften/Network/Connection.h
@@ -12,13 +12,15 @@ namespace Swift {
 			enum Error {
 				DomainNameResolveError,
 				ConnectionError,
-				ReadError
+				ReadError,
+				WriteError
 			};
 
-			Connection(const String& domain) : domain_(domain) {}
+			Connection() {}
 			virtual ~Connection() {}
 
-			virtual void connect() = 0;
+			virtual void listen() = 0;
+			virtual void connect(const String& domain) = 0;
 			virtual void disconnect() = 0;
 			virtual void write(const ByteArray& data) = 0;
 
@@ -26,14 +28,6 @@ namespace Swift {
 			boost::signal<void ()> onConnected;
 			boost::signal<void (Error)> onError;
 			boost::signal<void (const ByteArray&)> onDataRead;
-
-		protected:
-			const String& getDomain() const {
-				return domain_;
-			}
-
-		private:
-			String domain_;
 	};
 }
 
diff --git a/Swiften/Network/ConnectionFactory.h b/Swiften/Network/ConnectionFactory.h
index 2af9ebf..ef4eec9 100644
--- a/Swiften/Network/ConnectionFactory.h
+++ b/Swiften/Network/ConnectionFactory.h
@@ -2,14 +2,13 @@
 #define SWIFTEN_ConnectionFactory_H
 
 namespace Swift {
-	class String;
 	class Connection;
 
 	class ConnectionFactory {
 		public:
 			virtual ~ConnectionFactory();
 
-			virtual Connection* createConnection(const String& domain) = 0;
+			virtual Connection* createConnection() = 0;
 	};
 }
 
diff --git a/Swiften/Network/ConnectionServer.h b/Swiften/Network/ConnectionServer.h
index d376308..539367d 100644
--- a/Swiften/Network/ConnectionServer.h
+++ b/Swiften/Network/ConnectionServer.h
@@ -3,13 +3,13 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/signal.hpp>
 
-#include "Swiften/Network/IncomingConnection.h"
+#include "Swiften/Network/Connection.h"
 
 namespace Swift {
 	class ConnectionServer {
 		public:
 			virtual ~ConnectionServer();
 
-			boost::signal<void (boost::shared_ptr<IncomingConnection>)> onNewConnection;
+			boost::signal<void (boost::shared_ptr<Connection>)> onNewConnection;
 	};
 }
diff --git a/Swiften/Network/IncomingConnection.cpp b/Swiften/Network/IncomingConnection.cpp
deleted file mode 100644
index 669f68e..0000000
--- a/Swiften/Network/IncomingConnection.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "Swiften/Network/IncomingConnection.h"
-
-namespace Swift {
-
-IncomingConnection::~IncomingConnection() {
-}
-
-}
diff --git a/Swiften/Network/IncomingConnection.h b/Swiften/Network/IncomingConnection.h
deleted file mode 100644
index eaa2ad6..0000000
--- a/Swiften/Network/IncomingConnection.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-
-#include <boost/signal.hpp>
-
-#include "Swiften/Base/ByteArray.h"
-
-namespace Swift {
-	class IncomingConnection {
-		public:
-			virtual ~IncomingConnection();
-
-			virtual void write(const ByteArray& data) = 0;
-
-			//boost::signal<void (Error)> onError;
-			boost::signal<void (const ByteArray&)> onDataRead;
-	};
-}
diff --git a/Swiften/Network/Makefile.inc b/Swiften/Network/Makefile.inc
index 3e4ece6..d8c1ee9 100644
--- a/Swiften/Network/Makefile.inc
+++ b/Swiften/Network/Makefile.inc
@@ -5,7 +5,6 @@ SWIFTEN_SOURCES += \
 	Swiften/Network/BoostConnection.cpp \
 	Swiften/Network/BoostConnectionFactory.cpp \
 	Swiften/Network/ConnectionServer.cpp \
-	Swiften/Network/IncomingConnection.cpp \
 	Swiften/Network/BoostIOServiceThread.cpp \
 	Swiften/Network/Timer.cpp
 
diff --git a/Swiften/QA/ClientTest/Makefile.inc b/Swiften/QA/ClientTest/Makefile.inc
index 08a9b5b..16a87cf 100644
--- a/Swiften/QA/ClientTest/Makefile.inc
+++ b/Swiften/QA/ClientTest/Makefile.inc
@@ -7,6 +7,7 @@ CLIENTTEST_OBJECTS = \
 TEST_TARGETS += ClientTest
 
 CLEANFILES += $(CLIENTTEST_OBJECTS) $(CLIENTTEST_TARGET)
+DEPS += $(CLIENTTEST_SOURCES:.cpp=.dep)
 
 $(CLIENTTEST_TARGET): $(SWIFTEN_TARGET) $(CLIENTTEST_OBJECTS) $(BUNDLED_LIBS)
 	$(QUIET_LINK)$(CXX) -o $(CLIENTTEST_TARGET) $(CLIENTTEST_OBJECTS) $(LDFLAGS) $(CPPCLIENT_LDFLAGS) $(SWIFTEN_TARGET) $(BUNDLED_LIBS) $(LIBS)
diff --git a/Swiften/QA/NetworkTest/BoostConnectionTest.cpp b/Swiften/QA/NetworkTest/BoostConnectionTest.cpp
index 639097a..6090a97 100644
--- a/Swiften/QA/NetworkTest/BoostConnectionTest.cpp
+++ b/Swiften/QA/NetworkTest/BoostConnectionTest.cpp
@@ -4,6 +4,7 @@
 #include "Swiften/Base/String.h"
 #include "Swiften/Base/sleep.h"
 #include "Swiften/Network/BoostConnection.h"
+#include "Swiften/Network/BoostIOServiceThread.h"
 #include "Swiften/EventLoop/DummyEventLoop.h"
 
 using namespace Swift;
@@ -11,41 +12,44 @@ using namespace Swift;
 class BoostConnectionTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST_SUITE(BoostConnectionTest);
 		CPPUNIT_TEST(testDestructor);
-    CPPUNIT_TEST(testDestructor_PendingEvents);
+		CPPUNIT_TEST(testDestructor_PendingEvents);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
 		BoostConnectionTest() {}
 
-    void setUp() {
-      eventLoop_ = new DummyEventLoop();
-    }
+		void setUp() {
+			eventLoop_ = new DummyEventLoop();
+			boostIOServiceThread_ = new BoostIOServiceThread();
+		}
 
-    void tearDown() {
-      delete eventLoop_;
-    }
+		void tearDown() {
+			delete boostIOServiceThread_;
+			delete eventLoop_;
+		}
 
 		void testDestructor() {
-      {
-        std::string domain("el-tramo.be");
-        std::auto_ptr<BoostConnection> testling(new BoostConnection(domain));
-        testling->connect();
-      }
-    }
+			{
+				std::string domain("el-tramo.be");
+				std::auto_ptr<BoostConnection> testling(new BoostConnection(&boostIOServiceThread_->getIOService()));
+				testling->connect(domain);
+			}
+		}
 
 		void testDestructor_PendingEvents() {
-      {
-        std::auto_ptr<BoostConnection> testling(new BoostConnection("el-tramo.be"));
-        testling->connect();
-        while (!eventLoop_->hasEvents()) {
-          Swift::sleep(10);
-        }
-      }
-      eventLoop_->processEvents();
+			{
+				std::auto_ptr<BoostConnection> testling(new BoostConnection(&boostIOServiceThread_->getIOService()));
+				testling->connect("el-tramo.be");
+				while (!eventLoop_->hasEvents()) {
+					Swift::sleep(10);
+				}
+			}
+			eventLoop_->processEvents();
 		}
 
-  private:
-    DummyEventLoop* eventLoop_;
+	private:
+		BoostIOServiceThread* boostIOServiceThread_;
+		DummyEventLoop* eventLoop_;
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(BoostConnectionTest);
diff --git a/Swiften/QA/NetworkTest/Makefile.inc b/Swiften/QA/NetworkTest/Makefile.inc
index 055937b..5ac14c0 100644
--- a/Swiften/QA/NetworkTest/Makefile.inc
+++ b/Swiften/QA/NetworkTest/Makefile.inc
@@ -9,6 +9,7 @@ NETWORKTEST_OBJECTS = \
 TEST_TARGETS += NetworkTest
 
 CLEANFILES += $(NETWORKTEST_OBJECTS) $(NETWORKTEST_TARGET)
+DEPS += $(NETWORKTEST_SOURCES:.cpp=.dep)
 
 $(NETWORKTEST_TARGET): $(SWIFTEN_TARGET) $(CPPUNIT_TARGET) $(NETWORKTEST_OBJECTS) $(BUNDLED_LIBS)
 	$(QUIET_LINK)$(CXX) -o $(NETWORKTEST_TARGET) $(NETWORKTEST_OBJECTS) $(LDFLAGS) $(CPPNETWORK_LDFLAGS) $(SWIFTEN_TARGET) $(CPPUNIT_TARGET) $(BUNDLED_LIBS) $(LIBS)
diff --git a/Swiften/Server/IncomingConnection.cpp b/Swiften/Server/IncomingConnection.cpp
deleted file mode 100644
index e2317c8..0000000
--- a/Swiften/Server/IncomingConnection.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "Swiften/Server/IncomingConnection.h"
-
-namespace Swift {
-
-IncomingConnection::~IncomingConnection() {
-}
-
-}
diff --git a/Swiften/Server/IncomingConnection.h b/Swiften/Server/IncomingConnection.h
deleted file mode 100644
index 6ef64e8..0000000
--- a/Swiften/Server/IncomingConnection.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-
-#include <boost/signals.hpp>
-
-#include "Swiften/Base/ByteArray.h"
-#include "Swiften/Base/String.h"
-
-namespace Swift {
-	class IncomingConnection {
-		public:
-			enum Error {
-				ConnectionError,
-				ReadError
-			};
-
-			virtual ~IncomingConnection();
-
-			virtual void write(const ByteArray& data) = 0;
-
-		public:
-			boost::signal<void (Error)> onError;
-			boost::signal<void (const ByteArray&)> onDataRead;
-	};
-}
diff --git a/Swiften/Server/Makefile.inc b/Swiften/Server/Makefile.inc
index ae10bd2..ae38335 100644
--- a/Swiften/Server/Makefile.inc
+++ b/Swiften/Server/Makefile.inc
@@ -2,7 +2,6 @@ SWIFTEN_SOURCES += \
 	Swiften/Server/ServerSession.cpp \
 	Swiften/Server/ServerFromClientSession.cpp \
 	Swiften/Server/ServerStanzaRouter.cpp \
-	Swiften/Server/IncomingConnection.cpp \
 	Swiften/Server/UserRegistry.cpp \
 	Swiften/Server/SimpleUserRegistry.cpp
 
diff --git a/Swiften/Server/ServerFromClientSession.cpp b/Swiften/Server/ServerFromClientSession.cpp
index e6ba28a..612e667 100644
--- a/Swiften/Server/ServerFromClientSession.cpp
+++ b/Swiften/Server/ServerFromClientSession.cpp
@@ -3,9 +3,9 @@
 #include <boost/bind.hpp>
 
 #include "Swiften/Server/UserRegistry.h"
-#include "Swiften/Network/IncomingConnection.h"
+#include "Swiften/Network/Connection.h"
 #include "Swiften/StreamStack/StreamStack.h"
-#include "Swiften/StreamStack/IncomingConnectionLayer.h"
+#include "Swiften/StreamStack/ConnectionLayer.h"
 #include "Swiften/StreamStack/XMPPLayer.h"
 #include "Swiften/Elements/StreamFeatures.h"
 #include "Swiften/Elements/ResourceBind.h"
@@ -20,7 +20,7 @@ namespace Swift {
 
 ServerFromClientSession::ServerFromClientSession(
 		const String& id,
-		boost::shared_ptr<IncomingConnection> connection, 
+		boost::shared_ptr<Connection> connection, 
 		PayloadParserFactoryCollection* payloadParserFactories, 
 		PayloadSerializerCollection* payloadSerializers,
 		UserRegistry* userRegistry) : 
@@ -42,7 +42,7 @@ ServerFromClientSession::ServerFromClientSession(
 			boost::bind(boost::ref(onDataRead), _1));
 	xmppLayer_->onWriteData.connect(
 			boost::bind(boost::ref(onDataWritten), _1));
-	connectionLayer_ = new IncomingConnectionLayer(connection_.get());
+	connectionLayer_ = new ConnectionLayer(connection_.get());
 	streamStack_ = new StreamStack(xmppLayer_, connectionLayer_);
 }
 
diff --git a/Swiften/Server/ServerFromClientSession.h b/Swiften/Server/ServerFromClientSession.h
index 6c74093..9c37b3d 100644
--- a/Swiften/Server/ServerFromClientSession.h
+++ b/Swiften/Server/ServerFromClientSession.h
@@ -14,15 +14,15 @@ namespace Swift {
 	class StreamStack;
 	class UserRegistry;
 	class XMPPLayer;
-	class IncomingConnectionLayer;
-	class IncomingConnection;
+	class ConnectionLayer;
+	class Connection;
 	class ByteArray;
 
 	class ServerFromClientSession {
 		public:
 			ServerFromClientSession(
 					const String& id,
-					boost::shared_ptr<IncomingConnection> connection, 
+					boost::shared_ptr<Connection> connection, 
 					PayloadParserFactoryCollection* payloadParserFactories, 
 					PayloadSerializerCollection* payloadSerializers,
 					UserRegistry* userRegistry);
@@ -49,13 +49,13 @@ namespace Swift {
 
 		private:
 			String id_;
-			boost::shared_ptr<IncomingConnection> connection_;
+			boost::shared_ptr<Connection> connection_;
 			PayloadParserFactoryCollection* payloadParserFactories_;
 			PayloadSerializerCollection* payloadSerializers_;
 			UserRegistry* userRegistry_;
 			bool authenticated_;
 			bool initialized_;
-			IncomingConnectionLayer* connectionLayer_;
+			ConnectionLayer* connectionLayer_;
 			StreamStack* streamStack_;
 			XMPPLayer* xmppLayer_;
 			JID domain_;
diff --git a/Swiften/StreamStack/IncomingConnectionLayer.h b/Swiften/StreamStack/IncomingConnectionLayer.h
deleted file mode 100644
index c1a9eab..0000000
--- a/Swiften/StreamStack/IncomingConnectionLayer.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <boost/signal.hpp>
-
-#include "Swiften/StreamStack/LowLayer.h"
-#include "Swiften/Network/IncomingConnection.h"
-
-namespace Swift {
-	class IncomingConnectionLayer : public LowLayer {
-		public:
-			IncomingConnectionLayer(IncomingConnection* connection) : connection_(connection) {
-				connection_->onDataRead.connect(onDataRead);
-			}
-
-			void writeData(const ByteArray& data) {
-				connection_->write(data);
-			}
-
-		private:
-			IncomingConnection* connection_;
-	};
-}
-- 
cgit v0.10.2-6-g49f6