From 88a4a3b1bae97548142b73031ff415db6ebd31d0 Mon Sep 17 00:00:00 2001
From: Adam Ierymenko <adam.ierymenko@gmail.com>
Date: Tue, 11 Apr 2017 08:47:02 -0700
Subject: [PATCH] Pass tptr on leave.

---
 node/Network.cpp | 12 +++++++++++-
 node/Network.hpp |  7 +++----
 node/Node.cpp    | 21 +++++++++++++++------
 3 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/node/Network.cpp b/node/Network.cpp
index 3c607b28c..b7f25f7fa 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -729,7 +729,8 @@ Network::~Network()
 
 	char n[128];
 	if (_destroyed) {
-		RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
+		// This is done in Node::leave() so we can pass tPtr
+		//RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
 		Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
 		RR->node->dataStoreDelete((void *)0,n);
 	} else {
@@ -993,6 +994,9 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg)
 
 uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
 {
+	if (_destroyed)
+		return 0;
+
 	const unsigned int start = ptr;
 
 	ptr += 8; // skip network ID, which is already obviously known
@@ -1140,6 +1144,9 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
 
 int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk)
 {
+	if (_destroyed)
+		return 0;
+
 	// _lock is NOT locked when this is called
 	try {
 		if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
@@ -1190,6 +1197,9 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
 
 void Network::requestConfiguration(void *tPtr)
 {
+	if (_destroyed)
+		return;
+
 	/* ZeroTier addresses can't begin with 0xff, so this is used to mark controllerless
 	 * network IDs. Controllerless network IDs only support unicast IPv6 using the 6plane
 	 * addressing scheme and have the following format: 0xffSSSSEEEE000000 where SSSS
diff --git a/node/Network.hpp b/node/Network.hpp
index fccc267a3..faef0fed1 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -344,9 +344,8 @@ public:
 	/**
 	 * Destroy this network
 	 *
-	 * This causes the network to disable itself, destroy its tap device, and on
-	 * delete to delete all trace of itself on disk and remove any persistent tap
-	 * device instances. Call this when a network is being removed from the system.
+	 * This sets the network to completely remove itself on delete. This also prevents the
+	 * call of the normal port shutdown event on delete.
 	 */
 	void destroy();
 
@@ -364,7 +363,7 @@ public:
 	/**
 	 * @return Externally usable pointer-to-pointer exported via the core API
 	 */
-	inline void **userPtr() throw() { return &_uPtr; }
+	inline void **userPtr() { return &_uPtr; }
 
 private:
 	ZT_VirtualNetworkStatus _status() const;
diff --git a/node/Node.cpp b/node/Node.cpp
index e7dc637f4..9844b09e8 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -305,26 +305,35 @@ ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr)
 {
 	Mutex::Lock _l(_networks_m);
 	SharedPtr<Network> nw = _network(nwid);
-	if(!nw)
-		_networks.push_back(std::pair< uint64_t,SharedPtr<Network> >(nwid,SharedPtr<Network>(new Network(RR,tptr,nwid,uptr))));
-	std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<>
+	if(!nw) {
+		const std::pair< uint64_t,SharedPtr<Network> > nn(nwid,SharedPtr<Network>(new Network(RR,tptr,nwid,uptr)));
+		_networks.insert(std::upper_bound(_networks.begin(),_networks.end(),nn),nn);
+	}
 	return ZT_RESULT_OK;
 }
 
 ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
 {
+	ZT_VirtualNetworkConfig ctmp;
 	std::vector< std::pair< uint64_t,SharedPtr<Network> > > newn;
+	void **nUserPtr = (void **)0;
 	Mutex::Lock _l(_networks_m);
+
 	for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
-		if (n->first != nwid)
+		if (n->first != nwid) {
 			newn.push_back(*n);
-		else {
+		} else {
 			if (uptr)
-				*uptr = n->second->userPtr();
+				*uptr = *n->second->userPtr();
 			n->second->destroy();
+			nUserPtr = n->second->userPtr();
 		}
 	}
 	_networks.swap(newn);
+ 
+	if (nUserPtr)
+		RR->node->configureVirtualNetworkPort(tptr,nwid,nUserPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
+
 	return ZT_RESULT_OK;
 }