From 4457bc810a326de8d7895b3f2ff36ade5f1ae1a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 18 Jul 2009 21:04:32 +0200
Subject: Implement incoming linklocal connections.


diff --git a/Nim/main.cpp b/Nim/main.cpp
index 8166534..15c41c7 100644
--- a/Nim/main.cpp
+++ b/Nim/main.cpp
@@ -2,6 +2,7 @@
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 
+#include "Swiften/Network/BoostConnectionFactory.h"
 #include "Swiften/Elements/IQ.h"
 #include "Swiften/Elements/Presence.h"
 #include "Swiften/Elements/RosterPayload.h"
@@ -17,6 +18,9 @@
 #include "Swiften/Elements/Stanza.h"
 #include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
 #include "Swiften/LinkLocal/LinkLocalRoster.h"
+#include "Swiften/LinkLocal/LinkLocalSession.h"
+#include "Swiften/LinkLocal/OutgoingLinkLocalSession.h"
+#include "Swiften/LinkLocal/IncomingLinkLocalSession.h"
 #include "Swiften/LinkLocal/DNSSDService.h"
 #include "Swiften/LinkLocal/AppleDNSSDService.h"
 #include "Swiften/Network/ConnectionServer.h"
@@ -42,7 +46,7 @@ class DummyUserRegistry : public UserRegistry {
 
 class Server {
 	public:
-		Server(int clientConnectionPort, int linkLocalConnectionPort) : dnsSDServiceRegistered_(false), rosterRequested_(false), clientConnectionPort_(clientConnectionPort), linkLocalConnectionPort_(linkLocalConnectionPort) {
+		Server(int clientConnectionPort, int linkLocalConnectionPort) : boostConnectionFactory_(&boostIOServiceThread_.getIOService()), dnsSDServiceRegistered_(false), rosterRequested_(false), clientConnectionPort_(clientConnectionPort), linkLocalConnectionPort_(linkLocalConnectionPort) {
 			serverFromClientConnectionServer_ = boost::shared_ptr<BoostConnectionServer>(new BoostConnectionServer(clientConnectionPort, &boostIOServiceThread_.getIOService()));
 			serverFromClientConnectionServer_->onNewConnection.connect(boost::bind(&Server::handleNewClientConnection, this, _1));
 			serverFromClientConnectionServer_->start();
@@ -53,7 +57,6 @@ class Server {
 
 			dnsSDService_ = boost::shared_ptr<AppleDNSSDService>(new AppleDNSSDService());
 			dnsSDService_->onServiceRegistered.connect(boost::bind(&Server::handleServiceRegistered, this, _1));
-
 			linkLocalRoster_ = boost::shared_ptr<LinkLocalRoster>(new LinkLocalRoster(dnsSDService_));
 			linkLocalRoster_->onRosterChanged.connect(boost::bind(&Server::handleRosterChanged, this, _1));
 			linkLocalRoster_->onPresenceChanged.connect(boost::bind(&Server::handlePresenceChanged, this, _1));
@@ -71,20 +74,40 @@ class Server {
 			serverFromClientSession_->start();
 		}
 
-		void handleNewLinkLocalConnection(boost::shared_ptr<Connection>) {
-			std::cout << "Incoming link local connection" << std::endl;
+		void handleNewLinkLocalConnection(boost::shared_ptr<Connection> connection) {
+			boost::shared_ptr<IncomingLinkLocalSession> session(
+					new IncomingLinkLocalSession(
+						selfJID_, connection, 
+						&payloadParserFactories_, &payloadSerializers_));
+			registerLinkLocalSession(session);
 		}
 		
 		void handleServiceRegistered(const DNSSDService::Service& service) {
 			std::cout << "Service registered " << service.name << " " << service.type << " " << service.domain << std::endl;
+			selfJID_ = JID(service.name);
 		}
 
 		void handleSessionFinished(boost::shared_ptr<ServerFromClientSession>) {
 			serverFromClientSession_.reset();
 			unregisterService();
+			selfJID_ = JID();
 			rosterRequested_ = false;
 		}
 
+		void handleLinkLocalSessionFinished(boost::shared_ptr<LinkLocalSession> session) {
+			std::cout << "Link local session from " << session->getRemoteJID() << " ended" << std::endl;
+			linkLocalSessions_.erase(std::remove(linkLocalSessions_.begin(), linkLocalSessions_.end(), session), linkLocalSessions_.end());
+		}
+
+		void handleLinkLocalStanzaReceived(boost::shared_ptr<Stanza> stanza, boost::shared_ptr<LinkLocalSession> session) {
+			JID fromJID = session->getRemoteJID();
+			if (!linkLocalRoster_->hasItem(fromJID)) {
+				return; // TODO: Queue
+			}
+			stanza->setFrom(fromJID);
+			serverFromClientSession_->sendStanza(stanza);
+		}
+
 		void unregisterService() {
 			if (dnsSDServiceRegistered_) {
 				dnsSDServiceRegistered_ = false;
@@ -141,6 +164,47 @@ class Server {
 					}
 				}
 			}
+			else {
+				JID toJID = stanza->getTo();
+				boost::shared_ptr<LinkLocalSession> outgoingSession = 
+						getLinkLocalSessionForJID(toJID);
+				if (outgoingSession) {
+					outgoingSession->sendStanza(stanza);
+				}
+				else {
+					if (linkLocalRoster_->hasItem(toJID)) {
+						boost::shared_ptr<OutgoingLinkLocalSession> outgoingSession(
+								new OutgoingLinkLocalSession(
+									selfJID_, toJID, linkLocalRoster_->getHostname(toJID),
+									dnsSDService_, 
+									&payloadParserFactories_, &payloadSerializers_,
+									&boostConnectionFactory_));
+						registerLinkLocalSession(outgoingSession);
+						outgoingSession->sendStanza(stanza);
+					}
+					else {
+						session->sendStanza(IQ::createError(
+								stanza->getFrom(), stanza->getID(), 
+								Error::RecipientUnavailable, Error::Wait));
+					}
+				}
+			}
+		}
+
+		void registerLinkLocalSession(boost::shared_ptr<LinkLocalSession> session) {
+			session->onSessionFinished.connect(boost::bind(&Server::handleLinkLocalSessionFinished, this, session));
+			session->onStanzaReceived.connect(boost::bind(&Server::handleLinkLocalStanzaReceived, this, _1, session));
+			linkLocalSessions_.push_back(session);
+			session->start();
+		}
+
+		boost::shared_ptr<LinkLocalSession> getLinkLocalSessionForJID(const JID& jid) {
+			foreach(const boost::shared_ptr<LinkLocalSession> session, linkLocalSessions_) {
+				if (session->getRemoteJID() == jid) {
+					return session;
+				}
+			}
+			return boost::shared_ptr<LinkLocalSession>();
 		}
 
 		void handleRosterChanged(boost::shared_ptr<RosterPayload> roster) {
@@ -186,18 +250,22 @@ class Server {
 	private:
 		IDGenerator idGenerator_;
 		BoostIOServiceThread boostIOServiceThread_;
+		BoostConnectionFactory boostConnectionFactory_;
 		DummyUserRegistry userRegistry_;
 		boost::shared_ptr<AppleDNSSDService> dnsSDService_;
 		boost::shared_ptr<LinkLocalRoster> linkLocalRoster_;
 		boost::shared_ptr<BoostConnectionServer> serverFromClientConnectionServer_;
 		boost::shared_ptr<ServerFromClientSession> serverFromClientSession_;
 		boost::shared_ptr<BoostConnectionServer> serverFromNetworkConnectionServer_;
+		std::vector< boost::shared_ptr<LinkLocalSession> > linkLocalSessions_;
+		std::vector< boost::shared_ptr<Stanza> > queuedOutgoingStanzas_;
 		FullPayloadParserFactoryCollection payloadParserFactories_;
 		FullPayloadSerializerCollection payloadSerializers_;
 		bool dnsSDServiceRegistered_;
 		bool rosterRequested_;
 		int clientConnectionPort_;
 		int linkLocalConnectionPort_;
+		JID selfJID_;
 };
 
 int main() {
diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h
index 0da2e39..247a8a3 100644
--- a/Swiften/Base/String.h
+++ b/Swiften/Base/String.h
@@ -87,6 +87,11 @@ namespace Swift {
 				return *this;
 			}
 
+			String& operator=(const String& o) {
+				data_ = o.data_;
+				return *this;
+			}
+
 			friend bool operator>(const String& a, const String& b) {
 				return a.data_ > b.data_;
 			}
diff --git a/Swiften/Client/Session.cpp b/Swiften/Client/Session.cpp
index 2f0e076..6c2a873 100644
--- a/Swiften/Client/Session.cpp
+++ b/Swiften/Client/Session.cpp
@@ -3,6 +3,7 @@
 #include <boost/bind.hpp>
 
 #include "Swiften/Network/ConnectionFactory.h"
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/StreamStack/StreamStack.h"
 #include "Swiften/StreamStack/ConnectionLayer.h"
 #include "Swiften/StreamStack/XMPPLayer.h"
@@ -61,7 +62,9 @@ void Session::handleConnected() {
 }
 
 void Session::sendStreamHeader() {
-	xmppLayer_->writeHeader(jid_.getDomain());
+	ProtocolHeader header;
+	header.setTo(jid_.getDomain());
+	xmppLayer_->writeHeader(header);
 }
 
 void Session::initializeStreamStack() {
diff --git a/Swiften/Client/UnitTest/SessionTest.cpp b/Swiften/Client/UnitTest/SessionTest.cpp
index 45c0996..a11ddde 100644
--- a/Swiften/Client/UnitTest/SessionTest.cpp
+++ b/Swiften/Client/UnitTest/SessionTest.cpp
@@ -11,6 +11,7 @@
 #include "Swiften/StreamStack/TLSLayer.h"
 #include "Swiften/StreamStack/StreamStack.h"
 #include "Swiften/StreamStack/WhitespacePingLayer.h"
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/Elements/StreamFeatures.h"
 #include "Swiften/Elements/Element.h"
 #include "Swiften/Elements/Error.h"
@@ -486,6 +487,7 @@ class SessionTest : public CppUnit::TestFixture {
 				assert(false);
 			}
 
+			void connect(const HostAddressPort&) { assert(false); }
 			void connect(const String& domain) {
 				if (fail_) {
 					MainEventLoop::postEvent(boost::bind(boost::ref(onDisconnected), Connection::ConnectionError));
@@ -513,8 +515,8 @@ class SessionTest : public CppUnit::TestFixture {
 				parser_ = new XMPPParser(this, &payloadParserFactories_);
 			}
 
-			void handleStreamStart(const String&, const String& to, const String&) {
-				CPPUNIT_ASSERT_EQUAL(domain_, to);
+			void handleStreamStart(const ProtocolHeader& header) {
+				CPPUNIT_ASSERT_EQUAL(domain_, header.getTo());
 				handleEvent(Event::StreamStartEvent);
 			}
 
@@ -548,7 +550,11 @@ class SessionTest : public CppUnit::TestFixture {
 			String serializeEvent(const Event& event) {
 				switch (event.type) {
 					case Event::StreamStartEvent: 
-						return serializer_.serializeHeader("", domain_, "");
+						{
+							ProtocolHeader header;
+							header.setTo(domain_);
+							return serializer_.serializeHeader(header);
+						}
 					case Event::ElementEvent:
 						return serializer_.serializeElement(event.element);
 					case Event::StreamEndEvent:
diff --git a/Swiften/Elements/ProtocolHeader.h b/Swiften/Elements/ProtocolHeader.h
new file mode 100644
index 0000000..da64811
--- /dev/null
+++ b/Swiften/Elements/ProtocolHeader.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "Swiften/Base/String.h"
+
+namespace Swift {
+	class ProtocolHeader {
+		public:
+			ProtocolHeader() : version("1.0") {}
+
+			const String& getTo() const { return to; }
+			void setTo(const String& a)  { 
+				to = a;
+			}
+
+			const String& getFrom() const { return from; }
+			void setFrom(const String& a)  { 
+				from = a;
+			}
+
+			const String& getVersion() const { return version; }
+			void setVersion(const String& a)  { 
+				version = a;
+			}
+
+			const String& getID() const { return id; }
+			void setID(const String& a)  { 
+				id = a;
+			}
+	
+		private:
+			String to;
+			String from;
+			String id;
+			String version;
+	};
+}
diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp
index d4befd1..521c584 100644
--- a/Swiften/LinkLocal/AppleDNSSDService.cpp
+++ b/Swiften/LinkLocal/AppleDNSSDService.cpp
@@ -98,7 +98,6 @@ void AppleDNSSDService::stopResolvingService(const Service& service) {
 
 void AppleDNSSDService::resolveHostname(const String& hostname, int interfaceIndex) {
 	boost::lock_guard<boost::mutex> lock(sdRefsMutex);
-	std::cout << "Resolve " << hostname << std::endl;
 
 	DNSServiceRef hostnameResolveSDRef;
 	DNSServiceErrorType result = DNSServiceGetAddrInfo(&hostnameResolveSDRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4, hostname.getUTF8Data(), &AppleDNSSDService::handleHostnameResolvedGlobal, this);
@@ -159,7 +158,6 @@ void AppleDNSSDService::doStart() {
 
 			// Hostname resolving
 			for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) {
-				std::cout << "Adding ostname resolve " << std::endl;
 				int hostnameResolveSocket = DNSServiceRefSockFD(*i);
 				maxSocket = std::max(maxSocket, hostnameResolveSocket);
 				FD_SET(hostnameResolveSocket, &fdSet);
@@ -193,7 +191,6 @@ void AppleDNSSDService::doStart() {
 			for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) {
 				if (FD_ISSET(DNSServiceRefSockFD(*i), &fdSet)) {
 					DNSServiceProcessResult(*i);
-					std::cout << "Removing hostnameResolve" << std::endl;
 					hostnameResolveSDRefs.erase(std::remove(hostnameResolveSDRefs.begin(), hostnameResolveSDRefs.end(), *i), hostnameResolveSDRefs.end());
 					DNSServiceRefDeallocate(*i);
 					break; // Stop the loop, because we removed an element
@@ -211,7 +208,6 @@ void AppleDNSSDService::doStart() {
 		resolveSDRefs.clear();
 
 		for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) {
-			std::cout << "Removing hostnameResolve" << std::endl;
 			DNSServiceRefDeallocate(*i);
 		}
 		hostnameResolveSDRefs.clear();
diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp
new file mode 100644
index 0000000..db4b007
--- /dev/null
+++ b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp
@@ -0,0 +1,69 @@
+#include "Swiften/LinkLocal/IncomingLinkLocalSession.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/Elements/ProtocolHeader.h"
+#include "Swiften/Network/Connection.h"
+#include "Swiften/StreamStack/StreamStack.h"
+#include "Swiften/StreamStack/ConnectionLayer.h"
+#include "Swiften/StreamStack/XMPPLayer.h"
+#include "Swiften/Elements/StreamFeatures.h"
+#include "Swiften/Elements/IQ.h"
+#include "Swiften/SASL/PLAINMessage.h"
+
+namespace Swift {
+
+IncomingLinkLocalSession::IncomingLinkLocalSession(
+		const JID& localJID,
+		boost::shared_ptr<Connection> connection, 
+		PayloadParserFactoryCollection* payloadParserFactories, 
+		PayloadSerializerCollection* payloadSerializers) :
+			LinkLocalSession(
+				localJID, 
+				connection, 
+				payloadParserFactories, 
+				payloadSerializers) {
+}
+
+void IncomingLinkLocalSession::start() {
+	initializeStreamStack();
+}
+
+void IncomingLinkLocalSession::handleStreamStart(const ProtocolHeader& incomingHeader) {
+	remoteJID_ = JID(incomingHeader.getFrom());
+	if (!remoteJID_.isValid()) {
+		finishSession();
+		return;
+	}
+	ProtocolHeader header;
+	header.setFrom(getLocalJID());
+	getXMPPLayer()->writeHeader(header);
+
+	if (incomingHeader.getVersion() == "1.0") {
+		getXMPPLayer()->writeElement(boost::shared_ptr<StreamFeatures>(new StreamFeatures()));
+	}
+	else {
+		setInitialized();
+	}
+}
+
+void IncomingLinkLocalSession::handleElement(boost::shared_ptr<Element> element) {
+	boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element);
+	// If we get our first stanza before streamfeatures, our session is implicitly
+	// initialized
+	if (stanza && !isInitialized()) {
+		setInitialized();
+	}
+	
+	if (isInitialized()) {
+		if (stanza) {
+			onStanzaReceived(stanza);
+		}
+		else {
+			std::cerr << "Received unexpected element" << std::endl;
+		}
+	}
+}
+
+
+}
diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.h b/Swiften/LinkLocal/IncomingLinkLocalSession.h
new file mode 100644
index 0000000..d4fa91a
--- /dev/null
+++ b/Swiften/LinkLocal/IncomingLinkLocalSession.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/signal.hpp>
+
+#include "Swiften/LinkLocal/LinkLocalSession.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Network/Connection.h"
+
+namespace Swift {
+	class ProtocolHeader;
+	class String;
+	class Element;
+	class PayloadParserFactoryCollection;
+	class PayloadSerializerCollection;
+
+	class IncomingLinkLocalSession : public LinkLocalSession {
+		public:
+			IncomingLinkLocalSession(
+					const JID& localJID,
+					boost::shared_ptr<Connection> connection, 
+					PayloadParserFactoryCollection* payloadParserFactories, 
+					PayloadSerializerCollection* payloadSerializers);
+
+			const JID& getRemoteJID() const {
+				return remoteJID_;
+			}
+
+			void start();
+
+		private:
+			void handleElement(boost::shared_ptr<Element>);
+			void handleStreamStart(const ProtocolHeader&);
+
+		private:
+			bool initialized_;
+			JID remoteJID_;
+	};
+}
diff --git a/Swiften/LinkLocal/LinkLocalRoster.cpp b/Swiften/LinkLocal/LinkLocalRoster.cpp
index 89bfa55..6809377 100644
--- a/Swiften/LinkLocal/LinkLocalRoster.cpp
+++ b/Swiften/LinkLocal/LinkLocalRoster.cpp
@@ -77,6 +77,7 @@ void LinkLocalRoster::handleServiceAdded(const DNSSDService::Service& service) {
 	if (selfService && *selfService == service) {
 		return;
 	}
+	std::cout << "Service added: " << service.name << std::endl;
 	dnsSDService->startResolvingService(service);
 }
 
@@ -93,7 +94,7 @@ void LinkLocalRoster::handleServiceRemoved(const DNSSDService::Service& service)
 
 void LinkLocalRoster::handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result) {
 	services.insert(std::make_pair(service, result));
-	dnsSDService->resolveHostname(result.host);
+	std::cout << "Service resolved: " << service.name << std::endl;
 
 	boost::shared_ptr<RosterPayload> roster(new RosterPayload());
 	roster->addItem(getRosterItem(service, result));
@@ -109,4 +110,22 @@ void LinkLocalRoster::handleStopped(bool error) {
 	std::cout << "DNSSDService stopped: " << error << std::endl;
 }
 
+bool LinkLocalRoster::hasItem(const JID& j) const {
+	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
+		if (getJIDForService(i->first) == j) {
+			return true;
+		}
+	}
+	return false;
+}
+
+String LinkLocalRoster::getHostname(const JID& j) const {
+	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) {
+		if (getJIDForService(i->first) == j) {
+			return i->second.host;
+		}
+	}
+	return "";
+}
+
 }
diff --git a/Swiften/LinkLocal/LinkLocalRoster.h b/Swiften/LinkLocal/LinkLocalRoster.h
index 33dd455..bd774f4 100644
--- a/Swiften/LinkLocal/LinkLocalRoster.h
+++ b/Swiften/LinkLocal/LinkLocalRoster.h
@@ -23,6 +23,9 @@ namespace Swift {
 			boost::signal<void (boost::shared_ptr<RosterPayload>)> onRosterChanged;
 			boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChanged;
 
+			bool hasItem(const JID&) const;
+			String getHostname(const JID&) const;
+
 		private:
 			RosterItemPayload getRosterItem(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const;
 			String getRosterName(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const;
diff --git a/Swiften/LinkLocal/LinkLocalSession.cpp b/Swiften/LinkLocal/LinkLocalSession.cpp
new file mode 100644
index 0000000..a308686
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalSession.cpp
@@ -0,0 +1,59 @@
+#include "Swiften/LinkLocal/LinkLocalSession.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/StreamStack/XMPPLayer.h"
+#include "Swiften/StreamStack/StreamStack.h"
+
+namespace Swift {
+
+LinkLocalSession::LinkLocalSession(
+		const JID& localJID,
+		boost::shared_ptr<Connection> connection,
+		PayloadParserFactoryCollection* payloadParserFactories, 
+		PayloadSerializerCollection* payloadSerializers) : 
+			localJID(localJID),
+			payloadParserFactories(payloadParserFactories),
+			payloadSerializers(payloadSerializers),
+			connection(connection),
+			initialized(false) {
+}
+
+LinkLocalSession::~LinkLocalSession() {
+	delete streamStack;
+}
+
+void LinkLocalSession::initializeStreamStack() {
+	assert(connection);
+	xmppLayer = boost::shared_ptr<XMPPLayer>(
+			new XMPPLayer(payloadParserFactories, payloadSerializers));
+	xmppLayer->onStreamStart.connect(
+			boost::bind(&LinkLocalSession::handleStreamStart, this, _1));
+	xmppLayer->onElement.connect(
+			boost::bind(&LinkLocalSession::handleElement, this, _1));
+	//xmppLayer->onError.connect(
+	//		boost::bind(&LinkLocalSession::setError, this, XMLError));
+	connection->onDisconnected.connect(
+			boost::bind(&LinkLocalSession::handleDisconnected, shared_from_this(), _1));
+	connectionLayer = boost::shared_ptr<ConnectionLayer>(new ConnectionLayer(connection));
+	streamStack = new StreamStack(xmppLayer, connectionLayer);
+}
+
+void LinkLocalSession::finishSession() {
+	connection->disconnect();
+}
+
+void LinkLocalSession::sendStanza(boost::shared_ptr<Stanza> stanza) {
+	xmppLayer->writeElement(stanza);
+}
+
+void LinkLocalSession::handleDisconnected(const boost::optional<Connection::Error>&) {
+	onSessionFinished();
+}
+
+void LinkLocalSession::setInitialized() {
+	initialized = true;
+	onSessionStarted();
+}
+
+}
diff --git a/Swiften/LinkLocal/LinkLocalSession.h b/Swiften/LinkLocal/LinkLocalSession.h
new file mode 100644
index 0000000..9a7ac13
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalSession.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/signal.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/Element.h"
+#include "Swiften/Network/Connection.h"
+#include "Swiften/StreamStack/ConnectionLayer.h"
+
+namespace Swift {
+	class ProtocolHeader;
+	class StreamStack;
+	class JID;
+	class Stanza;
+	class ByteArray;
+	class PayloadParserFactoryCollection;
+	class PayloadSerializerCollection;
+	class XMPPLayer;
+
+	class LinkLocalSession : 
+			public boost::enable_shared_from_this<LinkLocalSession> {
+		public:
+			LinkLocalSession(
+					const JID& localJID,
+					boost::shared_ptr<Connection> connection,
+					PayloadParserFactoryCollection* payloadParserFactories, 
+					PayloadSerializerCollection* payloadSerializers);
+			virtual ~LinkLocalSession();
+
+			void finishSession();
+
+			// TODO: Make non-virtual when OutgoingSession is fixed
+			virtual void sendStanza(boost::shared_ptr<Stanza>);
+
+			virtual const JID& getRemoteJID() const = 0;
+
+			virtual void start() = 0;
+
+			boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaReceived;
+			boost::signal<void ()> onSessionFinished;
+			boost::signal<void ()> onSessionStarted;
+			boost::signal<void (const ByteArray&)> onDataWritten;
+			boost::signal<void (const ByteArray&)> onDataRead;
+
+		protected:
+			void initializeStreamStack();
+
+			const JID& getLocalJID() const {
+				return localJID;
+			}
+
+			boost::shared_ptr<XMPPLayer> getXMPPLayer() const {
+				return xmppLayer;
+			}
+
+			// TODO: Remove later
+			void setConnection(boost::shared_ptr<Connection> c) {
+				connection = c;
+			}
+
+			virtual void handleElement(boost::shared_ptr<Element>) = 0;
+			virtual void handleStreamStart(const ProtocolHeader&) = 0;
+
+			void setInitialized();
+			bool isInitialized() const { return initialized; }
+
+		private:
+			void handleDisconnected(const boost::optional<Connection::Error>& error);
+
+		private:
+			JID localJID;
+			PayloadParserFactoryCollection* payloadParserFactories;
+			PayloadSerializerCollection* payloadSerializers;
+			boost::shared_ptr<Connection> connection;
+			boost::shared_ptr<XMPPLayer> xmppLayer;
+			boost::shared_ptr<ConnectionLayer> connectionLayer;
+			StreamStack* streamStack;
+			bool initialized;
+	};
+}
diff --git a/Swiften/LinkLocal/Makefile.inc b/Swiften/LinkLocal/Makefile.inc
index 683447c..1d29844 100644
--- a/Swiften/LinkLocal/Makefile.inc
+++ b/Swiften/LinkLocal/Makefile.inc
@@ -1,7 +1,10 @@
 SWIFTEN_SOURCES += \
 	Swiften/LinkLocal/DNSSDService.cpp \
 	Swiften/LinkLocal/LinkLocalRoster.cpp \
-	Swiften/LinkLocal/LinkLocalServiceInfo.cpp
+	Swiften/LinkLocal/LinkLocalServiceInfo.cpp \
+	Swiften/LinkLocal/IncomingLinkLocalSession.cpp \
+	Swiften/LinkLocal/OutgoingLinkLocalSession.cpp \
+	Swiften/LinkLocal/LinkLocalSession.cpp
 
 
 ifeq ($(MACOSX),1)
diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp
new file mode 100644
index 0000000..57f3154
--- /dev/null
+++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp
@@ -0,0 +1,74 @@
+#include "Swiften/LinkLocal/OutgoingLinkLocalSession.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/Elements/ProtocolHeader.h"
+#include "Swiften/Network/Connection.h"
+#include "Swiften/StreamStack/StreamStack.h"
+#include "Swiften/LinkLocal/DNSSDService.h"
+#include "Swiften/StreamStack/ConnectionLayer.h"
+#include "Swiften/StreamStack/XMPPLayer.h"
+#include "Swiften/Elements/StreamFeatures.h"
+#include "Swiften/Elements/IQ.h"
+#include "Swiften/SASL/PLAINMessage.h"
+
+namespace Swift {
+
+OutgoingLinkLocalSession::OutgoingLinkLocalSession(
+		const JID& localJID,
+		const JID& remoteJID,
+		const String& hostname,
+		boost::shared_ptr<DNSSDService> resolver,
+		PayloadParserFactoryCollection* payloadParserFactories, 
+		PayloadSerializerCollection* payloadSerializers,
+		ConnectionFactory* connectionFactory) :
+			LinkLocalSession(
+				localJID, 
+				boost::shared_ptr<Connection>(), 
+				payloadParserFactories, 
+				payloadSerializers),
+			resolving_(false),
+			remoteJID_(remoteJID),
+			hostname_(hostname),
+			resolver_(resolver),
+			connectionFactory_(connectionFactory) {
+}
+
+void OutgoingLinkLocalSession::start() {
+	resolving_ = true;
+	//resolver_->onHostnameResolved.connect(boost::bind(&OutgoingLinkLocalSession::handleHostnameResolved, this, _1, _2));
+}
+
+#if 0
+void OutgoingLinkLocalSession::handleHostnameResolved(const String& hostname, const HostAddress&) {
+	if (resolving_) {
+		if (hostname == hostname_) {
+			boost::shared_ptr<Connection> connection = connectionFactory_->createConnection();
+			connection->onConnected.connect(boost::bind(&Session::handleConnected, shared_from_this()));
+			connection->onDisconnected.connect(boost::bind(&Session::handleDisconnected, shared_from_this(), _1));
+			connection_->connect(jid_.getDomain());
+			resolving_ = false;
+			boost::
+		}
+	}
+}
+#endif
+
+void OutgoingLinkLocalSession::handleStreamStart(const ProtocolHeader&) {
+	ProtocolHeader header;
+	header.setFrom(getLocalJID());
+	getXMPPLayer()->writeHeader(header);
+	setInitialized();
+}
+
+void OutgoingLinkLocalSession::handleElement(boost::shared_ptr<Element> element) {
+	if (isInitialized()) {
+		boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element);
+		if (stanza) {
+			onStanzaReceived(stanza);
+		}
+	}
+}
+
+
+}
diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.h b/Swiften/LinkLocal/OutgoingLinkLocalSession.h
new file mode 100644
index 0000000..ae1e86b
--- /dev/null
+++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/signal.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include "Swiften/LinkLocal/LinkLocalSession.h"
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+	class ConnectionFactory;
+	class HostAddress;
+	class String;
+	class Element;
+	class PayloadParserFactoryCollection;
+	class PayloadSerializerCollection;
+	class DNSSDService;
+
+	class OutgoingLinkLocalSession : public LinkLocalSession, public boost::enable_shared_from_this<OutgoingLinkLocalSession> {
+		public:
+			OutgoingLinkLocalSession(
+					const JID& localJID,
+					const JID& remoteJID,
+					const String& hostname,
+					boost::shared_ptr<DNSSDService> resolver,
+					PayloadParserFactoryCollection* payloadParserFactories, 
+					PayloadSerializerCollection* payloadSerializers,
+					ConnectionFactory* connectionFactory);
+
+			const JID& getRemoteJID() const {
+				return remoteJID_;
+			}
+
+			void start();
+
+		private:
+			void handleElement(boost::shared_ptr<Element>);
+			void handleStreamStart(const ProtocolHeader&);
+			//void handleHostnameResolved(const String& hostname, const HostAddress& address);
+
+		private:
+			bool resolving_;
+			JID remoteJID_;
+			String hostname_;
+			boost::shared_ptr<DNSSDService> resolver_;
+			ConnectionFactory* connectionFactory_;
+	};
+}
diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp
index d374221..b064c7a 100644
--- a/Swiften/Network/BoostConnection.cpp
+++ b/Swiften/Network/BoostConnection.cpp
@@ -51,18 +51,21 @@ void BoostConnection::listen() {
 void BoostConnection::connect(const String& domain) {
 	DomainNameResolver resolver;
 	try {
-		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(
-				endpoint,
-				boost::bind(&BoostConnection::handleConnectFinished, shared_from_this(), boost::asio::placeholders::error));
+		connect(resolver.resolve(domain.getUTF8String()));
 	}
 	catch (const DomainNameResolveException& e) {
 		onDisconnected(DomainNameResolveError);
 	}
 }
 
+void BoostConnection::connect(const HostAddressPort& addressPort) {
+	boost::asio::ip::tcp::endpoint endpoint(	
+			boost::asio::ip::address::from_string(addressPort.getAddress().toString()), addressPort.getPort());
+	socket_.async_connect(
+			endpoint,
+			boost::bind(&BoostConnection::handleConnectFinished, shared_from_this(), boost::asio::placeholders::error));
+}
+
 void BoostConnection::disconnect() {
 	//MainEventLoop::removeEventsFromOwner(shared_from_this());
 	socket_.close();
diff --git a/Swiften/Network/BoostConnection.h b/Swiften/Network/BoostConnection.h
index 76b6588..0ed6874 100644
--- a/Swiften/Network/BoostConnection.h
+++ b/Swiften/Network/BoostConnection.h
@@ -21,6 +21,7 @@ namespace Swift {
 
 			virtual void listen();
 			virtual void connect(const String& domain);
+			virtual void connect(const HostAddressPort& address);
 			virtual void disconnect();
 			virtual void write(const ByteArray& data);
 
diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h
index c34c21d..25f9a16 100644
--- a/Swiften/Network/Connection.h
+++ b/Swiften/Network/Connection.h
@@ -1,5 +1,4 @@
-#ifndef SWIFTEN_CONNECTION_H
-#define SWIFTEN_CONNECTION_H
+#pragma once
 
 #include <boost/signals.hpp>
 
@@ -7,6 +6,8 @@
 #include "Swiften/Base/String.h"
 
 namespace Swift {
+	class HostAddressPort;
+
 	class Connection {
 		public:
 			enum Error {
@@ -20,6 +21,7 @@ namespace Swift {
 			virtual ~Connection() {}
 
 			virtual void listen() = 0;
+			virtual void connect(const HostAddressPort& address) = 0;
 			virtual void connect(const String& domain) = 0;
 			virtual void disconnect() = 0;
 			virtual void write(const ByteArray& data) = 0;
@@ -30,5 +32,3 @@ namespace Swift {
 			boost::signal<void (const ByteArray&)> onDataRead;
 	};
 }
-
-#endif
diff --git a/Swiften/Parser/UnitTest/XMPPParserTest.cpp b/Swiften/Parser/UnitTest/XMPPParserTest.cpp
index a8b805e..ecdd565 100644
--- a/Swiften/Parser/UnitTest/XMPPParserTest.cpp
+++ b/Swiften/Parser/UnitTest/XMPPParserTest.cpp
@@ -2,6 +2,7 @@
 #include <cppunit/extensions/TestFactoryRegistry.h>
 #include <vector>
 
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/Base/String.h"
 #include "Swiften/Parser/XMPPParser.h"
 #include "Swiften/Parser/ElementParser.h"
@@ -165,8 +166,8 @@ class XMPPParserTest : public CppUnit::TestFixture
 
 				Client() {}
 
-				void handleStreamStart(const String& from, const String& to, const String& id) {
-					events.push_back(Event(StreamStart, from, to, id));
+				void handleStreamStart(const ProtocolHeader& header) {
+					events.push_back(Event(StreamStart, header.getFrom(), header.getTo(), header.getID()));
 				}
 
 				void handleElement(boost::shared_ptr<Element> element) {
diff --git a/Swiften/Parser/XMPPParser.cpp b/Swiften/Parser/XMPPParser.cpp
index 0f04cca..f97bed8 100644
--- a/Swiften/Parser/XMPPParser.cpp
+++ b/Swiften/Parser/XMPPParser.cpp
@@ -3,6 +3,7 @@
 #include <iostream>
 #include <cassert>
 
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/Base/String.h"
 #include "Swiften/Parser/XMLParser.h"
 #include "Swiften/Parser/PlatformXMLParserFactory.h"
@@ -54,7 +55,12 @@ 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("from"), attributes.getAttribute("to"), attributes.getAttribute("id"));
+			ProtocolHeader header;
+			header.setFrom(attributes.getAttribute("from"));
+			header.setTo(attributes.getAttribute("to"));
+			header.setID(attributes.getAttribute("id"));
+			header.setVersion(attributes.getAttribute("version"));
+			client_->handleStreamStart(header);
 		}
 		else {
 			parseErrorOccurred_ = true;
diff --git a/Swiften/Parser/XMPPParserClient.h b/Swiften/Parser/XMPPParserClient.h
index fb81df8..b8f8e46 100644
--- a/Swiften/Parser/XMPPParserClient.h
+++ b/Swiften/Parser/XMPPParserClient.h
@@ -1,5 +1,4 @@
-#ifndef SWIFTEN_XMPPPARSERCLIENT_H
-#define SWIFTEN_XMPPPARSERCLIENT_H
+#pragma once
 
 #include <boost/shared_ptr.hpp>
 
@@ -7,15 +6,14 @@
 
 namespace Swift {
 	class String;
+	class ProtocolHeader;
 
 	class XMPPParserClient {
 		public:
 			virtual ~XMPPParserClient();
 
-			virtual void handleStreamStart(const String& from, const String& to, const String& id) = 0;
+			virtual void handleStreamStart(const ProtocolHeader&) = 0;
 			virtual void handleElement(boost::shared_ptr<Element>) = 0;
 			virtual void handleStreamEnd() = 0;
 	};
 }
-
-#endif
diff --git a/Swiften/Serializer/XMPPSerializer.cpp b/Swiften/Serializer/XMPPSerializer.cpp
index 6139586..660bb37 100644
--- a/Swiften/Serializer/XMPPSerializer.cpp
+++ b/Swiften/Serializer/XMPPSerializer.cpp
@@ -3,6 +3,7 @@
 #include <boost/bind.hpp>
 #include <iostream>
 
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/Base/foreach.h"
 #include "Swiften/Serializer/CompressRequestSerializer.h"
 #include "Swiften/Serializer/CompressFailureSerializer.h"
@@ -34,16 +35,19 @@ XMPPSerializer::XMPPSerializer(PayloadSerializerCollection* payloadSerializers)
 	serializers_.push_back(boost::shared_ptr<ElementSerializer>(new StreamFeaturesSerializer()));
 }
 
-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 + "\"";
+String XMPPSerializer::serializeHeader(const ProtocolHeader& header) const {
+	String result = "<?xml version=\"1.0\"?><stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\"";
+	if (!header.getFrom().isEmpty()) {
+		result += " from=\"" + header.getFrom() + "\"";
 	}
-	if (!to.isEmpty()) {
-		result += " to=\"" + to + "\"";
+	if (!header.getTo().isEmpty()) {
+		result += " to=\"" + header.getTo() + "\"";
 	}
-	if (!id.isEmpty()) {
-		result += " id=\"" + id + "\"";
+	if (!header.getID().isEmpty()) {
+		result += " id=\"" + header.getID() + "\"";
+	}
+	if (!header.getVersion().isEmpty()) {
+		result += " version=\"" + header.getVersion() + "\"";
 	}
 	result += ">";
 	return result;
diff --git a/Swiften/Serializer/XMPPSerializer.h b/Swiften/Serializer/XMPPSerializer.h
index f77e14b..38ba3ff 100644
--- a/Swiften/Serializer/XMPPSerializer.h
+++ b/Swiften/Serializer/XMPPSerializer.h
@@ -1,5 +1,4 @@
-#ifndef SWIFTEN_XMPPSERIALIZER_H
-#define SWIFTEN_XMPPSERIALIZER_H
+#pragma once
 
 #include <boost/shared_ptr.hpp>
 #include <vector>
@@ -11,12 +10,13 @@
 namespace Swift {
 	class PayloadSerializerCollection;
 	class CompressRequestSerializer;
+	class ProtocolHeader;
 
 	class XMPPSerializer {
 		public:
 			XMPPSerializer(PayloadSerializerCollection*);
 
-			String serializeHeader(const String& from, const String& to, const String& id = "") const;
+			String serializeHeader(const ProtocolHeader&) const;
 			String serializeElement(boost::shared_ptr<Element> stanza) const;
 			String serializeFooter() const;
 		
@@ -24,5 +24,3 @@ namespace Swift {
 			std::vector< boost::shared_ptr<ElementSerializer> > serializers_;
 	};
 }
-
-#endif
diff --git a/Swiften/Server/ServerFromClientSession.cpp b/Swiften/Server/ServerFromClientSession.cpp
index 9a3cf83..45df3be 100644
--- a/Swiften/Server/ServerFromClientSession.cpp
+++ b/Swiften/Server/ServerFromClientSession.cpp
@@ -2,6 +2,7 @@
 
 #include <boost/bind.hpp>
 
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/Server/UserRegistry.h"
 #include "Swiften/Network/Connection.h"
 #include "Swiften/StreamStack/StreamStack.h"
@@ -42,7 +43,7 @@ ServerFromClientSession::~ServerFromClientSession() {
 
 void ServerFromClientSession::start() {
 	xmppLayer_->onStreamStart.connect(
-			boost::bind(&ServerFromClientSession::handleStreamStart, this, _2));
+			boost::bind(&ServerFromClientSession::handleStreamStart, this, _1));
 	xmppLayer_->onElement.connect(
 			boost::bind(&ServerFromClientSession::handleElement, this, _1));
 	//xmppLayer_->onError.connect(
@@ -99,9 +100,12 @@ void ServerFromClientSession::handleElement(boost::shared_ptr<Element> element)
 	}
 }
 
-void ServerFromClientSession::handleStreamStart(const String& domain) {
-	domain_ = JID("", domain);
-	xmppLayer_->writeHeader(domain, id_);
+void ServerFromClientSession::handleStreamStart(const ProtocolHeader& incomingHeader) {
+	domain_ = JID("", incomingHeader.getTo());
+	ProtocolHeader header;
+	header.setFrom(incomingHeader.getTo());
+	header.setID(id_);
+	xmppLayer_->writeHeader(header);
 
 	boost::shared_ptr<StreamFeatures> features(new StreamFeatures());
 	if (!authenticated_) {
diff --git a/Swiften/Server/ServerFromClientSession.h b/Swiften/Server/ServerFromClientSession.h
index e7df99d..733c428 100644
--- a/Swiften/Server/ServerFromClientSession.h
+++ b/Swiften/Server/ServerFromClientSession.h
@@ -9,6 +9,7 @@
 #include "Swiften/Network/Connection.h"
 
 namespace Swift {
+	class ProtocolHeader;
 	class Element;
 	class Stanza;
 	class PayloadParserFactoryCollection;
@@ -51,7 +52,7 @@ namespace Swift {
 		private:
 			void handleDisconnected(const boost::optional<Connection::Error>& error);
 			void handleElement(boost::shared_ptr<Element>);
-			void handleStreamStart(const String& domain);
+			void handleStreamStart(const ProtocolHeader& header);
 
 		private:
 			String id_;
diff --git a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp
index f60c370..e284ba9 100644
--- a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp
+++ b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp
@@ -3,6 +3,7 @@
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
 
+#include "Swiften/Elements/ProtocolHeader.h"
 #include "Swiften/Elements/Presence.h"
 #include "Swiften/Base/ByteArray.h"
 #include "Swiften/StreamStack/XMPPLayer.h"
@@ -68,9 +69,11 @@ class XMPPLayerTest : public CppUnit::TestFixture
 
 		void testWriteHeader() {
 			testling_->onWriteData.connect(boost::bind(&XMPPLayerTest::handleWriteData, this, _1));
-			testling_->writeHeader("example.com");
+			ProtocolHeader header;
+			header.setTo("example.com");
+			testling_->writeHeader(header);
 
-			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_);
+			CPPUNIT_ASSERT_EQUAL(String("<?xml version=\"1.0\"?><stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" to=\"example.com\" version=\"1.0\">"), dataReceived_);
 		}
 
 		void testWriteElement() {
diff --git a/Swiften/StreamStack/XMPPLayer.cpp b/Swiften/StreamStack/XMPPLayer.cpp
index 73d763a..b87cb4a 100644
--- a/Swiften/StreamStack/XMPPLayer.cpp
+++ b/Swiften/StreamStack/XMPPLayer.cpp
@@ -1,6 +1,7 @@
 #include "Swiften/StreamStack/XMPPLayer.h"
 #include "Swiften/Parser/XMPPParser.h"
 #include "Swiften/Serializer/XMPPSerializer.h"
+#include "Swiften/Elements/ProtocolHeader.h"
 
 namespace Swift {
 
@@ -20,12 +21,8 @@ XMPPLayer::~XMPPLayer() {
 	delete xmppParser_;
 }
 
-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::writeHeader(const ProtocolHeader& header) {
+	onWriteData(ByteArray(xmppSerializer_->serializeHeader(header)));
 }
 
 void XMPPLayer::writeFooter() {
@@ -60,8 +57,8 @@ void XMPPLayer::doResetParser() {
 	resetParserAfterParse_ = false;
 }
 
-void XMPPLayer::handleStreamStart(const String& from, const String& to, const String& id) {
-	onStreamStart(from, to, id);
+void XMPPLayer::handleStreamStart(const ProtocolHeader& header) {
+	onStreamStart(header);
 }
 
 void XMPPLayer::handleElement(boost::shared_ptr<Element> stanza) {
diff --git a/Swiften/StreamStack/XMPPLayer.h b/Swiften/StreamStack/XMPPLayer.h
index 7437112..7974811 100644
--- a/Swiften/StreamStack/XMPPLayer.h
+++ b/Swiften/StreamStack/XMPPLayer.h
@@ -1,5 +1,4 @@
-#ifndef SWIFTEN_XMPPLAYER_H
-#define SWIFTEN_XMPPLAYER_H
+#pragma once
 
 #include <boost/shared_ptr.hpp>
 #include <boost/signal.hpp>
@@ -10,6 +9,7 @@
 #include "Swiften/Parser/XMPPParserClient.h"
 
 namespace Swift {
+	class ProtocolHeader;
 	class XMPPParser;
 	class PayloadParserFactoryCollection;
 	class XMPPSerializer;
@@ -22,8 +22,7 @@ namespace Swift {
 					PayloadSerializerCollection* payloadSerializers);
 			~XMPPLayer();
 
-			void writeHeader(const String& from, const String& id);
-			void writeHeader(const String& to);
+			void writeHeader(const ProtocolHeader& header);
 			void writeFooter();
 			void writeElement(boost::shared_ptr<Element>);
 			void writeData(const String& data);
@@ -32,14 +31,14 @@ namespace Swift {
 			void resetParser();
 
 		public:
-			boost::signal<void (const String& /* from */, const String& /* to */ , const String& /* id */)> onStreamStart;
+			boost::signal<void (const ProtocolHeader&)> 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&, const String&, const String&);
+			void handleStreamStart(const ProtocolHeader&);
 			void handleElement(boost::shared_ptr<Element>);
 			void handleStreamEnd();
 
@@ -54,5 +53,3 @@ namespace Swift {
 			bool inParser_;
 	};
 }
-
-#endif
-- 
cgit v0.10.2-6-g49f6