Browse Source

Peers are now dumped on shutdown in a persistence cache and reloaded on startup, which is good enough for clients right now. Supernodes will get something else for long-term authoritative identity caching.

Adam Ierymenko 11 years ago
parent
commit
40e4f39181
6 changed files with 113 additions and 4 deletions
  1. 1 1
      Makefile.linux
  2. 5 0
      node/Constants.hpp
  3. 2 1
      node/Network.cpp
  4. 0 2
      node/Peer.hpp
  5. 102 0
      node/Topology.cpp
  6. 3 0
      node/Topology.hpp

+ 1 - 1
Makefile.linux

@@ -3,7 +3,7 @@ CXX=g++
 
 INCLUDES=
 ARCH=$(shell uname -m)
-DEFS=-DZT_ARCH="$(ARCH)" -DZT_OSNAME="linux" -DZT_TRACE
+DEFS=-DZT_ARCH="$(ARCH)" -DZT_OSNAME="linux"
 LIBS=
 
 # Uncomment for a release optimized build

+ 5 - 0
node/Constants.hpp

@@ -208,6 +208,11 @@ error_no_ZT_ARCH_defined;
  */
 #define ZT_DB_CLEAN_PERIOD 300000
 
+/**
+ * How long to remember peers in RAM if they haven't been used
+ */
+#define ZT_PEER_IN_MEMORY_EXPIRATION 600000
+
 /**
  * Delay between WHOIS retries in ms
  */

+ 2 - 1
node/Network.cpp

@@ -37,7 +37,7 @@
 #include "Packet.hpp"
 #include "Buffer.hpp"
 
-#define ZT_NETWORK_CERT_WRITE_BUF_SIZE 524288
+#define ZT_NETWORK_CERT_WRITE_BUF_SIZE 131072
 
 namespace ZeroTier {
 
@@ -324,6 +324,7 @@ void Network::_dumpMulticastCerts()
 	if (!mcdb)
 		return;
 	if (fwrite("ZTMCD0",6,1,mcdb) != 1) {
+		fclose(mcdb);
 		Utils::rm(mcdbPath);
 		return;
 	}

+ 0 - 2
node/Peer.hpp

@@ -349,7 +349,6 @@ public:
 
 	template<unsigned int C>
 	inline void serialize(Buffer<C> &b)
-		throw(std::out_of_range)
 	{
 		b.append((unsigned char)4); // version
 		b.append(_key,sizeof(_key));
@@ -367,7 +366,6 @@ public:
 
 	template<unsigned int C>
 	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-		throw(std::out_of_range,std::invalid_argument)
 	{
 		unsigned int p = startAt;
 

+ 102 - 0
node/Topology.cpp

@@ -31,16 +31,21 @@
 #include "NodeConfig.hpp"
 #include "CMWC4096.hpp"
 
+#define ZT_PEER_WRITE_BUF_SIZE 131072
+
 namespace ZeroTier {
 
 Topology::Topology(const RuntimeEnvironment *renv) :
 	_r(renv),
 	_amSupernode(false)
 {
+	_loadPeers();
 }
 
 Topology::~Topology()
 {
+	clean();
+	_dumpPeers();
 }
 
 void Topology::setSupernodes(const std::map< Identity,std::vector<InetAddress> > &sn)
@@ -159,6 +164,103 @@ skip_and_try_next_supernode:
 
 void Topology::clean()
 {
+	uint64_t now = Utils::now();
+	Mutex::Lock _l(_activePeers_m);
+	Mutex::Lock _l2(_supernodes_m);
+	for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();) {
+		if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(!_supernodeAddresses.count(p->second->address())))
+			_activePeers.erase(p++);
+		else ++p;
+	}
+}
+
+void Topology::_dumpPeers()
+{
+	Buffer<ZT_PEER_WRITE_BUF_SIZE> buf;
+	std::string pdpath(_r->homePath + ZT_PATH_SEPARATOR_S + "peers.persist");
+	Mutex::Lock _l(_activePeers_m);
+
+	FILE *pd = fopen(pdpath.c_str(),"wb");
+	if (!pd)
+		return;
+	if (fwrite("ZTPD0",5,1,pd) != 1) {
+		fclose(pd);
+		Utils::rm(pdpath);
+		return;
+	}
+
+	for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();++p) {
+		try {
+			p->second->serialize(buf);
+			if (buf.size() >= (ZT_PEER_WRITE_BUF_SIZE / 2)) {
+				if (fwrite(buf.data(),buf.size(),1,pd) != 1) {
+					fclose(pd);
+					Utils::rm(pdpath);
+					return;
+				}
+				buf.clear();
+			}
+		} catch ( ... ) {
+			fclose(pd);
+			Utils::rm(pdpath);
+			return;
+		}
+	}
+
+	if (buf.size()) {
+		if (fwrite(buf.data(),buf.size(),1,pd) != 1) {
+			fclose(pd);
+			Utils::rm(pdpath);
+			return;
+		}
+	}
+
+	fclose(pd);
+	Utils::lockDownFile(pdpath.c_str(),false);
+}
+
+void Topology::_loadPeers()
+{
+	Buffer<ZT_PEER_WRITE_BUF_SIZE> buf;
+	std::string pdpath(_r->homePath + ZT_PATH_SEPARATOR_S + "peers.persist");
+	Mutex::Lock _l(_activePeers_m);
+
+	_activePeers.clear();
+
+	FILE *pd = fopen(pdpath.c_str(),"rb");
+	if (!pd)
+		return;
+
+	try {
+		char magic[5];
+		if ((fread(magic,5,1,pd) == 1)&&(!memcmp("ZTPD0",magic,5))) {
+			long rlen = 0;
+			do {
+				long rlen = (long)fread(buf.data() + buf.size(),1,ZT_PEER_WRITE_BUF_SIZE - buf.size(),pd);
+				if (rlen < 0) rlen = 0;
+				buf.setSize(buf.size() + (unsigned int)rlen);
+				unsigned int ptr = 0;
+				while ((ptr < (ZT_PEER_WRITE_BUF_SIZE / 2))&&(ptr < buf.size())) {
+					SharedPtr<Peer> p(new Peer());
+					ptr += p->deserialize(buf,ptr);
+					_activePeers[p->address()] = p;
+				}
+				if (ptr) {
+					memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);
+					buf.setSize(buf.size() - ptr);
+				}
+			} while (rlen > 0);
+			fclose(pd);
+		} else {
+			fclose(pd);
+			Utils::rm(pdpath);
+		}
+	} catch ( ... ) {
+		// Membership cert dump file invalid. We'll re-learn them off the net.
+		_activePeers.clear();
+		fclose(pd);
+		Utils::rm(pdpath);
+	}
 }
 
 } // namespace ZeroTier

+ 3 - 0
node/Topology.hpp

@@ -271,6 +271,9 @@ public:
 private:
 	const RuntimeEnvironment *const _r;
 
+	void _dumpPeers();
+	void _loadPeers();
+
 	std::map< Address,SharedPtr<Peer> > _activePeers;
 	Mutex _activePeers_m;