Index: source/ariba/overlay/BaseOverlay.cpp
===================================================================
--- source/ariba/overlay/BaseOverlay.cpp	(revision 4839)
+++ source/ariba/overlay/BaseOverlay.cpp	(revision 5151)
@@ -39,72 +39,320 @@
 #include "BaseOverlay.h"
 
-#include "ariba/utility/misc/OvlVis.h"
+#include <sstream>
+#include <iostream>
+#include <string>
+#include <boost/foreach.hpp>
+
 #include "ariba/NodeListener.h"
 #include "ariba/CommunicationListener.h"
 #include "ariba/SideportListener.h"
 
+#include "ariba/overlay/LinkDescriptor.h"
 #include "ariba/overlay/messages/OverlayMsg.h"
 #include "ariba/overlay/messages/JoinRequest.h"
 #include "ariba/overlay/messages/JoinReply.h"
 #include "ariba/overlay/messages/LinkRequest.h"
+#include "ariba/overlay/messages/RelayMessage.h"
+
+#include "ariba/utility/misc/OvlVis.h"
 
 namespace ariba {
 namespace overlay {
 
+#define logging_force(x) std::cout << x << std::endl;
+#define logging_force1(x) std::cout << x << std::endl;
+
+LinkDescriptor* BaseOverlay::getDescriptor( const LinkID& link, bool communication ) {
+	BOOST_FOREACH( LinkDescriptor* lp, links )
+		if ((communication ? lp->communicationId : lp->overlayId) == link)
+			return lp;
+	return NULL;
+}
+
+const LinkDescriptor* BaseOverlay::getDescriptor( const LinkID& link, bool communication ) const {
+	BOOST_FOREACH( const LinkDescriptor* lp, links )
+		if ((communication ? lp->communicationId : lp->overlayId) == link)
+			return lp;
+	return NULL;
+}
+
+LinkDescriptor* BaseOverlay::getAutoDescriptor( const NodeID& node, const ServiceID& service ) {
+	BOOST_FOREACH( LinkDescriptor* lp, links )
+		if (lp->autolink && lp->remoteNode == node && lp->service == service)
+			return lp;
+	return NULL;
+}
+
+void BaseOverlay::eraseDescriptor( const LinkID& link, bool communication ) {
+	for ( vector<LinkDescriptor*>::iterator i = links.begin(); i!= links.end(); i++) {
+		LinkDescriptor* ld = *i;
+		if ((communication ? ld->communicationId : ld->overlayId) == link) {
+			delete ld;
+			links.erase(i);
+			break;
+		}
+	}
+}
+
+LinkDescriptor* BaseOverlay::addDescriptor( const LinkID& link ) {
+	LinkDescriptor* desc = getDescriptor( link );
+	if ( desc == NULL ) {
+		desc = new LinkDescriptor();
+		desc->overlayId = link;
+		links.push_back(desc);
+	}
+	return desc;
+}
+
+/// returns a direct link relay descriptor to the given relay node
+LinkDescriptor* BaseOverlay::getRelayDescriptor( const NodeID& relayNode ) {
+	BOOST_FOREACH( LinkDescriptor* lp, links )
+		if (lp->remoteNode == relayNode &&
+		    lp->service == OverlayInterface::OVERLAY_SERVICE_ID &&
+		    lp->relay == false &&
+		    lp->up)
+			return lp;
+	return NULL;
+}
+
+/// find a proper relay node
+const NodeID BaseOverlay::findRelayNode( const NodeID& id ) {
+	LinkDescriptor* rld = NULL;
+	NodeID relayNode = NodeID::UNSPECIFIED;
+
+	// get used next hop towards node
+	LinkID rlid = overlayInterface->getNextLinkId(id);
+	while ( relayNode.isUnspecified() && !rlid.isUnspecified() && rld == NULL ) {
+
+		// get descriptor of first hop
+		rld = getDescriptor(rlid);
+		logging_force1( rld );
+
+		// is first hop a relay path? yes-> try to find real link!
+		if ( rld->relay )
+			relayNode = getRelayDescriptor(rld->localRelay)->remoteNode;
+
+		// no-> a proper relay node has been found
+		else relayNode = rld->remoteNode;
+	}
+	logging_force1( "Potential relay node " << relayNode.toString() );
+	// do not return myself or use the node as relay node
+	if (relayNode == nodeId)
+		return NodeID::UNSPECIFIED;
+	else {
+		logging_force1( "Returning relay node " << relayNode.toString() );
+		return relayNode;
+	}
+}
+
+/// forwards a message over relays/overlay/directly using link descriptor
+seqnum_t BaseOverlay::sendMessage( Message* message, const LinkDescriptor* ld ) {
+
+	// directly send message
+	if ( !ld->communicationId.isUnspecified() && ld->communicationUp ) {
+		logging_debug("sendMessage: Sending message via Base Communication");
+		return bc->sendMessage( ld->communicationId, message );
+	}
+
+	// relay message
+	else if ( ld->relay ) {
+		logging_debug("sendMessage: Relaying message to node "
+			<< ld->remoteNode.toString()
+			<< " using relay " << ld->localRelay
+		);
+
+		// get local relay link descriptor and mark as used for relaying
+		LinkDescriptor* rld = getRelayDescriptor(ld->localRelay);
+		if (rld==NULL) {
+			logging_error("sendMessage: Relay descriptor for relay " <<
+				ld->localRelay.toString() << " unknown.");
+			return -1;
+		}
+		rld->markAsRelay();
+
+		// create a information relay message to inform the relay about
+		OverlayMsg overlay_msg( OverlayMsg::typeRelay, ld->service, nodeId );
+		RelayMessage relayMsg( RelayMessage::typeInform, ld->remoteRelay, ld->remoteNode, ld->remoteLinkId );
+		relayMsg.encapsulate( message );
+		overlay_msg.encapsulate( &relayMsg );
+
+		// route message to relay node in order to inform it!
+		logging_debug("sendMessage: Sending message over relayed link with" << ld );
+		overlayInterface->routeMessage(rld->remoteNode, rld->overlayId, &overlay_msg);
+		return 0;
+	}
+
+	// route message using overlay
+	else {
+		logging_error("Could not send message");
+		logging_debug( "sendMessage: Routing message to node " << ld->remoteNode.toString() );
+		overlayInterface->routeMessage( ld->remoteNode, message );
+		return 0;
+	}
+
+	return -1;
+}
+
+/// creates a link descriptor, apply relay semantics if possible
+LinkDescriptor* BaseOverlay::createLinkDescriptor(
+	const NodeID& remoteNode, const ServiceID& service, const LinkID& link_id ) {
+
+	// find listener
+	if( !communicationListeners.contains( service ) ) {
+		logging_error( "No listener found for service " << service.toString() );
+		return NULL;
+	}
+	CommunicationListener* listener = communicationListeners.get( service );
+	assert( listener != NULL );
+
+	// copy link id
+	LinkID linkid = link_id;
+
+	// create link id if necessary
+	if ( linkid.isUnspecified() )
+		linkid = LinkID::create();
+
+	// create relay link descriptor
+	NodeID relayNode = findRelayNode(remoteNode);
+
+	// add descriptor
+	LinkDescriptor* ld = addDescriptor( linkid );
+	ld->overlayId  = linkid;
+	ld->service    = service;
+	ld->listener   = listener;
+	ld->remoteNode = remoteNode;
+
+	// set relay node if available
+	ld->relay      = !relayNode.isUnspecified();
+	ld->localRelay = relayNode;
+
+	if (!ld->relay)
+		logging_error("No relay found!");
+
+	// debug output
+	logging_debug( "Created link descriptor: " << ld );
+
+	return ld;
+}
+
+
+// ----------------------------------------------------------------------------
+
 use_logging_cpp(BaseOverlay);
 
-BaseOverlay::BaseOverlay()
-	: bc(NULL), overlayInterface(NULL), nodeId(NodeID::UNSPECIFIED),
-		spovnetId(SpoVNetID::UNSPECIFIED), initiatorLink(LinkID::UNSPECIFIED),
-		state(BaseOverlayStateInvalid), sideport(&SideportListener::DEFAULT){
-}
-
-BaseOverlay::~BaseOverlay(){
-}
-
-void BaseOverlay::start( BaseCommunication& _basecomm, const NodeID& _nodeid ){
-
+// ----------------------------------------------------------------------------
+
+BaseOverlay::BaseOverlay() :
+	bc(NULL), overlayInterface(NULL), nodeId(NodeID::UNSPECIFIED),
+	spovnetId(SpoVNetID::UNSPECIFIED), initiatorLink(LinkID::UNSPECIFIED),
+	state(BaseOverlayStateInvalid), sideport(&SideportListener::DEFAULT) {
+}
+
+BaseOverlay::~BaseOverlay() {
+}
+
+// ----------------------------------------------------------------------------
+
+void BaseOverlay::start( BaseCommunication& _basecomm, const NodeID& _nodeid ) {
+	logging_info("Starting...");
+
+	// set parameters
 	bc = &_basecomm;
 	nodeId = _nodeid;
 
-	logging_info("creating base overlay");
-
+	// register at base communication
 	bc->registerMessageReceiver( this );
 	bc->registerEventListener( this );
 
-	ovl.visCreate( ovlId, nodeId, string(""), string("") );
-	ovl.visChangeNodeColor(ovlId, nodeId, OvlVis::NODE_COLORS_GREY);
-
-// 	if (Identifier(Configuration::instance().read<unsigned long>("BASE_nodeid")) ==
-// 	    Identifier(Configuration::instance().read<unsigned long>("SOURCE"))) {
-// 		ovl.visChangeNodeIcon(ovlId, nodeId, OvlVis::ICON_ID_CAMERA);
-// 	} else if (Identifier(Configuration::instance().read<unsigned long>("BASE_nodeid")) ==
-// 	    Identifier(Configuration::instance().read<unsigned long>("MR_A"))) {
-// 		ovl.visChangeNodeIcon(ovlId, nodeId, OvlVis::ICON_ID_CHARACTER_A);
-// 	} else if (Identifier(Configuration::instance().read<unsigned long>("BASE_nodeid")) ==
-// 	    Identifier(Configuration::instance().read<unsigned long>("MR_W"))) {
-// 		ovl.visChangeNodeIcon(ovlId, nodeId, OvlVis::ICON_ID_CHARACTER_W);
-// 	}
-
 	// timer for auto link management
-	Timer::setInterval( 5000 );
+	Timer::setInterval( 500 );
 	Timer::start();
 }
 
 void BaseOverlay::stop() {
-
-	logging_info("deleting base overlay");
-
+	logging_info("Stopping...");
+
+	// stop timer
 	Timer::stop();
+
+	// delete oberlay interface
+	if(overlayInterface != NULL) {
+		delete overlayInterface;
+		overlayInterface = NULL;
+	}
+
+	// unregister at base communication
 	bc->unregisterMessageReceiver( this );
 	bc->unregisterEventListener( this );
-
-	if(overlayInterface != NULL){
-		delete overlayInterface;
-		overlayInterface = NULL;
-	}
-}
-
-void BaseOverlay::createSpoVNet(const SpoVNetID& id, const OverlayParameterSet& param, const SecurityParameterSet& sec, const QoSParameterSet& qos){
+}
+
+// ----------------------------------------------------------------------------
+
+void BaseOverlay::joinSpoVNet(const SpoVNetID& id,
+		const EndpointDescriptor& bootstrapEp) {
+
+	ovl.visShowNodeBubble ( ovlId, nodeId, "joining..." );
+	logging_info( "Starting to join spovnet " << id.toString() <<
+			" with nodeid " << nodeId.toString());
+
+	// contact the spovnet initiator and request to join. if the join is granted we will
+	// receive further information on the structure of the overlay that is used in the spovnet
+	// but first, we have to establish a link to the initiator...
+	spovnetId = id;
+	state = BaseOverlayStateJoinInitiated;
+
+	initiatorLink = bc->establishLink( bootstrapEp );
+	logging_info("join process initiated for " << id.toString() << "...");
+}
+
+void BaseOverlay::leaveSpoVNet() {
+
+	logging_info( "Leaving spovnet " << spovnetId );
+	bool ret = ( state != this->BaseOverlayStateInvalid );
+
+	logging_debug( "Dropping all auto-links" );
+
+	// gather all service links
+	vector<LinkID> servicelinks;
+	BOOST_FOREACH( LinkDescriptor* ld, links ) {
+		if( ld->service != OverlayInterface::OVERLAY_SERVICE_ID )
+		servicelinks.push_back( ld->overlayId );
+	}
+
+	// drop all service links
+	BOOST_FOREACH( LinkID lnk, servicelinks )
+		dropLink( lnk );
+
+	// let the node leave the spovnet overlay interface
+	logging_debug( "Leaving overlay" );
+	if( overlayInterface != NULL )
+		overlayInterface->leaveOverlay();
+
+	// leave spovnet
+	if( state != BaseOverlayStateInitiator ) {
+		// then, leave the spovnet baseoverlay
+		OverlayMsg overMsg( OverlayMsg::typeBye, nodeId );
+		bc->sendMessage( initiatorLink, &overMsg );
+
+		// drop the link and set to correct state
+		bc->dropLink( initiatorLink );
+		initiatorLink = LinkID::UNSPECIFIED;
+	}
+
+	// change to inalid state
+	state = BaseOverlayStateInvalid;
+	ovl.visShutdown( ovlId, nodeId, string("") );
+
+	// inform all registered services of the event
+	BOOST_FOREACH( NodeListener* i, nodeListeners ) {
+		if( ret ) i->onLeaveCompleted( spovnetId );
+		else i->onLeaveFailed( spovnetId );
+	}
+}
+
+void BaseOverlay::createSpoVNet(const SpoVNetID& id,
+		const OverlayParameterSet& param,
+		const SecurityParameterSet& sec,
+		const QoSParameterSet& qos) {
 
 	// set the state that we are an initiator, this way incoming messages are
@@ -117,5 +365,5 @@
 
 	overlayInterface = OverlayFactory::create( *this, param, nodeId, this );
-	if( overlayInterface == NULL ){
+	if( overlayInterface == NULL ) {
 		logging_fatal( "overlay structure not supported" );
 		state = BaseOverlayStateInvalid;
@@ -129,89 +377,55 @@
 
 	ovl.visChangeNodeIcon ( ovlId, nodeId, OvlVis::ICON_ID_CAMERA );
-	ovl.visChangeNodeColor( ovlId, nodeId, OvlVis::NODE_COLORS_GREEN);
-}
-
-void BaseOverlay::joinSpoVNet(const SpoVNetID& id, const EndpointDescriptor& bootstrapEp){
-
-	ovl.visShowNodeBubble ( ovlId, nodeId, "joining..." );
-	logging_info( "starting to join spovnet " << id.toString() <<
-			" with nodeid " << nodeId.toString());
-
-	spovnetId = id;
-	state = BaseOverlayStateJoinInitiated;
-
-	//
-	// start bootstrapping for spovnets and publish our information
-	//
-
-	overlayBootstrap.start( this, spovnetId, nodeId );
-	overlayBootstrap.publish( bc->getEndpointDescriptor() );
-
-	//
-	// contact the spovnet initiator and request
-	// to join. if the join is granted we will
-	// receive further information on the structure
-	// of the overlay that is used in the spovnet
-	//
-	// but first, we have to establish a link to the initiator...
-	//
-
-	initiatorLink = bc->establishLink( bootstrapEp );
-	logging_info("join process initiated for " << id.toString() << "...");
-}
-
-void BaseOverlay::leaveSpoVNet(){
-
-	logging_info( "leaving spovnet " << spovnetId );
-	bool ret = ( state != this->BaseOverlayStateInvalid );
-
-	logging_debug( "dropping all auto-links ..." );
-
-	// now we start leaving the spovnet: fist delete all links
-	// that we still have in the baseoverlay initiated by
-	// some services, the leave the actual overlay structure,
-	// then leave the spovnet
-
-	// --> drop all service links
-
-	vector<LinkID> servicelinks;
-	BOOST_FOREACH( LinkPair item, linkMapping ){
-		if( item.second.service != OverlayInterface::OVERLAY_SERVICE_ID )
-			servicelinks.push_back( item.first );
-	}
-	BOOST_FOREACH( LinkID lnk, servicelinks ){
-		// the dropLink function will remove
-		// the item from the linkMapping
-		dropLink( lnk );
-	}
-
-	// --> leave overlay structure
-
-	logging_debug( "leaving overlay" );
-	// first, leave the overlay interface
-	if( overlayInterface != NULL )
-		overlayInterface->leaveOverlay();
-
-	// --> leave spovnet
-
-	if( state != BaseOverlayStateInitiator ){
-
-		// then, leave the spovnet baseoverlay
-		OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeBye, nodeId );
-		bc->sendMessage( initiatorLink, &overMsg );
-
-		// drop the link and set to correct state
-		bc->dropLink( initiatorLink );
-		initiatorLink = LinkID::UNSPECIFIED;
-	}
-
-	state = BaseOverlayStateInvalid;
-	ovl.visShutdown( ovlId, nodeId, string("") );
-
-	// inform all registered services of the event
-	BOOST_FOREACH( NodeListener* i, nodeListeners ){
-		if( ret ) i->onLeaveCompleted( spovnetId );
-		else      i->onLeaveFailed( spovnetId );
-	}
+	ovl.visChangeNodeColor( ovlId, nodeId, OvlVis::NODE_COLORS_GREEN );
+}
+
+// ----------------------------------------------------------------------------
+
+const LinkID BaseOverlay::establishLink(
+	const EndpointDescriptor& ep, const NodeID& nodeid,
+	const ServiceID& service, const LinkID& linkid ) {
+
+	LinkID link_id = linkid;
+
+	// establish link via overlay
+	if (!nodeid.isUnspecified())
+		link_id = establishLink( nodeid, service, link_id );
+
+	// establish link directly if only ep is known
+	if (nodeid.isUnspecified())
+		establishLink( ep, service, link_id );
+
+	return link_id;
+}
+
+/// call base communication's establish link and add link mapping
+const LinkID BaseOverlay::establishLink( const EndpointDescriptor& ep,
+		const ServiceID& service, const LinkID& linkid ) {
+
+	// create a new link id if necessary
+	LinkID link_id = linkid;
+	if (link_id.isUnspecified()) link_id = LinkID::create();
+
+	/// find a service listener
+	if( !communicationListeners.contains( service ) ) {
+		logging_error( "No listener registered for service id=" << service.toString() );
+		return LinkID::UNSPECIFIED;
+	}
+	CommunicationListener* listener = communicationListeners.get( service );
+	assert( listener != NULL );
+
+	/// establish link and add mapping
+	logging_info("Establishing direct link " << link_id.toString()
+		<< " using " << ep.toString());
+
+	// create descriptor
+	LinkDescriptor* ld = addDescriptor( link_id );
+	ld->overlayId = link_id;
+	ld->communicationId = link_id;
+	ld->listener = listener;
+	ld->service = service;
+	bc->establishLink( ep, link_id );
+
+	return link_id;
 }
 
@@ -220,221 +434,197 @@
 		const ServiceID& service, const LinkID& link_id ) {
 
-	if( !communicationListeners.contains( service ) ){
-		logging_error( "no registered listener on serviceid " << service.toString() );
-		return LinkID::UNSPECIFIED;
-	}
-
-	// copy link id
-	LinkID linkid = link_id;
-
-	// create link id if necessary
-	if (linkid.isUnspecified()) linkid = LinkID::create();
+	// do not establish a link to myself!
+	if (node == nodeId) return LinkID::UNSPECIFIED;
+
+	// create a link descriptor
+	LinkDescriptor* ld = createLinkDescriptor( node, service, link_id );
+
+	// create link request message with own link id
+	uint32_t nonce = (uint32_t)(rand() ^ (rand() << 16) ^ time(NULL));
+	LinkRequest link_request_msg(
+		nonce, &bc->getEndpointDescriptor(), false,
+		ld->overlayId, ld->localRelay );
+	OverlayMsg overlay_msg( OverlayMsg::typeLinkRequest, service, nodeId );
+	overlay_msg.encapsulate( &link_request_msg );
+	pendingLinks.insert( make_pair(nonce, ld->overlayId) );
 
 	// debug message
-	logging_debug( "BaseOverlay called to establish link between node " <<
-			node.toString() << " for service " << service.toString() );
-
-	// create link request message with own link id
-	OverlayMsg overlay_msg( OverlayMsg::OverlayMessageTypeLinkRequest, service, nodeId );
-	uint32_t nonce = (uint32_t)(rand() ^ (rand() << 16) ^ time(NULL));
-	LinkRequest link_request_msg( nonce, &bc->getEndpointDescriptor() );
-	overlay_msg.encapsulate( &link_request_msg );
-	pendingLinks.insert( make_pair(nonce, linkid) );
-
-	// debug message
-	logging_debug( "BaseOverlay routes LinkRequest message to node " << node.toString() );
-
-	// route message to overlay node
-	overlayInterface->routeMessage( node, &overlay_msg );
-
-	CommunicationListener* receiver = communicationListeners.get( service );
-	assert( receiver != NULL );
-
-	LinkItem item (linkid, NodeID::UNSPECIFIED, service, receiver);
-	linkMapping.insert( make_pair(linkid, item) );
-
-	return linkid;
-}
-
-const LinkID BaseOverlay::establishLink( const EndpointDescriptor& ep,
-		const ServiceID& service, const LinkID& linkid  ){
-
-	if( !communicationListeners.contains( service ) ){
-		logging_error( "no registered listener on serviceid " << service.toString() );
-		return LinkID::UNSPECIFIED;
-	}
-
-	const LinkID link = bc->establishLink( ep, linkid );
-
-	CommunicationListener* receiver = communicationListeners.get( service );
-	assert( receiver != NULL );
-
-	LinkItem item (link, NodeID::UNSPECIFIED, service, receiver);
-	linkMapping.insert( make_pair(link, item) );
-
-	return link;
-}
-
-void BaseOverlay::dropLink(const LinkID& link){
-
-	logging_debug( "baseoverlay dropping link " << link.toString() );
-	LinkMapping::iterator i = linkMapping.find( link );
+	logging_debug(
+		"Sending link request with"
+		<< " link id="        << ld->overlayId
+		<< " node id="        << ld->remoteNode.toString()
+		<< " service id="     << ld->service.toString()
+		<< " local relay id=" << ld->localRelay.toString()
+		<< " nonce= "         << nonce
+	);
+
+	// sending message through new link
+	sendMessage( &overlay_msg, ld );
+
+	return ld->overlayId;
+}
+
+/// drops an established link
+void BaseOverlay::dropLink(const LinkID& link) {
+	logging_debug( "Dropping link (initiated locally):" << link.toString() );
 
 	// find the link item to drop
-	if( i == linkMapping.end() ){
-		logging_warn( "can't drop link, mapping unknown " << link.toString() );
+	LinkDescriptor* ld = getDescriptor(link);
+	if( ld == NULL ) {
+		logging_warn( "Can't drop link, link is unknown!");
 		return;
 	}
 
-	LinkItem item = i->second;
-
 	// delete all queued messages
-	if( item.waitingmsg.size() > 0 ){
-
-		logging_warn( "dropping link " << link.toString() <<
-			" that has " << item.waitingmsg.size() << " waiting messages" );
-
-		item.deleteWaiting();
-	}
-
-	// erase the mapping and drop the link
-	linkMapping.erase( i );
-	bc->dropLink( link );
-
-	// tell sideports and listeners of the drop
-	item.interface->onLinkDown( link, item.node );
-	sideport->onLinkDown(link, this->nodeId, item.node, this->spovnetId );
-}
-
-seqnum_t BaseOverlay::sendMessage(const Message* message, const LinkID& link ){
-
-	logging_debug( "baseoverlay is sending data message on link " << link.toString() );
-
-	//
+	if( ld->messageQueue.size() > 0 ) {
+		logging_warn( "Dropping link " << ld->overlayId.toString() << " that has "
+				<< ld->messageQueue.size() << " waiting messages" );
+		ld->flushQueue();
+	}
+
+	// inform sideport and listener
+	ld->listener->onLinkDown( ld->overlayId, ld->remoteNode );
+	sideport->onLinkDown(ld->overlayId, this->nodeId, ld->remoteNode, this->spovnetId );
+
+	// do not drop relay links
+	if (!ld->usedAsRelay) {
+		// drop the link in base communication
+		if (ld->communicationUp) bc->dropLink( ld->communicationId );
+
+		// erase descriptor
+		eraseDescriptor( ld->overlayId );
+	} else
+		ld->dropWhenRelaysLeft = true;
+}
+
+// ----------------------------------------------------------------------------
+
+/// internal send message, always use this functions to send messages over links
+seqnum_t BaseOverlay::sendMessage( const Message* message, const LinkID& link ) {
+	logging_debug( "Sending data message on link " << link.toString() );
+
 	// get the mapping for this link
-	//
-
-	LinkMapping::iterator i = linkMapping.find( link );
-	if( i == linkMapping.end() ){
-		logging_error( "could not send message. link not found " << link.toString() );
+	LinkDescriptor* ld = getDescriptor(link);
+	if( ld == NULL ) {
+		logging_error("Could not send message. "
+			<< "Link not found id=" << link.toString());
 		return -1;
 	}
 
-	i->second.markused();
-
-	//
-	// check if the link is up yet, if its an autlink queue message
-	//
-
-	if( !i->second.linkup ){
-
-		if( i->second.autolink ){
-			logging_info( "auto link " << link.toString() << " is not up yet, queueing message" );
+	// check if the link is up yet, if its an auto link queue message
+	if( !ld->up ) {
+		ld->markAsUsed();
+		if( ld->autolink ) {
+			logging_info("Auto-link " << link.toString() << " not up, queue message");
 			Data data = data_serialize( message );
 			const_cast<Message*>(message)->dropPayload();
-			i->second.waitingmsg.push_back( new Message(data) );
+			ld->messageQueue.push_back( new Message(data) );
 		} else {
-			logging_error("link " << link.toString() << " is not up yet, dropping message" );
-		}
-
+			logging_error("Link " << link.toString() << " not up, drop message");
+		}
 		return -1;
 	}
 
-	//
-	// send the message through the basecomm
-	//
-
-	OverlayMsg overmsg( OverlayMsg::OverlayMessageTypeData,	i->second.service, nodeId );
+	// compile overlay message (has service and node id)
+	OverlayMsg overmsg( OverlayMsg::typeData, ld->service, nodeId );
 	overmsg.encapsulate( const_cast<Message*>(message) );
 
-	return bc->sendMessage( link, &overmsg );
-}
-
-seqnum_t BaseOverlay::sendMessage(const Message* message, const NodeID& node, const ServiceID& service){
-
-	LinkID link = LinkID::UNSPECIFIED;
-
-	LinkMapping::iterator i = linkMapping.begin();
-	LinkMapping::iterator iend = linkMapping.end();
-
-	//
-	// see if we find a link for this node and service destination
-	//
-
-	for( ; i != iend; i++ ){
-		if( i->second.node == node && i->second.service == service ){
-			link = i->second.link;
-			break;
-		}
-	}
-
-	//
+	// send message over relay/direct/overlay
+	return sendMessage( &overmsg, ld );
+}
+
+seqnum_t BaseOverlay::sendMessage(const Message* message,
+	const NodeID& node, const ServiceID& service) {
+
+	// find link for node and service
+	LinkDescriptor* ld = getAutoDescriptor( node, service );
+
 	// if we found no link, create an auto link
-	//
-
-	if( link == LinkID::UNSPECIFIED ){
-
-		logging_info( "no link could be found to send message to node " <<
-				node.toString() << " for service " << service.toString() <<
-				". creating auto link ...");
-
-		// call basecomm to create a link
-		link = establishLink( node, service );
+	if( ld == NULL ) {
+
+		// debug output
+		logging_info( "No link to send message to node "
+			<< node.toString() << " found for service "
+			<< service.toString() << ". Creating auto link ..."
+		);
 
 		// this will call onlinkup on us, if everything worked we now have a mapping
-		LinkMapping::iterator i = linkMapping.find( link );
-		i->second.autolink = true;
-
-		if( i == linkMapping.end() || link == LinkID::UNSPECIFIED ){
-			logging_error( "failed to establish auto link to node " << node.toString() <<
-					" for service " << service.toString() );
+		LinkID link = LinkID::create();
+
+		// call base overlay to create a link
+		link = establishLink( node, service, link );
+		ld = getDescriptor( link );
+		if( ld == NULL ) {
+			logging_error( "Failed to establish auto-link.");
 			return -1;
 		}
-
-		logging_debug( "establishing autolink in progress to node "
-				<< node.toString() << " with new link-id " << link.toString() );
-
-	} // if( link != LinkID::UNSPECIFIED )
-
-	assert( link != LinkID::UNSPECIFIED );
-
-	// mark the link as used, as we
-	// now send a message through it
-	i->second.markused();
-
-	// send the message through the new link. the link may not be functional,
-	// but for us there is a link-id so we can send messages through it. if
-	// the link is not yet up and the message needs to be cached, this is the
-	// task of the BaseCommunication, it will cache and send it later.
-	return sendMessage( message, link );
-}
-
-const EndpointDescriptor& BaseOverlay::getEndpointDescriptor(const LinkID& link) const {
-
-	return bc->getEndpointDescriptor( link );
-}
-
-const EndpointDescriptor& BaseOverlay::getEndpointDescriptor(const NodeID& node) const {
-
+		ld->autolink = true;
+
+		logging_debug( "Auto-link establishment in progress to node "
+				<< node.toString() << " with link id=" << link.toString() );
+	}
+	assert(ld != NULL);
+
+	// mark the link as used, as we now send a message through it
+	ld->markAsUsed();
+
+	// send / queue message
+	return sendMessage( message, ld->overlayId );
+}
+
+// ----------------------------------------------------------------------------
+
+const EndpointDescriptor& BaseOverlay::getEndpointDescriptor(
+		const LinkID& link) const {
+
+	// return own end-point descriptor
+	if( link == LinkID::UNSPECIFIED )
+		return bc->getEndpointDescriptor();
+
+	// find link descriptor. not found -> return unspecified
+	const LinkDescriptor* ld = getDescriptor(link);
+	if (ld==NULL) return EndpointDescriptor::UNSPECIFIED;
+
+	// return endpoint-descriptor from base communication
+	return bc->getEndpointDescriptor( ld->communicationId );
+}
+
+const EndpointDescriptor& BaseOverlay::getEndpointDescriptor(
+		const NodeID& node) const {
+
+	// return own end-point descriptor
 	if( node == nodeId || node == NodeID::UNSPECIFIED )
 		return bc->getEndpointDescriptor();
 
-	if( overlayInterface == NULL ){
+	// no joined and request remote descriptor? -> fail!
+	if( overlayInterface == NULL ) {
 		logging_error( "overlay interface not set, cannot resolve endpoint" );
 		return EndpointDescriptor::UNSPECIFIED;
 	}
 
-	// TODO: if this is not a onehop overlay the operation will go asynchronously
+	// resolve end-point descriptor from the base-overlay routing table
 	return overlayInterface->resolveNode( node );
 }
 
-
-bool BaseOverlay::bind(CommunicationListener* listener, const ServiceID& sid){
+// ----------------------------------------------------------------------------
+
+bool BaseOverlay::registerSidePort(SideportListener* _sideport) {
+	sideport = _sideport;
+	_sideport->configure( this );
+}
+
+bool BaseOverlay::unregisterSidePort(SideportListener* _sideport) {
+	sideport = &SideportListener::DEFAULT;
+}
+
+// ----------------------------------------------------------------------------
+
+bool BaseOverlay::bind(CommunicationListener* listener, const ServiceID& sid) {
 	logging_debug( "binding communication listener " << listener
-		<< " on serviceid " << sid.toString() );
-
-	if( communicationListeners.contains( sid ) ){
+			<< " on serviceid " << sid.toString() );
+
+	if( communicationListeners.contains( sid ) ) {
 		logging_error( "some listener already registered for service id "
-			<< sid.toString() );
+				<< sid.toString() );
 		return false;
 	}
@@ -444,25 +634,16 @@
 }
 
-bool BaseOverlay::registerSidePort(SideportListener* _sideport){
-	sideport = _sideport;
-	_sideport->configure( this );
-}
-
-bool BaseOverlay::unregisterSidePort(SideportListener* _sideport){
-	sideport = &SideportListener::DEFAULT;
-}
-
-bool BaseOverlay::unbind(CommunicationListener* listener, const ServiceID& sid){
-	logging_debug( "unbinding listener " << listener
-		<< " from serviceid " << sid.toString() );
-
-	if( !communicationListeners.contains( sid ) ){
+
+bool BaseOverlay::unbind(CommunicationListener* listener, const ServiceID& sid) {
+	logging_debug( "unbinding listener " << listener << " from serviceid " << sid.toString() );
+
+	if( !communicationListeners.contains( sid ) ) {
 		logging_warn( "cannot unbind listener. no listener registered on service id " << sid.toString() );
 		return false;
 	}
 
-	if( communicationListeners.get(sid) != listener ){
+	if( communicationListeners.get(sid) != listener ) {
 		logging_warn( "listener bound to service id " << sid.toString()
-			<< " is different than listener trying to unbind" );
+				<< " is different than listener trying to unbind" );
 		return false;
 	}
@@ -472,554 +653,734 @@
 }
 
-bool BaseOverlay::bind(NodeListener* listener){
-	logging_debug( "binding node listener " << listener );
-
-	NodeListenerVector::iterator i = find( nodeListeners.begin(), nodeListeners.end(), listener );
-	if( i != nodeListeners.end() ){
-		logging_warn( "node listener " << listener << " is already bound, cannot bind" );
+// ----------------------------------------------------------------------------
+
+bool BaseOverlay::bind(NodeListener* listener) {
+	logging_debug( "Binding node listener " << listener );
+
+	// already bound? yes-> warning
+	NodeListenerVector::iterator i =
+		find( nodeListeners.begin(), nodeListeners.end(), listener );
+	if( i != nodeListeners.end() ) {
+		logging_warn("Node listener " << listener << " is already bound!" );
 		return false;
 	}
 
+	// no-> add
 	nodeListeners.push_back( listener );
 	return true;
 }
 
-bool BaseOverlay::unbind(NodeListener* listener){
-	logging_debug( "unbinding node listener " << listener );
-
+bool BaseOverlay::unbind(NodeListener* listener) {
+	logging_debug( "Unbinding node listener " << listener );
+
+	// already unbound? yes-> warning
 	NodeListenerVector::iterator i = find( nodeListeners.begin(), nodeListeners.end(), listener );
-	if( i == nodeListeners.end() ){
-		logging_warn( "node listener " << listener << " is not bound, cannot unbind" );
+	if( i == nodeListeners.end() ) {
+		logging_warn( "Node listener " << listener << " is not bound!" );
 		return false;
 	}
 
+	// no-> remove
 	nodeListeners.erase( i );
 	return true;
 }
 
-void BaseOverlay::onLinkUp(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote){
-
-	logging_debug( "base overlay received linkup event " + id.toString() );
-	// TODO: updateOvlVis( getNodeID(id) );
-
-	//
-	// if we get up a link while we are in the
-	// join phase and this is the link that
-	// we have initiated towards the spovnet owner
-	// continue the join process by sending
-	// a join request message through the link
-	//
-
-	if( state == BaseOverlayStateJoinInitiated && id == initiatorLink){
-
+// ----------------------------------------------------------------------------
+
+void BaseOverlay::onLinkUp(const LinkID& id,
+	const NetworkLocator* local, const NetworkLocator* remote) {
+	logging_debug( "Link up with base communication link id=" << id );
+
+	// get descriptor for link
+	LinkDescriptor* ld = getDescriptor(id, true);
+
+	// handle initiator link
+	if(state == BaseOverlayStateJoinInitiated && id == initiatorLink) {
 		logging_info(
 			"Join has been initiated by me and the link is now up. " <<
-			"sending out join request for SpoVNet " << spovnetId.toString()
+			"Sending out join request for SpoVNet " << spovnetId.toString()
 		);
 
-		OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeJoinRequest, nodeId );
-		JoinRequest joinmsg( spovnetId, nodeId );
-		overMsg.encapsulate( &joinmsg );
-
-		state = BaseOverlayStateJoinInitiated; // state remains in JoinInitiated
-		bc->sendMessage( id, &overMsg );
-
+		// send join request message
+		OverlayMsg overlayMsg( OverlayMsg::typeJoinRequest, nodeId );
+		JoinRequest joinRequest( spovnetId, nodeId );
+		overlayMsg.encapsulate( &joinRequest );
+		bc->sendMessage( id, &overlayMsg );
 		return;
-
-	} // if( state == BaseOverlayStateJoinInitiated && id == initiatorLink)
-
-	//
-	// otherwise this is a link initiated by a service
-	// then we exchange update messages to exchange the
-	// service id and node id for the link. in this case
-	// we should have a link mapping for this link. if
-	// we have no link mapping this link was initiated by
-	// the remote side.
-	//
-
-	LinkMapping::iterator i = linkMapping.find( id );
-
-	if( i == linkMapping.end() ){
-
-		LinkItem item (id, NodeID::UNSPECIFIED, ServiceID::UNSPECIFIED, &CommunicationListener::DEFAULT );
-		linkMapping.insert( make_pair(id, item) );
-
+	}
+
+	// no link found? -> link establishment from remote, add one!
+	if (ld == NULL) {
+		ld = addDescriptor( id );
+		logging_debug( "onLinkUp (remote request) descriptor: " << ld );
+
+		// update descriptor
+		ld->fromRemote = true;
+		ld->communicationId = id;
+		ld->communicationUp = true;
+		ld->markAsUsed();
+
+		// in this case, do not inform listener, since service it unknown
+		// -> wait for update message!
+
+	// link mapping found? -> send update message with node-id and service id
 	} else {
-
-		logging_debug( "sending out OverlayMessageTypeUpdate" <<
-				" for service " << i->second.service.toString() <<
-				" with local node id " << nodeId.toString() <<
-				" on link " << id.toString() );
-
-		OverlayMsg overMsg(
-			OverlayMsg::OverlayMessageTypeUpdate,
-			i->second.service,
-			nodeId
-			);
-
-		bc->sendMessage( id, &overMsg );
-		i->second.markused();
-
-	} // if( i == linkMapping.end() )
-
-	// the link is only valid for the service when we receive
-	// the OverlayMessageTypeUpdate from the remote node and
-	// have the nodeid and serviceid for the link!
-}
-
-void BaseOverlay::onLinkDown(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote){
-
-	logging_debug( "link went down " << id.toString() );
-
-	//
-	// tell the service that the link went
-	// down and remove the mapping
-	//
-
-	LinkMapping::iterator i = linkMapping.find( id );
-	if( i == linkMapping.end() ) {
-		// this can also be one of the baseoverlay links that
-		// no mapping is stored for. therefore we issue no warning.
-		// it can also be a link that has been dropped and the
-		// mapping is already deleted in the dropLink function.
-		// also, the service notification is issued then in dropLink
-		return;
-	}
-
-	i->second.interface->onLinkDown( id, i->second.node );
-	sideport->onLinkDown( id, this->nodeId, i->second.node, this->spovnetId );
-
-	// delete all queued messages
-	if( i->second.waitingmsg.size() > 0 ){
-
-		logging_warn( "dropping link " << id.toString() <<
-			" that has " << i->second.waitingmsg.size() << " waiting messages" );
-
-		i->second.deleteWaiting();
-	}
-
-	linkMapping.erase( i );
-}
-
-void BaseOverlay::onLinkChanged(const LinkID& id, const NetworkLocator* oldlocal, const NetworkLocator* newlocal, const NetworkLocator* oldremote, const NetworkLocator* newremote){
-
-	logging_debug( "link changed " << id.toString() );
-
-	//
-	// tell the service that the link changed
-	//
-
-	LinkMapping::iterator i = linkMapping.find( id );
-	if( i == linkMapping.end() ) return;
-
-	i->second.interface->onLinkChanged( id, i->second.node );
-	sideport->onLinkChanged( id, this->nodeId, i->second.node, this->spovnetId );
-
-	// TODO call onLinkQoSChanged?
-
-	i->second.markused();
-}
-
-void BaseOverlay::onLinkFail(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote){
-
-	logging_debug( "link failed " << id.toString() );
-
-	//
-	// tell the service that the link failed
-	//
-
-	LinkMapping::iterator i = linkMapping.find( id );
-	if( i == linkMapping.end() ) return;
-
-	i->second.interface->onLinkFail( id, i->second.node );
-	sideport->onLinkFail( id, this->nodeId, i->second.node, this->spovnetId );
-
-	i->second.markused();
-}
-
-void BaseOverlay::onLinkQoSChanged(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote, const QoSParameterSet& qos) {
-
-	logging_debug( "link qos changed " << id.toString() );
-
-	//
-	// tell the service that the link qos has changed
-	//
-
-	LinkMapping::iterator i = linkMapping.find( id );
-	if( i == linkMapping.end() ) return;
-
-	// TODO: convert QoSParameterSet to the LinkProperties properties
-	// TODO: currently not in the interface: i->second.interface->onLinkQoSChanged( id, i->second.node, LinkProperties::DEFAULT );
-
-	i->second.markused();
-}
-
-bool BaseOverlay::onLinkRequest( const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote ){
-
-	// also see in the receiveMessage function. there the higher layer service
-	// is asked whether to accept link requests, but there a basic link association is
-	// already built up, so we know the node id
-	logging_debug("received link request from " << remote->toString() << ", accepting");
+		logging_debug( "onLinkUp descriptor (initiated locally):" << ld );
+
+		// note: necessary to validate the link on the remote side!
+		logging_debug( "Sending out update" <<
+			" for service " << ld->service.toString() <<
+			" with local node id " << nodeId.toString() <<
+			" on link " << ld->overlayId.toString() );
+
+		// update descriptor
+		ld->markAsUsed();
+		ld->communicationUp = true;
+
+		// if link is a relayed link ->convert to direct link
+		if (ld->relay) {
+			ld->up = true;
+			ld->relay = false;
+			ld->localRelay = NodeID::UNSPECIFIED;
+			OverlayMsg overMsg( OverlayMsg::typeDirectLink, ld->service, nodeId );
+			overMsg.setRelayLink( ld->remoteLinkId );
+			bc->sendMessage( ld->communicationId, &overMsg );
+		}
+
+		// compile and send update message
+		OverlayMsg overlayMsg( OverlayMsg::typeUpdate, ld->service, nodeId );
+		overlayMsg.setAutoLink( ld->autolink );
+		bc->sendMessage( ld->communicationId, &overlayMsg );
+	}
+}
+
+void BaseOverlay::onLinkDown(const LinkID& id,
+	const NetworkLocator* local, const NetworkLocator* remote) {
+
+	// get descriptor for link
+	LinkDescriptor* ld = getDescriptor(id, true);
+	if ( ld == NULL ) return; // not found? ->ignore!
+	logging_force( "onLinkDown descriptor: " << ld );
+
+	// inform listeners about link down
+	ld->communicationUp = false;
+	ld->listener->onLinkDown( ld->overlayId, ld->remoteNode );
+	sideport->onLinkDown( id, this->nodeId, ld->remoteNode, this->spovnetId );
+
+	// delete all queued messages (auto links)
+	if( ld->messageQueue.size() > 0 ) {
+		logging_warn( "Dropping link " << id.toString() << " that has "
+				<< ld->messageQueue.size() << " waiting messages" );
+		ld->flushQueue();
+	}
+
+	// erase mapping
+	eraseDescriptor(ld->overlayId);
+}
+
+void BaseOverlay::onLinkChanged(const LinkID& id,
+	const NetworkLocator* oldlocal, const NetworkLocator* newlocal,
+	const NetworkLocator* oldremote, const NetworkLocator* newremote) {
+
+	// get descriptor for link
+	LinkDescriptor* ld = getDescriptor(id, true);
+	if ( ld == NULL ) return; // not found? ->ignore!
+	logging_debug( "onLinkChanged descriptor: " << ld );
+
+	// inform listeners
+	ld->listener->onLinkChanged( ld->overlayId, ld->remoteNode );
+	sideport->onLinkChanged( id, this->nodeId, ld->remoteNode, this->spovnetId );
+
+	// autolinks: refresh timestamp
+	ld->markAsUsed();
+}
+
+void BaseOverlay::onLinkFail(const LinkID& id,
+	const NetworkLocator* local, const NetworkLocator* remote) {
+	logging_debug( "Link fail with base communication link id=" << id );
+
+	// get descriptor for link
+	LinkDescriptor* ld = getDescriptor(id, true);
+	if ( ld == NULL ) return; // not found? ->ignore!
+	logging_debug( "Link failed id=" << ld->overlayId.toString() );
+
+	// inform listeners
+	ld->listener->onLinkFail( ld->overlayId, ld->remoteNode );
+	sideport->onLinkFail( id, this->nodeId, ld->remoteNode, this->spovnetId );
+
+	// autolinks: refresh timestamp
+	ld->markAsUsed();
+}
+
+void BaseOverlay::onLinkQoSChanged(const LinkID& id, const NetworkLocator* local,
+	const NetworkLocator* remote, const QoSParameterSet& qos) {
+	logging_debug( "Link quality changed with base communication link id=" << id );
+
+	// get descriptor for link
+	LinkDescriptor* ld = getDescriptor(id, true);
+	if ( ld == NULL ) return; // not found? ->ignore!
+	logging_debug( "Link quality changed id=" << ld->overlayId.toString() );
+
+	// autolinks: refresh timestamp
+	ld->markAsUsed();
+}
+
+bool BaseOverlay::onLinkRequest( const LinkID& id, const NetworkLocator* local,
+	const NetworkLocator* remote ) {
+	logging_debug("Accepting link request from " << remote->toString() );
 	return true;
 }
 
-
+/// handles a message from base communication
 bool BaseOverlay::receiveMessage(const Message* message,
-	const LinkID& link, const NodeID&
-	/*the nodeid is invalid in this case! removed var to prevent errors*/ ){
+		const LinkID& link, const NodeID& ) {
+	// get descriptor for link
+	LinkDescriptor* ld = getDescriptor( link, true );
+
+	// link known?
+	if (ld == NULL) { // no-> handle with unspecified params
+		logging_debug("Received message from base communication, link descriptor unknown" );
+		return handleMessage( message, LinkID::UNSPECIFIED, link, NodeID::UNSPECIFIED );
+	} else { // yes -> handle with overlay link id
+		logging_debug("Received message from base communication, link id=" << ld->overlayId.toString() );
+		return handleMessage( message, ld->overlayId, link, NodeID::UNSPECIFIED );
+	}
+}
+
+// ----------------------------------------------------------------------------
+
+/// handles a message from an overlay
+void BaseOverlay::incomingRouteMessage( Message* msg, const LinkID& link, const NodeID& source ) {
+	logging_debug("Received message from overlay -- "
+		<< " link id=" << link.toString()
+		<< " node id=" << source.toString() );
+	handleMessage( msg, link, LinkID::UNSPECIFIED, source );
+}
+
+// ----------------------------------------------------------------------------
+
+/// handles an incoming message
+bool BaseOverlay::handleMessage( const Message* message,
+	const LinkID& boLink, const LinkID& bcLink, const NodeID& remoteNode ) {
+	logging_debug( "Handling message: " << message->toString());
 
 	// decapsulate overlay message
-	logging_debug( "receiveMessage: " << message->toString());
-	OverlayMsg* overlayMsg = const_cast<Message*>(message)->decapsulate<OverlayMsg>();
+	OverlayMsg* overlayMsg =
+		const_cast<Message*>(message)->decapsulate<OverlayMsg>();
 	if( overlayMsg == NULL ) return false;
 
 	// mark the link as in action
-	LinkMapping::iterator item = linkMapping.find( link );
-	if( item != linkMapping.end() ) item->second.markused();
-
-	/* ************************************************************************
-	/* handle user date that we forward to the appropriate service using the
-	 * service id in the message. as we don't know the class of message that
-	 * the service handles, we forward it as a pure Message
-	 */
-	if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeData) ) {
-
-		logging_debug( "baseoverlay received message of type OverlayMessageTypeData" );
-
-		const ServiceID& service = overlayMsg->getService();
-		CommunicationListener* serviceListener = communicationListeners.get( service );
-
-		logging_debug( "received data for service " << service.toString() );
-
-		if( serviceListener != NULL )
-			serviceListener->onMessage( overlayMsg, overlayMsg->getSourceNode(), link );
-
-		return true;
-
-	} // if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeData) )
-
-	/* ************************************************************************
-	/* Handle spovnet instance join requests
-	 */
-	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinRequest) ){
-
-		logging_debug(
-			"baseoverlay received message of type OverlayMessageTypeJoinRequest"
-		);
-
-		JoinRequest* joinReq = overlayMsg->decapsulate<JoinRequest>();
-		logging_info( "received join request for spovnet " <<
-					 joinReq->getSpoVNetID().toString() );
-
-		/* make sure that the node actually wants to join
-		 * the correct spovnet id that we administrate */
-		if( joinReq->getSpoVNetID() != spovnetId ){
-			logging_error( "received join request for spovnet we don't handle " <<
+	LinkDescriptor* ld = getDescriptor(boLink);
+	if (ld == NULL) ld = getDescriptor(bcLink, true);
+	if (ld != NULL) {
+		ld->markAsUsed();
+		ld->markAlive();
+	}
+
+	switch ( overlayMsg->getType() ) {
+		// ---------------------------------------------------------------------
+		// Handle spovnet instance join requests
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeJoinRequest: {
+
+			// decapsulate message
+			JoinRequest* joinReq = overlayMsg->decapsulate<JoinRequest>();
+			logging_info( "Received join request for spovnet " <<
 					joinReq->getSpoVNetID().toString() );
-			return false;
-		}
-
-		//
-		// only if all services allow the node to join it is allowed
-		// using the isJoinAllowed interface security policies can be
-		// implemented by higher layer services
-		//
-
-		// TODO: here you can implement mechanisms to deny joining of a node
-		bool allow = true;
-
-		logging_info( "sending back join reply for spovnet " <<
-				spovnetId.toString() << " to node " <<
-				overlayMsg->getSourceNode().toString() <<
-				". result: " << (allow ? "allowed" : "denied") );
-
-		joiningNodes.push_back( overlayMsg->getSourceNode() );
-
-		//
-		// send back our spovnetid, default overlay parameters, join allow
-		// result, and ourself as the end-point to bootstrap the overlay against
-		//
-
-		assert( overlayInterface != NULL );
-		OverlayParameterSet parameters = overlayInterface->getParameters();
-
-		OverlayMsg retmsg( OverlayMsg::OverlayMessageTypeJoinReply, nodeId );
-		JoinReply replyMsg( spovnetId, parameters,
+
+			// check spovnet id
+			if( joinReq->getSpoVNetID() != spovnetId ) {
+				logging_error(
+					"Received join request for spovnet we don't handle " <<
+					joinReq->getSpoVNetID().toString() );
+				return false;
+			}
+
+			// TODO: here you can implement mechanisms to deny joining of a node
+			bool allow = true;
+			logging_info( "Sending join reply for spovnet " <<
+					spovnetId.toString() << " to node " <<
+					overlayMsg->getSourceNode().toString() <<
+					". Result: " << (allow ? "allowed" : "denied") );
+			joiningNodes.push_back( overlayMsg->getSourceNode() );
+
+			// return overlay parameters
+			assert( overlayInterface != NULL );
+			logging_debug( "Using bootstrap end-point "
+				<< getEndpointDescriptor().toString() )
+			OverlayParameterSet parameters = overlayInterface->getParameters();
+			OverlayMsg retmsg( OverlayMsg::typeJoinReply, nodeId );
+			JoinReply replyMsg( spovnetId, parameters,
 					allow, getEndpointDescriptor() );
-
-		retmsg.encapsulate(&replyMsg);
-		bc->sendMessage( link, &retmsg );
-
-		return true;
-
-	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinRequest))
-
-	/* ************************************************************************
-	 * handle replies to spovnet instance join requests
-	 */
-	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinReply) &&
-						state == BaseOverlayStateJoinInitiated){
-
-		logging_debug(
-			"baseoverlay received message of type OverlayMessageTypeJoinReply");
-
-		JoinReply* replyMsg = overlayMsg->decapsulate<JoinReply>();
-		logging_info( "received spovnet join reply" );
-
-		// ensure that we actually wanted to get into the spovnet whose id is
-		// in the message
-		if( replyMsg->getSpoVNetID() != spovnetId ){
-			logging_error( "received spovnet join reply for spovnet " <<
-					replyMsg->getSpoVNetID().toString() <<
-					" but we wanted to join spovnet " <<
+			retmsg.encapsulate(&replyMsg);
+			bc->sendMessage( bcLink, &retmsg );
+			return true;
+		}
+
+		// ---------------------------------------------------------------------
+		// handle replies to spovnet instance join requests
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeJoinReply: {
+
+			// decapsulate message
+			logging_debug("received join reply message");
+			JoinReply* replyMsg = overlayMsg->decapsulate<JoinReply>();
+			assert(state == BaseOverlayStateJoinInitiated);
+
+			// correct spovnet?
+			if( replyMsg->getSpoVNetID() != spovnetId ) { // no-> fail
+				logging_error( "Received SpoVNet join reply for " <<
+						replyMsg->getSpoVNetID().toString() <<
+						" != " << spovnetId.toString() );
+				return false;
+			}
+
+			// access granted? no -> fail
+			if( !replyMsg->getJoinAllowed() ) {
+				logging_error( "Our join request has been denied" );
+
+				// drop initiator link
+				bc->dropLink( initiatorLink );
+				initiatorLink = LinkID::UNSPECIFIED;
+				state = BaseOverlayStateInvalid;
+
+				// inform all registered services of the event
+				BOOST_FOREACH( NodeListener* i, nodeListeners )
+					i->onJoinFailed( spovnetId );
+				return true;
+			}
+
+			// access has been granted -> continue!
+			logging_info("Join request has been accepted for spovnet " <<
 					spovnetId.toString() );
 
-			// state does not change here, maybe the reply does come in later
-			return false;
-		}
-
-		// if we did not get access to the spovnet notify of the failure and
-		// close the link to the initiator
-		if( ! replyMsg->getJoinAllowed() ){
-
-			logging_error( "our join request has been denied" );
-
-			bc->dropLink( initiatorLink );
-			initiatorLink = LinkID::UNSPECIFIED;
-			state = BaseOverlayStateInvalid;
-
-			// inform all registered services of the event
-			BOOST_FOREACH( NodeListener* i, nodeListeners ){
+			// create overlay structure from spovnet parameter set
+			overlayInterface = OverlayFactory::create(
+				*this, replyMsg->getParam(), nodeId, this );
+
+			// overlay structure supported? no-> fail!
+			if( overlayInterface == NULL ) {
+				logging_error( "overlay structure not supported" );
+
+				bc->dropLink( initiatorLink );
+				initiatorLink = LinkID::UNSPECIFIED;
+				state = BaseOverlayStateInvalid;
+
+				// inform all registered services of the event
+				BOOST_FOREACH( NodeListener* i, nodeListeners )
 				i->onJoinFailed( spovnetId );
+
+				return true;
 			}
 
-			return true;
-		}
-
-		logging_info( "join request has been accepted for spovnet " <<
-				spovnetId.toString() );
-
-		// if we did get access to the spovnet we try to create the overlay
-		// structure as given in the reply message
-		overlayInterface = OverlayFactory::create( *this,
-				replyMsg->getParam(), nodeId, this );
-
-		if( overlayInterface == NULL ){
-			logging_error( "overlay structure not supported" );
-
-			bc->dropLink( initiatorLink );
-			initiatorLink = LinkID::UNSPECIFIED;
-			state = BaseOverlayStateInvalid;
+			// everything ok-> join the overlay!
+			state = BaseOverlayStateCompleted;
+			overlayInterface->createOverlay();
+			logging_debug( "Using bootstrap end-point "
+				<< replyMsg->getBootstrapEndpoint().toString() );
+			overlayInterface->joinOverlay( replyMsg->getBootstrapEndpoint() );
+
+			// update ovlvis
+			ovl.visChangeNodeColor( ovlId, nodeId, OvlVis::NODE_COLORS_GREEN);
 
 			// inform all registered services of the event
 			BOOST_FOREACH( NodeListener* i, nodeListeners )
-				i->onJoinFailed( spovnetId );
+				i->onJoinCompleted( spovnetId );
 
 			return true;
 		}
 
-		/* now start the join process for the overlay. the join process for the
-		 * spovnet baseoverlay is now complete. we use the endpoint for overlay
-		 * structure bootstrapping that the initiator provided in his reply
-		 * message */
-		state = BaseOverlayStateCompleted;
-		ovl.visChangeNodeColor( ovlId, nodeId, OvlVis::NODE_COLORS_GREEN);
-
-		overlayInterface->createOverlay();
-		overlayInterface->joinOverlay( replyMsg->getBootstrapEndpoint() );
-
-		// inform all registered services of the event
-		BOOST_FOREACH( NodeListener* i, nodeListeners ){
-			i->onJoinCompleted( spovnetId );
-		}
-
-		return true;
-
-	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinReply) && state == BaseOverlayStateJoinInitiated)
-
-
-	/* ************************************************************************
-     * handle update messages for link establishment
-     */
-	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeUpdate) ){
-
-		logging_debug(
-			"baseoverlay received message of type OverlayMessageTypeUpdate"
-		);
-
-		const NodeID& sourcenode = overlayMsg->getSourceNode();
-		const ServiceID& service = overlayMsg->getService();
-
-		// linkmapping for the link available? no-> ignore
-		LinkMapping::iterator i = linkMapping.find( link );
-		if( i == linkMapping.end() ) {
-			logging_warn( "received overlay update message for link " <<
-					link.toString() << " for which we have no mapping" );
-			return false;
-		}
-
-		// update our link mapping information for this link
-		bool changed = ( i->second.node != sourcenode ) || ( i->second.service != service );
-		i->second.node = sourcenode;
-		i->second.service = service;
-
-		// if our link information changed, we send out an update, too
-		if( changed ){
-			OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeUpdate, i->second.service, nodeId );
-			bc->sendMessage( link, &overMsg );
-		}
-
-		// set the correct listener service for the linkitem
-		// now we can tell the registered service of the linkup event
-		if( !communicationListeners.contains( service ) ){
-			logging_warn( "linkup event for service that has not been registered" );
-			return false;
-		}
-
-		CommunicationListener* iface = communicationListeners.get( service );
-		if( iface == NULL || iface == &CommunicationListener::DEFAULT ){
-			logging_warn( "linkup event for service that has been registered "
-				"with a NULL interface" );
+		// ---------------------------------------------------------------------
+		// handle data forward messages
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeData: {
+
+			// get service
+			const ServiceID& service = overlayMsg->getService();
+			logging_debug( "received data for service " << service.toString() );
+
+			// find listener
+			CommunicationListener* listener =
+				communicationListeners.get( service );
+			if( listener == NULL ) return true;
+
+			// delegate data message
+			listener->onMessage( overlayMsg,
+				overlayMsg->getSourceNode(), ld->overlayId );
+
 			return true;
 		}
 
-		i->second.interface = iface;
-		i->second.markused();
-
-		// ask the service whether it wants to accept this link
-		if( !iface->onLinkRequest(sourcenode) ){
-
-			logging_debug("link " << link.toString() <<
-								" has been denied by service " << service.toString() << ", dropping link");
-
-			// prevent onLinkDown calls to the service
-			i->second.interface = &CommunicationListener::DEFAULT;
-			// drop the link
-			dropLink( link );
-
-			return true;
-		}
-
-		//
-		// link has been accepted, link is now up, send messages out first
-		//
-
-		i->second.linkup = true;
-		logging_debug("link " << link.toString() <<
-						" has been accepted by service " << service.toString() << " and is now up");
-
-		if( i->second.waitingmsg.size() > 0 ){
-			logging_info( "sending out queued messages on link " << link.toString() );
-
-			BOOST_FOREACH( Message* msg, i->second.waitingmsg ){
-				sendMessage( msg, link );
-				delete msg;
+		// ---------------------------------------------------------------------
+		// handle update messages for link establishment
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeUpdate: {
+			logging_debug("Received type update message on link " << ld );
+
+			// get info
+			const NodeID& sourcenode = overlayMsg->getSourceNode();
+			const ServiceID& service = overlayMsg->getService();
+
+			// no link descriptor available -> error!
+			if( ld == NULL ) {
+				logging_warn( "received overlay update message for link " <<
+						ld->overlayId.toString() << " for which we have no mapping" );
+				return false;
 			}
 
-			i->second.waitingmsg.clear();
-		}
-
-		// call the notification functions
-		iface->onLinkUp( link, sourcenode );
-		sideport->onLinkUp( link, nodeId, sourcenode, this->spovnetId );
-
-		return true;
-
-	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeUpdate) )
-
-	/* ************************************************************************
-	 * handle bye messages
-	 */
-	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeBye) ) {
-
-		logging_debug( "BaseOverlay received message of type OverlayMessageTypeBye" );
-		logging_debug( "Received bye message from " <<
-				overlayMsg->getSourceNode().toString() );
-
-		/* if we are the initiator and receive a bye from a node
-		 * the node just left. if we are a node and receive a bye
-		 * from the initiator, we have to close, too.
-		 */
-		if( overlayMsg->getSourceNode() == spovnetInitiator ){
-
-			bc->dropLink( initiatorLink );
-			initiatorLink = LinkID::UNSPECIFIED;
-			state = BaseOverlayStateInvalid;
-
-			logging_fatal( "initiator ended spovnet" );
-
-			// inform all registered services of the event
-			BOOST_FOREACH( NodeListener* i, nodeListeners ){
-				i->onLeaveFailed( spovnetId );
+			// update our link mapping information for this link
+			bool changed =
+				( ld->remoteNode != sourcenode ) || ( ld->service != service );
+			ld->remoteNode = sourcenode;
+			ld->service = service;
+			ld->autolink = overlayMsg->isAutoLink();
+
+			// if our link information changed, we send out an update, too
+			if( changed ) {
+				OverlayMsg overMsg( OverlayMsg::typeUpdate, ld->service, nodeId );
+				overMsg.setAutoLink(ld->autolink);
+				bc->sendMessage( ld->communicationId, &overMsg );
 			}
 
-		} else {
-			// a node that said goodbye and we are the initiator don't have to
-			// do much here, as the node also will go out of the overlay
-			// structure
-			logging_info( "node left " << overlayMsg->getSourceNode() );
-		}
-
-		return true;
-
-	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeBye))
-
-	/* ************************************************************************
-	 * handle link request forwarded through the overlay
-	 */
-	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeLinkRequest)) {
-		LinkRequest* linkReq = overlayMsg->decapsulate<LinkRequest>();
-		const ServiceID& service = overlayMsg->getService();
-		if (linkReq->isReply()) {
-
-			// find link
-			PendingLinkMap::iterator i = pendingLinks.find( linkReq->getNonce() );
-			if ( i == pendingLinks.end() ) {
-				logging_error( "Nonce not found in link request" );
+			// service registered? no-> error!
+			if( !communicationListeners.contains( service ) ) {
+				logging_warn( "Link up: event listener has not been registered" );
+				return false;
+			}
+
+			// default or no service registered?
+			CommunicationListener* listener = communicationListeners.get( service );
+			if( listener == NULL || listener == &CommunicationListener::DEFAULT ) {
+				logging_warn("Link up: event listener is default or null!" );
 				return true;
 			}
 
-			// debug message
-			logging_debug( "LinkRequest reply received. Establishing link "
-				<< i->second << " to " << (linkReq->getEndpoint()->toString())
-				<< " for service " << service.toString()
-				<< " with nonce " << linkReq->getNonce()
+			// update descriptor
+			ld->listener = listener;
+			ld->markAsUsed();
+			ld->markAlive();
+
+			// ask the service whether it wants to accept this link
+			if( !listener->onLinkRequest(sourcenode) ) {
+
+				logging_debug("Link id=" << ld->overlayId.toString() <<
+					" has been denied by service " << service.toString() << ", dropping link");
+
+				// prevent onLinkDown calls to the service
+				ld->listener = &CommunicationListener::DEFAULT;
+
+				// drop the link
+				dropLink( ld->overlayId );
+				return true;
+			}
+
+			// set link up
+			ld->up = true;
+			logging_debug(
+				   "Link " << ld->overlayId.toString()
+				<< " has been accepted by service " << service.toString()
+				<< " and is now up"
 			);
 
-			// establishing link
-			bc->establishLink( *linkReq->getEndpoint(), i->second );
-		} else {
-			OverlayMsg overlay_msg( OverlayMsg::OverlayMessageTypeLinkRequest, service, nodeId );
-			LinkRequest link_request_msg(
-					linkReq->getNonce(), &bc->getEndpointDescriptor(), true );
-			overlay_msg.encapsulate( &link_request_msg );
-
-			// debug message
-			logging_debug( "Sending LinkRequest reply for link with nonce " <<
-					linkReq->getNonce()	);
-
-			// route message back over overlay
-			overlayInterface->routeMessage(
-				overlayMsg->getSourceNode(), &overlay_msg
-			);
-		}
-	} // if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeLinkRequest))
-
-	/* ************************************************************************
-	 * unknown message type ... error!
-	 */
-	else {
-
-		logging_error( "received message in invalid state! don't know " <<
-				"what to do with this message of type " <<
-				overlayMsg->getType() );
-		return false;
-
-	} // else
-
+			// auto links: link has been accepted -> send queued messages
+			if( ld->messageQueue.size() > 0 ) {
+				logging_info( "sending out queued messages on link " <<
+					ld->overlayId.toString() );
+				BOOST_FOREACH( Message* msg, ld->messageQueue ) {
+					sendMessage( msg, ld->overlayId );
+					delete msg;
+				}
+				ld->messageQueue.clear();
+			}
+
+			// call the notification functions
+			listener->onLinkUp( ld->overlayId, sourcenode );
+			sideport->onLinkUp( ld->overlayId, nodeId, sourcenode, this->spovnetId );
+
+			return true;
+		}
+
+		// ---------------------------------------------------------------------
+		// handle bye messages
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeBye: {
+			logging_debug( "received bye message from " <<
+					overlayMsg->getSourceNode().toString() );
+
+			/* if we are the initiator and receive a bye from a node
+			 * the node just left. if we are a node and receive a bye
+			 * from the initiator, we have to close, too.
+			 */
+			if( overlayMsg->getSourceNode() == spovnetInitiator ) {
+
+				bc->dropLink( initiatorLink );
+				initiatorLink = LinkID::UNSPECIFIED;
+				state = BaseOverlayStateInvalid;
+
+				logging_fatal( "initiator ended spovnet" );
+
+				// inform all registered services of the event
+				BOOST_FOREACH( NodeListener* i, nodeListeners )
+					i->onLeaveFailed( spovnetId );
+
+			} else {
+				// a node that said goodbye and we are the initiator don't have to
+				// do much here, as the node also will go out of the overlay
+				// structure
+				logging_info( "node left " << overlayMsg->getSourceNode() );
+			}
+
+			return true;
+
+		}
+
+		// ---------------------------------------------------------------------
+		// handle link request forwarded through the overlay
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeLinkRequest: {
+
+			// decapsulate message
+			LinkRequest* linkReq = overlayMsg->decapsulate<LinkRequest>();
+			const ServiceID& service = overlayMsg->getService();
+
+			// is request reply?
+			if ( linkReq->isReply() ) {
+
+				// find link
+				PendingLinkMap::iterator i = pendingLinks.find( linkReq->getNonce() );
+				if ( i == pendingLinks.end() ) {
+					logging_error( "Nonce not found in link request" );
+					return true;
+				}
+
+				// debug message
+				logging_debug( "Link request reply received. Establishing link "
+					<< i->second << " to " << (linkReq->getEndpoint()->toString())
+					<< " for service " << service.toString()
+					<< " with nonce "  << linkReq->getNonce()
+					<< " using relay " << linkReq->getRelay().toString()
+					<< " and remote link id=" << linkReq->getRemoteLinkId()
+				);
+
+				// get descriptor
+				LinkDescriptor* ldn = getDescriptor(i->second);
+
+				// check if link request reply has a relay node ...
+				if (!linkReq->getRelay().isUnspecified()) { // yes->
+					ldn->up = true;
+					ldn->relay = true;
+					if (ldn->localRelay.isUnspecified())  {
+						logging_error("On LinkRequest reply: local relay is unspecifed on link " << ldn );
+						showLinkState();
+					}
+					ldn->remoteRelay  = linkReq->getRelay();
+					ldn->remoteLinkId = linkReq->getRemoteLinkId();
+					ldn->remoteNode   = overlayMsg->getSourceNode();
+
+					ldn->markAlive();
+
+					// compile and send update message
+					OverlayMsg _overlayMsg( OverlayMsg::typeUpdate, ldn->service, nodeId );
+					_overlayMsg.setAutoLink(ldn->autolink);
+					sendMessage( &_overlayMsg, ldn );
+
+					// auto links: link has been accepted -> send queued messages
+					if( ldn->messageQueue.size() > 0 ) {
+						logging_info( "Sending out queued messages on link " <<
+							ldn->overlayId.toString() );
+						BOOST_FOREACH( Message* msg, ldn->messageQueue ) {
+							sendMessage( msg, ldn->overlayId );
+							delete msg;
+						}
+						ldn->messageQueue.clear();
+					}
+
+					ldn->listener->onLinkUp( ldn->overlayId, ldn->remoteNode );
+
+					// try to establish a direct link
+					ldn->communicationId =
+						bc->establishLink( *linkReq->getEndpoint(), i->second );
+				}
+
+				// no relay node-> use overlay routing
+				else {
+					ldn->up = true;
+
+					// establish direct link
+					ldn->communicationId =
+							bc->establishLink( *linkReq->getEndpoint(), i->second );
+				}
+			} else {
+				logging_debug( "Link request received from node id="
+						<< overlayMsg->getSourceNode() );
+
+				// create link descriptor
+				LinkDescriptor* ldn =
+					createLinkDescriptor(overlayMsg->getSourceNode(),
+							overlayMsg->getService(), LinkID::UNSPECIFIED );
+				assert(!ldn->overlayId.isUnspecified());
+
+				// create reply message
+				OverlayMsg overlay_msg( OverlayMsg::typeLinkRequest, service, nodeId );
+				LinkRequest link_request_msg(
+					linkReq->getNonce(),
+					&bc->getEndpointDescriptor(),
+					true, ldn->overlayId, ldn->localRelay
+				);
+				overlay_msg.encapsulate( &link_request_msg );
+
+				// debug message
+				logging_debug( "Sending LinkRequest reply for link with nonce " <<
+						linkReq->getNonce() );
+
+				// if this is a relay link-> update information & inform listeners
+				if (!linkReq->getRelay().isUnspecified()) {
+					// set flags
+					ldn->up = true;
+					ldn->relay = true;
+					if (ldn->localRelay.isUnspecified()) {
+						logging_error("On LinkRequest request: local relay is unspecifed on link " << ldn );
+						showLinkState();
+					}
+					ldn->remoteRelay  = linkReq->getRelay();
+					ldn->remoteNode   = overlayMsg->getSourceNode();
+					ldn->remoteLinkId = linkReq->getRemoteLinkId();
+					ldn->listener->onLinkUp( ldn->overlayId, ldn->remoteNode );
+				}
+
+				// route message back over overlay
+				sendMessage( &overlay_msg, ldn );
+			}
+			return true;
+		}
+
+		// ---------------------------------------------------------------------
+		// handle relay message to forward messages
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeRelay: {
+
+			// decapsulate message
+			RelayMessage* relayMsg = overlayMsg->decapsulate<RelayMessage>();
+
+			// is relay message informative?
+			switch (relayMsg->getType()) {
+
+				// handle relay notification
+				case RelayMessage::typeInform: {
+					logging_info("Received relay information message with"
+							<< " relay " << relayMsg->getRelayNode()
+							<< " destination " << relayMsg->getDestNode() );
+
+					// mark incoming link as relay
+					if (ld!=NULL) ld->markAsRelay();
+
+					// am I the destination of this message? yes->
+					if (relayMsg->getDestNode() == nodeId ) {
+						// deliver relay message locally!
+						logging_debug("Relay message reached destination. Handling the message.");
+						handleMessage( relayMsg, relayMsg->getDestLink(), LinkID::UNSPECIFIED, remoteNode );
+						return true;
+					}
+
+					// create route message
+					OverlayMsg _overMsg( *overlayMsg );
+					RelayMessage _relayMsg( *relayMsg );
+					_relayMsg.setType( RelayMessage::typeRoute );
+					_overMsg.encapsulate( &_relayMsg );
+
+					// forward message
+					if (relayMsg->getRelayNode() == nodeId || relayMsg->getRelayNode().isUnspecified()) {
+						logging_info("Routing relay message to " << relayMsg->getDestNode().toString() );
+						overlayInterface->routeMessage(relayMsg->getDestNode(), &_overMsg );
+					} else {
+						logging_info("Routing relay message to " << relayMsg->getRelayNode().toString() );
+						overlayInterface->routeMessage(relayMsg->getRelayNode(), &_overMsg );
+					}
+					return true;
+				}
+
+				// handle relay routing
+				case RelayMessage::typeRoute: {
+					logging_info("Received relay route message with"
+							<< " relay " << relayMsg->getRelayNode()
+							<< " destination " << relayMsg->getDestNode() );
+
+					// mark incoming link as relay
+					if (ld!=NULL) ld->markAsRelay();
+
+					// am I the destination of this message? yes->
+					if (relayMsg->getDestNode() == nodeId ) {
+						// deliver relay message locally!
+						logging_debug("Relay message reached destination. Handling the message.");
+						handleMessage( relayMsg, relayMsg->getDestLink(), LinkID::UNSPECIFIED, remoteNode );
+						return true;
+					}
+
+					// am I the relay for this message? yes->
+					if (relayMsg->getRelayNode() == nodeId ) {
+						logging_debug("I'm the relay for this message. Sending to destination.");
+						OverlayMsg _overMsg( *overlayMsg );
+						RelayMessage _relayMsg( *relayMsg );
+						_overMsg.encapsulate(&_relayMsg);
+
+						/// this must be handled by using relay link!
+						overlayInterface->routeMessage(relayMsg->getDestNode(), &_overMsg );
+						return true;
+					}
+
+					// error: I'm not a relay or destination!
+					logging_error("This node is neither relay nor destination. Dropping Message!");
+					return true;
+				}
+				default: {
+					logging_error("RelayMessage Unknown!");
+					return true;
+				}
+			}
+
+			break;
+		}
+
+		// ---------------------------------------------------------------------
+		// handle keep-alive messages
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeKeepAlive: {
+			if ( ld != NULL ) {
+				//logging_force("Keep-Alive for "<< ld->overlayId);
+				ld->markAlive();
+			}
+			break;
+		}
+
+		// ---------------------------------------------------------------------
+		// handle direct link replacement messages
+		// ---------------------------------------------------------------------
+		case OverlayMsg::typeDirectLink: {
+			LinkDescriptor* rld = getDescriptor( overlayMsg->getRelayLink() );
+			rld->communicationId = ld->communicationId;
+			rld->relay = false;
+			rld->localRelay = NodeID::UNSPECIFIED;
+			rld->remoteRelay = NodeID::UNSPECIFIED;
+			eraseDescriptor(ld->overlayId);
+			break;
+		}
+
+		// ---------------------------------------------------------------------
+		// handle unknown message type
+		// ---------------------------------------------------------------------
+		default: {
+			logging_error( "received message in invalid state! don't know " <<
+					"what to do with this message of type " <<
+					overlayMsg->getType() );
+			return false;
+		}
+
+	} /* switch */
 	return false;
 }
 
-void BaseOverlay::broadcastMessage(Message* message, const ServiceID& service){
+// ----------------------------------------------------------------------------
+
+void BaseOverlay::broadcastMessage(Message* message, const ServiceID& service) {
 
 	logging_debug( "broadcasting message to all known nodes " <<
@@ -1027,9 +1388,6 @@
 
 	OverlayInterface::NodeList nodes = overlayInterface->getKnownNodes();
-
 	OverlayInterface::NodeList::iterator i = nodes.begin();
-	OverlayInterface::NodeList::iterator iend = nodes.end();
-
-	for( ; i != iend; i++ ){
+	for(; i != nodes.end(); i++ ) {
 		if( *i == nodeId) continue; // don't send to ourselfs
 		sendMessage( message, *i, service );
@@ -1038,102 +1396,121 @@
 
 vector<NodeID> BaseOverlay::getOverlayNeighbors() const {
-	// the known nodes _can_ also include our
-	// node, so we remove ourselfs
-
+	// the known nodes _can_ also include our node, so we remove ourself
 	vector<NodeID> nodes = overlayInterface->getKnownNodes();
 	vector<NodeID>::iterator i = find( nodes.begin(), nodes.end(), this->nodeId );
 	if( i != nodes.end() ) nodes.erase( i );
-
 	return nodes;
 }
 
-void BaseOverlay::updateOvlVis( const NodeID& n ) {
-	NodeID node = n;
-/*	void visShowNodeBubble (
-        NETWORK_ID network,
-        NodeID& node,
-        string label
-        );
-*/
-	using namespace std;
-
-	if (node == nodeId || node.isUnspecified()) return;
-
-	// min/max
-	if ( node < min || min.isUnspecified() ) min = node;
-	if ( node > max || max.isUnspecified() ) max = node;
-
-	// successor
-	if ( succ.isUnspecified() || (node > nodeId && (succ < nodeId || (node-nodeId) < (succ-nodeId))) ) {
-		if (!succ.isUnspecified() && node != succ)
-			ovl.visDisconnect(ovlId, nodeId, succ, string(""));
-		succ = node;
-		ovl.visConnect(ovlId, nodeId, succ, string(""));
-	}
-
-	// set successor (circle-wrap)
-	if (succ.isUnspecified() && !min.isUnspecified()) {
-		succ = min;
-		ovl.visConnect(ovlId, nodeId, succ, string(""));
-	}
-}
-
 const NodeID& BaseOverlay::getNodeID(const LinkID& lid) const {
-
 	if( lid == LinkID::UNSPECIFIED ) return nodeId;
-
-	LinkMapping::const_iterator i = linkMapping.find( lid );
-	if( i == linkMapping.end() ) return NodeID::UNSPECIFIED;
-	else return i->second.node;
+	const LinkDescriptor* ld = getDescriptor(lid);
+	if( ld == NULL ) return NodeID::UNSPECIFIED;
+	else return ld->remoteNode;
 }
 
 vector<LinkID> BaseOverlay::getLinkIDs( const NodeID& nid ) const {
-
 	vector<LinkID> linkvector;
-
-	BOOST_FOREACH( LinkPair item, linkMapping ){
-		if( item.second.node == nid || nid == NodeID::UNSPECIFIED ){
-			linkvector.push_back( item.second.link );
-		}
-	}
-
+	BOOST_FOREACH( LinkDescriptor* ld, links ) {
+		if( ld->remoteNode == nid || nid == NodeID::UNSPECIFIED ) {
+			linkvector.push_back( ld->overlayId );
+		}
+	}
 	return linkvector;
 }
 
-void BaseOverlay::incomingRouteMessage(Message* msg){
-	// gets handled as normal data message
-	receiveMessage( msg, LinkID::UNSPECIFIED, NodeID::UNSPECIFIED );
-}
-
-void BaseOverlay::onNodeJoin(const NodeID& node){
-
+
+void BaseOverlay::onNodeJoin(const NodeID& node) {
 	JoiningNodes::iterator i = std::find( joiningNodes.begin(), joiningNodes.end(), node );
 	if( i == joiningNodes.end() ) return;
 
 	logging_info( "node has successfully joined baseoverlay and overlay structure "
-				<< node.toString() );
+			<< node.toString() );
 
 	joiningNodes.erase( i );
 }
 
-void BaseOverlay::eventFunction(){
-
-	list<LinkID> oldlinks;
+void BaseOverlay::eventFunction() {
+
+	// send keep-alive messages over established links
+	BOOST_FOREACH( LinkDescriptor* ld, links ) {
+		if (!ld->up) continue;
+		OverlayMsg overMsg( OverlayMsg::typeKeepAlive,
+			OverlayInterface::OVERLAY_SERVICE_ID, nodeId );
+		sendMessage( &overMsg, ld );
+	}
+
+	// iterate over all links and check for time boundaries
+	vector<LinkDescriptor*> oldlinks;
 	time_t now = time(NULL);
-
-	// first gather all the links from linkMapping that need droppin
-	// don't directly drop, as the dropLink function affects the
-	// linkMapping structure that we are traversing here.
-	// drop links after a timeout of 30s
-
-	BOOST_FOREACH( LinkPair item, linkMapping ){
-		if( item.second.autolink && difftime(now, item.second.lastuse) > 30)
-			oldlinks.push_back( item.first );
-	}
-
-	BOOST_FOREACH( const LinkID lnk, oldlinks ) {
-		logging_debug( "auto-link " << lnk.toString() << " timed out and is getting dropped" );
-		dropLink( lnk );
-	}
+	BOOST_FOREACH( LinkDescriptor* ld, links ) {
+		// remote used as relay flag
+		if ( ld->usedAsRelay && difftime( now, ld->timeUsedAsRelay ) > 10)
+			ld->usedAsRelay = false;
+
+		// keep alives missed? yes->
+		if ( !ld->up && difftime( now, ld->keepAliveTime ) > 2 ) {
+
+			// increase counter
+			ld->keepAliveMissed++;
+
+			// missed more than four keep-alive messages (4 sec)? -> drop link
+			if (ld->keepAliveMissed > 10) {
+				logging_force( "Link connection request is stale, closing: " << ld );
+				oldlinks.push_back( ld );
+			}
+		}
+
+		if (!ld->up) continue;
+
+		// drop links that are dropped and not used as relay
+		if (ld->dropWhenRelaysLeft && !ld->usedAsRelay && !ld->autolink)
+			oldlinks.push_back( ld );
+		else
+
+		// auto-link time exceeded?
+		if ( ld->autolink && difftime( now, ld->lastuse ) > 30 )
+			oldlinks.push_back( ld );
+
+		else
+
+		// keep alives missed? yes->
+		if ( !ld->autolink && difftime( now, ld->keepAliveTime ) > 2 ) {
+
+			// increase counter
+			ld->keepAliveMissed++;
+
+			// missed more than four keep-alive messages (4 sec)? -> drop link
+			if (ld->keepAliveMissed >= 8) {
+				logging_force( "Link is stale, closing: " << ld );
+				oldlinks.push_back( ld );
+			}
+		}
+	}
+
+	// show link state
+	counter++;
+	if (counter>=4) showLinkState();
+	if (counter>=4 || counter<0) counter = 0;
+
+	// drop links
+	BOOST_FOREACH( const LinkDescriptor* ld, oldlinks ) {
+		if (!ld->communicationId.isUnspecified() && ld->communicationId == initiatorLink) {
+			logging_force( "Not dropping initiator link: " << ld );
+			continue;
+		}
+		logging_force( "Link timed out. Dropping " << ld );
+		dropLink( ld->overlayId );
+	}
+}
+
+void BaseOverlay::showLinkState() {
+	int i=0;
+	logging_force("--- link state -------------------------------");
+	BOOST_FOREACH( LinkDescriptor* ld, links ) {
+		logging_force("link " << i << ": " << ld);
+		i++;
+	}
+	logging_force("----------------------------------------------");
 }
 
