Kaynağa Gözat

Implement peer serialization and deserialization.

Adam Ierymenko 8 yıl önce
ebeveyn
işleme
64758c46b6
5 değiştirilmiş dosya ile 132 ekleme ve 12 silme
  1. 1 1
      node/Peer.cpp
  2. 84 0
      node/Peer.hpp
  3. 25 6
      node/Topology.cpp
  4. 2 0
      node/Topology.hpp
  5. 20 5
      service/OneService.cpp

+ 1 - 1
node/Peer.cpp

@@ -369,7 +369,7 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now)
 		_lastTriedMemorizedPath = now;
 		InetAddress mp;
 		if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp))
-			attemptToContactAt(tPtr,InetAddress(),mp,now,true,0);
+			attemptToContactAt(tPtr,-1,mp,now,true,0);
 	}
 }
 

+ 84 - 0
node/Peer.hpp

@@ -439,6 +439,90 @@ public:
 		return false;
 	}
 
+	/**
+	 * Serialize a peer for storage in local cache
+	 *
+	 * This does not serialize everything, just identity and addresses where the peer
+	 * may be reached.
+	 */
+	template<unsigned int C>
+	inline void serialize(Buffer<C> &b) const
+	{
+		b.append((uint8_t)0);
+
+		_id.serialize(b);
+
+		b.append(_lastReceive);
+		b.append(_lastNontrivialReceive);
+		b.append(_lastTriedMemorizedPath);
+		b.append(_lastDirectPathPushSent);
+		b.append(_lastDirectPathPushReceive);
+		b.append(_lastCredentialRequestSent);
+		b.append(_lastWhoisRequestReceived);
+		b.append(_lastEchoRequestReceived);
+		b.append(_lastComRequestReceived);
+		b.append(_lastComRequestSent);
+		b.append(_lastCredentialsReceived);
+		b.append(_lastTrustEstablishedPacketReceived);
+
+		b.append((uint16_t)_vProto);
+		b.append((uint16_t)_vMajor);
+		b.append((uint16_t)_vMinor);
+		b.append((uint16_t)_vRevision);
+
+		{
+			Mutex::Lock _l(_paths_m);
+			unsigned int pcount = 0;
+			if (_v4Path.p) ++pcount;
+			if (_v6Path.p) ++pcount;
+			b.append((uint8_t)pcount);
+			if (_v4Path.p) _v4Path.p->address().serialize(b);
+			if (_v6Path.p) _v6Path.p->address().serialize(b);
+		}
+
+		b.append((uint16_t)0);
+	}
+
+	template<unsigned int C>
+	inline static SharedPtr<Peer> deserializeFromCache(uint64_t now,void *tPtr,Buffer<C> &b,const RuntimeEnvironment *renv)
+	{
+		try {
+			unsigned int ptr = 0;
+			if (b[ptr++] != 0)
+				return SharedPtr<Peer>();
+
+			Identity id;
+			ptr += id.deserialize(b,ptr);
+			if (!id)
+				return SharedPtr<Peer>();
+
+			SharedPtr<Peer> p(new Peer(renv,renv->identity,id));
+
+			ptr += 12 * 8; // skip deserializing ephemeral state in this case
+
+			p->_vProto = b.template at<uint16_t>(ptr); ptr += 2;
+			p->_vMajor = b.template at<uint16_t>(ptr); ptr += 2;
+			p->_vMinor = b.template at<uint16_t>(ptr); ptr += 2;
+			p->_vRevision = b.template at<uint16_t>(ptr); ptr += 2;
+
+			const unsigned int pcount = (unsigned int)b[ptr++];
+			for(unsigned int i=0;i<pcount;++i) {
+				InetAddress inaddr;
+				try {
+					ptr += inaddr.deserialize(b,ptr);
+					if (inaddr)
+						p->attemptToContactAt(tPtr,-1,inaddr,now,true,0);
+				} catch ( ... ) {
+					break;
+				}
+			}
+
+			return p;
+		} catch ( ... ) {
+			return SharedPtr<Peer>();
+		}
+	}
+
 private:
 	struct _PeerPath
 	{

+ 25 - 6
node/Topology.cpp

@@ -88,6 +88,15 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
 	addWorld(tPtr,defaultPlanet,false);
 }
 
