From 6ca206b0d0645e50a8a2c59ebd134f9c0f164b9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Mon, 13 Jul 2009 09:17:57 +0200
Subject: Server stream header support.


diff --git a/Limber/main.cpp b/Limber/main.cpp
index 6dad151..969a390 100644
--- a/Limber/main.cpp
+++ b/Limber/main.cpp
@@ -9,6 +9,7 @@
 #include <boost/thread.hpp>
 
 #include "Swiften/Base/ByteArray.h"
+#include "Swiften/Base/IDGenerator.h"
 #include "Swiften/EventLoop/MainEventLoop.h"
 #include "Swiften/EventLoop/SimpleEventLoop.h"
 #include "Swiften/Network/ConnectionServer.h"
@@ -19,6 +20,8 @@
 
 using namespace Swift;
 
+static const size_t BUFFER_SIZE = 4096;
+
 // A reference-counted non-modifiable buffer class.
 class SharedBuffer {
 	public:
@@ -58,17 +61,39 @@ class IncomingBoostConnection : public IncomingConnection, public boost::enable_
 						boost::asio::placeholders::error));
 		}
 
+		void start() {
+			read();
+		}
+
 	private:
-		IncomingBoostConnection(boost::asio::io_service& ioService) : socket_(ioService) {
+		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) {
-				std::cerr << "ERROR: Unable to write data to socket" << std::endl;
+			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 {
@@ -87,6 +112,7 @@ class BoostConnectionServer : public ConnectionServer {
 		void handleAccept(IncomingBoostConnection::pointer newConnection, const boost::system::error_code& error) {
 			if (!error) {
 				MainEventLoop::postEvent(boost::bind(boost::ref(onNewConnection), newConnection), this);
+				newConnection->start();
 				acceptNextConnection();
 			}
 		}
@@ -107,7 +133,7 @@ class Server {
 
 	private:
 		void handleNewConnection(boost::shared_ptr<IncomingConnection> c) {
-			ServerFromClientSession* session = new ServerFromClientSession(c, &payloadParserFactories_, &payloadSerializers_);
+			ServerFromClientSession* session = new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_);
 			serverFromClientSessions_.push_back(session);
 			session->onSessionFinished.connect(boost::bind(&Server::handleSessionFinished, this, session));
 		}
@@ -118,6 +144,7 @@ class Server {
 		}
 
 	private:
+		IDGenerator idGenerator_;
 		BoostIOServiceThread boostIOServiceThread_;
 		BoostConnectionServer* serverFromClientConnectionServer_;
 		std::vector<ServerFromClientSession*> serverFromClientSessions_;
diff --git a/Swiften/Client/UnitTest/SessionTest.cpp b/Swiften/Client/UnitTest/SessionTest.cpp
index f4c40da..c2b99db 100644
--- a/Swiften/Client/UnitTest/SessionTest.cpp
+++ b/Swiften/Client/UnitTest/SessionTest.cpp
@@ -509,7 +509,8 @@ class SessionTest : public CppUnit::TestFixture {
 				parser_ = new XMPPParser(this, &payloadParserFactories_);
 			}
 
-			void handleStreamStart() {
+			void handleStreamStart(const String&, const String& to, const String&) {
+				CPPUNIT_ASSERT_EQUAL(getDomain(), to);
 				handleEvent(Event::StreamStartEvent);
 			}
 
@@ -543,7 +544,7 @@ class SessionTest : public CppUnit::TestFixture {
 			String serializeEvent(const Event& event) {
 				switch (event.type) {
 					case Event::StreamStartEvent: 
-						return serializer_.serializeHeader(getDomain());
+						return serializer_.serializeHeader("", getDomain(), "");
 					case Event::ElementEvent:
 						return serializer_.serializeElement(event.element);
 					case Event::StreamEndEvent:
diff --git a/Swiften/Parser/UnitTest/XMPPParserTest.cpp b/Swiften/Parser/UnitTest/XMPPParserTest.cpp
index 787828c..a8b805e 100644
--- a/Swiften/Parser/UnitTest/XMPPParserTest.cpp
+++ b/Swiften/Parser/UnitTest/XMPPParserTest.cpp
@@ -19,6 +19,7 @@ class XMPPParserTest : public CppUnit::TestFixture
 {
 		CPPUNIT_TEST_SUITE(XMPPParserTest);
 		CPPUNIT_TEST(testParse_SimpleSession);
+		CPPUNIT_TEST(testParse_SimpleClientFromServerSession);
 		CPPUNIT_TEST(testParse_Presence);
 		CPPUNIT_TEST(testParse_IQ);
 		CPPUNIT_TEST(testParse_Message);
@@ -43,12 +44,26 @@ class XMPPParserTest : public CppUnit::TestFixture
 
 			CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(client_.events.size()));
 			CPPUNIT_ASSERT_EQUAL(Client::StreamStart, client_.events[0].type);
+			CPPUNIT_ASSERT_EQUAL(String("example.com"), client_.events[0].to); 
 			CPPUNIT_ASSERT_EQUAL(Client::ElementEvent, client_.events[1].type);
 			CPPUNIT_ASSERT_EQUAL(Client::ElementEvent, client_.events[2].type);
 			CPPUNIT_ASSERT_EQUAL(Client::ElementEvent, client_.events[3].type);
 			CPPUNIT_ASSERT_EQUAL(Client::StreamEnd, client_.events[4].type);
 		}
 
+		void testParse_SimpleClientFromServerSession() {
+			XMPPParser testling(&client_, &factories_);
+
+			CPPUNIT_ASSERT(testling.parse("<?xml version='1.0'?>"));
+			CPPUNIT_ASSERT(testling.parse("<stream:stream from='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='aeab'>"));
+
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(client_.events.size()));
+			CPPUNIT_ASSERT_EQUAL(Client::StreamStart, client_.events[0].type);
+			CPPUNIT_ASSERT_EQUAL(String("example.com"), client_.events[0].from); 
+			CPPUNIT_ASSERT_EQUAL(String("aeab"), client_.events[0].id); 
+		}
+
+
 		void testParse_Presence() {
 			XMPPParser testling(&client_, &factories_);
 
@@ -137,17 +152,21 @@ class XMPPParserTest : public CppUnit::TestFixture
 				struct Event {
 					Event(Type type, boost::shared_ptr<Element> element) 
 						: type(type), element(element) {}
+					Event(Type type, const String& from, const String& to, const String& id) : type(type), from(from), to(to), id(id) {}
 
 					Event(Type type) : type(type) {}
 
 					Type type;
+					String from;
+					String to;
+					String id;
 					boost::shared_ptr<Element> element;
 				};
 
 				Client() {}
 
-				void handleStreamStart() {
-					events.push_back(Event(StreamStart));
+				void handleStreamStart(const String& from, const String& to, const String& id) {
+					events.push_back(Event(StreamStart, from, to, id));
 				}
 
 				void handleElement(boost::shared_ptr<Element> element) {
diff --git a/Swiften/Parser/XMPPParser.cpp b/Swiften/Parser/XMPPParser.cpp
index 59cfce7..0f04cca 100644
--- a/Swiften/Parser/XMPPParser.cpp
+++ b/Swiften/Parser/XMPPParser.cpp
@@ -54,7 +54,7 @@ bool XMPPParser::parse(const String& data) {
 void XMPPParser::handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) {
 	if (!inStream()) {
 		if (element == "stream" && ns == "http://etherx.jabber.org/streams") {
-			client_->handleStreamStart(attributes.getAttribute("to"));
+			client_->handleStreamStart(attributes.getAttribute("from"), attributes.getAttribute("to"), attributes.getAttribute("id"));
 		}
 		else {
 			parseErrorOccurred_ = true;
diff --git a/Swiften/Parser/XMPPParserClient.h b/Swiften/Parser/XMPPParserClient.h
index d19c7d0..fb81df8 100644
--- a/Swiften/Parser/XMPPParserClient.h
+++ b/Swiften/Parser/XMPPParserClient.h
@@ -12,7 +12,7 @@ namespace Swift {
 		public:
 			virtual ~XMPPParserClient();
 
-			virtual void handleStreamStart(const String& header) = 0;
+			virtual void handleStreamStart(const String& from, const String& to, const String& id) = 0;
 			virtual void handleElement(boost::shared_ptr<Element>) = 0;
 			virtual void handleStreamEnd() = 0;
 	};
diff --git a/Swiften/Serializer/XMPPSerializer.cpp b/Swiften/Serializer/XMPPSerializer.cpp
index c43f9db..6139586 100644
--- a/Swiften/Serializer/XMPPSerializer.cpp
+++ b/Swiften/Serializer/XMPPSerializer.cpp
@@ -34,8 +34,19 @@ XMPPSerializer::XMPPSerializer(PayloadSerializerCollection* payloadSerializers)
 	serializers_.push_back(boost::shared_ptr<ElementSerializer>(new StreamFeaturesSerializer()));
 }
 
-String XMPPSerializer::serializeHeader(const String& domain) const {
-	return "<?xml version='1.0'?><stream:stream to='" + domain + "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' >";
+String XMPPSerializer::serializeHeader(const String& from, const String& to, const String& id) const {
+	String result = "<?xml version=\"1.0\"?><stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\"";
+	if (!from.isEmpty()) {
+		result += " from=\"" + from + "\"";
+	}
+	if (!to.isEmpty()) {
+		result += " to=\"" + to + "\"";
+	}
+	if (!id.isEmpty()) {
+		result += " id=\"" + id + "\"";
+	}
+	result += ">";
+	return result;
 }
 
 String XMPPSerializer::serializeElement(boost::shared_ptr<Element> element) const {
diff --git a/Swiften/Serializer/XMPPSerializer.h b/Swiften/Serializer/XMPPSerializer.h
index 1fc8b9d..f77e14b 100644
--- a/Swiften/Serializer/XMPPSerializer.h
+++ b/Swiften/Serializer/XMPPSerializer.h
@@ -16,7 +16,7 @@ namespace Swift {
 		public:
 			XMPPSerializer(PayloadSerializerCollection*);
 
-			String serializeHeader(const String& domain) const;
+			String serializeHeader(const String& from, const String& to, const String& id = "") const;
 			String serializeElement(boost::shared_ptr<Element> stanza) const;
 			String serializeFooter() const;
 		
diff --git a/Swiften/Server/ServerFromClientSession.cpp b/Swiften/Server/ServerFromClientSession.cpp
index e85021e..be8b601 100644
--- a/Swiften/Server/ServerFromClientSession.cpp
+++ b/Swiften/Server/ServerFromClientSession.cpp
@@ -10,15 +10,17 @@
 namespace Swift {
 
 ServerFromClientSession::ServerFromClientSession(
+		const String& id,
 		boost::shared_ptr<IncomingConnection> connection, 
 		PayloadParserFactoryCollection* payloadParserFactories, 
 		PayloadSerializerCollection* payloadSerializers) : 
+			id_(id),
 			connection_(connection), 
 			payloadParserFactories_(payloadParserFactories), 
 			payloadSerializers_(payloadSerializers) {
 	xmppLayer_ = new XMPPLayer(payloadParserFactories_, payloadSerializers_);
 	xmppLayer_->onStreamStart.connect(
-			boost::bind(&ServerFromClientSession::handleStreamStart, this, _1));
+			boost::bind(&ServerFromClientSession::handleStreamStart, this, _2));
 	xmppLayer_->onElement.connect(
 			boost::bind(&ServerFromClientSession::handleElement, this, _1));
 	//xmppLayer_->onError.connect(
@@ -41,7 +43,8 @@ void ServerFromClientSession::handleElement(boost::shared_ptr<Element>) {
 }
 
 void ServerFromClientSession::handleStreamStart(const String& domain) {
-	xmppLayer_->writeHeader(domain);
+	domain_ = domain;
+	xmppLayer_->writeHeader(domain_, id_);
 }
 
 }
diff --git a/Swiften/Server/ServerFromClientSession.h b/Swiften/Server/ServerFromClientSession.h
index cedfcdb..3413a03 100644
--- a/Swiften/Server/ServerFromClientSession.h
+++ b/Swiften/Server/ServerFromClientSession.h
@@ -3,6 +3,8 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/signal.hpp>
 
+#include "Swiften/Base/String.h"
+
 namespace Swift {
 	class Element;
 	class PayloadParserFactoryCollection;
@@ -12,11 +14,11 @@ namespace Swift {
 	class IncomingConnectionLayer;
 	class IncomingConnection;
 	class ByteArray;
-	class String;
 
 	class ServerFromClientSession {
 		public:
 			ServerFromClientSession(
+					const String& id,
 					boost::shared_ptr<IncomingConnection> connection, 
 					PayloadParserFactoryCollection* payloadParserFactories, 
 					PayloadSerializerCollection* payloadSerializers);
@@ -31,11 +33,13 @@ namespace Swift {
 			void handleStreamStart(const String& domain);
 
 		private:
+			String id_;
 			boost::shared_ptr<IncomingConnection> connection_;
 			PayloadParserFactoryCollection* payloadParserFactories_;
 			PayloadSerializerCollection* payloadSerializers_;
 			IncomingConnectionLayer* connectionLayer_;
 			StreamStack* streamStack_;
 			XMPPLayer* xmppLayer_;
+			String domain_;
 	};
 }
diff --git a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp
index 2150f4d..f60c370 100644
--- a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp
+++ b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp
@@ -48,9 +48,9 @@ class XMPPLayerTest : public CppUnit::TestFixture
 			testling_->onElement.connect(boost::bind(&XMPPLayerTest::handleElement, this, _1));
 			testling_->onError.connect(boost::bind(&XMPPLayerTest::handleError, this));
 
-			testling_->parseData("<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' >");
+			testling_->parseData("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" >");
 			testling_->resetParser();
-			testling_->parseData("<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' >");
+			testling_->parseData("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" >");
 			testling_->parseData("<presence/>");
 
 			CPPUNIT_ASSERT_EQUAL(1, elementsReceived_);
@@ -59,8 +59,8 @@ class XMPPLayerTest : public CppUnit::TestFixture
 
 		void testResetParser_FromSlot() {
 			testling_->onElement.connect(boost::bind(&XMPPLayerTest::handleElementAndReset, this, _1));
-			testling_->parseData("<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' ><presence/>");
-			testling_->parseData("<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' ><presence/>");
+			testling_->parseData("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" ><presence/>");
+			testling_->parseData("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" ><presence/>");
 
 			CPPUNIT_ASSERT_EQUAL(2, elementsReceived_);
 			CPPUNIT_ASSERT_EQUAL(0, errorReceived_);
@@ -70,7 +70,7 @@ class XMPPLayerTest : public CppUnit::TestFixture
 			testling_->onWriteData.connect(boost::bind(&XMPPLayerTest::handleWriteData, this, _1));
 			testling_->writeHeader("example.com");
 
-			CPPUNIT_ASSERT_EQUAL(String("<?xml version='1.0'?><stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' >"), dataReceived_);
+			CPPUNIT_ASSERT_EQUAL(String("<?xml version=\"1.0\"?><stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\" to=\"example.com\">"), dataReceived_);
 		}
 
 		void testWriteElement() {
diff --git a/Swiften/StreamStack/XMPPLayer.cpp b/Swiften/StreamStack/XMPPLayer.cpp
index 464d4b0..73d763a 100644
--- a/Swiften/StreamStack/XMPPLayer.cpp
+++ b/Swiften/StreamStack/XMPPLayer.cpp
@@ -20,8 +20,12 @@ XMPPLayer::~XMPPLayer() {
 	delete xmppParser_;
 }
 
-void XMPPLayer::writeHeader(const String& domain) {
-	onWriteData(ByteArray(xmppSerializer_->serializeHeader(domain)));
+void XMPPLayer::writeHeader(const String& to) {
+	onWriteData(ByteArray(xmppSerializer_->serializeHeader("", to)));
+}
+
+void XMPPLayer::writeHeader(const String& from, const String& id) {
+	onWriteData(ByteArray(xmppSerializer_->serializeHeader(from, "", id)));
 }
 
 void XMPPLayer::writeFooter() {
@@ -56,8 +60,8 @@ void XMPPLayer::doResetParser() {
 	resetParserAfterParse_ = false;
 }
 
-void XMPPLayer::handleStreamStart(const String& domain) {
-	onStreamStart(domain);
+void XMPPLayer::handleStreamStart(const String& from, const String& to, const String& id) {
+	onStreamStart(from, to, id);
 }
 
 void XMPPLayer::handleElement(boost::shared_ptr<Element> stanza) {
diff --git a/Swiften/StreamStack/XMPPLayer.h b/Swiften/StreamStack/XMPPLayer.h
index e064d94..7437112 100644
--- a/Swiften/StreamStack/XMPPLayer.h
+++ b/Swiften/StreamStack/XMPPLayer.h
@@ -22,7 +22,8 @@ namespace Swift {
 					PayloadSerializerCollection* payloadSerializers);
 			~XMPPLayer();
 
-			void writeHeader(const String& domain);
+			void writeHeader(const String& from, const String& id);
+			void writeHeader(const String& to);
 			void writeFooter();
 			void writeElement(boost::shared_ptr<Element>);
 			void writeData(const String& data);
@@ -31,14 +32,14 @@ namespace Swift {
 			void resetParser();
 
 		public:
-			boost::signal<void (const String& domain)> onStreamStart;
+			boost::signal<void (const String& /* from */, const String& /* to */ , const String& /* id */)> onStreamStart;
 			boost::signal<void (boost::shared_ptr<Element>)> onElement;
 			boost::signal<void (const ByteArray&)> onWriteData;
 			boost::signal<void (const ByteArray&)> onDataRead;
 			boost::signal<void ()> onError;
 
 		private:
-			void handleStreamStart(const String&);
+			void handleStreamStart(const String&, const String&, const String&);
 			void handleElement(boost::shared_ptr<Element>);
 			void handleStreamEnd();
 
-- 
cgit v0.10.2-6-g49f6