+Topology::~Topology()
+{
+	Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
+	Address *a = (Address *)0;
+	SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+	while (i.next(a,p))
+		_savePeer((void *)0,*p);
+}
+
 SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
 {
 	SharedPtr<Peer> np;
@@ -113,23 +122,21 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
 			return *ap;
 	}
 
-	/*
 	try {
-		char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE];
+		Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf;
 		uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0;
-		int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf));
+		int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE);
 		if (len > 0) {
 			Mutex::Lock _l(_peers_m);
 			SharedPtr<Peer> &ap = _peers[zta];
 			if (ap)
 				return ap;
-			ap = Peer::createFromStateUpdate(RR,tPtr,buf,len);
+			ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR);
 			if (!ap)
 				_peers.erase(zta);
 			return ap;
 		}
 	} catch ( ... ) {} // ignore invalid identities or other strage failures
-	*/
 
 	return SharedPtr<Peer>();
 }
@@ -383,8 +390,10 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now)
 		Address *a = (Address *)0;
 		SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
 		while (i.next(a,p)) {
-			if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) )
+			if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) {
+				_savePeer(tPtr,*p);
 				_peers.erase(*a);
+			}
 		}
 	}
 
@@ -440,4 +449,14 @@ void Topology::_memoizeUpstreams(void *tPtr)
 	_cor.sign(RR->identity,RR->node->now());
 }
 
+void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
+{
+	try {
+		Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf;
+		peer->serialize(buf);
+		uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0;
+		RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size());
+	} catch ( ... ) {} // sanity check, discard invalid entries
+}
+
 } // namespace ZeroTier

+ 2 - 0
node/Topology.hpp

@@ -59,6 +59,7 @@ class Topology
 {
 public:
 	Topology(const RuntimeEnvironment *renv,void *tPtr);
+	~Topology();
 
 	/**
 	 * Add a peer to database
@@ -419,6 +420,7 @@ public:
 private:
 	Identity _getIdentity(void *tPtr,const Address &zta);
 	void _memoizeUpstreams(void *tPtr);
+	void _savePeer(void *tPtr,const SharedPtr<Peer> &peer);
 
 	const RuntimeEnvironment *const RR;
 

+ 20 - 5
service/OneService.cpp

@@ -2047,6 +2047,8 @@ public:
 		char p[1024];
 		FILE *f;
 		bool secure = false;
+		char dirname[1024];
+		dirname[0] = 0;
 
 		switch(type) {
 			case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
@@ -2060,12 +2062,18 @@ public:
 				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
 				break;
 			case ZT_STATE_OBJECT_MOON:
-				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]);
+				OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str());
+				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]);
 				break;
 			case ZT_STATE_OBJECT_NETWORK_CONFIG:
-				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
+				OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str());
+				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]);
 				secure = true;
 				break;
+			case ZT_STATE_OBJECT_PEER:
+				OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str());
+				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]);
+				break;
 			default:
 				return;
 		}
@@ -2084,6 +2092,10 @@ public:
 			}
 
 			f = fopen(p,"w");
+			if ((!f)&&(dirname[0])) { // create subdirectory if it does not exist
+				OSUtils::mkdir(dirname);
+				f = fopen(p,"w");
+			}
 			if (f) {
 				if (fwrite(data,len,1,f) != 1)
 					fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p);
@@ -2108,15 +2120,18 @@ public:
 			case ZT_STATE_OBJECT_IDENTITY_SECRET:
 				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
 				break;
-			case ZT_STATE_OBJECT_NETWORK_CONFIG:
-				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id);
-				break;
 			case ZT_STATE_OBJECT_PLANET:
 				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
 				break;
 			case ZT_STATE_OBJECT_MOON:
 				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id);
 				break;
+			case ZT_STATE_OBJECT_NETWORK_CONFIG:
+				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id);
+				break;
+			case ZT_STATE_OBJECT_PEER:
+				OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d/%.10llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
+				break;
 			default:
 				return -1;
 		}